1 /* $NetBSD: tctrl.c,v 1.59 2014/07/25 08:10:34 dholland Exp $ */ 2 3 /*- 4 * Copyright (c) 1998, 2005, 2006 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Matt Thomas. 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/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: tctrl.c,v 1.59 2014/07/25 08:10:34 dholland Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/ioctl.h> 38 #include <sys/select.h> 39 #include <sys/tty.h> 40 #include <sys/proc.h> 41 #include <sys/conf.h> 42 #include <sys/file.h> 43 #include <sys/uio.h> 44 #include <sys/kernel.h> 45 #include <sys/kthread.h> 46 #include <sys/syslog.h> 47 #include <sys/types.h> 48 #include <sys/device.h> 49 #include <sys/envsys.h> 50 #include <sys/poll.h> 51 #include <sys/kauth.h> 52 53 #include <machine/apmvar.h> 54 #include <machine/autoconf.h> 55 #include <sys/bus.h> 56 #include <machine/intr.h> 57 #include <machine/tctrl.h> 58 59 #include <sparc/dev/ts102reg.h> 60 #include <sparc/dev/tctrlvar.h> 61 #include <sparc/sparc/auxiotwo.h> 62 #include <sparc/sparc/auxreg.h> 63 64 #include <dev/sysmon/sysmonvar.h> 65 #include <dev/sysmon/sysmon_taskq.h> 66 67 #include "sysmon_envsys.h" 68 69 /*#define TCTRLDEBUG*/ 70 71 /* disk spinner */ 72 #include <sys/disk.h> 73 #include <dev/scsipi/sdvar.h> 74 75 /* ethernet carrier */ 76 #include <net/if.h> 77 #include <net/if_dl.h> 78 #include <net/if_ether.h> 79 #include <net/if_media.h> 80 #include <dev/ic/lancevar.h> 81 82 extern struct cfdriver tctrl_cd; 83 84 dev_type_open(tctrlopen); 85 dev_type_close(tctrlclose); 86 dev_type_ioctl(tctrlioctl); 87 dev_type_poll(tctrlpoll); 88 dev_type_kqfilter(tctrlkqfilter); 89 90 const struct cdevsw tctrl_cdevsw = { 91 .d_open = tctrlopen, 92 .d_close = tctrlclose, 93 .d_read = noread, 94 .d_write = nowrite, 95 .d_ioctl = tctrlioctl, 96 .d_stop = nostop, 97 .d_tty = notty, 98 .d_poll = tctrlpoll, 99 .d_mmap = nommap, 100 .d_kqfilter = tctrlkqfilter, 101 .d_discard = nodiscard, 102 .d_flag = 0 103 }; 104 105 static const char *tctrl_ext_statuses[16] = { 106 "main power available", 107 "internal battery attached", 108 "external battery attached", 109 "external VGA attached", 110 "external keyboard attached", 111 "external mouse attached", 112 "lid down", 113 "internal battery charging", 114 "external battery charging", 115 "internal battery discharging", 116 "external battery discharging", 117 }; 118 119 struct tctrl_softc { 120 device_t sc_dev; 121 bus_space_tag_t sc_memt; 122 bus_space_handle_t sc_memh; 123 unsigned int sc_junk; 124 unsigned int sc_ext_status; 125 unsigned int sc_flags; 126 #define TCTRL_SEND_REQUEST 0x0001 127 #define TCTRL_APM_CTLOPEN 0x0002 128 uint32_t sc_wantdata; 129 uint32_t sc_ext_pending; 130 volatile uint16_t sc_lcdstate; 131 uint16_t sc_lcdwanted; 132 133 enum { TCTRL_IDLE, TCTRL_ARGS, 134 TCTRL_ACK, TCTRL_DATA } sc_state; 135 uint8_t sc_cmdbuf[16]; 136 uint8_t sc_rspbuf[16]; 137 uint8_t sc_bitport; 138 uint8_t sc_tft_on; 139 uint8_t sc_op; 140 uint8_t sc_cmdoff; 141 uint8_t sc_cmdlen; 142 uint8_t sc_rspoff; 143 uint8_t sc_rsplen; 144 /* APM stuff */ 145 #define APM_NEVENTS 16 146 struct apm_event_info sc_event_list[APM_NEVENTS]; 147 int sc_event_count; 148 int sc_event_ptr; 149 struct selinfo sc_rsel; 150 151 /* ENVSYS stuff */ 152 #define ENVSYS_NUMSENSORS 3 153 struct evcnt sc_intrcnt; /* interrupt counting */ 154 struct sysmon_envsys *sc_sme; 155 envsys_data_t sc_sensor[ENVSYS_NUMSENSORS]; 156 157 struct sysmon_pswitch sc_sm_pbutton; /* power button */ 158 struct sysmon_pswitch sc_sm_lid; /* lid state */ 159 struct sysmon_pswitch sc_sm_ac; /* AC adaptor presence */ 160 int sc_powerpressed; 161 162 /* hardware status stuff */ 163 int sc_lid; /* 1 - open, 0 - closed */ 164 int sc_power_state; 165 int sc_spl; 166 167 /* 168 * we call this when we detect connection or removal of an external 169 * monitor. 0 for no monitor, !=0 for monitor present 170 */ 171 void (*sc_video_callback)(void *, int); 172 void *sc_video_callback_cookie; 173 int sc_extvga; 174 175 uint32_t sc_events; 176 lwp_t *sc_thread; /* event thread */ 177 kmutex_t sc_requestlock; 178 }; 179 180 #define TCTRL_STD_DEV 0 181 #define TCTRL_APMCTL_DEV 8 182 183 static int tctrl_match(device_t, cfdata_t, void *); 184 static void tctrl_attach(device_t, device_t, void *); 185 static void tctrl_write(struct tctrl_softc *, bus_size_t, uint8_t); 186 static uint8_t tctrl_read(struct tctrl_softc *, bus_size_t); 187 static void tctrl_write_data(struct tctrl_softc *, uint8_t); 188 static uint8_t tctrl_read_data(struct tctrl_softc *); 189 static int tctrl_intr(void *); 190 static void tctrl_setup_bitport(void); 191 static void tctrl_setup_bitport_nop(void); 192 static void tctrl_read_ext_status(void); 193 static void tctrl_read_event_status(struct tctrl_softc *); 194 static int tctrl_apm_record_event(struct tctrl_softc *, u_int); 195 static void tctrl_init_lcd(void); 196 197 static void tctrl_sensor_setup(struct tctrl_softc *); 198 static void tctrl_refresh(struct sysmon_envsys *, envsys_data_t *); 199 200 static void tctrl_power_button_pressed(void *); 201 static void tctrl_lid_state(struct tctrl_softc *); 202 static void tctrl_ac_state(struct tctrl_softc *); 203 204 static int tctrl_powerfail(void *); 205 206 static void tctrl_event_thread(void *); 207 void tctrl_update_lcd(struct tctrl_softc *); 208 209 static void tctrl_lock(struct tctrl_softc *); 210 static void tctrl_unlock(struct tctrl_softc *); 211 212 CFATTACH_DECL_NEW(tctrl, sizeof(struct tctrl_softc), 213 tctrl_match, tctrl_attach, NULL, NULL); 214 215 static int tadpole_request(struct tctrl_req *, int, int); 216 217 /* XXX wtf is this? see i386/apm.c */ 218 int tctrl_apm_evindex; 219 220 static int 221 tctrl_match(device_t parent, cfdata_t cf, void *aux) 222 { 223 union obio_attach_args *uoba = aux; 224 struct sbus_attach_args *sa = &uoba->uoba_sbus; 225 226 if (uoba->uoba_isobio4 != 0) { 227 return (0); 228 } 229 230 /* Tadpole 3GX/3GS uses "uctrl" for the Tadpole Microcontroller 231 * (who's interface is off the TS102 PCMCIA controller but there 232 * exists a OpenProm for microcontroller interface). 233 */ 234 return strcmp("uctrl", sa->sa_name) == 0; 235 } 236 237 static void 238 tctrl_attach(device_t parent, device_t self, void *aux) 239 { 240 struct tctrl_softc *sc = device_private(self); 241 union obio_attach_args *uoba = aux; 242 struct sbus_attach_args *sa = &uoba->uoba_sbus; 243 unsigned int i, v; 244 245 /* We're living on a sbus slot that looks like an obio that 246 * looks like an sbus slot. 247 */ 248 sc->sc_dev = self; 249 sc->sc_memt = sa->sa_bustag; 250 if (sbus_bus_map(sc->sc_memt, 251 sa->sa_slot, 252 sa->sa_offset - TS102_REG_UCTRL_INT, 253 sa->sa_size, 254 BUS_SPACE_MAP_LINEAR, &sc->sc_memh) != 0) { 255 printf(": can't map registers\n"); 256 return; 257 } 258 259 printf("\n"); 260 261 sc->sc_tft_on = 1; 262 263 /* clear any pending data. 264 */ 265 for (i = 0; i < 10000; i++) { 266 if ((TS102_UCTRL_STS_RXNE_STA & 267 tctrl_read(sc, TS102_REG_UCTRL_STS)) == 0) { 268 break; 269 } 270 v = tctrl_read(sc, TS102_REG_UCTRL_DATA); 271 tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA); 272 } 273 274 if (sa->sa_nintr != 0) { 275 (void)bus_intr_establish(sc->sc_memt, sa->sa_pri, IPL_NONE, 276 tctrl_intr, sc); 277 evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, NULL, 278 device_xname(sc->sc_dev), "intr"); 279 } 280 281 /* See what the external status is */ 282 sc->sc_ext_status = 0; 283 tctrl_read_ext_status(); 284 if (sc->sc_ext_status != 0) { 285 const char *sep; 286 287 printf("%s: ", device_xname(sc->sc_dev)); 288 v = sc->sc_ext_status; 289 for (i = 0, sep = ""; v != 0; i++, v >>= 1) { 290 if (v & 1) { 291 printf("%s%s", sep, tctrl_ext_statuses[i]); 292 sep = ", "; 293 } 294 } 295 printf("\n"); 296 } 297 298 /* Get a current of the control bitport */ 299 tctrl_setup_bitport_nop(); 300 tctrl_write(sc, TS102_REG_UCTRL_INT, 301 TS102_UCTRL_INT_RXNE_REQ|TS102_UCTRL_INT_RXNE_MSK); 302 sc->sc_lid = (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) == 0; 303 sc->sc_power_state = PWR_RESUME; 304 305 sc->sc_extvga = (sc->sc_ext_status & 306 TS102_EXT_STATUS_EXTERNAL_VGA_ATTACHED) != 0; 307 sc->sc_video_callback = NULL; 308 309 310 sc->sc_wantdata = 0; 311 sc->sc_event_count = 0; 312 sc->sc_ext_pending = 0; 313 sc->sc_ext_pending = 0; 314 315 mutex_init(&sc->sc_requestlock, MUTEX_DEFAULT, IPL_NONE); 316 selinit(&sc->sc_rsel); 317 318 /* setup sensors and register the power button */ 319 tctrl_sensor_setup(sc); 320 tctrl_lid_state(sc); 321 tctrl_ac_state(sc); 322 323 /* initialize the LCD */ 324 tctrl_init_lcd(); 325 326 /* initialize sc_lcdstate */ 327 sc->sc_lcdstate = 0; 328 sc->sc_lcdwanted = 0; 329 tadpole_set_lcd(2, 0); 330 331 /* fire up the LCD event thread */ 332 sc->sc_events = 0; 333 334 if (kthread_create(PRI_NONE, 0, NULL, tctrl_event_thread, sc, 335 &sc->sc_thread, "%s", device_xname(sc->sc_dev)) != 0) { 336 printf("%s: unable to create event kthread", 337 device_xname(sc->sc_dev)); 338 } 339 } 340 341 static int 342 tctrl_intr(void *arg) 343 { 344 struct tctrl_softc *sc = arg; 345 unsigned int v, d; 346 int progress = 0; 347 348 again: 349 /* find out the cause(s) of the interrupt */ 350 v = tctrl_read(sc, TS102_REG_UCTRL_STS) & TS102_UCTRL_STS_MASK; 351 352 /* clear the cause(s) of the interrupt */ 353 tctrl_write(sc, TS102_REG_UCTRL_STS, v); 354 355 v &= ~(TS102_UCTRL_STS_RXO_STA|TS102_UCTRL_STS_TXE_STA); 356 if (sc->sc_cmdoff >= sc->sc_cmdlen) { 357 v &= ~TS102_UCTRL_STS_TXNF_STA; 358 if (tctrl_read(sc, TS102_REG_UCTRL_INT) & 359 TS102_UCTRL_INT_TXNF_REQ) { 360 tctrl_write(sc, TS102_REG_UCTRL_INT, 0); 361 progress = 1; 362 } 363 } 364 if ((v == 0) && ((sc->sc_flags & TCTRL_SEND_REQUEST) == 0 || 365 sc->sc_state != TCTRL_IDLE)) { 366 wakeup(sc); 367 return progress; 368 } 369 370 progress = 1; 371 if (v & TS102_UCTRL_STS_RXNE_STA) { 372 d = tctrl_read_data(sc); 373 switch (sc->sc_state) { 374 case TCTRL_IDLE: 375 if (d == 0xfa) { 376 /* 377 * external event, 378 * set a flag and wakeup the event thread 379 */ 380 sc->sc_ext_pending = 1; 381 } else { 382 printf("%s: (op=0x%02x): unexpected data (0x%02x)\n", 383 device_xname(sc->sc_dev), sc->sc_op, d); 384 } 385 goto again; 386 case TCTRL_ACK: 387 if (d != 0xfe) { 388 printf("%s: (op=0x%02x): unexpected ack value (0x%02x)\n", 389 device_xname(sc->sc_dev), sc->sc_op, d); 390 } 391 #ifdef TCTRLDEBUG 392 printf(" ack=0x%02x", d); 393 #endif 394 sc->sc_rsplen--; 395 sc->sc_rspoff = 0; 396 sc->sc_state = sc->sc_rsplen ? TCTRL_DATA : TCTRL_IDLE; 397 sc->sc_wantdata = sc->sc_rsplen ? 1 : 0; 398 #ifdef TCTRLDEBUG 399 if (sc->sc_rsplen > 0) { 400 printf(" [data(%u)]", sc->sc_rsplen); 401 } else { 402 printf(" [idle]\n"); 403 } 404 #endif 405 goto again; 406 case TCTRL_DATA: 407 sc->sc_rspbuf[sc->sc_rspoff++] = d; 408 #ifdef TCTRLDEBUG 409 printf(" [%d]=0x%02x", sc->sc_rspoff-1, d); 410 #endif 411 if (sc->sc_rspoff == sc->sc_rsplen) { 412 #ifdef TCTRLDEBUG 413 printf(" [idle]\n"); 414 #endif 415 sc->sc_state = TCTRL_IDLE; 416 sc->sc_wantdata = 0; 417 } 418 goto again; 419 default: 420 printf("%s: (op=0x%02x): unexpected data (0x%02x) in state %d\n", 421 device_xname(sc->sc_dev), sc->sc_op, d, sc->sc_state); 422 goto again; 423 } 424 } 425 if ((sc->sc_state == TCTRL_IDLE && sc->sc_wantdata == 0) || 426 sc->sc_flags & TCTRL_SEND_REQUEST) { 427 if (sc->sc_flags & TCTRL_SEND_REQUEST) { 428 sc->sc_flags &= ~TCTRL_SEND_REQUEST; 429 sc->sc_wantdata = 1; 430 } 431 if (sc->sc_cmdlen > 0) { 432 tctrl_write(sc, TS102_REG_UCTRL_INT, 433 tctrl_read(sc, TS102_REG_UCTRL_INT) 434 |TS102_UCTRL_INT_TXNF_MSK 435 |TS102_UCTRL_INT_TXNF_REQ); 436 v = tctrl_read(sc, TS102_REG_UCTRL_STS); 437 } 438 } 439 if ((sc->sc_cmdoff < sc->sc_cmdlen) && (v & TS102_UCTRL_STS_TXNF_STA)) { 440 tctrl_write_data(sc, sc->sc_cmdbuf[sc->sc_cmdoff++]); 441 #ifdef TCTRLDEBUG 442 if (sc->sc_cmdoff == 1) { 443 printf("%s: op=0x%02x(l=%u)", device_xname(sc->sc_dev), 444 sc->sc_cmdbuf[0], sc->sc_rsplen); 445 } else { 446 printf(" [%d]=0x%02x", sc->sc_cmdoff-1, 447 sc->sc_cmdbuf[sc->sc_cmdoff-1]); 448 } 449 #endif 450 if (sc->sc_cmdoff == sc->sc_cmdlen) { 451 sc->sc_state = sc->sc_rsplen ? TCTRL_ACK : TCTRL_IDLE; 452 #ifdef TCTRLDEBUG 453 printf(" %s", sc->sc_rsplen ? "[ack]" : "[idle]\n"); 454 #endif 455 if (sc->sc_cmdoff == 1) { 456 sc->sc_op = sc->sc_cmdbuf[0]; 457 } 458 tctrl_write(sc, TS102_REG_UCTRL_INT, 459 tctrl_read(sc, TS102_REG_UCTRL_INT) 460 & (~TS102_UCTRL_INT_TXNF_MSK 461 |TS102_UCTRL_INT_TXNF_REQ)); 462 } else if (sc->sc_state == TCTRL_IDLE) { 463 sc->sc_op = sc->sc_cmdbuf[0]; 464 sc->sc_state = TCTRL_ARGS; 465 #ifdef TCTRLDEBUG 466 printf(" [args]"); 467 #endif 468 } 469 } 470 goto again; 471 } 472 473 static void 474 tctrl_setup_bitport_nop(void) 475 { 476 struct tctrl_softc *sc; 477 struct tctrl_req req; 478 int s; 479 480 sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV); 481 req.cmdbuf[0] = TS102_OP_CTL_BITPORT; 482 req.cmdbuf[1] = 0xff; 483 req.cmdbuf[2] = 0x00; 484 req.cmdlen = 3; 485 req.rsplen = 2; 486 tadpole_request(&req, 1, 0); 487 s = splts102(); 488 sc->sc_bitport = (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2]; 489 splx(s); 490 } 491 492 static void 493 tctrl_setup_bitport(void) 494 { 495 struct tctrl_softc *sc; 496 struct tctrl_req req; 497 int s; 498 499 sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV); 500 s = splts102(); 501 req.cmdbuf[2] = 0; 502 if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) 503 || (!sc->sc_tft_on)) { 504 req.cmdbuf[2] = TS102_BITPORT_TFTPWR; 505 } 506 req.cmdbuf[0] = TS102_OP_CTL_BITPORT; 507 req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR; 508 req.cmdlen = 3; 509 req.rsplen = 2; 510 tadpole_request(&req, 1, 0); 511 s = splts102(); 512 sc->sc_bitport = (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2]; 513 splx(s); 514 } 515 516 /* 517 * The tadpole microcontroller is not preprogrammed with icon 518 * representations. The machine boots with the DC-IN light as 519 * a blank (all 0x00) and the other lights, as 4 rows of horizontal 520 * bars. The below code initializes the icons in the system to 521 * sane values. Some of these icons could be used for any purpose 522 * desired, namely the pcmcia, LAN and WAN lights. For the disk spinner, 523 * only the backslash is unprogrammed. (sigh) 524 * 525 * programming the icons is simple. It is a 5x8 matrix, which each row a 526 * bitfield in the order 0x10 0x08 0x04 0x02 0x01. 527 */ 528 529 static void 530 tctrl_init_lcd(void) 531 { 532 struct tctrl_req req; 533 534 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR; 535 req.cmdlen = 11; 536 req.rsplen = 1; 537 req.cmdbuf[1] = 0x08; /*len*/ 538 req.cmdbuf[2] = TS102_BLK_OFF_DEF_DC_GOOD; 539 req.cmdbuf[3] = 0x00; /* ..... */ 540 req.cmdbuf[4] = 0x00; /* ..... */ 541 req.cmdbuf[5] = 0x1f; /* XXXXX */ 542 req.cmdbuf[6] = 0x00; /* ..... */ 543 req.cmdbuf[7] = 0x15; /* X.X.X */ 544 req.cmdbuf[8] = 0x00; /* ..... */ 545 req.cmdbuf[9] = 0x00; /* ..... */ 546 req.cmdbuf[10] = 0x00; /* ..... */ 547 tadpole_request(&req, 1, 0); 548 549 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR; 550 req.cmdlen = 11; 551 req.rsplen = 1; 552 req.cmdbuf[1] = 0x08; /*len*/ 553 req.cmdbuf[2] = TS102_BLK_OFF_DEF_BACKSLASH; 554 req.cmdbuf[3] = 0x00; /* ..... */ 555 req.cmdbuf[4] = 0x10; /* X.... */ 556 req.cmdbuf[5] = 0x08; /* .X... */ 557 req.cmdbuf[6] = 0x04; /* ..X.. */ 558 req.cmdbuf[7] = 0x02; /* ...X. */ 559 req.cmdbuf[8] = 0x01; /* ....X */ 560 req.cmdbuf[9] = 0x00; /* ..... */ 561 req.cmdbuf[10] = 0x00; /* ..... */ 562 tadpole_request(&req, 1, 0); 563 564 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR; 565 req.cmdlen = 11; 566 req.rsplen = 1; 567 req.cmdbuf[1] = 0x08; /*len*/ 568 req.cmdbuf[2] = TS102_BLK_OFF_DEF_WAN1; 569 req.cmdbuf[3] = 0x0c; /* .XXX. */ 570 req.cmdbuf[4] = 0x16; /* X.XX. */ 571 req.cmdbuf[5] = 0x10; /* X.... */ 572 req.cmdbuf[6] = 0x15; /* X.X.X */ 573 req.cmdbuf[7] = 0x10; /* X.... */ 574 req.cmdbuf[8] = 0x16; /* X.XX. */ 575 req.cmdbuf[9] = 0x0c; /* .XXX. */ 576 req.cmdbuf[10] = 0x00; /* ..... */ 577 tadpole_request(&req, 1, 0); 578 579 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR; 580 req.cmdlen = 11; 581 req.rsplen = 1; 582 req.cmdbuf[1] = 0x08; /*len*/ 583 req.cmdbuf[2] = TS102_BLK_OFF_DEF_WAN2; 584 req.cmdbuf[3] = 0x0c; /* .XXX. */ 585 req.cmdbuf[4] = 0x0d; /* .XX.X */ 586 req.cmdbuf[5] = 0x01; /* ....X */ 587 req.cmdbuf[6] = 0x15; /* X.X.X */ 588 req.cmdbuf[7] = 0x01; /* ....X */ 589 req.cmdbuf[8] = 0x0d; /* .XX.X */ 590 req.cmdbuf[9] = 0x0c; /* .XXX. */ 591 req.cmdbuf[10] = 0x00; /* ..... */ 592 tadpole_request(&req, 1, 0); 593 594 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR; 595 req.cmdlen = 11; 596 req.rsplen = 1; 597 req.cmdbuf[1] = 0x08; /*len*/ 598 req.cmdbuf[2] = TS102_BLK_OFF_DEF_LAN1; 599 req.cmdbuf[3] = 0x00; /* ..... */ 600 req.cmdbuf[4] = 0x04; /* ..X.. */ 601 req.cmdbuf[5] = 0x08; /* .X... */ 602 req.cmdbuf[6] = 0x13; /* X..XX */ 603 req.cmdbuf[7] = 0x08; /* .X... */ 604 req.cmdbuf[8] = 0x04; /* ..X.. */ 605 req.cmdbuf[9] = 0x00; /* ..... */ 606 req.cmdbuf[10] = 0x00; /* ..... */ 607 tadpole_request(&req, 1, 0); 608 609 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR; 610 req.cmdlen = 11; 611 req.rsplen = 1; 612 req.cmdbuf[1] = 0x08; /*len*/ 613 req.cmdbuf[2] = TS102_BLK_OFF_DEF_LAN2; 614 req.cmdbuf[3] = 0x00; /* ..... */ 615 req.cmdbuf[4] = 0x04; /* ..X.. */ 616 req.cmdbuf[5] = 0x02; /* ...X. */ 617 req.cmdbuf[6] = 0x19; /* XX..X */ 618 req.cmdbuf[7] = 0x02; /* ...X. */ 619 req.cmdbuf[8] = 0x04; /* ..X.. */ 620 req.cmdbuf[9] = 0x00; /* ..... */ 621 req.cmdbuf[10] = 0x00; /* ..... */ 622 tadpole_request(&req, 1, 0); 623 624 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR; 625 req.cmdlen = 11; 626 req.rsplen = 1; 627 req.cmdbuf[1] = 0x08; /*len*/ 628 req.cmdbuf[2] = TS102_BLK_OFF_DEF_PCMCIA; 629 req.cmdbuf[3] = 0x00; /* ..... */ 630 req.cmdbuf[4] = 0x0c; /* .XXX. */ 631 req.cmdbuf[5] = 0x1f; /* XXXXX */ 632 req.cmdbuf[6] = 0x1f; /* XXXXX */ 633 req.cmdbuf[7] = 0x1f; /* XXXXX */ 634 req.cmdbuf[8] = 0x1f; /* XXXXX */ 635 req.cmdbuf[9] = 0x00; /* ..... */ 636 req.cmdbuf[10] = 0x00; /* ..... */ 637 tadpole_request(&req, 1, 0); 638 } 639 640 /* sc_lcdwanted -> lcd_state */ 641 void 642 tctrl_update_lcd(struct tctrl_softc *sc) 643 { 644 struct tctrl_req req; 645 int s; 646 647 s = splhigh(); 648 if (sc->sc_lcdwanted == sc->sc_lcdstate) { 649 splx(s); 650 return; 651 } 652 sc->sc_lcdstate = sc->sc_lcdwanted; 653 splx(s); 654 655 /* 656 * the mask setup on this particular command is *very* bizzare 657 * and totally undocumented. 658 */ 659 req.cmdbuf[0] = TS102_OP_CTL_LCD; 660 661 /* leave caps-lock alone */ 662 req.cmdbuf[2] = (u_int8_t)(sc->sc_lcdstate & 0xfe); 663 req.cmdbuf[3] = (u_int8_t)((sc->sc_lcdstate & 0x100)>>8); 664 665 req.cmdbuf[1] = 1; 666 req.cmdbuf[4] = 0; 667 668 669 /* XXX this thing is weird.... */ 670 req.cmdlen = 3; 671 req.rsplen = 2; 672 673 /* below are the values one would expect but which won't work */ 674 #if 0 675 req.cmdlen = 5; 676 req.rsplen = 4; 677 #endif 678 tadpole_request(&req, 1, 0); 679 } 680 681 682 /* 683 * set the blinken-lights on the lcd. what: 684 * what = 0 off, what = 1 on, what = 2 toggle 685 */ 686 687 void 688 tadpole_set_lcd(int what, unsigned short which) 689 { 690 struct tctrl_softc *sc; 691 int s; 692 693 sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV); 694 695 s = splhigh(); 696 switch (what) { 697 case 0: 698 sc->sc_lcdwanted &= ~which; 699 break; 700 case 1: 701 sc->sc_lcdwanted |= which; 702 break; 703 case 2: 704 sc->sc_lcdwanted ^= which; 705 break; 706 } 707 splx(s); 708 } 709 710 static void 711 tctrl_read_ext_status(void) 712 { 713 struct tctrl_softc *sc; 714 struct tctrl_req req; 715 int s; 716 717 sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV); 718 req.cmdbuf[0] = TS102_OP_RD_EXT_STATUS; 719 req.cmdlen = 1; 720 req.rsplen = 3; 721 #ifdef TCTRLDEBUG 722 printf("pre read: sc->sc_ext_status = 0x%x\n", sc->sc_ext_status); 723 #endif 724 tadpole_request(&req, 1, 0); 725 s = splts102(); 726 sc->sc_ext_status = (req.rspbuf[0] << 8) + req.rspbuf[1]; 727 splx(s); 728 #ifdef TCTRLDEBUG 729 printf("post read: sc->sc_ext_status = 0x%x\n", sc->sc_ext_status); 730 #endif 731 } 732 733 /* 734 * return 0 if the user will notice and handle the event, 735 * return 1 if the kernel driver should do so. 736 */ 737 static int 738 tctrl_apm_record_event(struct tctrl_softc *sc, u_int event_type) 739 { 740 struct apm_event_info *evp; 741 742 if ((sc->sc_flags & TCTRL_APM_CTLOPEN) && 743 (sc->sc_event_count < APM_NEVENTS)) { 744 evp = &sc->sc_event_list[sc->sc_event_ptr]; 745 sc->sc_event_count++; 746 sc->sc_event_ptr++; 747 sc->sc_event_ptr %= APM_NEVENTS; 748 evp->type = event_type; 749 evp->index = ++tctrl_apm_evindex; 750 selnotify(&sc->sc_rsel, 0, 0); 751 return(sc->sc_flags & TCTRL_APM_CTLOPEN) ? 0 : 1; 752 } 753 return(1); 754 } 755 756 static void 757 tctrl_read_event_status(struct tctrl_softc *sc) 758 { 759 struct tctrl_req req; 760 int s; 761 uint32_t v; 762 763 req.cmdbuf[0] = TS102_OP_RD_EVENT_STATUS; 764 req.cmdlen = 1; 765 req.rsplen = 3; 766 tadpole_request(&req, 1, 0); 767 s = splts102(); 768 v = req.rspbuf[0] * 256 + req.rspbuf[1]; 769 #ifdef TCTRLDEBUG 770 printf("event: %x\n",v); 771 #endif 772 if (v & TS102_EVENT_STATUS_POWERON_BTN_PRESSED) { 773 printf("%s: Power button pressed\n",device_xname(sc->sc_dev)); 774 tctrl_powerfail(sc); 775 } 776 if (v & TS102_EVENT_STATUS_SHUTDOWN_REQUEST) { 777 printf("%s: SHUTDOWN REQUEST!\n", device_xname(sc->sc_dev)); 778 tctrl_powerfail(sc); 779 } 780 if (v & TS102_EVENT_STATUS_VERY_LOW_POWER_WARNING) { 781 /*printf("%s: VERY LOW POWER WARNING!\n", device_xname(sc->sc_dev));*/ 782 /* according to a tadpole header, and observation */ 783 #ifdef TCTRLDEBUG 784 printf("%s: Battery charge level change\n", 785 device_xname(sc->sc_dev)); 786 #endif 787 } 788 if (v & TS102_EVENT_STATUS_LOW_POWER_WARNING) { 789 if (tctrl_apm_record_event(sc, APM_BATTERY_LOW)) 790 printf("%s: LOW POWER WARNING!\n", device_xname(sc->sc_dev)); 791 } 792 if (v & TS102_EVENT_STATUS_DC_STATUS_CHANGE) { 793 splx(s); 794 tctrl_read_ext_status(); 795 tctrl_ac_state(sc); 796 s = splts102(); 797 if (tctrl_apm_record_event(sc, APM_POWER_CHANGE)) 798 printf("%s: main power %s\n", device_xname(sc->sc_dev), 799 (sc->sc_ext_status & 800 TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ? 801 "restored" : "removed"); 802 } 803 if (v & TS102_EVENT_STATUS_LID_STATUS_CHANGE) { 804 splx(s); 805 tctrl_read_ext_status(); 806 tctrl_lid_state(sc); 807 tctrl_setup_bitport(); 808 #ifdef TCTRLDEBUG 809 printf("%s: lid %s\n", device_xname(sc->sc_dev), 810 (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) 811 ? "closed" : "opened"); 812 #endif 813 } 814 if (v & TS102_EVENT_STATUS_EXTERNAL_VGA_STATUS_CHANGE) { 815 int vga; 816 splx(s); 817 tctrl_read_ext_status(); 818 vga = (sc->sc_ext_status & 819 TS102_EXT_STATUS_EXTERNAL_VGA_ATTACHED) != 0; 820 if (vga != sc->sc_extvga) { 821 sc->sc_extvga = vga; 822 if (sc->sc_video_callback != NULL) { 823 sc->sc_video_callback( 824 sc->sc_video_callback_cookie, 825 sc->sc_extvga); 826 } 827 } 828 } 829 #ifdef DIAGNOSTIC 830 if (v & TS102_EVENT_STATUS_EXT_MOUSE_STATUS_CHANGE) { 831 splx(s); 832 tctrl_read_ext_status(); 833 if (sc->sc_ext_status & 834 TS102_EXT_STATUS_EXTERNAL_MOUSE_ATTACHED) { 835 printf("tctrl: external mouse detected\n"); 836 } 837 } 838 #endif 839 sc->sc_ext_pending = 0; 840 splx(s); 841 } 842 843 static void 844 tctrl_lock(struct tctrl_softc *sc) 845 { 846 847 mutex_enter(&sc->sc_requestlock); 848 } 849 850 static void 851 tctrl_unlock(struct tctrl_softc *sc) 852 { 853 854 mutex_exit(&sc->sc_requestlock); 855 } 856 857 int 858 tadpole_request(struct tctrl_req *req, int spin, int sleep) 859 { 860 struct tctrl_softc *sc; 861 int i, s; 862 863 sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV); 864 if (!sc) 865 return ENODEV; 866 867 tctrl_lock(sc); 868 869 if (spin) 870 s = splhigh(); 871 else 872 s = splts102(); 873 sc->sc_flags |= TCTRL_SEND_REQUEST; 874 memcpy(sc->sc_cmdbuf, req->cmdbuf, req->cmdlen); 875 #ifdef DIAGNOSTIC 876 if (sc->sc_wantdata != 0) { 877 splx(s); 878 printf("tctrl: we lost the race\n"); 879 tctrl_unlock(sc); 880 return EAGAIN; 881 } 882 #endif 883 sc->sc_wantdata = 1; 884 sc->sc_rsplen = req->rsplen; 885 sc->sc_cmdlen = req->cmdlen; 886 sc->sc_cmdoff = sc->sc_rspoff = 0; 887 888 /* we spin for certain commands, like poweroffs */ 889 if (spin) { 890 /* for (i = 0; i < 30000; i++) {*/ 891 i = 0; 892 while ((sc->sc_wantdata == 1) && (i < 30000)) { 893 tctrl_intr(sc); 894 DELAY(1); 895 i++; 896 } 897 #ifdef DIAGNOSTIC 898 if (i >= 30000) { 899 printf("tctrl: timeout busy waiting for micro controller request!\n"); 900 sc->sc_wantdata = 0; 901 splx(s); 902 tctrl_unlock(sc); 903 return EAGAIN; 904 } 905 #endif 906 } else { 907 int timeout = 5 * (sc->sc_rsplen + sc->sc_cmdlen); 908 tctrl_intr(sc); 909 i = 0; 910 while (((sc->sc_rspoff != sc->sc_rsplen) || 911 (sc->sc_cmdoff != sc->sc_cmdlen)) && 912 (i < timeout)) 913 if (sleep) { 914 tsleep(sc, PWAIT, "tctrl_data", 15); 915 i++; 916 } else 917 DELAY(1); 918 #ifdef DIAGNOSTIC 919 if (i >= timeout) { 920 printf("tctrl: timeout waiting for microcontroller request\n"); 921 sc->sc_wantdata = 0; 922 splx(s); 923 tctrl_unlock(sc); 924 return EAGAIN; 925 } 926 #endif 927 } 928 /* 929 * we give the user a reasonable amount of time for a command 930 * to complete. If it doesn't complete in time, we hand them 931 * garbage. This is here to stop things like setting the 932 * rsplen too long, and sleeping forever in a CMD_REQ ioctl. 933 */ 934 sc->sc_wantdata = 0; 935 memcpy(req->rspbuf, sc->sc_rspbuf, req->rsplen); 936 splx(s); 937 938 tctrl_unlock(sc); 939 return 0; 940 } 941 942 void 943 tadpole_powerdown(void) 944 { 945 struct tctrl_req req; 946 947 req.cmdbuf[0] = TS102_OP_ADMIN_POWER_OFF; 948 req.cmdlen = 1; 949 req.rsplen = 1; 950 tadpole_request(&req, 1, 0); 951 } 952 953 void 954 tadpole_set_video(int enabled) 955 { 956 struct tctrl_softc *sc; 957 struct tctrl_req req; 958 int s; 959 960 sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV); 961 while (sc->sc_wantdata != 0) 962 DELAY(1); 963 s = splts102(); 964 if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN && !enabled) 965 || (sc->sc_tft_on)) { 966 req.cmdbuf[2] = TS102_BITPORT_TFTPWR; 967 } else { 968 req.cmdbuf[2] = 0; 969 } 970 req.cmdbuf[0] = TS102_OP_CTL_BITPORT; 971 req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR; 972 req.cmdlen = 3; 973 req.rsplen = 2; 974 975 if ((sc->sc_tft_on && !enabled) || (!sc->sc_tft_on && enabled)) { 976 sc->sc_tft_on = enabled; 977 if (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) { 978 splx(s); 979 return; 980 } 981 tadpole_request(&req, 1, 0); 982 sc->sc_bitport = 983 (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2]; 984 } 985 splx(s); 986 } 987 988 static void 989 tctrl_write_data(struct tctrl_softc *sc, uint8_t v) 990 { 991 unsigned int i; 992 993 for (i = 0; i < 100; i++) { 994 if (TS102_UCTRL_STS_TXNF_STA & 995 tctrl_read(sc, TS102_REG_UCTRL_STS)) 996 break; 997 } 998 tctrl_write(sc, TS102_REG_UCTRL_DATA, v); 999 } 1000 1001 static uint8_t 1002 tctrl_read_data(struct tctrl_softc *sc) 1003 { 1004 unsigned int i, v; 1005 1006 for (i = 0; i < 100000; i++) { 1007 if (TS102_UCTRL_STS_RXNE_STA & 1008 tctrl_read(sc, TS102_REG_UCTRL_STS)) 1009 break; 1010 DELAY(1); 1011 } 1012 1013 v = tctrl_read(sc, TS102_REG_UCTRL_DATA); 1014 tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA); 1015 return v; 1016 } 1017 1018 static uint8_t 1019 tctrl_read(struct tctrl_softc *sc, bus_size_t off) 1020 { 1021 1022 sc->sc_junk = bus_space_read_1(sc->sc_memt, sc->sc_memh, off); 1023 return sc->sc_junk; 1024 } 1025 1026 static void 1027 tctrl_write(struct tctrl_softc *sc, bus_size_t off, uint8_t v) 1028 { 1029 1030 sc->sc_junk = v; 1031 bus_space_write_1(sc->sc_memt, sc->sc_memh, off, v); 1032 } 1033 1034 int 1035 tctrlopen(dev_t dev, int flags, int mode, struct lwp *l) 1036 { 1037 int unit = (minor(dev)&0xf0); 1038 int ctl = (minor(dev)&0x0f); 1039 struct tctrl_softc *sc; 1040 1041 if (unit >= tctrl_cd.cd_ndevs) 1042 return(ENXIO); 1043 sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV); 1044 if (!sc) 1045 return(ENXIO); 1046 1047 switch (ctl) { 1048 case TCTRL_STD_DEV: 1049 break; 1050 case TCTRL_APMCTL_DEV: 1051 if (!(flags & FWRITE)) 1052 return(EINVAL); 1053 if (sc->sc_flags & TCTRL_APM_CTLOPEN) 1054 return(EBUSY); 1055 sc->sc_flags |= TCTRL_APM_CTLOPEN; 1056 break; 1057 default: 1058 return(ENXIO); 1059 break; 1060 } 1061 1062 return(0); 1063 } 1064 1065 int 1066 tctrlclose(dev_t dev, int flags, int mode, struct lwp *l) 1067 { 1068 int ctl = (minor(dev)&0x0f); 1069 struct tctrl_softc *sc; 1070 1071 sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV); 1072 if (!sc) 1073 return(ENXIO); 1074 1075 switch (ctl) { 1076 case TCTRL_STD_DEV: 1077 break; 1078 case TCTRL_APMCTL_DEV: 1079 sc->sc_flags &= ~TCTRL_APM_CTLOPEN; 1080 break; 1081 } 1082 return(0); 1083 } 1084 1085 int 1086 tctrlioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l) 1087 { 1088 struct tctrl_req req, *reqn; 1089 struct tctrl_pwr *pwrreq; 1090 struct apm_power_info *powerp; 1091 struct apm_event_info *evp; 1092 struct tctrl_softc *sc; 1093 int i; 1094 uint8_t c; 1095 1096 sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV); 1097 if (!sc) 1098 return ENXIO; 1099 1100 switch (cmd) { 1101 1102 case APM_IOC_STANDBY: 1103 /* turn off backlight and so on ? */ 1104 1105 return 0; /* for now */ 1106 1107 case APM_IOC_SUSPEND: 1108 /* not sure what to do here - we can't really suspend */ 1109 1110 return 0; /* for now */ 1111 1112 case OAPM_IOC_GETPOWER: 1113 case APM_IOC_GETPOWER: 1114 powerp = (struct apm_power_info *)data; 1115 req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_RATE; 1116 req.cmdlen = 1; 1117 req.rsplen = 2; 1118 tadpole_request(&req, 0, l->l_proc ? 1 : 0); 1119 if (req.rspbuf[0] > 0x00) 1120 powerp->battery_state = APM_BATT_CHARGING; 1121 req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_LEVEL; 1122 req.cmdlen = 1; 1123 req.rsplen = 3; 1124 tadpole_request(&req, 0, l->l_proc ? 1 : 0); 1125 c = req.rspbuf[0]; 1126 powerp->battery_life = c; 1127 if (c > 0x70) /* the tadpole sometimes dips below zero, and */ 1128 c = 0; /* into the 255 range. */ 1129 powerp->minutes_left = (45 * c) / 100; /* XXX based on 45 min */ 1130 if (powerp->battery_state != APM_BATT_CHARGING) { 1131 if (c < 0x20) 1132 powerp->battery_state = APM_BATT_CRITICAL; 1133 else if (c < 0x40) 1134 powerp->battery_state = APM_BATT_LOW; 1135 else if (c < 0x66) 1136 powerp->battery_state = APM_BATT_HIGH; 1137 else 1138 powerp->battery_state = APM_BATT_UNKNOWN; 1139 } 1140 1141 if (sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) 1142 powerp->ac_state = APM_AC_ON; 1143 else 1144 powerp->ac_state = APM_AC_OFF; 1145 break; 1146 1147 case APM_IOC_NEXTEVENT: 1148 if (!sc->sc_event_count) 1149 return EAGAIN; 1150 1151 evp = (struct apm_event_info *)data; 1152 i = sc->sc_event_ptr + APM_NEVENTS - sc->sc_event_count; 1153 i %= APM_NEVENTS; 1154 *evp = sc->sc_event_list[i]; 1155 sc->sc_event_count--; 1156 return(0); 1157 1158 /* this ioctl assumes the caller knows exactly what he is doing */ 1159 case TCTRL_CMD_REQ: 1160 reqn = (struct tctrl_req *)data; 1161 if ((i = kauth_authorize_device_passthru(l->l_cred, 1162 dev, KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL, data)) != 0 && 1163 (reqn->cmdbuf[0] == TS102_OP_CTL_BITPORT || 1164 (reqn->cmdbuf[0] >= TS102_OP_CTL_WATCHDOG && 1165 reqn->cmdbuf[0] <= TS102_OP_CTL_SECURITY_KEY) || 1166 reqn->cmdbuf[0] == TS102_OP_CTL_TIMEZONE || 1167 reqn->cmdbuf[0] == TS102_OP_CTL_DIAGNOSTIC_MODE || 1168 reqn->cmdbuf[0] == TS102_OP_CMD_SOFTWARE_RESET || 1169 (reqn->cmdbuf[0] >= TS102_OP_CMD_SET_RTC && 1170 reqn->cmdbuf[0] < TS102_OP_RD_INT_CHARGE_LEVEL) || 1171 reqn->cmdbuf[0] > TS102_OP_RD_EXT_CHARGE_LEVEL)) 1172 return(i); 1173 tadpole_request(reqn, 0, l->l_proc ? 1 : 0); 1174 break; 1175 /* serial power mode (via auxiotwo) */ 1176 case TCTRL_SERIAL_PWR: 1177 pwrreq = (struct tctrl_pwr *)data; 1178 if (pwrreq->rw) 1179 pwrreq->state = auxiotwoserialgetapm(); 1180 else 1181 auxiotwoserialsetapm(pwrreq->state); 1182 break; 1183 1184 /* modem power mode (via auxio) */ 1185 case TCTRL_MODEM_PWR: 1186 return(EOPNOTSUPP); /* for now */ 1187 break; 1188 1189 1190 default: 1191 return (ENOTTY); 1192 } 1193 return (0); 1194 } 1195 1196 int 1197 tctrlpoll(dev_t dev, int events, struct lwp *l) 1198 { 1199 struct tctrl_softc *sc = device_lookup_private(&tctrl_cd, 1200 TCTRL_STD_DEV); 1201 int revents = 0; 1202 1203 if (events & (POLLIN | POLLRDNORM)) { 1204 if (sc->sc_event_count) 1205 revents |= events & (POLLIN | POLLRDNORM); 1206 else 1207 selrecord(l, &sc->sc_rsel); 1208 } 1209 1210 return (revents); 1211 } 1212 1213 static void 1214 filt_tctrlrdetach(struct knote *kn) 1215 { 1216 struct tctrl_softc *sc = kn->kn_hook; 1217 int s; 1218 1219 s = splts102(); 1220 SLIST_REMOVE(&sc->sc_rsel.sel_klist, kn, knote, kn_selnext); 1221 splx(s); 1222 } 1223 1224 static int 1225 filt_tctrlread(struct knote *kn, long hint) 1226 { 1227 struct tctrl_softc *sc = kn->kn_hook; 1228 1229 kn->kn_data = sc->sc_event_count; 1230 return (kn->kn_data > 0); 1231 } 1232 1233 static const struct filterops tctrlread_filtops = 1234 { 1, NULL, filt_tctrlrdetach, filt_tctrlread }; 1235 1236 int 1237 tctrlkqfilter(dev_t dev, struct knote *kn) 1238 { 1239 struct tctrl_softc *sc = device_lookup_private(&tctrl_cd, 1240 TCTRL_STD_DEV); 1241 struct klist *klist; 1242 int s; 1243 1244 switch (kn->kn_filter) { 1245 case EVFILT_READ: 1246 klist = &sc->sc_rsel.sel_klist; 1247 kn->kn_fop = &tctrlread_filtops; 1248 break; 1249 1250 default: 1251 return (1); 1252 } 1253 1254 kn->kn_hook = sc; 1255 1256 s = splts102(); 1257 SLIST_INSERT_HEAD(klist, kn, kn_selnext); 1258 splx(s); 1259 1260 return (0); 1261 } 1262 1263 static void 1264 tctrl_sensor_setup(struct tctrl_softc *sc) 1265 { 1266 int i, error; 1267 1268 sc->sc_sme = sysmon_envsys_create(); 1269 1270 /* case temperature */ 1271 (void)strlcpy(sc->sc_sensor[0].desc, "Case temperature", 1272 sizeof(sc->sc_sensor[0].desc)); 1273 sc->sc_sensor[0].units = ENVSYS_STEMP; 1274 sc->sc_sensor[0].state = ENVSYS_SINVALID; 1275 1276 /* battery voltage */ 1277 (void)strlcpy(sc->sc_sensor[1].desc, "Internal battery voltage", 1278 sizeof(sc->sc_sensor[1].desc)); 1279 sc->sc_sensor[1].units = ENVSYS_SVOLTS_DC; 1280 sc->sc_sensor[1].state = ENVSYS_SINVALID; 1281 1282 /* DC voltage */ 1283 (void)strlcpy(sc->sc_sensor[2].desc, "DC-In voltage", 1284 sizeof(sc->sc_sensor[2].desc)); 1285 sc->sc_sensor[2].units = ENVSYS_SVOLTS_DC; 1286 sc->sc_sensor[2].state = ENVSYS_SINVALID; 1287 1288 for (i = 0; i < ENVSYS_NUMSENSORS; i++) { 1289 if (sysmon_envsys_sensor_attach(sc->sc_sme, 1290 &sc->sc_sensor[i])) { 1291 sysmon_envsys_destroy(sc->sc_sme); 1292 return; 1293 } 1294 } 1295 1296 sc->sc_sme->sme_name = device_xname(sc->sc_dev); 1297 sc->sc_sme->sme_cookie = sc; 1298 sc->sc_sme->sme_refresh = tctrl_refresh; 1299 1300 if ((error = sysmon_envsys_register(sc->sc_sme)) != 0) { 1301 printf("%s: couldn't register sensors (%d)\n", 1302 device_xname(sc->sc_dev), error); 1303 sysmon_envsys_destroy(sc->sc_sme); 1304 return; 1305 } 1306 1307 /* now register the power button */ 1308 1309 sysmon_task_queue_init(); 1310 1311 sc->sc_powerpressed = 0; 1312 memset(&sc->sc_sm_pbutton, 0, sizeof(struct sysmon_pswitch)); 1313 sc->sc_sm_pbutton.smpsw_name = device_xname(sc->sc_dev); 1314 sc->sc_sm_pbutton.smpsw_type = PSWITCH_TYPE_POWER; 1315 if (sysmon_pswitch_register(&sc->sc_sm_pbutton) != 0) 1316 printf("%s: unable to register power button with sysmon\n", 1317 device_xname(sc->sc_dev)); 1318 1319 memset(&sc->sc_sm_lid, 0, sizeof(struct sysmon_pswitch)); 1320 sc->sc_sm_lid.smpsw_name = device_xname(sc->sc_dev); 1321 sc->sc_sm_lid.smpsw_type = PSWITCH_TYPE_LID; 1322 if (sysmon_pswitch_register(&sc->sc_sm_lid) != 0) 1323 printf("%s: unable to register lid switch with sysmon\n", 1324 device_xname(sc->sc_dev)); 1325 1326 memset(&sc->sc_sm_ac, 0, sizeof(struct sysmon_pswitch)); 1327 sc->sc_sm_ac.smpsw_name = device_xname(sc->sc_dev); 1328 sc->sc_sm_ac.smpsw_type = PSWITCH_TYPE_ACADAPTER; 1329 if (sysmon_pswitch_register(&sc->sc_sm_ac) != 0) 1330 printf("%s: unable to register AC adaptor with sysmon\n", 1331 device_xname(sc->sc_dev)); 1332 } 1333 1334 static void 1335 tctrl_power_button_pressed(void *arg) 1336 { 1337 struct tctrl_softc *sc = arg; 1338 1339 sysmon_pswitch_event(&sc->sc_sm_pbutton, PSWITCH_EVENT_PRESSED); 1340 sc->sc_powerpressed = 0; 1341 } 1342 1343 static void 1344 tctrl_lid_state(struct tctrl_softc *sc) 1345 { 1346 int state; 1347 1348 state = (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) ? 1349 PSWITCH_EVENT_PRESSED : PSWITCH_EVENT_RELEASED; 1350 sysmon_pswitch_event(&sc->sc_sm_lid, state); 1351 } 1352 1353 static void 1354 tctrl_ac_state(struct tctrl_softc *sc) 1355 { 1356 int state; 1357 1358 state = (sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ? 1359 PSWITCH_EVENT_PRESSED : PSWITCH_EVENT_RELEASED; 1360 sysmon_pswitch_event(&sc->sc_sm_ac, state); 1361 } 1362 1363 static int 1364 tctrl_powerfail(void *arg) 1365 { 1366 struct tctrl_softc *sc = (struct tctrl_softc *)arg; 1367 1368 /* 1369 * We lost power. Queue a callback with thread context to 1370 * handle all the real work. 1371 */ 1372 if (sc->sc_powerpressed == 0) { 1373 sc->sc_powerpressed = 1; 1374 sysmon_task_queue_sched(0, tctrl_power_button_pressed, sc); 1375 } 1376 return (1); 1377 } 1378 1379 static void 1380 tctrl_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 1381 { 1382 /*struct tctrl_softc *sc = sme->sme_cookie;*/ 1383 struct tctrl_req req; 1384 int sleepable; 1385 int i; 1386 1387 i = edata->sensor; 1388 sleepable = curlwp ? 1 : 0; 1389 1390 switch (i) 1391 { 1392 case 0: /* case temperature */ 1393 req.cmdbuf[0] = TS102_OP_RD_CURRENT_TEMP; 1394 req.cmdlen = 1; 1395 req.rsplen = 2; 1396 tadpole_request(&req, 0, sleepable); 1397 edata->value_cur = /* 273160? */ 1398 (uint32_t)((int)((int)req.rspbuf[0] - 32) * 5000000 1399 / 9 + 273150000); 1400 req.cmdbuf[0] = TS102_OP_RD_MAX_TEMP; 1401 req.cmdlen = 1; 1402 req.rsplen = 2; 1403 tadpole_request(&req, 0, sleepable); 1404 edata->value_max = 1405 (uint32_t)((int)((int)req.rspbuf[0] - 32) * 5000000 1406 / 9 + 273150000); 1407 edata->flags |= ENVSYS_FVALID_MAX; 1408 req.cmdbuf[0] = TS102_OP_RD_MIN_TEMP; 1409 req.cmdlen = 1; 1410 req.rsplen = 2; 1411 tadpole_request(&req, 0, sleepable); 1412 edata->value_min = 1413 (uint32_t)((int)((int)req.rspbuf[0] - 32) * 5000000 1414 / 9 + 273150000); 1415 edata->flags |= ENVSYS_FVALID_MIN; 1416 edata->units = ENVSYS_STEMP; 1417 break; 1418 1419 case 1: /* battery voltage */ 1420 { 1421 edata->units = ENVSYS_SVOLTS_DC; 1422 req.cmdbuf[0] = TS102_OP_RD_INT_BATT_VLT; 1423 req.cmdlen = 1; 1424 req.rsplen = 2; 1425 tadpole_request(&req, 0, sleepable); 1426 edata->value_cur = (int32_t)req.rspbuf[0] * 1427 1000000 / 11; 1428 } 1429 break; 1430 case 2: /* DC voltage */ 1431 { 1432 edata->units = ENVSYS_SVOLTS_DC; 1433 req.cmdbuf[0] = TS102_OP_RD_DC_IN_VLT; 1434 req.cmdlen = 1; 1435 req.rsplen = 2; 1436 tadpole_request(&req, 0, sleepable); 1437 edata->value_cur = (int32_t)req.rspbuf[0] * 1438 1000000 / 11; 1439 } 1440 break; 1441 } 1442 edata->state = ENVSYS_SVALID; 1443 } 1444 1445 static void 1446 tctrl_event_thread(void *v) 1447 { 1448 struct tctrl_softc *sc = v; 1449 device_t dv; 1450 struct sd_softc *sd = NULL; 1451 struct lance_softc *le = NULL; 1452 int ticks = hz/2; 1453 int rcount, wcount; 1454 int s; 1455 1456 while (sd == NULL) { 1457 dv = device_find_by_xname("sd0"); 1458 if (dv != NULL) 1459 sd = device_private(dv); 1460 else 1461 tsleep(&sc->sc_events, PWAIT, "probe_disk", hz); 1462 } 1463 dv = device_find_by_xname("le0"); 1464 if (dv != NULL) 1465 le = device_private(dv); 1466 printf("found %s\n", device_xname(sd->sc_dev)); 1467 rcount = sd->sc_dk.dk_stats->io_rxfer; 1468 wcount = sd->sc_dk.dk_stats->io_wxfer; 1469 1470 tctrl_read_event_status(sc); 1471 1472 while (1) { 1473 tsleep(&sc->sc_events, PWAIT, "tctrl_event", ticks); 1474 s = splhigh(); 1475 if ((rcount != sd->sc_dk.dk_stats->io_rxfer) || 1476 (wcount != sd->sc_dk.dk_stats->io_wxfer)) { 1477 rcount = sd->sc_dk.dk_stats->io_rxfer; 1478 wcount = sd->sc_dk.dk_stats->io_wxfer; 1479 sc->sc_lcdwanted |= TS102_LCD_DISK_ACTIVE; 1480 } else 1481 sc->sc_lcdwanted &= ~TS102_LCD_DISK_ACTIVE; 1482 if (le != NULL) { 1483 if (le->sc_havecarrier != 0) { 1484 sc->sc_lcdwanted |= TS102_LCD_LAN_ACTIVE; 1485 } else 1486 sc->sc_lcdwanted &= ~TS102_LCD_LAN_ACTIVE; 1487 } 1488 splx(s); 1489 tctrl_update_lcd(sc); 1490 if (sc->sc_ext_pending) 1491 tctrl_read_event_status(sc); 1492 } 1493 } 1494 1495 void 1496 tadpole_register_callback(void (*callback)(void *, int), void *cookie) 1497 { 1498 struct tctrl_softc *sc; 1499 1500 sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV); 1501 sc->sc_video_callback = callback; 1502 sc->sc_video_callback_cookie = cookie; 1503 if (sc->sc_video_callback != NULL) { 1504 sc->sc_video_callback(sc->sc_video_callback_cookie, 1505 sc->sc_extvga); 1506 } 1507 } 1508