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