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