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