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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 700 txintr(struct satmgr_softc *sc) 701 { 702 703 cv_signal(&sc->sc_wrcv); 704 startoutput(sc); 705 } 706 707 static void 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 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 750 kreboot(struct satmgr_softc *sc) 751 { 752 753 send_sat(sc, "CCGG"); /* perform reboot */ 754 } 755 756 static void 757 kpwroff(struct satmgr_softc *sc) 758 { 759 760 send_sat(sc, "EEGG"); /* force power off */ 761 } 762 763 static void 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 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 796 sreboot(struct satmgr_softc *sc) 797 { 798 799 send_sat(sc, "C"); 800 } 801 802 static void 803 spwroff(struct satmgr_softc *sc) 804 { 805 806 send_sat(sc, "1"); 807 } 808 809 static void 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 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 833 qreboot(struct satmgr_softc *sc) 834 { 835 836 send_sat(sc, "Pf"); /* beep and reboot */ 837 } 838 839 static void 840 qpwroff(struct satmgr_softc *sc) 841 { 842 843 send_sat(sc, "PA"); /* beep and power off */ 844 } 845 846 static void 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 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 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 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 905 ireboot(struct satmgr_softc *sc) 906 { 907 908 isattalk(sc, 'g', 0, 0, 0, 0, 0); 909 } 910 911 static void 912 ipwroff(struct satmgr_softc *sc) 913 { 914 915 isattalk(sc, 'c', 0, 0, 0, 0, 0); 916 } 917 918 static void 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 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 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 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 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 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 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 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 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 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