1 /* $NetBSD: tctrl.c,v 1.47 2008/04/28 20:23:35 martin 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.47 2008/04/28 20:23:35 martin 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/user.h> 42 #include <sys/conf.h> 43 #include <sys/file.h> 44 #include <sys/uio.h> 45 #include <sys/kernel.h> 46 #include <sys/kthread.h> 47 #include <sys/syslog.h> 48 #include <sys/types.h> 49 #include <sys/device.h> 50 #include <sys/envsys.h> 51 #include <sys/poll.h> 52 #include <sys/kauth.h> 53 54 #include <machine/apmvar.h> 55 #include <machine/autoconf.h> 56 #include <machine/bus.h> 57 #include <machine/intr.h> 58 #include <machine/tctrl.h> 59 60 #include <sparc/dev/ts102reg.h> 61 #include <sparc/dev/tctrlvar.h> 62 #include <sparc/sparc/auxiotwo.h> 63 #include <sparc/sparc/auxreg.h> 64 65 #include <dev/sysmon/sysmonvar.h> 66 #include <dev/sysmon/sysmon_taskq.h> 67 68 #include "sysmon_envsys.h" 69 70 /*#define TCTRLDEBUG*/ 71 72 /* disk spinner */ 73 #include <sys/disk.h> 74 #include <dev/scsipi/sdvar.h> 75 76 /* ethernet carrier */ 77 #include <net/if.h> 78 #include <net/if_dl.h> 79 #include <net/if_ether.h> 80 #include <net/if_media.h> 81 #include <dev/ic/lancevar.h> 82 83 extern struct cfdriver tctrl_cd; 84 85 dev_type_open(tctrlopen); 86 dev_type_close(tctrlclose); 87 dev_type_ioctl(tctrlioctl); 88 dev_type_poll(tctrlpoll); 89 dev_type_kqfilter(tctrlkqfilter); 90 91 const struct cdevsw tctrl_cdevsw = { 92 tctrlopen, tctrlclose, noread, nowrite, tctrlioctl, 93 nostop, notty, tctrlpoll, nommap, tctrlkqfilter, 94 }; 95 96 static const char *tctrl_ext_statuses[16] = { 97 "main power available", 98 "internal battery attached", 99 "external battery attached", 100 "external VGA attached", 101 "external keyboard attached", 102 "external mouse attached", 103 "lid down", 104 "internal battery charging", 105 "external battery charging", 106 "internal battery discharging", 107 "external battery discharging", 108 }; 109 110 struct tctrl_softc { 111 struct device sc_dev; 112 bus_space_tag_t sc_memt; 113 bus_space_handle_t sc_memh; 114 unsigned int sc_junk; 115 unsigned int sc_ext_status; 116 unsigned int sc_flags; 117 #define TCTRL_SEND_REQUEST 0x0001 118 #define TCTRL_APM_CTLOPEN 0x0002 119 uint32_t sc_wantdata; 120 uint32_t sc_ext_pending; 121 volatile uint16_t sc_lcdstate; 122 uint16_t sc_lcdwanted; 123 124 enum { TCTRL_IDLE, TCTRL_ARGS, 125 TCTRL_ACK, TCTRL_DATA } sc_state; 126 uint8_t sc_cmdbuf[16]; 127 uint8_t sc_rspbuf[16]; 128 uint8_t sc_bitport; 129 uint8_t sc_tft_on; 130 uint8_t sc_op; 131 uint8_t sc_cmdoff; 132 uint8_t sc_cmdlen; 133 uint8_t sc_rspoff; 134 uint8_t sc_rsplen; 135 /* APM stuff */ 136 #define APM_NEVENTS 16 137 struct apm_event_info sc_event_list[APM_NEVENTS]; 138 int sc_event_count; 139 int sc_event_ptr; 140 struct selinfo sc_rsel; 141 142 /* ENVSYS stuff */ 143 #define ENVSYS_NUMSENSORS 3 144 struct evcnt sc_intrcnt; /* interrupt counting */ 145 struct sysmon_envsys *sc_sme; 146 envsys_data_t sc_sensor[ENVSYS_NUMSENSORS]; 147 148 struct sysmon_pswitch sc_sm_pbutton; /* power button */ 149 struct sysmon_pswitch sc_sm_lid; /* lid state */ 150 struct sysmon_pswitch sc_sm_ac; /* AC adaptor presence */ 151 int sc_powerpressed; 152 153 /* hardware status stuff */ 154 int sc_lid; /* 1 - open, 0 - closed */ 155 int sc_power_state; 156 int sc_spl; 157 158 /* 159 * we call this when we detect connection or removal of an external 160 * monitor. 0 for no monitor, !=0 for monitor present 161 */ 162 void (*sc_video_callback)(void *, int); 163 void *sc_video_callback_cookie; 164 int sc_extvga; 165 166 uint32_t sc_events; 167 lwp_t *sc_thread; /* event thread */ 168 kmutex_t sc_requestlock; 169 }; 170 171 #define TCTRL_STD_DEV 0 172 #define TCTRL_APMCTL_DEV 8 173 174 static int tctrl_match(struct device *, struct cfdata *, void *); 175 static void tctrl_attach(struct device *, struct device *, void *); 176 static void tctrl_write(struct tctrl_softc *, bus_size_t, uint8_t); 177 static uint8_t tctrl_read(struct tctrl_softc *, bus_size_t); 178 static void tctrl_write_data(struct tctrl_softc *, uint8_t); 179 static uint8_t tctrl_read_data(struct tctrl_softc *); 180 static int tctrl_intr(void *); 181 static void tctrl_setup_bitport(void); 182 static void tctrl_setup_bitport_nop(void); 183 static void tctrl_read_ext_status(void); 184 static void tctrl_read_event_status(struct tctrl_softc *); 185 static int tctrl_apm_record_event(struct tctrl_softc *, u_int); 186 static void tctrl_init_lcd(void); 187 188 static void tctrl_sensor_setup(struct tctrl_softc *); 189 static void tctrl_refresh(struct sysmon_envsys *, envsys_data_t *); 190 191 static void tctrl_power_button_pressed(void *); 192 static void tctrl_lid_state(struct tctrl_softc *); 193 static void tctrl_ac_state(struct tctrl_softc *); 194 195 static int tctrl_powerfail(void *); 196 197 static void tctrl_event_thread(void *); 198 void tctrl_update_lcd(struct tctrl_softc *); 199 200 static void tctrl_lock(struct tctrl_softc *); 201 static void tctrl_unlock(struct tctrl_softc *); 202 203 CFATTACH_DECL(tctrl, sizeof(struct tctrl_softc), 204 tctrl_match, tctrl_attach, NULL, NULL); 205 206 static int tadpole_request(struct tctrl_req *, int, int); 207 208 /* XXX wtf is this? see i386/apm.c */ 209 int tctrl_apm_evindex; 210 211 static int 212 tctrl_match(struct device *parent, struct cfdata *cf, void *aux) 213 { 214 union obio_attach_args *uoba = aux; 215 struct sbus_attach_args *sa = &uoba->uoba_sbus; 216 217 if (uoba->uoba_isobio4 != 0) { 218 return (0); 219 } 220 221 /* Tadpole 3GX/3GS uses "uctrl" for the Tadpole Microcontroller 222 * (who's interface is off the TS102 PCMCIA controller but there 223 * exists a OpenProm for microcontroller interface). 224 */ 225 return strcmp("uctrl", sa->sa_name) == 0; 226 } 227 228 static void 229 tctrl_attach(struct device *parent, struct device *self, void *aux) 230 { 231 struct tctrl_softc *sc = (void *)self; 232 union obio_attach_args *uoba = aux; 233 struct sbus_attach_args *sa = &uoba->uoba_sbus; 234 unsigned int i, v; 235 236 /* We're living on a sbus slot that looks like an obio that 237 * looks like an sbus slot. 238 */ 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 sc->sc_dev.dv_xname, "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: ", sc->sc_dev.dv_xname); 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", sc->sc_dev.dv_xname) != 0) { 326 printf("%s: unable to create event kthread", 327 sc->sc_dev.dv_xname); 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 sc->sc_dev.dv_xname, 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 sc->sc_dev.dv_xname, 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 sc->sc_dev.dv_xname, 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)", sc->sc_dev.dv_xname, 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 = (struct tctrl_softc *) tctrl_cd.cd_devs[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 = (struct tctrl_softc *) tctrl_cd.cd_devs[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 = (struct tctrl_softc *) tctrl_cd.cd_devs[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 = (struct tctrl_softc *) tctrl_cd.cd_devs[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, lid; 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",sc->sc_dev.dv_xname); 764 tctrl_powerfail(sc); 765 } 766 if (v & TS102_EVENT_STATUS_SHUTDOWN_REQUEST) { 767 printf("%s: SHUTDOWN REQUEST!\n", sc->sc_dev.dv_xname); 768 tctrl_powerfail(sc); 769 } 770 if (v & TS102_EVENT_STATUS_VERY_LOW_POWER_WARNING) { 771 /*printf("%s: VERY LOW POWER WARNING!\n", sc->sc_dev.dv_xname);*/ 772 /* according to a tadpole header, and observation */ 773 #ifdef TCTRLDEBUG 774 printf("%s: Battery charge level change\n", 775 sc->sc_dev.dv_xname); 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", sc->sc_dev.dv_xname); 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", sc->sc_dev.dv_xname, 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", sc->sc_dev.dv_xname, 800 (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) 801 ? "closed" : "opened"); 802 #endif 803 lid = (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) == 0; 804 } 805 if (v & TS102_EVENT_STATUS_EXTERNAL_VGA_STATUS_CHANGE) { 806 int vga; 807 splx(s); 808 tctrl_read_ext_status(); 809 vga = (sc->sc_ext_status & 810 TS102_EXT_STATUS_EXTERNAL_VGA_ATTACHED) != 0; 811 if (vga != sc->sc_extvga) { 812 sc->sc_extvga = vga; 813 if (sc->sc_video_callback != NULL) { 814 sc->sc_video_callback( 815 sc->sc_video_callback_cookie, 816 sc->sc_extvga); 817 } 818 } 819 } 820 #ifdef DIAGNOSTIC 821 if (v & TS102_EVENT_STATUS_EXT_MOUSE_STATUS_CHANGE) { 822 splx(s); 823 tctrl_read_ext_status(); 824 if (sc->sc_ext_status & 825 TS102_EXT_STATUS_EXTERNAL_MOUSE_ATTACHED) { 826 printf("tctrl: external mouse detected\n"); 827 } 828 } 829 #endif 830 sc->sc_ext_pending = 0; 831 splx(s); 832 } 833 834 static void 835 tctrl_lock(struct tctrl_softc *sc) 836 { 837 838 mutex_enter(&sc->sc_requestlock); 839 } 840 841 static void 842 tctrl_unlock(struct tctrl_softc *sc) 843 { 844 845 mutex_exit(&sc->sc_requestlock); 846 } 847 848 int 849 tadpole_request(struct tctrl_req *req, int spin, int sleep) 850 { 851 struct tctrl_softc *sc; 852 int i, s; 853 854 if (tctrl_cd.cd_devs == NULL 855 || tctrl_cd.cd_ndevs == 0 856 || tctrl_cd.cd_devs[TCTRL_STD_DEV] == NULL) { 857 return ENODEV; 858 } 859 860 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV]; 861 tctrl_lock(sc); 862 863 if (spin) 864 s = splhigh(); 865 else 866 s = splts102(); 867 sc->sc_flags |= TCTRL_SEND_REQUEST; 868 memcpy(sc->sc_cmdbuf, req->cmdbuf, req->cmdlen); 869 #ifdef DIAGNOSTIC 870 if (sc->sc_wantdata != 0) { 871 splx(s); 872 printf("tctrl: we lost the race\n"); 873 tctrl_unlock(sc); 874 return EAGAIN; 875 } 876 #endif 877 sc->sc_wantdata = 1; 878 sc->sc_rsplen = req->rsplen; 879 sc->sc_cmdlen = req->cmdlen; 880 sc->sc_cmdoff = sc->sc_rspoff = 0; 881 882 /* we spin for certain commands, like poweroffs */ 883 if (spin) { 884 /* for (i = 0; i < 30000; i++) {*/ 885 i = 0; 886 while ((sc->sc_wantdata == 1) && (i < 30000)) { 887 tctrl_intr(sc); 888 DELAY(1); 889 i++; 890 } 891 #ifdef DIAGNOSTIC 892 if (i >= 30000) { 893 printf("tctrl: timeout busy waiting for micro controller request!\n"); 894 sc->sc_wantdata = 0; 895 splx(s); 896 tctrl_unlock(sc); 897 return EAGAIN; 898 } 899 #endif 900 } else { 901 int timeout = 5 * (sc->sc_rsplen + sc->sc_cmdlen); 902 tctrl_intr(sc); 903 i = 0; 904 while (((sc->sc_rspoff != sc->sc_rsplen) || 905 (sc->sc_cmdoff != sc->sc_cmdlen)) && 906 (i < timeout)) 907 if (sleep) { 908 tsleep(sc, PWAIT, "tctrl_data", 15); 909 i++; 910 } else 911 DELAY(1); 912 #ifdef DIAGNOSTIC 913 if (i >= timeout) { 914 printf("tctrl: timeout waiting for microcontroller request\n"); 915 sc->sc_wantdata = 0; 916 splx(s); 917 tctrl_unlock(sc); 918 return EAGAIN; 919 } 920 #endif 921 } 922 /* 923 * we give the user a reasonable amount of time for a command 924 * to complete. If it doesn't complete in time, we hand them 925 * garbage. This is here to stop things like setting the 926 * rsplen too long, and sleeping forever in a CMD_REQ ioctl. 927 */ 928 sc->sc_wantdata = 0; 929 memcpy(req->rspbuf, sc->sc_rspbuf, req->rsplen); 930 splx(s); 931 932 tctrl_unlock(sc); 933 return 0; 934 } 935 936 void 937 tadpole_powerdown(void) 938 { 939 struct tctrl_req req; 940 941 req.cmdbuf[0] = TS102_OP_ADMIN_POWER_OFF; 942 req.cmdlen = 1; 943 req.rsplen = 1; 944 tadpole_request(&req, 1, 0); 945 } 946 947 void 948 tadpole_set_video(int enabled) 949 { 950 struct tctrl_softc *sc; 951 struct tctrl_req req; 952 int s; 953 954 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV]; 955 while (sc->sc_wantdata != 0) 956 DELAY(1); 957 s = splts102(); 958 if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN && !enabled) 959 || (sc->sc_tft_on)) { 960 req.cmdbuf[2] = TS102_BITPORT_TFTPWR; 961 } else { 962 req.cmdbuf[2] = 0; 963 } 964 req.cmdbuf[0] = TS102_OP_CTL_BITPORT; 965 req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR; 966 req.cmdlen = 3; 967 req.rsplen = 2; 968 969 if ((sc->sc_tft_on && !enabled) || (!sc->sc_tft_on && enabled)) { 970 sc->sc_tft_on = enabled; 971 if (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) { 972 splx(s); 973 return; 974 } 975 tadpole_request(&req, 1, 0); 976 sc->sc_bitport = 977 (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2]; 978 } 979 splx(s); 980 } 981 982 static void 983 tctrl_write_data(struct tctrl_softc *sc, uint8_t v) 984 { 985 unsigned int i; 986 987 for (i = 0; i < 100; i++) { 988 if (TS102_UCTRL_STS_TXNF_STA & 989 tctrl_read(sc, TS102_REG_UCTRL_STS)) 990 break; 991 } 992 tctrl_write(sc, TS102_REG_UCTRL_DATA, v); 993 } 994 995 static uint8_t 996 tctrl_read_data(struct tctrl_softc *sc) 997 { 998 unsigned int i, v; 999 1000 for (i = 0; i < 100000; i++) { 1001 if (TS102_UCTRL_STS_RXNE_STA & 1002 tctrl_read(sc, TS102_REG_UCTRL_STS)) 1003 break; 1004 DELAY(1); 1005 } 1006 1007 v = tctrl_read(sc, TS102_REG_UCTRL_DATA); 1008 tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA); 1009 return v; 1010 } 1011 1012 static uint8_t 1013 tctrl_read(struct tctrl_softc *sc, bus_size_t off) 1014 { 1015 1016 sc->sc_junk = bus_space_read_1(sc->sc_memt, sc->sc_memh, off); 1017 return sc->sc_junk; 1018 } 1019 1020 static void 1021 tctrl_write(struct tctrl_softc *sc, bus_size_t off, uint8_t v) 1022 { 1023 1024 sc->sc_junk = v; 1025 bus_space_write_1(sc->sc_memt, sc->sc_memh, off, v); 1026 } 1027 1028 int 1029 tctrlopen(dev_t dev, int flags, int mode, struct lwp *l) 1030 { 1031 int unit = (minor(dev)&0xf0); 1032 int ctl = (minor(dev)&0x0f); 1033 struct tctrl_softc *sc; 1034 1035 if (unit >= tctrl_cd.cd_ndevs) 1036 return(ENXIO); 1037 sc = tctrl_cd.cd_devs[TCTRL_STD_DEV]; 1038 if (!sc) 1039 return(ENXIO); 1040 1041 switch (ctl) { 1042 case TCTRL_STD_DEV: 1043 break; 1044 case TCTRL_APMCTL_DEV: 1045 if (!(flags & FWRITE)) 1046 return(EINVAL); 1047 if (sc->sc_flags & TCTRL_APM_CTLOPEN) 1048 return(EBUSY); 1049 sc->sc_flags |= TCTRL_APM_CTLOPEN; 1050 break; 1051 default: 1052 return(ENXIO); 1053 break; 1054 } 1055 1056 return(0); 1057 } 1058 1059 int 1060 tctrlclose(dev_t dev, int flags, int mode, struct lwp *l) 1061 { 1062 int ctl = (minor(dev)&0x0f); 1063 struct tctrl_softc *sc; 1064 1065 sc = tctrl_cd.cd_devs[TCTRL_STD_DEV]; 1066 if (!sc) 1067 return(ENXIO); 1068 1069 switch (ctl) { 1070 case TCTRL_STD_DEV: 1071 break; 1072 case TCTRL_APMCTL_DEV: 1073 sc->sc_flags &= ~TCTRL_APM_CTLOPEN; 1074 break; 1075 } 1076 return(0); 1077 } 1078 1079 int 1080 tctrlioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l) 1081 { 1082 struct tctrl_req req, *reqn; 1083 struct tctrl_pwr *pwrreq; 1084 struct apm_power_info *powerp; 1085 struct apm_event_info *evp; 1086 struct tctrl_softc *sc; 1087 int i; 1088 uint8_t c; 1089 1090 if (tctrl_cd.cd_devs == NULL 1091 || tctrl_cd.cd_ndevs == 0 1092 || tctrl_cd.cd_devs[TCTRL_STD_DEV] == NULL) { 1093 return ENXIO; 1094 } 1095 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV]; 1096 switch (cmd) { 1097 1098 case APM_IOC_STANDBY: 1099 /* turn off backlight and so on ? */ 1100 1101 return 0; /* for now */ 1102 1103 case APM_IOC_SUSPEND: 1104 /* not sure what to do here - we can't really suspend */ 1105 1106 return 0; /* for now */ 1107 1108 case OAPM_IOC_GETPOWER: 1109 case APM_IOC_GETPOWER: 1110 powerp = (struct apm_power_info *)data; 1111 req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_RATE; 1112 req.cmdlen = 1; 1113 req.rsplen = 2; 1114 tadpole_request(&req, 0, l->l_proc ? 1 : 0); 1115 if (req.rspbuf[0] > 0x00) 1116 powerp->battery_state = APM_BATT_CHARGING; 1117 req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_LEVEL; 1118 req.cmdlen = 1; 1119 req.rsplen = 3; 1120 tadpole_request(&req, 0, l->l_proc ? 1 : 0); 1121 c = req.rspbuf[0]; 1122 powerp->battery_life = c; 1123 if (c > 0x70) /* the tadpole sometimes dips below zero, and */ 1124 c = 0; /* into the 255 range. */ 1125 powerp->minutes_left = (45 * c) / 100; /* XXX based on 45 min */ 1126 if (powerp->battery_state != APM_BATT_CHARGING) { 1127 if (c < 0x20) 1128 powerp->battery_state = APM_BATT_CRITICAL; 1129 else if (c < 0x40) 1130 powerp->battery_state = APM_BATT_LOW; 1131 else if (c < 0x66) 1132 powerp->battery_state = APM_BATT_HIGH; 1133 else 1134 powerp->battery_state = APM_BATT_UNKNOWN; 1135 } 1136 1137 if (sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) 1138 powerp->ac_state = APM_AC_ON; 1139 else 1140 powerp->ac_state = APM_AC_OFF; 1141 break; 1142 1143 case APM_IOC_NEXTEVENT: 1144 if (!sc->sc_event_count) 1145 return EAGAIN; 1146 1147 evp = (struct apm_event_info *)data; 1148 i = sc->sc_event_ptr + APM_NEVENTS - sc->sc_event_count; 1149 i %= APM_NEVENTS; 1150 *evp = sc->sc_event_list[i]; 1151 sc->sc_event_count--; 1152 return(0); 1153 1154 /* this ioctl assumes the caller knows exactly what he is doing */ 1155 case TCTRL_CMD_REQ: 1156 reqn = (struct tctrl_req *)data; 1157 if ((i = kauth_authorize_generic(l->l_cred, 1158 KAUTH_GENERIC_ISSUSER, NULL)) != 0 && 1159 (reqn->cmdbuf[0] == TS102_OP_CTL_BITPORT || 1160 (reqn->cmdbuf[0] >= TS102_OP_CTL_WATCHDOG && 1161 reqn->cmdbuf[0] <= TS102_OP_CTL_SECURITY_KEY) || 1162 reqn->cmdbuf[0] == TS102_OP_CTL_TIMEZONE || 1163 reqn->cmdbuf[0] == TS102_OP_CTL_DIAGNOSTIC_MODE || 1164 reqn->cmdbuf[0] == TS102_OP_CMD_SOFTWARE_RESET || 1165 (reqn->cmdbuf[0] >= TS102_OP_CMD_SET_RTC && 1166 reqn->cmdbuf[0] < TS102_OP_RD_INT_CHARGE_LEVEL) || 1167 reqn->cmdbuf[0] > TS102_OP_RD_EXT_CHARGE_LEVEL)) 1168 return(i); 1169 tadpole_request(reqn, 0, l->l_proc ? 1 : 0); 1170 break; 1171 /* serial power mode (via auxiotwo) */ 1172 case TCTRL_SERIAL_PWR: 1173 pwrreq = (struct tctrl_pwr *)data; 1174 if (pwrreq->rw) 1175 pwrreq->state = auxiotwoserialgetapm(); 1176 else 1177 auxiotwoserialsetapm(pwrreq->state); 1178 break; 1179 1180 /* modem power mode (via auxio) */ 1181 case TCTRL_MODEM_PWR: 1182 return(EOPNOTSUPP); /* for now */ 1183 break; 1184 1185 1186 default: 1187 return (ENOTTY); 1188 } 1189 return (0); 1190 } 1191 1192 int 1193 tctrlpoll(dev_t dev, int events, struct lwp *l) 1194 { 1195 struct tctrl_softc *sc = tctrl_cd.cd_devs[TCTRL_STD_DEV]; 1196 int revents = 0; 1197 1198 if (events & (POLLIN | POLLRDNORM)) { 1199 if (sc->sc_event_count) 1200 revents |= events & (POLLIN | POLLRDNORM); 1201 else 1202 selrecord(l, &sc->sc_rsel); 1203 } 1204 1205 return (revents); 1206 } 1207 1208 static void 1209 filt_tctrlrdetach(struct knote *kn) 1210 { 1211 struct tctrl_softc *sc = kn->kn_hook; 1212 int s; 1213 1214 s = splts102(); 1215 SLIST_REMOVE(&sc->sc_rsel.sel_klist, kn, knote, kn_selnext); 1216 splx(s); 1217 } 1218 1219 static int 1220 filt_tctrlread(struct knote *kn, long hint) 1221 { 1222 struct tctrl_softc *sc = kn->kn_hook; 1223 1224 kn->kn_data = sc->sc_event_count; 1225 return (kn->kn_data > 0); 1226 } 1227 1228 static const struct filterops tctrlread_filtops = 1229 { 1, NULL, filt_tctrlrdetach, filt_tctrlread }; 1230 1231 int 1232 tctrlkqfilter(dev_t dev, struct knote *kn) 1233 { 1234 struct tctrl_softc *sc = tctrl_cd.cd_devs[TCTRL_STD_DEV]; 1235 struct klist *klist; 1236 int s; 1237 1238 switch (kn->kn_filter) { 1239 case EVFILT_READ: 1240 klist = &sc->sc_rsel.sel_klist; 1241 kn->kn_fop = &tctrlread_filtops; 1242 break; 1243 1244 default: 1245 return (1); 1246 } 1247 1248 kn->kn_hook = sc; 1249 1250 s = splts102(); 1251 SLIST_INSERT_HEAD(klist, kn, kn_selnext); 1252 splx(s); 1253 1254 return (0); 1255 } 1256 1257 static void 1258 tctrl_sensor_setup(struct tctrl_softc *sc) 1259 { 1260 int i, error; 1261 1262 sc->sc_sme = sysmon_envsys_create(); 1263 1264 /* case temperature */ 1265 (void)strlcpy(sc->sc_sensor[0].desc, "Case temperature", 1266 sizeof(sc->sc_sensor[0].desc)); 1267 sc->sc_sensor[0].units = ENVSYS_STEMP; 1268 1269 /* battery voltage */ 1270 (void)strlcpy(sc->sc_sensor[1].desc, "Internal battery voltage", 1271 sizeof(sc->sc_sensor[1].desc)); 1272 sc->sc_sensor[1].units = ENVSYS_SVOLTS_DC; 1273 1274 /* DC voltage */ 1275 (void)strlcpy(sc->sc_sensor[2].desc, "DC-In voltage", 1276 sizeof(sc->sc_sensor[2].desc)); 1277 sc->sc_sensor[2].units = ENVSYS_SVOLTS_DC; 1278 1279 for (i = 0; i < ENVSYS_NUMSENSORS; i++) { 1280 if (sysmon_envsys_sensor_attach(sc->sc_sme, 1281 &sc->sc_sensor[i])) { 1282 sysmon_envsys_destroy(sc->sc_sme); 1283 return; 1284 } 1285 } 1286 1287 sc->sc_sme->sme_name = sc->sc_dev.dv_xname; 1288 sc->sc_sme->sme_cookie = sc; 1289 sc->sc_sme->sme_refresh = tctrl_refresh; 1290 1291 if ((error = sysmon_envsys_register(sc->sc_sme)) != 0) { 1292 printf("%s: couldn't register sensors (%d)\n", 1293 sc->sc_dev.dv_xname, error); 1294 sysmon_envsys_destroy(sc->sc_sme); 1295 return; 1296 } 1297 1298 /* now register the power button */ 1299 1300 sysmon_task_queue_init(); 1301 1302 sc->sc_powerpressed = 0; 1303 memset(&sc->sc_sm_pbutton, 0, sizeof(struct sysmon_pswitch)); 1304 sc->sc_sm_pbutton.smpsw_name = sc->sc_dev.dv_xname; 1305 sc->sc_sm_pbutton.smpsw_type = PSWITCH_TYPE_POWER; 1306 if (sysmon_pswitch_register(&sc->sc_sm_pbutton) != 0) 1307 printf("%s: unable to register power button with sysmon\n", 1308 sc->sc_dev.dv_xname); 1309 1310 memset(&sc->sc_sm_lid, 0, sizeof(struct sysmon_pswitch)); 1311 sc->sc_sm_lid.smpsw_name = sc->sc_dev.dv_xname; 1312 sc->sc_sm_lid.smpsw_type = PSWITCH_TYPE_LID; 1313 if (sysmon_pswitch_register(&sc->sc_sm_lid) != 0) 1314 printf("%s: unable to register lid switch with sysmon\n", 1315 sc->sc_dev.dv_xname); 1316 1317 memset(&sc->sc_sm_ac, 0, sizeof(struct sysmon_pswitch)); 1318 sc->sc_sm_ac.smpsw_name = sc->sc_dev.dv_xname; 1319 sc->sc_sm_ac.smpsw_type = PSWITCH_TYPE_ACADAPTER; 1320 if (sysmon_pswitch_register(&sc->sc_sm_ac) != 0) 1321 printf("%s: unable to register AC adaptor with sysmon\n", 1322 sc->sc_dev.dv_xname); 1323 } 1324 1325 static void 1326 tctrl_power_button_pressed(void *arg) 1327 { 1328 struct tctrl_softc *sc = arg; 1329 1330 sysmon_pswitch_event(&sc->sc_sm_pbutton, PSWITCH_EVENT_PRESSED); 1331 sc->sc_powerpressed = 0; 1332 } 1333 1334 static void 1335 tctrl_lid_state(struct tctrl_softc *sc) 1336 { 1337 int state; 1338 1339 state = (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) ? 1340 PSWITCH_EVENT_PRESSED : PSWITCH_EVENT_RELEASED; 1341 sysmon_pswitch_event(&sc->sc_sm_lid, state); 1342 } 1343 1344 static void 1345 tctrl_ac_state(struct tctrl_softc *sc) 1346 { 1347 int state; 1348 1349 state = (sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ? 1350 PSWITCH_EVENT_PRESSED : PSWITCH_EVENT_RELEASED; 1351 sysmon_pswitch_event(&sc->sc_sm_ac, state); 1352 } 1353 1354 static int 1355 tctrl_powerfail(void *arg) 1356 { 1357 struct tctrl_softc *sc = (struct tctrl_softc *)arg; 1358 1359 /* 1360 * We lost power. Queue a callback with thread context to 1361 * handle all the real work. 1362 */ 1363 if (sc->sc_powerpressed == 0) { 1364 sc->sc_powerpressed = 1; 1365 sysmon_task_queue_sched(0, tctrl_power_button_pressed, sc); 1366 } 1367 return (1); 1368 } 1369 1370 static void 1371 tctrl_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 1372 { 1373 /*struct tctrl_softc *sc = sme->sme_cookie;*/ 1374 struct tctrl_req req; 1375 int sleepable; 1376 int i; 1377 1378 i = edata->sensor; 1379 sleepable = curlwp ? 1 : 0; 1380 1381 switch (i) 1382 { 1383 case 0: /* case temperature */ 1384 req.cmdbuf[0] = TS102_OP_RD_CURRENT_TEMP; 1385 req.cmdlen = 1; 1386 req.rsplen = 2; 1387 tadpole_request(&req, 0, sleepable); 1388 edata->value_cur = /* 273160? */ 1389 (uint32_t)((int)((int)req.rspbuf[0] - 32) * 5000000 1390 / 9 + 273150000); 1391 req.cmdbuf[0] = TS102_OP_RD_MAX_TEMP; 1392 req.cmdlen = 1; 1393 req.rsplen = 2; 1394 tadpole_request(&req, 0, sleepable); 1395 edata->value_max = 1396 (uint32_t)((int)((int)req.rspbuf[0] - 32) * 5000000 1397 / 9 + 273150000); 1398 edata->flags |= ENVSYS_FVALID_MAX; 1399 req.cmdbuf[0] = TS102_OP_RD_MIN_TEMP; 1400 req.cmdlen = 1; 1401 req.rsplen = 2; 1402 tadpole_request(&req, 0, sleepable); 1403 edata->value_min = 1404 (uint32_t)((int)((int)req.rspbuf[0] - 32) * 5000000 1405 / 9 + 273150000); 1406 edata->flags |= ENVSYS_FVALID_MIN; 1407 edata->units = ENVSYS_STEMP; 1408 break; 1409 1410 case 1: /* battery voltage */ 1411 { 1412 edata->units = ENVSYS_SVOLTS_DC; 1413 req.cmdbuf[0] = TS102_OP_RD_INT_BATT_VLT; 1414 req.cmdlen = 1; 1415 req.rsplen = 2; 1416 tadpole_request(&req, 0, sleepable); 1417 edata->value_cur = (int32_t)req.rspbuf[0] * 1418 1000000 / 11; 1419 } 1420 break; 1421 case 2: /* DC voltage */ 1422 { 1423 edata->units = ENVSYS_SVOLTS_DC; 1424 req.cmdbuf[0] = TS102_OP_RD_DC_IN_VLT; 1425 req.cmdlen = 1; 1426 req.rsplen = 2; 1427 tadpole_request(&req, 0, sleepable); 1428 edata->value_cur = (int32_t)req.rspbuf[0] * 1429 1000000 / 11; 1430 } 1431 break; 1432 } 1433 edata->state = ENVSYS_SVALID; 1434 } 1435 1436 static void 1437 tctrl_event_thread(void *v) 1438 { 1439 struct tctrl_softc *sc = v; 1440 struct device *dv; 1441 struct sd_softc *sd = NULL; 1442 struct lance_softc *le = NULL; 1443 int ticks = hz/2; 1444 int rcount, wcount; 1445 int s; 1446 1447 while (sd == NULL) { 1448 dv = device_find_by_xname("sd0"); 1449 if (dv != NULL) 1450 sd = device_private(dv); 1451 else 1452 tsleep(&sc->sc_events, PWAIT, "probe_disk", hz); 1453 } 1454 dv = device_find_by_xname("le0"); 1455 if (dv != NULL) 1456 le = device_private(dv); 1457 printf("found %s\n", sd->sc_dev.dv_xname); 1458 rcount = sd->sc_dk.dk_stats->io_rxfer; 1459 wcount = sd->sc_dk.dk_stats->io_wxfer; 1460 1461 tctrl_read_event_status(sc); 1462 1463 while (1) { 1464 tsleep(&sc->sc_events, PWAIT, "tctrl_event", ticks); 1465 s = splhigh(); 1466 if ((rcount != sd->sc_dk.dk_stats->io_rxfer) || 1467 (wcount != sd->sc_dk.dk_stats->io_wxfer)) { 1468 rcount = sd->sc_dk.dk_stats->io_rxfer; 1469 wcount = sd->sc_dk.dk_stats->io_wxfer; 1470 sc->sc_lcdwanted |= TS102_LCD_DISK_ACTIVE; 1471 } else 1472 sc->sc_lcdwanted &= ~TS102_LCD_DISK_ACTIVE; 1473 if (le != NULL) { 1474 if (le->sc_havecarrier != 0) { 1475 sc->sc_lcdwanted |= TS102_LCD_LAN_ACTIVE; 1476 } else 1477 sc->sc_lcdwanted &= ~TS102_LCD_LAN_ACTIVE; 1478 } 1479 splx(s); 1480 tctrl_update_lcd(sc); 1481 if (sc->sc_ext_pending) 1482 tctrl_read_event_status(sc); 1483 } 1484 } 1485 1486 void 1487 tadpole_register_callback(void (*callback)(void *, int), void *cookie) 1488 { 1489 struct tctrl_softc *sc; 1490 1491 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV]; 1492 sc->sc_video_callback = callback; 1493 sc->sc_video_callback_cookie = cookie; 1494 if (sc->sc_video_callback != NULL) { 1495 sc->sc_video_callback(sc->sc_video_callback_cookie, 1496 sc->sc_extvga); 1497 } 1498 } 1499