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