1 /* $NetBSD: tctrl.c,v 1.44 2007/11/16 08:00:12 xtraeme 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 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: tctrl.c,v 1.44 2007/11/16 08:00:12 xtraeme Exp $"); 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/ioctl.h> 45 #include <sys/select.h> 46 #include <sys/tty.h> 47 #include <sys/proc.h> 48 #include <sys/user.h> 49 #include <sys/conf.h> 50 #include <sys/file.h> 51 #include <sys/uio.h> 52 #include <sys/kernel.h> 53 #include <sys/kthread.h> 54 #include <sys/syslog.h> 55 #include <sys/types.h> 56 #include <sys/device.h> 57 #include <sys/envsys.h> 58 #include <sys/poll.h> 59 #include <sys/kauth.h> 60 61 #include <machine/apmvar.h> 62 #include <machine/autoconf.h> 63 #include <machine/bus.h> 64 #include <machine/intr.h> 65 #include <machine/tctrl.h> 66 67 #include <sparc/dev/ts102reg.h> 68 #include <sparc/dev/tctrlvar.h> 69 #include <sparc/sparc/auxiotwo.h> 70 #include <sparc/sparc/auxreg.h> 71 72 #include <dev/sysmon/sysmonvar.h> 73 #include <dev/sysmon/sysmon_taskq.h> 74 75 #include "sysmon_envsys.h" 76 77 /*#define TCTRLDEBUG*/ 78 79 /* disk spinner */ 80 #include <sys/disk.h> 81 #include <dev/scsipi/sdvar.h> 82 83 /* ethernet carrier */ 84 #include <net/if.h> 85 #include <net/if_dl.h> 86 #include <net/if_ether.h> 87 #include <net/if_media.h> 88 #include <dev/ic/lancevar.h> 89 90 extern struct cfdriver tctrl_cd; 91 92 dev_type_open(tctrlopen); 93 dev_type_close(tctrlclose); 94 dev_type_ioctl(tctrlioctl); 95 dev_type_poll(tctrlpoll); 96 dev_type_kqfilter(tctrlkqfilter); 97 98 const struct cdevsw tctrl_cdevsw = { 99 tctrlopen, tctrlclose, noread, nowrite, tctrlioctl, 100 nostop, notty, tctrlpoll, nommap, tctrlkqfilter, 101 }; 102 103 static const char *tctrl_ext_statuses[16] = { 104 "main power available", 105 "internal battery attached", 106 "external battery attached", 107 "external VGA attached", 108 "external keyboard attached", 109 "external mouse attached", 110 "lid down", 111 "internal battery charging", 112 "external battery charging", 113 "internal battery discharging", 114 "external battery discharging", 115 }; 116 117 struct tctrl_softc { 118 struct device sc_dev; 119 bus_space_tag_t sc_memt; 120 bus_space_handle_t sc_memh; 121 unsigned int sc_junk; 122 unsigned int sc_ext_status; 123 unsigned int sc_flags; 124 #define TCTRL_SEND_REQUEST 0x0001 125 #define TCTRL_APM_CTLOPEN 0x0002 126 uint32_t sc_wantdata; 127 uint32_t sc_ext_pending; 128 volatile uint16_t sc_lcdstate; 129 uint16_t sc_lcdwanted; 130 131 enum { TCTRL_IDLE, TCTRL_ARGS, 132 TCTRL_ACK, TCTRL_DATA } sc_state; 133 uint8_t sc_cmdbuf[16]; 134 uint8_t sc_rspbuf[16]; 135 uint8_t sc_bitport; 136 uint8_t sc_tft_on; 137 uint8_t sc_op; 138 uint8_t sc_cmdoff; 139 uint8_t sc_cmdlen; 140 uint8_t sc_rspoff; 141 uint8_t sc_rsplen; 142 /* APM stuff */ 143 #define APM_NEVENTS 16 144 struct apm_event_info sc_event_list[APM_NEVENTS]; 145 int sc_event_count; 146 int sc_event_ptr; 147 struct selinfo sc_rsel; 148 149 /* ENVSYS stuff */ 150 #define ENVSYS_NUMSENSORS 3 151 struct evcnt sc_intrcnt; /* interrupt counting */ 152 struct sysmon_envsys *sc_sme; 153 envsys_data_t sc_sensor[ENVSYS_NUMSENSORS]; 154 155 struct sysmon_pswitch sc_sm_pbutton; /* power button */ 156 struct sysmon_pswitch sc_sm_lid; /* lid state */ 157 struct sysmon_pswitch sc_sm_ac; /* AC adaptor presence */ 158 int sc_powerpressed; 159 160 /* hardware status stuff */ 161 int sc_lid; /* 1 - open, 0 - closed */ 162 int sc_power_state; 163 int sc_spl; 164 165 /* 166 * we call this when we detect connection or removal of an external 167 * monitor. 0 for no monitor, !=0 for monitor present 168 */ 169 void (*sc_video_callback)(void *, int); 170 void *sc_video_callback_cookie; 171 int sc_extvga; 172 173 uint32_t sc_events; 174 lwp_t *sc_thread; /* event thread */ 175 kmutex_t sc_requestlock; 176 }; 177 178 #define TCTRL_STD_DEV 0 179 #define TCTRL_APMCTL_DEV 8 180 181 static int tctrl_match(struct device *, struct cfdata *, void *); 182 static void tctrl_attach(struct device *, struct device *, void *); 183 static void tctrl_write(struct tctrl_softc *, bus_size_t, uint8_t); 184 static uint8_t tctrl_read(struct tctrl_softc *, bus_size_t); 185 static void tctrl_write_data(struct tctrl_softc *, uint8_t); 186 static uint8_t tctrl_read_data(struct tctrl_softc *); 187 static int tctrl_intr(void *); 188 static void tctrl_setup_bitport(void); 189 static void tctrl_setup_bitport_nop(void); 190 static void tctrl_read_ext_status(void); 191 static void tctrl_read_event_status(struct tctrl_softc *); 192 static int tctrl_apm_record_event(struct tctrl_softc *, u_int); 193 static void tctrl_init_lcd(void); 194 195 static void tctrl_sensor_setup(struct tctrl_softc *); 196 static void tctrl_refresh(struct sysmon_envsys *, envsys_data_t *); 197 198 static void tctrl_power_button_pressed(void *); 199 static void tctrl_lid_state(struct tctrl_softc *); 200 static void tctrl_ac_state(struct tctrl_softc *); 201 202 static int tctrl_powerfail(void *); 203 204 static void tctrl_event_thread(void *); 205 void tctrl_update_lcd(struct tctrl_softc *); 206 207 static void tctrl_lock(struct tctrl_softc *); 208 static void tctrl_unlock(struct tctrl_softc *); 209 210 CFATTACH_DECL(tctrl, sizeof(struct tctrl_softc), 211 tctrl_match, tctrl_attach, NULL, NULL); 212 213 static int tadpole_request(struct tctrl_req *, int, int); 214 215 /* XXX wtf is this? see i386/apm.c */ 216 int tctrl_apm_evindex; 217 218 static int 219 tctrl_match(struct device *parent, struct cfdata *cf, void *aux) 220 { 221 union obio_attach_args *uoba = aux; 222 struct sbus_attach_args *sa = &uoba->uoba_sbus; 223 224 if (uoba->uoba_isobio4 != 0) { 225 return (0); 226 } 227 228 /* Tadpole 3GX/3GS uses "uctrl" for the Tadpole Microcontroller 229 * (who's interface is off the TS102 PCMCIA controller but there 230 * exists a OpenProm for microcontroller interface). 231 */ 232 return strcmp("uctrl", sa->sa_name) == 0; 233 } 234 235 static void 236 tctrl_attach(struct device *parent, struct device *self, void *aux) 237 { 238 struct tctrl_softc *sc = (void *)self; 239 union obio_attach_args *uoba = aux; 240 struct sbus_attach_args *sa = &uoba->uoba_sbus; 241 unsigned int i, v; 242 243 /* We're living on a sbus slot that looks like an obio that 244 * looks like an sbus slot. 245 */ 246 sc->sc_memt = sa->sa_bustag; 247 if (sbus_bus_map(sc->sc_memt, 248 sa->sa_slot, 249 sa->sa_offset - TS102_REG_UCTRL_INT, 250 sa->sa_size, 251 BUS_SPACE_MAP_LINEAR, &sc->sc_memh) != 0) { 252 printf(": can't map registers\n"); 253 return; 254 } 255 256 printf("\n"); 257 258 sc->sc_tft_on = 1; 259 260 /* clear any pending data. 261 */ 262 for (i = 0; i < 10000; i++) { 263 if ((TS102_UCTRL_STS_RXNE_STA & 264 tctrl_read(sc, TS102_REG_UCTRL_STS)) == 0) { 265 break; 266 } 267 v = tctrl_read(sc, TS102_REG_UCTRL_DATA); 268 tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA); 269 } 270 271 if (sa->sa_nintr != 0) { 272 (void)bus_intr_establish(sc->sc_memt, sa->sa_pri, IPL_NONE, 273 tctrl_intr, sc); 274 evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, NULL, 275 sc->sc_dev.dv_xname, "intr"); 276 } 277 278 /* See what the external status is */ 279 sc->sc_ext_status = 0; 280 tctrl_read_ext_status(); 281 if (sc->sc_ext_status != 0) { 282 const char *sep; 283 284 printf("%s: ", sc->sc_dev.dv_xname); 285 v = sc->sc_ext_status; 286 for (i = 0, sep = ""; v != 0; i++, v >>= 1) { 287 if (v & 1) { 288 printf("%s%s", sep, tctrl_ext_statuses[i]); 289 sep = ", "; 290 } 291 } 292 printf("\n"); 293 } 294 295 /* Get a current of the control bitport */ 296 tctrl_setup_bitport_nop(); 297 tctrl_write(sc, TS102_REG_UCTRL_INT, 298 TS102_UCTRL_INT_RXNE_REQ|TS102_UCTRL_INT_RXNE_MSK); 299 sc->sc_lid = (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) == 0; 300 sc->sc_power_state = PWR_RESUME; 301 302 sc->sc_extvga = (sc->sc_ext_status & 303 TS102_EXT_STATUS_EXTERNAL_VGA_ATTACHED) != 0; 304 sc->sc_video_callback = NULL; 305 306 307 sc->sc_wantdata = 0; 308 sc->sc_event_count = 0; 309 sc->sc_ext_pending = 0; 310 sc->sc_ext_pending = 0; 311 312 mutex_init(&sc->sc_requestlock, MUTEX_DEFAULT, IPL_NONE); 313 314 /* setup sensors and register the power button */ 315 tctrl_sensor_setup(sc); 316 tctrl_lid_state(sc); 317 tctrl_ac_state(sc); 318 319 /* initialize the LCD */ 320 tctrl_init_lcd(); 321 322 /* initialize sc_lcdstate */ 323 sc->sc_lcdstate = 0; 324 sc->sc_lcdwanted = 0; 325 tadpole_set_lcd(2, 0); 326 327 /* fire up the LCD event thread */ 328 sc->sc_events = 0; 329 330 if (kthread_create(PRI_NONE, 0, NULL, tctrl_event_thread, sc, 331 &sc->sc_thread, "%s", sc->sc_dev.dv_xname) != 0) { 332 printf("%s: unable to create event kthread", 333 sc->sc_dev.dv_xname); 334 } 335 } 336 337 static int 338 tctrl_intr(void *arg) 339 { 340 struct tctrl_softc *sc = arg; 341 unsigned int v, d; 342 int progress = 0; 343 344 again: 345 /* find out the cause(s) of the interrupt */ 346 v = tctrl_read(sc, TS102_REG_UCTRL_STS) & TS102_UCTRL_STS_MASK; 347 348 /* clear the cause(s) of the interrupt */ 349 tctrl_write(sc, TS102_REG_UCTRL_STS, v); 350 351 v &= ~(TS102_UCTRL_STS_RXO_STA|TS102_UCTRL_STS_TXE_STA); 352 if (sc->sc_cmdoff >= sc->sc_cmdlen) { 353 v &= ~TS102_UCTRL_STS_TXNF_STA; 354 if (tctrl_read(sc, TS102_REG_UCTRL_INT) & 355 TS102_UCTRL_INT_TXNF_REQ) { 356 tctrl_write(sc, TS102_REG_UCTRL_INT, 0); 357 progress = 1; 358 } 359 } 360 if ((v == 0) && ((sc->sc_flags & TCTRL_SEND_REQUEST) == 0 || 361 sc->sc_state != TCTRL_IDLE)) { 362 wakeup(sc); 363 return progress; 364 } 365 366 progress = 1; 367 if (v & TS102_UCTRL_STS_RXNE_STA) { 368 d = tctrl_read_data(sc); 369 switch (sc->sc_state) { 370 case TCTRL_IDLE: 371 if (d == 0xfa) { 372 /* 373 * external event, 374 * set a flag and wakeup the event thread 375 */ 376 sc->sc_ext_pending = 1; 377 } else { 378 printf("%s: (op=0x%02x): unexpected data (0x%02x)\n", 379 sc->sc_dev.dv_xname, sc->sc_op, d); 380 } 381 goto again; 382 case TCTRL_ACK: 383 if (d != 0xfe) { 384 printf("%s: (op=0x%02x): unexpected ack value (0x%02x)\n", 385 sc->sc_dev.dv_xname, sc->sc_op, d); 386 } 387 #ifdef TCTRLDEBUG 388 printf(" ack=0x%02x", d); 389 #endif 390 sc->sc_rsplen--; 391 sc->sc_rspoff = 0; 392 sc->sc_state = sc->sc_rsplen ? TCTRL_DATA : TCTRL_IDLE; 393 sc->sc_wantdata = sc->sc_rsplen ? 1 : 0; 394 #ifdef TCTRLDEBUG 395 if (sc->sc_rsplen > 0) { 396 printf(" [data(%u)]", sc->sc_rsplen); 397 } else { 398 printf(" [idle]\n"); 399 } 400 #endif 401 goto again; 402 case TCTRL_DATA: 403 sc->sc_rspbuf[sc->sc_rspoff++] = d; 404 #ifdef TCTRLDEBUG 405 printf(" [%d]=0x%02x", sc->sc_rspoff-1, d); 406 #endif 407 if (sc->sc_rspoff == sc->sc_rsplen) { 408 #ifdef TCTRLDEBUG 409 printf(" [idle]\n"); 410 #endif 411 sc->sc_state = TCTRL_IDLE; 412 sc->sc_wantdata = 0; 413 } 414 goto again; 415 default: 416 printf("%s: (op=0x%02x): unexpected data (0x%02x) in state %d\n", 417 sc->sc_dev.dv_xname, sc->sc_op, d, sc->sc_state); 418 goto again; 419 } 420 } 421 if ((sc->sc_state == TCTRL_IDLE && sc->sc_wantdata == 0) || 422 sc->sc_flags & TCTRL_SEND_REQUEST) { 423 if (sc->sc_flags & TCTRL_SEND_REQUEST) { 424 sc->sc_flags &= ~TCTRL_SEND_REQUEST; 425 sc->sc_wantdata = 1; 426 } 427 if (sc->sc_cmdlen > 0) { 428 tctrl_write(sc, TS102_REG_UCTRL_INT, 429 tctrl_read(sc, TS102_REG_UCTRL_INT) 430 |TS102_UCTRL_INT_TXNF_MSK 431 |TS102_UCTRL_INT_TXNF_REQ); 432 v = tctrl_read(sc, TS102_REG_UCTRL_STS); 433 } 434 } 435 if ((sc->sc_cmdoff < sc->sc_cmdlen) && (v & TS102_UCTRL_STS_TXNF_STA)) { 436 tctrl_write_data(sc, sc->sc_cmdbuf[sc->sc_cmdoff++]); 437 #ifdef TCTRLDEBUG 438 if (sc->sc_cmdoff == 1) { 439 printf("%s: op=0x%02x(l=%u)", sc->sc_dev.dv_xname, 440 sc->sc_cmdbuf[0], sc->sc_rsplen); 441 } else { 442 printf(" [%d]=0x%02x", sc->sc_cmdoff-1, 443 sc->sc_cmdbuf[sc->sc_cmdoff-1]); 444 } 445 #endif 446 if (sc->sc_cmdoff == sc->sc_cmdlen) { 447 sc->sc_state = sc->sc_rsplen ? TCTRL_ACK : TCTRL_IDLE; 448 #ifdef TCTRLDEBUG 449 printf(" %s", sc->sc_rsplen ? "[ack]" : "[idle]\n"); 450 #endif 451 if (sc->sc_cmdoff == 1) { 452 sc->sc_op = sc->sc_cmdbuf[0]; 453 } 454 tctrl_write(sc, TS102_REG_UCTRL_INT, 455 tctrl_read(sc, TS102_REG_UCTRL_INT) 456 & (~TS102_UCTRL_INT_TXNF_MSK 457 |TS102_UCTRL_INT_TXNF_REQ)); 458 } else if (sc->sc_state == TCTRL_IDLE) { 459 sc->sc_op = sc->sc_cmdbuf[0]; 460 sc->sc_state = TCTRL_ARGS; 461 #ifdef TCTRLDEBUG 462 printf(" [args]"); 463 #endif 464 } 465 } 466 goto again; 467 } 468 469 static void 470 tctrl_setup_bitport_nop(void) 471 { 472 struct tctrl_softc *sc; 473 struct tctrl_req req; 474 int s; 475 476 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV]; 477 req.cmdbuf[0] = TS102_OP_CTL_BITPORT; 478 req.cmdbuf[1] = 0xff; 479 req.cmdbuf[2] = 0x00; 480 req.cmdlen = 3; 481 req.rsplen = 2; 482 tadpole_request(&req, 1, 0); 483 s = splts102(); 484 sc->sc_bitport = (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2]; 485 splx(s); 486 } 487 488 static void 489 tctrl_setup_bitport(void) 490 { 491 struct tctrl_softc *sc; 492 struct tctrl_req req; 493 int s; 494 495 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV]; 496 s = splts102(); 497 req.cmdbuf[2] = 0; 498 if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) 499 || (!sc->sc_tft_on)) { 500 req.cmdbuf[2] = TS102_BITPORT_TFTPWR; 501 } 502 req.cmdbuf[0] = TS102_OP_CTL_BITPORT; 503 req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR; 504 req.cmdlen = 3; 505 req.rsplen = 2; 506 tadpole_request(&req, 1, 0); 507 s = splts102(); 508 sc->sc_bitport = (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2]; 509 splx(s); 510 } 511 512 /* 513 * The tadpole microcontroller is not preprogrammed with icon 514 * representations. The machine boots with the DC-IN light as 515 * a blank (all 0x00) and the other lights, as 4 rows of horizontal 516 * bars. The below code initializes the icons in the system to 517 * sane values. Some of these icons could be used for any purpose 518 * desired, namely the pcmcia, LAN and WAN lights. For the disk spinner, 519 * only the backslash is unprogrammed. (sigh) 520 * 521 * programming the icons is simple. It is a 5x8 matrix, which each row a 522 * bitfield in the order 0x10 0x08 0x04 0x02 0x01. 523 */ 524 525 static void 526 tctrl_init_lcd(void) 527 { 528 struct tctrl_req req; 529 530 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR; 531 req.cmdlen = 11; 532 req.rsplen = 1; 533 req.cmdbuf[1] = 0x08; /*len*/ 534 req.cmdbuf[2] = TS102_BLK_OFF_DEF_DC_GOOD; 535 req.cmdbuf[3] = 0x00; /* ..... */ 536 req.cmdbuf[4] = 0x00; /* ..... */ 537 req.cmdbuf[5] = 0x1f; /* XXXXX */ 538 req.cmdbuf[6] = 0x00; /* ..... */ 539 req.cmdbuf[7] = 0x15; /* X.X.X */ 540 req.cmdbuf[8] = 0x00; /* ..... */ 541 req.cmdbuf[9] = 0x00; /* ..... */ 542 req.cmdbuf[10] = 0x00; /* ..... */ 543 tadpole_request(&req, 1, 0); 544 545 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR; 546 req.cmdlen = 11; 547 req.rsplen = 1; 548 req.cmdbuf[1] = 0x08; /*len*/ 549 req.cmdbuf[2] = TS102_BLK_OFF_DEF_BACKSLASH; 550 req.cmdbuf[3] = 0x00; /* ..... */ 551 req.cmdbuf[4] = 0x10; /* X.... */ 552 req.cmdbuf[5] = 0x08; /* .X... */ 553 req.cmdbuf[6] = 0x04; /* ..X.. */ 554 req.cmdbuf[7] = 0x02; /* ...X. */ 555 req.cmdbuf[8] = 0x01; /* ....X */ 556 req.cmdbuf[9] = 0x00; /* ..... */ 557 req.cmdbuf[10] = 0x00; /* ..... */ 558 tadpole_request(&req, 1, 0); 559 560 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR; 561 req.cmdlen = 11; 562 req.rsplen = 1; 563 req.cmdbuf[1] = 0x08; /*len*/ 564 req.cmdbuf[2] = TS102_BLK_OFF_DEF_WAN1; 565 req.cmdbuf[3] = 0x0c; /* .XXX. */ 566 req.cmdbuf[4] = 0x16; /* X.XX. */ 567 req.cmdbuf[5] = 0x10; /* X.... */ 568 req.cmdbuf[6] = 0x15; /* X.X.X */ 569 req.cmdbuf[7] = 0x10; /* X.... */ 570 req.cmdbuf[8] = 0x16; /* X.XX. */ 571 req.cmdbuf[9] = 0x0c; /* .XXX. */ 572 req.cmdbuf[10] = 0x00; /* ..... */ 573 tadpole_request(&req, 1, 0); 574 575 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR; 576 req.cmdlen = 11; 577 req.rsplen = 1; 578 req.cmdbuf[1] = 0x08; /*len*/ 579 req.cmdbuf[2] = TS102_BLK_OFF_DEF_WAN2; 580 req.cmdbuf[3] = 0x0c; /* .XXX. */ 581 req.cmdbuf[4] = 0x0d; /* .XX.X */ 582 req.cmdbuf[5] = 0x01; /* ....X */ 583 req.cmdbuf[6] = 0x15; /* X.X.X */ 584 req.cmdbuf[7] = 0x01; /* ....X */ 585 req.cmdbuf[8] = 0x0d; /* .XX.X */ 586 req.cmdbuf[9] = 0x0c; /* .XXX. */ 587 req.cmdbuf[10] = 0x00; /* ..... */ 588 tadpole_request(&req, 1, 0); 589 590 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR; 591 req.cmdlen = 11; 592 req.rsplen = 1; 593 req.cmdbuf[1] = 0x08; /*len*/ 594 req.cmdbuf[2] = TS102_BLK_OFF_DEF_LAN1; 595 req.cmdbuf[3] = 0x00; /* ..... */ 596 req.cmdbuf[4] = 0x04; /* ..X.. */ 597 req.cmdbuf[5] = 0x08; /* .X... */ 598 req.cmdbuf[6] = 0x13; /* X..XX */ 599 req.cmdbuf[7] = 0x08; /* .X... */ 600 req.cmdbuf[8] = 0x04; /* ..X.. */ 601 req.cmdbuf[9] = 0x00; /* ..... */ 602 req.cmdbuf[10] = 0x00; /* ..... */ 603 tadpole_request(&req, 1, 0); 604 605 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR; 606 req.cmdlen = 11; 607 req.rsplen = 1; 608 req.cmdbuf[1] = 0x08; /*len*/ 609 req.cmdbuf[2] = TS102_BLK_OFF_DEF_LAN2; 610 req.cmdbuf[3] = 0x00; /* ..... */ 611 req.cmdbuf[4] = 0x04; /* ..X.. */ 612 req.cmdbuf[5] = 0x02; /* ...X. */ 613 req.cmdbuf[6] = 0x19; /* XX..X */ 614 req.cmdbuf[7] = 0x02; /* ...X. */ 615 req.cmdbuf[8] = 0x04; /* ..X.. */ 616 req.cmdbuf[9] = 0x00; /* ..... */ 617 req.cmdbuf[10] = 0x00; /* ..... */ 618 tadpole_request(&req, 1, 0); 619 620 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR; 621 req.cmdlen = 11; 622 req.rsplen = 1; 623 req.cmdbuf[1] = 0x08; /*len*/ 624 req.cmdbuf[2] = TS102_BLK_OFF_DEF_PCMCIA; 625 req.cmdbuf[3] = 0x00; /* ..... */ 626 req.cmdbuf[4] = 0x0c; /* .XXX. */ 627 req.cmdbuf[5] = 0x1f; /* XXXXX */ 628 req.cmdbuf[6] = 0x1f; /* XXXXX */ 629 req.cmdbuf[7] = 0x1f; /* XXXXX */ 630 req.cmdbuf[8] = 0x1f; /* XXXXX */ 631 req.cmdbuf[9] = 0x00; /* ..... */ 632 req.cmdbuf[10] = 0x00; /* ..... */ 633 tadpole_request(&req, 1, 0); 634 } 635 636 /* sc_lcdwanted -> lcd_state */ 637 void 638 tctrl_update_lcd(struct tctrl_softc *sc) 639 { 640 struct tctrl_req req; 641 int s; 642 643 s = splhigh(); 644 if (sc->sc_lcdwanted == sc->sc_lcdstate) { 645 splx(s); 646 return; 647 } 648 sc->sc_lcdstate = sc->sc_lcdwanted; 649 splx(s); 650 651 /* 652 * the mask setup on this particular command is *very* bizzare 653 * and totally undocumented. 654 */ 655 req.cmdbuf[0] = TS102_OP_CTL_LCD; 656 657 /* leave caps-lock alone */ 658 req.cmdbuf[2] = (u_int8_t)(sc->sc_lcdstate & 0xfe); 659 req.cmdbuf[3] = (u_int8_t)((sc->sc_lcdstate & 0x100)>>8); 660 661 req.cmdbuf[1] = 1; 662 req.cmdbuf[4] = 0; 663 664 665 /* XXX this thing is weird.... */ 666 req.cmdlen = 3; 667 req.rsplen = 2; 668 669 /* below are the values one would expect but which won't work */ 670 #if 0 671 req.cmdlen = 5; 672 req.rsplen = 4; 673 #endif 674 tadpole_request(&req, 1, 0); 675 } 676 677 678 /* 679 * set the blinken-lights on the lcd. what: 680 * what = 0 off, what = 1 on, what = 2 toggle 681 */ 682 683 void 684 tadpole_set_lcd(int what, unsigned short which) 685 { 686 struct tctrl_softc *sc; 687 int s; 688 689 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV]; 690 691 s = splhigh(); 692 switch (what) { 693 case 0: 694 sc->sc_lcdwanted &= ~which; 695 break; 696 case 1: 697 sc->sc_lcdwanted |= which; 698 break; 699 case 2: 700 sc->sc_lcdwanted ^= which; 701 break; 702 } 703 splx(s); 704 } 705 706 static void 707 tctrl_read_ext_status(void) 708 { 709 struct tctrl_softc *sc; 710 struct tctrl_req req; 711 int s; 712 713 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV]; 714 req.cmdbuf[0] = TS102_OP_RD_EXT_STATUS; 715 req.cmdlen = 1; 716 req.rsplen = 3; 717 #ifdef TCTRLDEBUG 718 printf("pre read: sc->sc_ext_status = 0x%x\n", sc->sc_ext_status); 719 #endif 720 tadpole_request(&req, 1, 0); 721 s = splts102(); 722 sc->sc_ext_status = (req.rspbuf[0] << 8) + req.rspbuf[1]; 723 splx(s); 724 #ifdef TCTRLDEBUG 725 printf("post read: sc->sc_ext_status = 0x%x\n", sc->sc_ext_status); 726 #endif 727 } 728 729 /* 730 * return 0 if the user will notice and handle the event, 731 * return 1 if the kernel driver should do so. 732 */ 733 static int 734 tctrl_apm_record_event(struct tctrl_softc *sc, u_int event_type) 735 { 736 struct apm_event_info *evp; 737 738 if ((sc->sc_flags & TCTRL_APM_CTLOPEN) && 739 (sc->sc_event_count < APM_NEVENTS)) { 740 evp = &sc->sc_event_list[sc->sc_event_ptr]; 741 sc->sc_event_count++; 742 sc->sc_event_ptr++; 743 sc->sc_event_ptr %= APM_NEVENTS; 744 evp->type = event_type; 745 evp->index = ++tctrl_apm_evindex; 746 selnotify(&sc->sc_rsel, 0); 747 return(sc->sc_flags & TCTRL_APM_CTLOPEN) ? 0 : 1; 748 } 749 return(1); 750 } 751 752 static void 753 tctrl_read_event_status(struct tctrl_softc *sc) 754 { 755 struct tctrl_req req; 756 int s, lid; 757 uint32_t v; 758 759 req.cmdbuf[0] = TS102_OP_RD_EVENT_STATUS; 760 req.cmdlen = 1; 761 req.rsplen = 3; 762 tadpole_request(&req, 1, 0); 763 s = splts102(); 764 v = req.rspbuf[0] * 256 + req.rspbuf[1]; 765 #ifdef TCTRLDEBUG 766 printf("event: %x\n",v); 767 #endif 768 if (v & TS102_EVENT_STATUS_POWERON_BTN_PRESSED) { 769 printf("%s: Power button pressed\n",sc->sc_dev.dv_xname); 770 tctrl_powerfail(sc); 771 } 772 if (v & TS102_EVENT_STATUS_SHUTDOWN_REQUEST) { 773 printf("%s: SHUTDOWN REQUEST!\n", sc->sc_dev.dv_xname); 774 tctrl_powerfail(sc); 775 } 776 if (v & TS102_EVENT_STATUS_VERY_LOW_POWER_WARNING) { 777 /*printf("%s: VERY LOW POWER WARNING!\n", sc->sc_dev.dv_xname);*/ 778 /* according to a tadpole header, and observation */ 779 #ifdef TCTRLDEBUG 780 printf("%s: Battery charge level change\n", 781 sc->sc_dev.dv_xname); 782 #endif 783 } 784 if (v & TS102_EVENT_STATUS_LOW_POWER_WARNING) { 785 if (tctrl_apm_record_event(sc, APM_BATTERY_LOW)) 786 printf("%s: LOW POWER WARNING!\n", sc->sc_dev.dv_xname); 787 } 788 if (v & TS102_EVENT_STATUS_DC_STATUS_CHANGE) { 789 splx(s); 790 tctrl_read_ext_status(); 791 tctrl_ac_state(sc); 792 s = splts102(); 793 if (tctrl_apm_record_event(sc, APM_POWER_CHANGE)) 794 printf("%s: main power %s\n", sc->sc_dev.dv_xname, 795 (sc->sc_ext_status & 796 TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ? 797 "restored" : "removed"); 798 } 799 if (v & TS102_EVENT_STATUS_LID_STATUS_CHANGE) { 800 splx(s); 801 tctrl_read_ext_status(); 802 tctrl_lid_state(sc); 803 tctrl_setup_bitport(); 804 #ifdef TCTRLDEBUG 805 printf("%s: lid %s\n", sc->sc_dev.dv_xname, 806 (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) 807 ? "closed" : "opened"); 808 #endif 809 lid = (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) == 0; 810 } 811 if (v & TS102_EVENT_STATUS_EXTERNAL_VGA_STATUS_CHANGE) { 812 int vga; 813 splx(s); 814 tctrl_read_ext_status(); 815 vga = (sc->sc_ext_status & 816 TS102_EXT_STATUS_EXTERNAL_VGA_ATTACHED) != 0; 817 if (vga != sc->sc_extvga) { 818 sc->sc_extvga = vga; 819 if (sc->sc_video_callback != NULL) { 820 sc->sc_video_callback( 821 sc->sc_video_callback_cookie, 822 sc->sc_extvga); 823 } 824 } 825 } 826 #ifdef DIAGNOSTIC 827 if (v & TS102_EVENT_STATUS_EXT_MOUSE_STATUS_CHANGE) { 828 splx(s); 829 tctrl_read_ext_status(); 830 if (sc->sc_ext_status & 831 TS102_EXT_STATUS_EXTERNAL_MOUSE_ATTACHED) { 832 printf("tctrl: external mouse detected\n"); 833 } 834 } 835 #endif 836 sc->sc_ext_pending = 0; 837 splx(s); 838 } 839 840 static void 841 tctrl_lock(struct tctrl_softc *sc) 842 { 843 844 mutex_enter(&sc->sc_requestlock); 845 } 846 847 static void 848 tctrl_unlock(struct tctrl_softc *sc) 849 { 850 851 mutex_exit(&sc->sc_requestlock); 852 } 853 854 int 855 tadpole_request(struct tctrl_req *req, int spin, int sleep) 856 { 857 struct tctrl_softc *sc; 858 int i, s; 859 860 if (tctrl_cd.cd_devs == NULL 861 || tctrl_cd.cd_ndevs == 0 862 || tctrl_cd.cd_devs[TCTRL_STD_DEV] == NULL) { 863 return ENODEV; 864 } 865 866 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV]; 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 = (struct tctrl_softc *) tctrl_cd.cd_devs[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 = tctrl_cd.cd_devs[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 = tctrl_cd.cd_devs[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 if (tctrl_cd.cd_devs == NULL 1097 || tctrl_cd.cd_ndevs == 0 1098 || tctrl_cd.cd_devs[TCTRL_STD_DEV] == NULL) { 1099 return ENXIO; 1100 } 1101 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV]; 1102 switch (cmd) { 1103 1104 case APM_IOC_STANDBY: 1105 /* turn off backlight and so on ? */ 1106 1107 return 0; /* for now */ 1108 1109 case APM_IOC_SUSPEND: 1110 /* not sure what to do here - we can't really suspend */ 1111 1112 return 0; /* for now */ 1113 1114 case OAPM_IOC_GETPOWER: 1115 case APM_IOC_GETPOWER: 1116 powerp = (struct apm_power_info *)data; 1117 req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_RATE; 1118 req.cmdlen = 1; 1119 req.rsplen = 2; 1120 tadpole_request(&req, 0, l->l_proc ? 1 : 0); 1121 if (req.rspbuf[0] > 0x00) 1122 powerp->battery_state = APM_BATT_CHARGING; 1123 req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_LEVEL; 1124 req.cmdlen = 1; 1125 req.rsplen = 3; 1126 tadpole_request(&req, 0, l->l_proc ? 1 : 0); 1127 c = req.rspbuf[0]; 1128 powerp->battery_life = c; 1129 if (c > 0x70) /* the tadpole sometimes dips below zero, and */ 1130 c = 0; /* into the 255 range. */ 1131 powerp->minutes_left = (45 * c) / 100; /* XXX based on 45 min */ 1132 if (powerp->battery_state != APM_BATT_CHARGING) { 1133 if (c < 0x20) 1134 powerp->battery_state = APM_BATT_CRITICAL; 1135 else if (c < 0x40) 1136 powerp->battery_state = APM_BATT_LOW; 1137 else if (c < 0x66) 1138 powerp->battery_state = APM_BATT_HIGH; 1139 else 1140 powerp->battery_state = APM_BATT_UNKNOWN; 1141 } 1142 1143 if (sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) 1144 powerp->ac_state = APM_AC_ON; 1145 else 1146 powerp->ac_state = APM_AC_OFF; 1147 break; 1148 1149 case APM_IOC_NEXTEVENT: 1150 if (!sc->sc_event_count) 1151 return EAGAIN; 1152 1153 evp = (struct apm_event_info *)data; 1154 i = sc->sc_event_ptr + APM_NEVENTS - sc->sc_event_count; 1155 i %= APM_NEVENTS; 1156 *evp = sc->sc_event_list[i]; 1157 sc->sc_event_count--; 1158 return(0); 1159 1160 /* this ioctl assumes the caller knows exactly what he is doing */ 1161 case TCTRL_CMD_REQ: 1162 reqn = (struct tctrl_req *)data; 1163 if ((i = kauth_authorize_generic(l->l_cred, 1164 KAUTH_GENERIC_ISSUSER, NULL)) != 0 && 1165 (reqn->cmdbuf[0] == TS102_OP_CTL_BITPORT || 1166 (reqn->cmdbuf[0] >= TS102_OP_CTL_WATCHDOG && 1167 reqn->cmdbuf[0] <= TS102_OP_CTL_SECURITY_KEY) || 1168 reqn->cmdbuf[0] == TS102_OP_CTL_TIMEZONE || 1169 reqn->cmdbuf[0] == TS102_OP_CTL_DIAGNOSTIC_MODE || 1170 reqn->cmdbuf[0] == TS102_OP_CMD_SOFTWARE_RESET || 1171 (reqn->cmdbuf[0] >= TS102_OP_CMD_SET_RTC && 1172 reqn->cmdbuf[0] < TS102_OP_RD_INT_CHARGE_LEVEL) || 1173 reqn->cmdbuf[0] > TS102_OP_RD_EXT_CHARGE_LEVEL)) 1174 return(i); 1175 tadpole_request(reqn, 0, l->l_proc ? 1 : 0); 1176 break; 1177 /* serial power mode (via auxiotwo) */ 1178 case TCTRL_SERIAL_PWR: 1179 pwrreq = (struct tctrl_pwr *)data; 1180 if (pwrreq->rw) 1181 pwrreq->state = auxiotwoserialgetapm(); 1182 else 1183 auxiotwoserialsetapm(pwrreq->state); 1184 break; 1185 1186 /* modem power mode (via auxio) */ 1187 case TCTRL_MODEM_PWR: 1188 return(EOPNOTSUPP); /* for now */ 1189 break; 1190 1191 1192 default: 1193 return (ENOTTY); 1194 } 1195 return (0); 1196 } 1197 1198 int 1199 tctrlpoll(dev_t dev, int events, struct lwp *l) 1200 { 1201 struct tctrl_softc *sc = tctrl_cd.cd_devs[TCTRL_STD_DEV]; 1202 int revents = 0; 1203 1204 if (events & (POLLIN | POLLRDNORM)) { 1205 if (sc->sc_event_count) 1206 revents |= events & (POLLIN | POLLRDNORM); 1207 else 1208 selrecord(l, &sc->sc_rsel); 1209 } 1210 1211 return (revents); 1212 } 1213 1214 static void 1215 filt_tctrlrdetach(struct knote *kn) 1216 { 1217 struct tctrl_softc *sc = kn->kn_hook; 1218 int s; 1219 1220 s = splts102(); 1221 SLIST_REMOVE(&sc->sc_rsel.sel_klist, kn, knote, kn_selnext); 1222 splx(s); 1223 } 1224 1225 static int 1226 filt_tctrlread(struct knote *kn, long hint) 1227 { 1228 struct tctrl_softc *sc = kn->kn_hook; 1229 1230 kn->kn_data = sc->sc_event_count; 1231 return (kn->kn_data > 0); 1232 } 1233 1234 static const struct filterops tctrlread_filtops = 1235 { 1, NULL, filt_tctrlrdetach, filt_tctrlread }; 1236 1237 int 1238 tctrlkqfilter(dev_t dev, struct knote *kn) 1239 { 1240 struct tctrl_softc *sc = tctrl_cd.cd_devs[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 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 1280 /* DC voltage */ 1281 (void)strlcpy(sc->sc_sensor[2].desc, "DC-In voltage", 1282 sizeof(sc->sc_sensor[2].desc)); 1283 sc->sc_sensor[2].units = ENVSYS_SVOLTS_DC; 1284 1285 for (i = 0; i < ENVSYS_NUMSENSORS; i++) { 1286 if (sysmon_envsys_sensor_attach(sc->sc_sme, 1287 &sc->sc_sensor[i])) { 1288 sysmon_envsys_destroy(sc->sc_sme); 1289 return; 1290 } 1291 } 1292 1293 sc->sc_sme->sme_name = sc->sc_dev.dv_xname; 1294 sc->sc_sme->sme_cookie = sc; 1295 sc->sc_sme->sme_refresh = tctrl_refresh; 1296 1297 if ((error = sysmon_envsys_register(sc->sc_sme)) != 0) { 1298 printf("%s: couldn't register sensors (%d)\n", 1299 sc->sc_dev.dv_xname, error); 1300 sysmon_envsys_destroy(sc->sc_sme); 1301 return; 1302 } 1303 1304 /* now register the power button */ 1305 1306 sysmon_task_queue_init(); 1307 1308 sc->sc_powerpressed = 0; 1309 memset(&sc->sc_sm_pbutton, 0, sizeof(struct sysmon_pswitch)); 1310 sc->sc_sm_pbutton.smpsw_name = sc->sc_dev.dv_xname; 1311 sc->sc_sm_pbutton.smpsw_type = PSWITCH_TYPE_POWER; 1312 if (sysmon_pswitch_register(&sc->sc_sm_pbutton) != 0) 1313 printf("%s: unable to register power button with sysmon\n", 1314 sc->sc_dev.dv_xname); 1315 1316 memset(&sc->sc_sm_lid, 0, sizeof(struct sysmon_pswitch)); 1317 sc->sc_sm_lid.smpsw_name = sc->sc_dev.dv_xname; 1318 sc->sc_sm_lid.smpsw_type = PSWITCH_TYPE_LID; 1319 if (sysmon_pswitch_register(&sc->sc_sm_lid) != 0) 1320 printf("%s: unable to register lid switch with sysmon\n", 1321 sc->sc_dev.dv_xname); 1322 1323 memset(&sc->sc_sm_ac, 0, sizeof(struct sysmon_pswitch)); 1324 sc->sc_sm_ac.smpsw_name = sc->sc_dev.dv_xname; 1325 sc->sc_sm_ac.smpsw_type = PSWITCH_TYPE_ACADAPTER; 1326 if (sysmon_pswitch_register(&sc->sc_sm_ac) != 0) 1327 printf("%s: unable to register AC adaptor with sysmon\n", 1328 sc->sc_dev.dv_xname); 1329 } 1330 1331 static void 1332 tctrl_power_button_pressed(void *arg) 1333 { 1334 struct tctrl_softc *sc = arg; 1335 1336 sysmon_pswitch_event(&sc->sc_sm_pbutton, PSWITCH_EVENT_PRESSED); 1337 sc->sc_powerpressed = 0; 1338 } 1339 1340 static void 1341 tctrl_lid_state(struct tctrl_softc *sc) 1342 { 1343 int state; 1344 1345 state = (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) ? 1346 PSWITCH_EVENT_PRESSED : PSWITCH_EVENT_RELEASED; 1347 sysmon_pswitch_event(&sc->sc_sm_lid, state); 1348 } 1349 1350 static void 1351 tctrl_ac_state(struct tctrl_softc *sc) 1352 { 1353 int state; 1354 1355 state = (sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ? 1356 PSWITCH_EVENT_PRESSED : PSWITCH_EVENT_RELEASED; 1357 sysmon_pswitch_event(&sc->sc_sm_ac, state); 1358 } 1359 1360 static int 1361 tctrl_powerfail(void *arg) 1362 { 1363 struct tctrl_softc *sc = (struct tctrl_softc *)arg; 1364 1365 /* 1366 * We lost power. Queue a callback with thread context to 1367 * handle all the real work. 1368 */ 1369 if (sc->sc_powerpressed == 0) { 1370 sc->sc_powerpressed = 1; 1371 sysmon_task_queue_sched(0, tctrl_power_button_pressed, sc); 1372 } 1373 return (1); 1374 } 1375 1376 static void 1377 tctrl_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 1378 { 1379 /*struct tctrl_softc *sc = sme->sme_cookie;*/ 1380 struct tctrl_req req; 1381 int sleepable; 1382 int i; 1383 1384 i = edata->sensor; 1385 sleepable = curlwp ? 1 : 0; 1386 1387 switch (i) 1388 { 1389 case 0: /* case temperature */ 1390 req.cmdbuf[0] = TS102_OP_RD_CURRENT_TEMP; 1391 req.cmdlen = 1; 1392 req.rsplen = 2; 1393 tadpole_request(&req, 0, sleepable); 1394 edata->value_cur = /* 273160? */ 1395 (uint32_t)((int)((int)req.rspbuf[0] - 32) * 5000000 1396 / 9 + 273150000); 1397 req.cmdbuf[0] = TS102_OP_RD_MAX_TEMP; 1398 req.cmdlen = 1; 1399 req.rsplen = 2; 1400 tadpole_request(&req, 0, sleepable); 1401 edata->value_max = 1402 (uint32_t)((int)((int)req.rspbuf[0] - 32) * 5000000 1403 / 9 + 273150000); 1404 edata->flags |= ENVSYS_FVALID_MAX; 1405 req.cmdbuf[0] = TS102_OP_RD_MIN_TEMP; 1406 req.cmdlen = 1; 1407 req.rsplen = 2; 1408 tadpole_request(&req, 0, sleepable); 1409 edata->value_min = 1410 (uint32_t)((int)((int)req.rspbuf[0] - 32) * 5000000 1411 / 9 + 273150000); 1412 edata->flags |= ENVSYS_FVALID_MIN; 1413 edata->units = ENVSYS_STEMP; 1414 break; 1415 1416 case 1: /* battery voltage */ 1417 { 1418 edata->units = ENVSYS_SVOLTS_DC; 1419 req.cmdbuf[0] = TS102_OP_RD_INT_BATT_VLT; 1420 req.cmdlen = 1; 1421 req.rsplen = 2; 1422 tadpole_request(&req, 0, sleepable); 1423 edata->value_cur = (int32_t)req.rspbuf[0] * 1424 1000000 / 11; 1425 } 1426 break; 1427 case 2: /* DC voltage */ 1428 { 1429 edata->units = ENVSYS_SVOLTS_DC; 1430 req.cmdbuf[0] = TS102_OP_RD_DC_IN_VLT; 1431 req.cmdlen = 1; 1432 req.rsplen = 2; 1433 tadpole_request(&req, 0, sleepable); 1434 edata->value_cur = (int32_t)req.rspbuf[0] * 1435 1000000 / 11; 1436 } 1437 break; 1438 } 1439 edata->state = ENVSYS_SVALID; 1440 } 1441 1442 static void 1443 tctrl_event_thread(void *v) 1444 { 1445 struct tctrl_softc *sc = v; 1446 struct device *dv; 1447 struct sd_softc *sd = NULL; 1448 struct lance_softc *le = NULL; 1449 int ticks = hz/2; 1450 int rcount, wcount; 1451 int s; 1452 1453 while (sd == NULL) { 1454 for (dv = alldevs.tqh_first; dv; dv = dv->dv_list.tqe_next) { 1455 if (strcmp(dv->dv_xname, "sd0") == 0) { 1456 sd = (struct sd_softc *)dv; 1457 } 1458 if (le == NULL) { 1459 if (strcmp(dv->dv_xname, "le0") == 0) 1460 le = (struct lance_softc *)dv; 1461 } 1462 } 1463 if (sd == NULL) 1464 tsleep(&sc->sc_events, PWAIT, "probe_disk", hz); 1465 } 1466 printf("found %s\n", sd->sc_dev.dv_xname); 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 = (struct tctrl_softc *) tctrl_cd.cd_devs[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