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