1 /* $NetBSD: satmgr.c,v 1.31 2021/09/26 01:16:08 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 2010 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Tohru Nishimura.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/device.h>
36 #include <sys/conf.h>
37 #include <sys/proc.h>
38 #include <sys/vnode.h>
39 #include <sys/select.h>
40 #include <sys/poll.h>
41 #include <sys/callout.h>
42 #include <sys/sysctl.h>
43 #include <sys/reboot.h>
44 #include <sys/intr.h>
45
46 #include <dev/sysmon/sysmonvar.h>
47 #include <dev/sysmon/sysmon_taskq.h>
48
49 #include <dev/ic/comreg.h>
50
51 #include <sys/bus.h>
52 #include <machine/intr.h>
53 #include <machine/bootinfo.h>
54
55 #include <sandpoint/sandpoint/eumbvar.h>
56 #include "locators.h"
57
58
59 struct satops;
60
61 struct satmgr_softc {
62 device_t sc_dev;
63 bus_space_tag_t sc_iot;
64 bus_space_handle_t sc_ioh;
65 struct selinfo sc_rsel;
66 callout_t sc_ch_wdog;
67 callout_t sc_ch_pbutton;
68 callout_t sc_ch_sync;
69 struct sysmon_pswitch sc_sm_pbutton;
70 int sc_open;
71 void *sc_si;
72 uint32_t sc_ierror, sc_overr;
73 kmutex_t sc_lock;
74 kcondvar_t sc_rdcv, sc_wrcv;
75 char sc_rd_buf[16];
76 char *sc_rd_lim, *sc_rd_cur, *sc_rd_ptr;
77 char sc_wr_buf[16];
78 char *sc_wr_lim, *sc_wr_cur, *sc_wr_ptr;
79 int sc_rd_cnt, sc_wr_cnt;
80 struct satops *sc_ops;
81 char sc_btn_buf[8];
82 int sc_btn_cnt;
83 char sc_cmd_buf[8];
84 kmutex_t sc_replk;
85 kcondvar_t sc_repcv;
86 int sc_sysctl_wdog;
87 int sc_sysctl_fanlow;
88 int sc_sysctl_fanhigh;
89 };
90
91 static int satmgr_match(device_t, cfdata_t, void *);
92 static void satmgr_attach(device_t, device_t, void *);
93
94 CFATTACH_DECL_NEW(satmgr, sizeof(struct satmgr_softc),
95 satmgr_match, satmgr_attach, NULL, NULL);
96 extern struct cfdriver satmgr_cd;
97
98 static int found = 0;
99 extern void (*md_reboot)(int);
100
101 static dev_type_open(satopen);
102 static dev_type_close(satclose);
103 static dev_type_read(satread);
104 static dev_type_write(satwrite);
105 static dev_type_poll(satpoll);
106 static dev_type_kqfilter(satkqfilter);
107
108 const struct cdevsw satmgr_cdevsw = {
109 .d_open = satopen,
110 .d_close = satclose,
111 .d_read = satread,
112 .d_write = satwrite,
113 .d_ioctl = noioctl,
114 .d_stop = nostop,
115 .d_tty = notty,
116 .d_poll = satpoll,
117 .d_mmap = nommap,
118 .d_kqfilter = satkqfilter,
119 .d_discard = nodiscard,
120 .d_flag = D_OTHER
121 };
122
123 static void satmgr_reboot(int);
124 static int satmgr_sysctl_wdogenable(SYSCTLFN_PROTO);
125 static int satmgr_sysctl_fanlow(SYSCTLFN_PROTO);
126 static int satmgr_sysctl_fanhigh(SYSCTLFN_PROTO);
127 static void wdog_tickle(void *);
128 static void send_sat(struct satmgr_softc *, const char *);
129 static void send_sat_len(struct satmgr_softc *, const char *, int);
130 static int hwintr(void *);
131 static void rxintr(struct satmgr_softc *);
132 static void txintr(struct satmgr_softc *);
133 static void startoutput(struct satmgr_softc *);
134 static void swintr(void *);
135 static void minit(device_t);
136 static void sinit(device_t);
137 static void qinit(device_t);
138 static void iinit(device_t);
139 static void kreboot(struct satmgr_softc *);
140 static void mreboot(struct satmgr_softc *);
141 static void sreboot(struct satmgr_softc *);
142 static void qreboot(struct satmgr_softc *);
143 static void ireboot(struct satmgr_softc *);
144 static void kpwroff(struct satmgr_softc *);
145 static void mpwroff(struct satmgr_softc *);
146 static void spwroff(struct satmgr_softc *);
147 static void qpwroff(struct satmgr_softc *);
148 static void dpwroff(struct satmgr_softc *);
149 static void ipwroff(struct satmgr_softc *);
150 static void kbutton(struct satmgr_softc *, int);
151 static void mbutton(struct satmgr_softc *, int);
152 static void sbutton(struct satmgr_softc *, int);
153 static void qbutton(struct satmgr_softc *, int);
154 static void dbutton(struct satmgr_softc *, int);
155 static void ibutton(struct satmgr_softc *, int);
156 static void msattalk(struct satmgr_softc *, const char *);
157 static void isattalk(struct satmgr_softc *, int, int, int, int, int, int);
158 static int mbtnintr(void *);
159 static void guarded_pbutton(void *);
160 static void sched_sysmon_pbutton(void *);
161
162 struct satops {
163 const char *family;
164 void (*init)(device_t);
165 void (*reboot)(struct satmgr_softc *);
166 void (*pwroff)(struct satmgr_softc *);
167 void (*dispatch)(struct satmgr_softc *, int);
168 };
169
170 static struct satops satmodel[] = {
171 { "dlink", NULL, NULL, dpwroff, dbutton },
172 { "iomega", iinit, ireboot, ipwroff, ibutton },
173 { "kurobox", NULL, kreboot, kpwroff, kbutton },
174 { "kurot4", minit, mreboot, mpwroff, mbutton },
175 { "qnap", qinit, qreboot, qpwroff, qbutton },
176 { "synology", sinit, sreboot, spwroff, sbutton }
177 };
178
179 /* single byte stride register layout */
180 #define RBR 0
181 #define THR 0
182 #define DLB 0
183 #define IER 1
184 #define DMB 1
185 #define IIR 2
186 #define LCR 3
187 #define LSR 5
188 #define CSR_READ(t,r) bus_space_read_1((t)->sc_iot, (t)->sc_ioh, (r))
189 #define CSR_WRITE(t,r,v) bus_space_write_1((t)->sc_iot, (t)->sc_ioh, (r), (v))
190
191 static int
satmgr_match(device_t parent,cfdata_t match,void * aux)192 satmgr_match(device_t parent, cfdata_t match, void *aux)
193 {
194 struct eumb_attach_args *eaa = aux;
195 int unit = eaa->eumb_unit;
196
197 if (unit == EUMBCF_UNIT_DEFAULT && found == 0)
198 return 1;
199 if (unit == 0 || unit == 1)
200 return 1;
201 return 0;
202 }
203
204 static void
satmgr_attach(device_t parent,device_t self,void * aux)205 satmgr_attach(device_t parent, device_t self, void *aux)
206 {
207 struct eumb_attach_args *eaa = aux;
208 struct satmgr_softc *sc = device_private(self);
209 struct btinfo_prodfamily *pfam;
210 struct satops *ops;
211 int i, sataddr, epicirq;
212 char intr_xname[INTRDEVNAMEBUF];
213
214 found = 1;
215
216 if ((pfam = lookup_bootinfo(BTINFO_PRODFAMILY)) == NULL)
217 goto notavail;
218 ops = NULL;
219 for (i = 0; i < (int)(sizeof(satmodel)/sizeof(satmodel[0])); i++) {
220 if (strcmp(pfam->name, satmodel[i].family) == 0) {
221 ops = &satmodel[i];
222 break;
223 }
224 }
225 if (ops == NULL)
226 goto notavail;
227 aprint_naive(": button manager\n");
228 aprint_normal(": button manager (%s)\n", ops->family);
229 sc->sc_ops = ops;
230
231 sc->sc_dev = self;
232 sataddr = (eaa->eumb_unit == 0) ? 0x4500 : 0x4600;
233 sc->sc_iot = eaa->eumb_bt;
234 bus_space_map(eaa->eumb_bt, sataddr, 0x20, 0, &sc->sc_ioh);
235 sc->sc_open = 0;
236 sc->sc_rd_cnt = 0;
237 sc->sc_rd_cur = sc->sc_rd_ptr = &sc->sc_rd_buf[0];
238 sc->sc_rd_lim = sc->sc_rd_cur + sizeof(sc->sc_rd_buf);
239 sc->sc_wr_cnt = 0;
240 sc->sc_wr_cur = sc->sc_wr_ptr = &sc->sc_wr_buf[0];
241 sc->sc_wr_lim = sc->sc_wr_cur + sizeof(sc->sc_wr_buf);
242 sc->sc_ierror = sc->sc_overr = 0;
243 selinit(&sc->sc_rsel);
244 callout_init(&sc->sc_ch_wdog, 0);
245 callout_init(&sc->sc_ch_pbutton, 0);
246 callout_init(&sc->sc_ch_sync, 0);
247 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_HIGH);
248 cv_init(&sc->sc_rdcv, "satrd");
249 cv_init(&sc->sc_wrcv, "satwr");
250 sc->sc_btn_cnt = 0;
251 mutex_init(&sc->sc_replk, MUTEX_DEFAULT, IPL_SERIAL);
252 cv_init(&sc->sc_repcv, "stalk");
253
254 epicirq = (eaa->eumb_unit == 0) ? 24 : 25;
255 intr_establish_xname(epicirq + I8259_ICU, IST_LEVEL, IPL_SERIAL,
256 hwintr, sc, device_xname(self));
257 aprint_normal_dev(self, "interrupting at irq %d\n",
258 epicirq + I8259_ICU);
259 sc->sc_si = softint_establish(SOFTINT_SERIAL, swintr, sc);
260
261 CSR_WRITE(sc, IER, 0x7f); /* all but MSR */
262
263 if (!pmf_device_register(sc->sc_dev, NULL, NULL))
264 aprint_error_dev(sc->sc_dev, "couldn't establish handler\n");
265
266 sysmon_task_queue_init();
267 memset(&sc->sc_sm_pbutton, 0, sizeof(struct sysmon_pswitch));
268 sc->sc_sm_pbutton.smpsw_name = device_xname(sc->sc_dev);
269 sc->sc_sm_pbutton.smpsw_type = PSWITCH_TYPE_POWER;
270 if (sysmon_pswitch_register(&sc->sc_sm_pbutton) != 0)
271 aprint_error_dev(sc->sc_dev,
272 "unable to register power button with sysmon\n");
273
274 /* create machdep.satmgr subtree for those models which support it */
275 if (strcmp(ops->family, "kurobox") == 0) {
276 const struct sysctlnode *rnode;
277 struct sysctllog *clog;
278
279 clog = NULL;
280 sysctl_createv(&clog, 0, NULL, &rnode,
281 CTLFLAG_PERMANENT,
282 CTLTYPE_NODE, "machdep", NULL,
283 NULL, 0, NULL, 0,
284 CTL_MACHDEP, CTL_EOL);
285 sysctl_createv(&clog, 0, &rnode, &rnode,
286 CTLFLAG_PERMANENT,
287 CTLTYPE_NODE, "satmgr", NULL,
288 NULL, 0, NULL, 0,
289 CTL_CREATE, CTL_EOL);
290 sysctl_createv(&clog, 0, &rnode, NULL,
291 CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
292 CTLTYPE_INT, "hwwdog_enable",
293 SYSCTL_DESCR("watchdog enable"),
294 satmgr_sysctl_wdogenable, 0, NULL, 0,
295 CTL_CREATE, CTL_EOL);
296 }
297 else if (strcmp(ops->family, "iomega") == 0) {
298 const struct sysctlnode *rnode;
299 struct sysctllog *clog;
300
301 clog = NULL;
302 sysctl_createv(&clog, 0, NULL, &rnode,
303 CTLFLAG_PERMANENT,
304 CTLTYPE_NODE, "machdep", NULL,
305 NULL, 0, NULL, 0,
306 CTL_MACHDEP, CTL_EOL);
307 sysctl_createv(&clog, 0, &rnode, &rnode,
308 CTLFLAG_PERMANENT,
309 CTLTYPE_NODE, "satmgr", NULL,
310 NULL, 0, NULL, 0,
311 CTL_CREATE, CTL_EOL);
312 sysctl_createv(&clog, 0, &rnode, NULL,
313 CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
314 CTLTYPE_INT, "fan_low_temp",
315 SYSCTL_DESCR("Turn off fan below this temperature"),
316 satmgr_sysctl_fanlow, 0, NULL, 0,
317 CTL_CREATE, CTL_EOL);
318 sysctl_createv(&clog, 0, &rnode, NULL,
319 CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
320 CTLTYPE_INT, "fan_high_temp",
321 SYSCTL_DESCR("Turn on fan above this temperature"),
322 satmgr_sysctl_fanhigh, 0, NULL, 0,
323 CTL_CREATE, CTL_EOL);
324 }
325 else if (strcmp(ops->family, "kurot4") == 0) {
326 snprintf(intr_xname, sizeof(intr_xname), "%s mbtn",
327 device_xname(self));
328 intr_establish_xname(2 + I8259_ICU,
329 IST_LEVEL, IPL_SERIAL, mbtnintr, sc, intr_xname);
330 }
331
332 md_reboot = satmgr_reboot; /* cpu_reboot() hook */
333 if (ops->init != NULL) /* init sat.cpu, LEDs, etc. */
334 config_interrupts(self, ops->init);
335 return;
336
337 notavail:
338 aprint_normal(": button manager (not supported)\n");
339 }
340
341 static void
satmgr_reboot(int howto)342 satmgr_reboot(int howto)
343 {
344 struct satmgr_softc *sc = device_lookup_private(&satmgr_cd, 0);
345
346 if ((howto & RB_POWERDOWN) == RB_AUTOBOOT) {
347 if (sc->sc_ops->reboot != NULL)
348 (*sc->sc_ops->reboot)(sc); /* REBOOT */
349 else
350 return; /* default reboot */
351 } else
352 if (sc->sc_ops->pwroff != NULL)
353 (*sc->sc_ops->pwroff)(sc); /* HALT or POWERDOWN */
354
355 tsleep(satmgr_reboot, PWAIT, "reboot", 0);
356 /*NOTREACHED*/
357 }
358
359 static int
satmgr_sysctl_wdogenable(SYSCTLFN_ARGS)360 satmgr_sysctl_wdogenable(SYSCTLFN_ARGS)
361 {
362 struct sysctlnode node;
363 struct satmgr_softc *sc;
364 int error, t;
365
366 sc = device_lookup_private(&satmgr_cd, 0);
367 node = *rnode;
368 t = sc->sc_sysctl_wdog;
369 node.sysctl_data = &t;
370 error = sysctl_lookup(SYSCTLFN_CALL(&node));
371 if (error || newp == NULL)
372 return error;
373 if (t < 0 || t > 1)
374 return EINVAL;
375
376 sc->sc_sysctl_wdog = t;
377 if (t == 1) {
378 callout_setfunc(&sc->sc_ch_wdog, wdog_tickle, sc);
379 callout_schedule(&sc->sc_ch_wdog, 90 * hz);
380 send_sat(sc, "JJ");
381 } else {
382 callout_stop(&sc->sc_ch_wdog);
383 send_sat(sc, "KK");
384 }
385 return 0;
386 }
387
388 /* disarm watchdog timer periodically */
389 static void
wdog_tickle(void * arg)390 wdog_tickle(void *arg)
391 {
392 struct satmgr_softc *sc = arg;
393
394 send_sat(sc, "GG");
395 callout_schedule(&sc->sc_ch_wdog, 90 * hz);
396 }
397
398 static int
satmgr_sysctl_fanlow(SYSCTLFN_ARGS)399 satmgr_sysctl_fanlow(SYSCTLFN_ARGS)
400 {
401 struct sysctlnode node;
402 struct satmgr_softc *sc;
403 int error, t;
404
405 sc = device_lookup_private(&satmgr_cd, 0);
406 node = *rnode;
407 t = sc->sc_sysctl_fanlow;
408 node.sysctl_data = &t;
409 error = sysctl_lookup(SYSCTLFN_CALL(&node));
410 if (error || newp == NULL)
411 return error;
412 if (t < 0 || t > 99)
413 return EINVAL;
414 sc->sc_sysctl_fanlow = t;
415 isattalk(sc, 'b', 'b', 10, 'a',
416 sc->sc_sysctl_fanhigh, sc->sc_sysctl_fanlow);
417 return 0;
418 }
419
420 static int
satmgr_sysctl_fanhigh(SYSCTLFN_ARGS)421 satmgr_sysctl_fanhigh(SYSCTLFN_ARGS)
422 {
423 struct sysctlnode node;
424 struct satmgr_softc *sc;
425 int error, t;
426
427 sc = device_lookup_private(&satmgr_cd, 0);
428 node = *rnode;
429 t = sc->sc_sysctl_fanhigh;
430 node.sysctl_data = &t;
431 error = sysctl_lookup(SYSCTLFN_CALL(&node));
432 if (error || newp == NULL)
433 return error;
434 if (t < 0 || t > 99)
435 return EINVAL;
436 sc->sc_sysctl_fanhigh = t;
437 isattalk(sc, 'b', 'b', 10, 'a',
438 sc->sc_sysctl_fanhigh, sc->sc_sysctl_fanlow);
439 return 0;
440 }
441
442 static void
send_sat(struct satmgr_softc * sc,const char * msg)443 send_sat(struct satmgr_softc *sc, const char *msg)
444 {
445
446 send_sat_len(sc, msg, strlen(msg));
447 }
448
449
450 static void
send_sat_len(struct satmgr_softc * sc,const char * msg,int len)451 send_sat_len(struct satmgr_softc *sc, const char *msg, int len)
452 {
453 unsigned lsr;
454 int n;
455
456 again:
457 do {
458 lsr = CSR_READ(sc, LSR);
459 } while ((lsr & LSR_TXRDY) == 0);
460 n = 16; /* FIFO depth */
461 while (len-- > 0 && n-- > 0)
462 CSR_WRITE(sc, THR, *msg++);
463 if (len > 0)
464 goto again;
465 }
466
467 static int
satopen(dev_t dev,int flags,int fmt,struct lwp * l)468 satopen(dev_t dev, int flags, int fmt, struct lwp *l)
469 {
470 struct satmgr_softc *sc;
471
472 sc = device_lookup_private(&satmgr_cd, 0);
473 if (sc == NULL)
474 return ENXIO;
475 if (sc->sc_open > 0)
476 return EBUSY;
477 sc->sc_open = 1;
478 return 0;
479 }
480
481 static int
satclose(dev_t dev,int flags,int fmt,struct lwp * l)482 satclose(dev_t dev, int flags, int fmt, struct lwp *l)
483 {
484 struct satmgr_softc *sc;
485
486 sc = device_lookup_private(&satmgr_cd, 0);
487 if (sc == NULL)
488 return ENXIO;
489 KASSERT(sc->sc_open > 0);
490 sc->sc_open = 0;
491 return 0;
492 }
493
494 static int
satread(dev_t dev,struct uio * uio,int flags)495 satread(dev_t dev, struct uio *uio, int flags)
496 {
497 struct satmgr_softc *sc;
498 size_t n;
499 int error;
500
501 sc = device_lookup_private(&satmgr_cd, 0);
502 if (sc == NULL)
503 return ENXIO;
504
505 mutex_enter(&sc->sc_lock);
506 if (sc->sc_rd_cnt == 0 && (flags & IO_NDELAY)) {
507 error = EWOULDBLOCK;
508 goto out;
509 }
510 error = 0;
511 while (sc->sc_rd_cnt == 0) {
512 error = cv_wait_sig(&sc->sc_rdcv, &sc->sc_lock);
513 if (error)
514 goto out;
515 }
516 while (uio->uio_resid > 0 && sc->sc_rd_cnt > 0) {
517 n = uimin(sc->sc_rd_cnt, uio->uio_resid);
518 n = uimin(n, sc->sc_rd_lim - sc->sc_rd_ptr);
519 error = uiomove(sc->sc_rd_ptr, n, uio);
520 if (error)
521 goto out;
522 sc->sc_rd_cnt -= n;
523 sc->sc_rd_ptr += n;
524 if (sc->sc_rd_ptr == sc->sc_rd_lim)
525 sc->sc_rd_ptr = &sc->sc_rd_buf[0];
526 }
527 out:
528 mutex_exit(&sc->sc_lock);
529 return error;
530 }
531
532 static int
satwrite(dev_t dev,struct uio * uio,int flags)533 satwrite(dev_t dev, struct uio *uio, int flags)
534 {
535 struct satmgr_softc *sc;
536 int error;
537 size_t n;
538
539 sc = device_lookup_private(&satmgr_cd, 0);
540 if (sc == NULL)
541 return ENXIO;
542
543 mutex_enter(&sc->sc_lock);
544 if (sc->sc_wr_cnt == sizeof(sc->sc_wr_buf) && (flags & IO_NDELAY)) {
545 error = EWOULDBLOCK;
546 goto out;
547 }
548 error = 0;
549 while (sc->sc_wr_cnt == sizeof(sc->sc_wr_buf)) {
550 error = cv_wait_sig(&sc->sc_wrcv, &sc->sc_lock);
551 if (error)
552 goto out;
553 }
554 while (uio->uio_resid > 0 && sc->sc_wr_cnt < sizeof(sc->sc_wr_buf)) {
555 n = uimin(uio->uio_resid, sizeof(sc->sc_wr_buf));
556 n = uimin(n, sc->sc_wr_lim - sc->sc_wr_cur);
557 error = uiomove(sc->sc_wr_cur, n, uio);
558 if (error)
559 goto out;
560 sc->sc_wr_cnt += n;
561 sc->sc_wr_cur += n;
562 if (sc->sc_wr_cur == sc->sc_wr_lim)
563 sc->sc_wr_cur = &sc->sc_wr_buf[0];
564 }
565 startoutput(sc); /* start xmit */
566 out:
567 mutex_exit(&sc->sc_lock);
568 return error;
569 }
570
571 static int
satpoll(dev_t dev,int events,struct lwp * l)572 satpoll(dev_t dev, int events, struct lwp *l)
573 {
574 struct satmgr_softc *sc;
575 int revents = 0;
576
577 sc = device_lookup_private(&satmgr_cd, 0);
578 mutex_enter(&sc->sc_lock);
579 if (events & (POLLIN | POLLRDNORM)) {
580 if (sc->sc_rd_cnt)
581 revents |= events & (POLLIN | POLLRDNORM);
582 else
583 selrecord(l, &sc->sc_rsel);
584 }
585 mutex_exit(&sc->sc_lock);
586
587 return revents;
588 }
589
590 static void
filt_rdetach(struct knote * kn)591 filt_rdetach(struct knote *kn)
592 {
593 struct satmgr_softc *sc = kn->kn_hook;
594
595 mutex_enter(&sc->sc_lock);
596 selremove_knote(&sc->sc_rsel, kn);
597 mutex_exit(&sc->sc_lock);
598 }
599
600 static int
filt_read(struct knote * kn,long hint)601 filt_read(struct knote *kn, long hint)
602 {
603 struct satmgr_softc *sc = kn->kn_hook;
604
605 kn->kn_data = sc->sc_rd_cnt;
606 return (kn->kn_data > 0);
607 }
608
609 static const struct filterops read_filtops ={
610 .f_flags = FILTEROP_ISFD,
611 .f_attach = NULL,
612 .f_detach = filt_rdetach,
613 .f_event = filt_read,
614 };
615
616 static int
satkqfilter(dev_t dev,struct knote * kn)617 satkqfilter(dev_t dev, struct knote *kn)
618 {
619 struct satmgr_softc *sc = device_lookup_private(&satmgr_cd, 0);
620
621 switch (kn->kn_filter) {
622 case EVFILT_READ:
623 kn->kn_fop = &read_filtops;
624 break;
625
626 default:
627 return EINVAL;
628 }
629
630 kn->kn_hook = sc;
631
632 mutex_enter(&sc->sc_lock);
633 selrecord_knote(&sc->sc_rsel, kn);
634 mutex_exit(&sc->sc_lock);
635
636 return 0;
637 }
638
639 static int
hwintr(void * arg)640 hwintr(void *arg)
641 {
642 struct satmgr_softc *sc = arg;
643 int iir;
644
645 mutex_spin_enter(&sc->sc_lock);
646 iir = CSR_READ(sc, IIR) & IIR_IMASK;
647 if (iir == IIR_NOPEND) {
648 mutex_spin_exit(&sc->sc_lock);
649 return 0;
650 }
651 do {
652 switch (iir) {
653 case IIR_RLS: /* LSR updated */
654 case IIR_RXRDY: /* RxFIFO has been accumulated */
655 case IIR_RXTOUT:/* receive timeout occurred */
656 rxintr(sc);
657 break;
658 case IIR_TXRDY: /* TxFIFO is ready to swallow data */
659 txintr(sc);
660 break;
661 case IIR_MLSC: /* MSR updated */
662 break;
663 }
664 iir = CSR_READ(sc, IIR) & IIR_IMASK;
665 } while (iir != IIR_NOPEND);
666 mutex_spin_exit(&sc->sc_lock);
667 return 1;
668 }
669
670 static void
rxintr(struct satmgr_softc * sc)671 rxintr(struct satmgr_softc *sc)
672 {
673 int lsr, ch;
674
675 lsr = CSR_READ(sc, LSR);
676 if (lsr & LSR_OE)
677 sc->sc_overr++;
678 ch = -1;
679 while (lsr & LSR_RXRDY) {
680 if (lsr & (LSR_BI | LSR_FE | LSR_PE)) {
681 (void) CSR_READ(sc, RBR);
682 sc->sc_ierror++;
683 lsr = CSR_READ(sc, LSR);
684 continue;
685 }
686 ch = CSR_READ(sc, RBR);
687 if (sc->sc_rd_cnt < sizeof(sc->sc_rd_buf)) {
688 *sc->sc_rd_cur = ch;
689 if (++sc->sc_rd_cur == sc->sc_rd_lim)
690 sc->sc_rd_cur = &sc->sc_rd_buf[0];
691 sc->sc_rd_cnt += 1;
692 }
693 lsr = CSR_READ(sc, LSR);
694 }
695 if (ch != -1)
696 softint_schedule(sc->sc_si);
697 }
698
699 static void
txintr(struct satmgr_softc * sc)700 txintr(struct satmgr_softc *sc)
701 {
702
703 cv_signal(&sc->sc_wrcv);
704 startoutput(sc);
705 }
706
707 static void
startoutput(struct satmgr_softc * sc)708 startoutput(struct satmgr_softc *sc)
709 {
710 int n;
711
712 mutex_enter(&sc->sc_replk);
713 n = uimin(sc->sc_wr_cnt, 16);
714 while (n-- > 0) {
715 CSR_WRITE(sc, THR, *sc->sc_wr_ptr);
716 if (++sc->sc_wr_ptr == sc->sc_wr_lim)
717 sc->sc_wr_ptr = &sc->sc_wr_buf[0];
718 sc->sc_wr_cnt -= 1;
719 }
720 mutex_exit(&sc->sc_replk);
721 }
722
723 static void
swintr(void * arg)724 swintr(void *arg)
725 {
726 struct satmgr_softc *sc = arg;
727 char *ptr;
728 int n;
729
730 /* we're now in softint(9) context */
731 mutex_spin_enter(&sc->sc_lock);
732 ptr = sc->sc_rd_ptr;
733 for (n = 0; n < sc->sc_rd_cnt; n++) {
734 (*sc->sc_ops->dispatch)(sc, *ptr);
735 if (++ptr == sc->sc_rd_lim)
736 ptr = &sc->sc_rd_buf[0];
737 }
738 if (sc->sc_open == 0) {
739 sc->sc_rd_cnt = 0;
740 sc->sc_rd_ptr = ptr;
741 mutex_spin_exit(&sc->sc_lock);
742 return; /* drop characters down to the floor */
743 }
744 cv_signal(&sc->sc_rdcv);
745 selnotify(&sc->sc_rsel, 0, 0);
746 mutex_spin_exit(&sc->sc_lock);
747 }
748
749 static void
kreboot(struct satmgr_softc * sc)750 kreboot(struct satmgr_softc *sc)
751 {
752
753 send_sat(sc, "CCGG"); /* perform reboot */
754 }
755
756 static void
kpwroff(struct satmgr_softc * sc)757 kpwroff(struct satmgr_softc *sc)
758 {
759
760 send_sat(sc, "EEGG"); /* force power off */
761 }
762
763 static void
kbutton(struct satmgr_softc * sc,int ch)764 kbutton(struct satmgr_softc *sc, int ch)
765 {
766
767 switch (ch) {
768 case '!':
769 /* schedule 3 second poweroff guard time */
770 if (callout_pending(&sc->sc_ch_pbutton) == true)
771 callout_stop(&sc->sc_ch_pbutton);
772 callout_reset(&sc->sc_ch_pbutton,
773 3 * hz, guarded_pbutton, sc);
774 break;
775 case ' ':
776 if (callout_expired(&sc->sc_ch_pbutton) == false)
777 callout_stop(&sc->sc_ch_pbutton);
778 else
779 /* should never come here */;
780 break;
781 case '#':
782 case '"':
783 break;
784 }
785 }
786
787 static void
sinit(device_t self)788 sinit(device_t self)
789 {
790 struct satmgr_softc *sc = device_private(self);
791
792 send_sat(sc, "8"); /* status LED green */
793 }
794
795 static void
sreboot(struct satmgr_softc * sc)796 sreboot(struct satmgr_softc *sc)
797 {
798
799 send_sat(sc, "C");
800 }
801
802 static void
spwroff(struct satmgr_softc * sc)803 spwroff(struct satmgr_softc *sc)
804 {
805
806 send_sat(sc, "1");
807 }
808
809 static void
sbutton(struct satmgr_softc * sc,int ch)810 sbutton(struct satmgr_softc *sc, int ch)
811 {
812
813 switch (ch) {
814 case '0':
815 /* notified after 5 seconds guard time */
816 sysmon_task_queue_sched(0, sched_sysmon_pbutton, sc);
817 break;
818 case 'a':
819 case '`':
820 break;
821 }
822 }
823
824 static void
qinit(device_t self)825 qinit(device_t self)
826 {
827 struct satmgr_softc *sc = device_private(self);
828
829 send_sat(sc, "V"); /* status LED green */
830 }
831
832 static void
qreboot(struct satmgr_softc * sc)833 qreboot(struct satmgr_softc *sc)
834 {
835
836 send_sat(sc, "Pf"); /* beep and reboot */
837 }
838
839 static void
qpwroff(struct satmgr_softc * sc)840 qpwroff(struct satmgr_softc *sc)
841 {
842
843 send_sat(sc, "PA"); /* beep and power off */
844 }
845
846 static void
qbutton(struct satmgr_softc * sc,int ch)847 qbutton(struct satmgr_softc *sc, int ch)
848 {
849
850 switch (ch) {
851 case '@':
852 /* power button, notified after 2 seconds guard time */
853 sysmon_task_queue_sched(0, sched_sysmon_pbutton, sc);
854 break;
855 case 'j': /* reset to default button */
856 case 'h': /* USB copy button */
857 break;
858 }
859 }
860
861 static void
dpwroff(struct satmgr_softc * sc)862 dpwroff(struct satmgr_softc *sc)
863 {
864
865 send_sat(sc, "ZWC\n");
866
867 /*
868 * When this line is reached, then this board revision doesn't
869 * support hardware-shutdown, so we flash the power LED
870 * to indicate that the device can be switched off.
871 */
872 send_sat(sc, "SYN\nSYN\n");
873
874 /* drops into default power-off handling (looping forever) */
875 }
876
877 static void
dbutton(struct satmgr_softc * sc,int ch)878 dbutton(struct satmgr_softc *sc, int ch)
879 {
880
881 if (sc->sc_btn_cnt < sizeof(sc->sc_btn_buf))
882 sc->sc_btn_buf[sc->sc_btn_cnt++] = ch;
883 if (ch == '\n' || ch == '\r') {
884 if (memcmp(sc->sc_btn_buf, "PKO", 3) == 0) {
885 /* notified after 5 seconds guard time */
886 sysmon_task_queue_sched(0, sched_sysmon_pbutton, sc);
887 }
888 sc->sc_btn_cnt = 0;
889 }
890 }
891
892 static void
iinit(device_t self)893 iinit(device_t self)
894 {
895 struct satmgr_softc *sc = device_private(self);
896
897 /* LED blue, auto-fan, turn on at 50C, turn off at 45C */
898 sc->sc_sysctl_fanhigh = 50;
899 sc->sc_sysctl_fanlow = 45;
900 isattalk(sc, 'b', 'b', 10, 'a',
901 sc->sc_sysctl_fanhigh, sc->sc_sysctl_fanlow);
902 }
903
904 static void
ireboot(struct satmgr_softc * sc)905 ireboot(struct satmgr_softc *sc)
906 {
907
908 isattalk(sc, 'g', 0, 0, 0, 0, 0);
909 }
910
911 static void
ipwroff(struct satmgr_softc * sc)912 ipwroff(struct satmgr_softc *sc)
913 {
914
915 isattalk(sc, 'c', 0, 0, 0, 0, 0);
916 }
917
918 static void
ibutton(struct satmgr_softc * sc,int ch)919 ibutton(struct satmgr_softc *sc, int ch)
920 {
921
922 mutex_enter(&sc->sc_replk);
923 if (++sc->sc_btn_cnt >= 8) {
924 cv_signal(&sc->sc_repcv);
925 sc->sc_btn_cnt = 0;
926 }
927 mutex_exit(&sc->sc_replk);
928 }
929
930 static void
isattalk(struct satmgr_softc * sc,int pow,int led,int rat,int fan,int fhi,int flo)931 isattalk(struct satmgr_softc *sc, int pow, int led, int rat, int fan,
932 int fhi, int flo)
933 {
934 char *p = sc->sc_cmd_buf;
935 int i, cksum;
936
937 /*
938 * Construct the command packet. Values of -1 (0xff) will be
939 * replaced later by the current values from the last status.
940 */
941 p[0] = pow;
942 p[1] = led;
943 p[2] = rat;
944 p[3] = fan;
945 p[4] = fhi;
946 p[5] = flo;
947 p[6] = 7; /* host id */
948 for (i = 0, cksum = 0; i < 7; i++)
949 cksum += p[i];
950 p[7] = cksum & 0x7f;
951 send_sat_len(sc, p, 8);
952
953 mutex_enter(&sc->sc_replk);
954 sc->sc_btn_cnt = 0;
955 cv_wait(&sc->sc_repcv, &sc->sc_replk);
956 mutex_exit(&sc->sc_replk);
957 }
958
959
960 static void
minit(device_t self)961 minit(device_t self)
962 {
963 struct satmgr_softc *sc = device_private(self);
964 #if 0
965 static char msg[35] = "\x20\x92NetBSD/sandpoint";
966 int m, n;
967
968 m = strlen(osrelease);
969 n = (16 - m) / 2;
970 memset(&msg[18], ' ', 16);
971 memcpy(&msg[18 + n], osrelease, m);
972
973 msattalk(sc, "\x00\x03"); /* boot has completed */
974 msattalk(sc, msg); /* NB banner at disp2 */
975 msattalk(sc, "\x01\x32\x80"); /* select disp2 */
976 msattalk(sc, "\x00\x27"); /* show disp2 */
977 #else
978 msattalk(sc, "\x00\x03"); /* boot has completed */
979 #endif
980 }
981
982 static void
mreboot(struct satmgr_softc * sc)983 mreboot(struct satmgr_softc *sc)
984 {
985
986 msattalk(sc, "\x01\x35\x00"); /* stop watchdog timer */
987 msattalk(sc, "\x00\x0c"); /* shutdown in progress */
988 msattalk(sc, "\x00\x03"); /* boot has completed */
989 msattalk(sc, "\x00\x0e"); /* perform reboot */
990 }
991
992 static void
mpwroff(struct satmgr_softc * sc)993 mpwroff(struct satmgr_softc *sc)
994 {
995
996 msattalk(sc, "\x01\x35\x00"); /* stop watchdog timer */
997 msattalk(sc, "\x00\x0c"); /* shutdown in progress */
998 msattalk(sc, "\x00\x03"); /* boot has completed */
999 msattalk(sc, "\x00\x06"); /* force power off */
1000 }
1001
1002 static void
msattalk(struct satmgr_softc * sc,const char * cmd)1003 msattalk(struct satmgr_softc *sc, const char *cmd)
1004 {
1005 int len, i;
1006 uint8_t pa;
1007
1008 if (cmd[0] != 0x80)
1009 len = 2 + cmd[0]; /* cmd[0] is data portion length */
1010 else
1011 len = 2; /* read report */
1012
1013 for (i = 0, pa = 0; i < len; i++)
1014 pa += cmd[i];
1015 pa = 0 - pa; /* parity formula */
1016
1017 send_sat_len(sc, cmd, len);
1018 send_sat_len(sc, &pa, 1);
1019
1020 mutex_enter(&sc->sc_replk);
1021 sc->sc_btn_cnt = 0;
1022 cv_wait(&sc->sc_repcv, &sc->sc_replk);
1023 mutex_exit(&sc->sc_replk);
1024 }
1025
1026 static void
mbutton(struct satmgr_softc * sc,int ch)1027 mbutton(struct satmgr_softc *sc, int ch)
1028 {
1029
1030 mutex_enter(&sc->sc_replk);
1031 if (sc->sc_btn_cnt < 4) /* record the first four */
1032 sc->sc_btn_buf[sc->sc_btn_cnt] = ch;
1033 sc->sc_btn_cnt++;
1034 if (sc->sc_btn_cnt == sc->sc_btn_buf[0] + 3) {
1035 if (sc->sc_btn_buf[1] == 0x36 && (sc->sc_btn_buf[2]&01) == 0) {
1036 /* power button pressed */
1037 sysmon_task_queue_sched(0, sched_sysmon_pbutton, sc);
1038 }
1039 else {
1040 /* unblock the talker */
1041 cv_signal(&sc->sc_repcv);
1042 }
1043 sc->sc_btn_cnt = 0;
1044 }
1045 mutex_exit(&sc->sc_replk);
1046 }
1047
1048 static int
mbtnintr(void * arg)1049 mbtnintr(void *arg)
1050 {
1051 /* notified after 3 seconds guard time */
1052 struct satmgr_softc *sc = arg;
1053
1054 send_sat(sc, "\x80\x36\x4a"); /* query button state with parity */
1055 mutex_enter(&sc->sc_replk);
1056 sc->sc_btn_cnt = 0;
1057 mutex_exit(&sc->sc_replk);
1058 return 1;
1059 }
1060
1061 static void
guarded_pbutton(void * arg)1062 guarded_pbutton(void *arg)
1063 {
1064 struct satmgr_softc *sc = arg;
1065
1066 /* we're now in callout(9) context */
1067 sysmon_task_queue_sched(0, sched_sysmon_pbutton, sc);
1068 send_sat(sc, "UU"); /* make front panel LED flashing */
1069 }
1070
1071 static void
sched_sysmon_pbutton(void * arg)1072 sched_sysmon_pbutton(void *arg)
1073 {
1074 struct satmgr_softc *sc = arg;
1075
1076 /* we're now in kthread(9) context */
1077 sysmon_pswitch_event(&sc->sc_sm_pbutton, PSWITCH_EVENT_PRESSED);
1078 }
1079