1 /* $NetBSD: tctrl.c,v 1.21 2002/11/26 19:50:29 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 1998 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/param.h> 40 #include <sys/systm.h> 41 #include <sys/callout.h> 42 #include <sys/ioctl.h> 43 #include <sys/select.h> 44 #include <sys/tty.h> 45 #include <sys/proc.h> 46 #include <sys/user.h> 47 #include <sys/conf.h> 48 #include <sys/file.h> 49 #include <sys/uio.h> 50 #include <sys/kernel.h> 51 #include <sys/syslog.h> 52 #include <sys/types.h> 53 #include <sys/device.h> 54 #include <sys/envsys.h> 55 #include <sys/poll.h> 56 57 #include <machine/apmvar.h> 58 #include <machine/autoconf.h> 59 #include <machine/bus.h> 60 #include <machine/intr.h> 61 #include <machine/tctrl.h> 62 63 #include <sparc/dev/ts102reg.h> 64 #include <sparc/dev/tctrlvar.h> 65 #include <sparc/sparc/auxiotwo.h> 66 67 extern struct cfdriver tctrl_cd; 68 69 dev_type_open(tctrlopen); 70 dev_type_close(tctrlclose); 71 dev_type_ioctl(tctrlioctl); 72 dev_type_poll(tctrlpoll); 73 dev_type_kqfilter(tctrlkqfilter); 74 75 const struct cdevsw tctrl_cdevsw = { 76 tctrlopen, tctrlclose, noread, nowrite, tctrlioctl, 77 nostop, notty, tctrlpoll, nommap, tctrlkqfilter, 78 }; 79 80 static const char *tctrl_ext_statuses[16] = { 81 "main power available", 82 "internal battery attached", 83 "external battery attached", 84 "external VGA attached", 85 "external keyboard attached", 86 "external mouse attached", 87 "lid down", 88 "internal battery charging", 89 "external battery charging", 90 "internal battery discharging", 91 "external battery discharging", 92 }; 93 94 struct tctrl_softc { 95 struct device sc_dev; 96 bus_space_tag_t sc_memt; 97 bus_space_handle_t sc_memh; 98 unsigned int sc_junk; 99 unsigned int sc_ext_status; 100 unsigned int sc_flags; 101 #define TCTRL_SEND_REQUEST 0x0001 102 #define TCTRL_APM_CTLOPEN 0x0002 103 unsigned int sc_wantdata; 104 volatile unsigned short sc_lcdstate; 105 enum { TCTRL_IDLE, TCTRL_ARGS, 106 TCTRL_ACK, TCTRL_DATA } sc_state; 107 u_int8_t sc_cmdbuf[16]; 108 u_int8_t sc_rspbuf[16]; 109 u_int8_t sc_bitport; 110 u_int8_t sc_tft_on; 111 u_int8_t sc_op; 112 u_int8_t sc_cmdoff; 113 u_int8_t sc_cmdlen; 114 u_int8_t sc_rspoff; 115 u_int8_t sc_rsplen; 116 /* APM stuff */ 117 #define APM_NEVENTS 16 118 struct apm_event_info sc_event_list[APM_NEVENTS]; 119 int sc_event_count; 120 int sc_event_ptr; 121 struct selinfo sc_rsel; 122 /* ENVSYS stuff */ 123 #define ENVSYS_NUMSENSORS 3 124 struct envsys_sensor sc_esensors[ENVSYS_NUMSENSORS]; 125 126 struct evcnt sc_intrcnt; /* interrupt counting */ 127 }; 128 129 #define TCTRL_STD_DEV 0 130 #define TCTRL_APMCTL_DEV 8 131 132 static struct callout tctrl_event_ch = CALLOUT_INITIALIZER; 133 134 static int tctrl_match __P((struct device *parent, struct cfdata *cf, 135 void *aux)); 136 static void tctrl_attach __P((struct device *parent, struct device *self, 137 void *aux)); 138 static void tctrl_write __P((struct tctrl_softc *sc, bus_size_t off, 139 u_int8_t v)); 140 static u_int8_t tctrl_read __P((struct tctrl_softc *sc, bus_size_t off)); 141 static void tctrl_write_data __P((struct tctrl_softc *sc, u_int8_t v)); 142 static u_int8_t tctrl_read_data __P((struct tctrl_softc *sc)); 143 static int tctrl_intr __P((void *arg)); 144 static void tctrl_setup_bitport __P((void)); 145 static void tctrl_setup_bitport_nop __P((void)); 146 static void tctrl_read_ext_status __P((void)); 147 static void tctrl_read_event_status __P((void *arg)); 148 static int tctrl_apm_record_event __P((struct tctrl_softc *sc, 149 u_int event_type)); 150 static void tctrl_init_lcd __P((void)); 151 152 CFATTACH_DECL(tctrl, sizeof(struct tctrl_softc), 153 tctrl_match, tctrl_attach, NULL, NULL); 154 155 extern struct cfdriver tctrl_cd; 156 /* XXX wtf is this? see i386/apm.c */ 157 int tctrl_apm_evindex; 158 159 static int 160 tctrl_match(parent, cf, aux) 161 struct device *parent; 162 struct cfdata *cf; 163 void *aux; 164 { 165 union obio_attach_args *uoba = aux; 166 struct sbus_attach_args *sa = &uoba->uoba_sbus; 167 168 if (uoba->uoba_isobio4 != 0) { 169 return (0); 170 } 171 172 /* Tadpole 3GX/3GS uses "uctrl" for the Tadpole Microcontroller 173 * (who's interface is off the TS102 PCMCIA controller but there 174 * exists a OpenProm for microcontroller interface). 175 */ 176 return strcmp("uctrl", sa->sa_name) == 0; 177 } 178 179 static void 180 tctrl_attach(parent, self, aux) 181 struct device *parent; 182 struct device *self; 183 void *aux; 184 { 185 struct tctrl_softc *sc = (void *)self; 186 union obio_attach_args *uoba = aux; 187 struct sbus_attach_args *sa = &uoba->uoba_sbus; 188 unsigned int i, v; 189 #if 0 190 unsigned int ack, msb, lsb; 191 #endif 192 193 /* We're living on a sbus slot that looks like an obio that 194 * looks like an sbus slot. 195 */ 196 sc->sc_memt = sa->sa_bustag; 197 if (sbus_bus_map(sc->sc_memt, 198 sa->sa_slot, 199 sa->sa_offset - TS102_REG_UCTRL_INT, 200 sa->sa_size, 201 BUS_SPACE_MAP_LINEAR, &sc->sc_memh) != 0) { 202 printf(": can't map registers\n"); 203 return; 204 } 205 206 printf("\n"); 207 208 sc->sc_tft_on = 1; 209 210 /* clear any pending data. 211 */ 212 for (i = 0; i < 10000; i++) { 213 if ((TS102_UCTRL_STS_RXNE_STA & 214 tctrl_read(sc, TS102_REG_UCTRL_STS)) == 0) { 215 break; 216 } 217 v = tctrl_read(sc, TS102_REG_UCTRL_DATA); 218 tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA); 219 } 220 221 if (sa->sa_nintr != 0) { 222 (void)bus_intr_establish(sc->sc_memt, sa->sa_pri, IPL_NONE, 223 0, tctrl_intr, sc); 224 evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, NULL, 225 sc->sc_dev.dv_xname, "intr"); 226 } 227 228 /* See what the external status is 229 */ 230 231 tctrl_read_ext_status(); 232 if (sc->sc_ext_status != 0) { 233 const char *sep; 234 235 printf("%s: ", sc->sc_dev.dv_xname); 236 v = sc->sc_ext_status; 237 for (i = 0, sep = ""; v != 0; i++, v >>= 1) { 238 if (v & 1) { 239 printf("%s%s", sep, tctrl_ext_statuses[i]); 240 sep = ", "; 241 } 242 } 243 printf("\n"); 244 } 245 246 /* Get a current of the control bitport; 247 */ 248 tctrl_setup_bitport_nop(); 249 tctrl_write(sc, TS102_REG_UCTRL_INT, 250 TS102_UCTRL_INT_RXNE_REQ|TS102_UCTRL_INT_RXNE_MSK); 251 252 sc->sc_wantdata = 0; 253 sc->sc_event_count = 0; 254 255 /* prime the sensor data */ 256 sprintf(sc->sc_esensors[0].desc, "%s", "Internal Unit Temperature"); 257 sc->sc_esensors[0].units = ENVSYS_STEMP; 258 sprintf(sc->sc_esensors[1].desc, "%s", "Internal Battery Voltage"); 259 sc->sc_esensors[1].units = ENVSYS_SVOLTS_DC; 260 sprintf(sc->sc_esensors[2].desc, "%s", "DC-In Voltage"); 261 sc->sc_esensors[2].units = ENVSYS_SVOLTS_DC; 262 263 /* initialize the LCD */ 264 tctrl_init_lcd(); 265 266 /* initialize sc_lcdstate */ 267 sc->sc_lcdstate = 0; 268 tctrl_set_lcd(2, 0); 269 } 270 271 static int 272 tctrl_intr(arg) 273 void *arg; 274 { 275 struct tctrl_softc *sc = arg; 276 unsigned int v, d; 277 int progress = 0; 278 279 again: 280 /* find out the cause(s) of the interrupt */ 281 v = tctrl_read(sc, TS102_REG_UCTRL_STS) & TS102_UCTRL_STS_MASK; 282 283 /* clear the cause(s) of the interrupt */ 284 tctrl_write(sc, TS102_REG_UCTRL_STS, v); 285 286 v &= ~(TS102_UCTRL_STS_RXO_STA|TS102_UCTRL_STS_TXE_STA); 287 if (sc->sc_cmdoff >= sc->sc_cmdlen) { 288 v &= ~TS102_UCTRL_STS_TXNF_STA; 289 if (tctrl_read(sc, TS102_REG_UCTRL_INT) & TS102_UCTRL_INT_TXNF_REQ) { 290 tctrl_write(sc, TS102_REG_UCTRL_INT, 0); 291 progress = 1; 292 } 293 } 294 if ((v == 0) && ((sc->sc_flags & TCTRL_SEND_REQUEST) == 0 || 295 sc->sc_state != TCTRL_IDLE)) { 296 wakeup(sc); 297 return progress; 298 } 299 300 progress = 1; 301 if (v & TS102_UCTRL_STS_RXNE_STA) { 302 d = tctrl_read_data(sc); 303 switch (sc->sc_state) { 304 case TCTRL_IDLE: 305 if (d == 0xfa) { 306 /* external event */ 307 callout_reset(&tctrl_event_ch, 1, 308 tctrl_read_event_status, NULL); 309 } else { 310 printf("%s: (op=0x%02x): unexpected data (0x%02x)\n", 311 sc->sc_dev.dv_xname, sc->sc_op, d); 312 } 313 goto again; 314 case TCTRL_ACK: 315 if (d != 0xfe) { 316 printf("%s: (op=0x%02x): unexpected ack value (0x%02x)\n", 317 sc->sc_dev.dv_xname, sc->sc_op, d); 318 } 319 #ifdef TCTRLDEBUG 320 printf(" ack=0x%02x", d); 321 #endif 322 sc->sc_rsplen--; 323 sc->sc_rspoff = 0; 324 sc->sc_state = sc->sc_rsplen ? TCTRL_DATA : TCTRL_IDLE; 325 sc->sc_wantdata = sc->sc_rsplen ? 1 : 0; 326 #ifdef TCTRLDEBUG 327 if (sc->sc_rsplen > 0) { 328 printf(" [data(%u)]", sc->sc_rsplen); 329 } else { 330 printf(" [idle]\n"); 331 } 332 #endif 333 goto again; 334 case TCTRL_DATA: 335 sc->sc_rspbuf[sc->sc_rspoff++] = d; 336 #ifdef TCTRLDEBUG 337 printf(" [%d]=0x%02x", sc->sc_rspoff-1, d); 338 #endif 339 if (sc->sc_rspoff == sc->sc_rsplen) { 340 #ifdef TCTRLDEBUG 341 printf(" [idle]\n"); 342 #endif 343 sc->sc_state = TCTRL_IDLE; 344 sc->sc_wantdata = 0; 345 } 346 goto again; 347 default: 348 printf("%s: (op=0x%02x): unexpected data (0x%02x) in state %d\n", 349 sc->sc_dev.dv_xname, sc->sc_op, d, sc->sc_state); 350 goto again; 351 } 352 } 353 if ((sc->sc_state == TCTRL_IDLE && sc->sc_wantdata == 0) || 354 sc->sc_flags & TCTRL_SEND_REQUEST) { 355 if (sc->sc_flags & TCTRL_SEND_REQUEST) { 356 sc->sc_flags &= ~TCTRL_SEND_REQUEST; 357 sc->sc_wantdata = 1; 358 } 359 if (sc->sc_cmdlen > 0) { 360 tctrl_write(sc, TS102_REG_UCTRL_INT, 361 tctrl_read(sc, TS102_REG_UCTRL_INT) 362 |TS102_UCTRL_INT_TXNF_MSK 363 |TS102_UCTRL_INT_TXNF_REQ); 364 v = tctrl_read(sc, TS102_REG_UCTRL_STS); 365 } 366 } 367 if ((sc->sc_cmdoff < sc->sc_cmdlen) && (v & TS102_UCTRL_STS_TXNF_STA)) { 368 tctrl_write_data(sc, sc->sc_cmdbuf[sc->sc_cmdoff++]); 369 #ifdef TCTRLDEBUG 370 if (sc->sc_cmdoff == 1) { 371 printf("%s: op=0x%02x(l=%u)", sc->sc_dev.dv_xname, 372 sc->sc_cmdbuf[0], sc->sc_rsplen); 373 } else { 374 printf(" [%d]=0x%02x", sc->sc_cmdoff-1, 375 sc->sc_cmdbuf[sc->sc_cmdoff-1]); 376 } 377 #endif 378 if (sc->sc_cmdoff == sc->sc_cmdlen) { 379 sc->sc_state = sc->sc_rsplen ? TCTRL_ACK : TCTRL_IDLE; 380 #ifdef TCTRLDEBUG 381 printf(" %s", sc->sc_rsplen ? "[ack]" : "[idle]\n"); 382 #endif 383 if (sc->sc_cmdoff == 1) { 384 sc->sc_op = sc->sc_cmdbuf[0]; 385 } 386 tctrl_write(sc, TS102_REG_UCTRL_INT, 387 tctrl_read(sc, TS102_REG_UCTRL_INT) 388 & (~TS102_UCTRL_INT_TXNF_MSK 389 |TS102_UCTRL_INT_TXNF_REQ)); 390 } else if (sc->sc_state == TCTRL_IDLE) { 391 sc->sc_op = sc->sc_cmdbuf[0]; 392 sc->sc_state = TCTRL_ARGS; 393 #ifdef TCTRLDEBUG 394 printf(" [args]"); 395 #endif 396 } 397 } 398 goto again; 399 } 400 401 static void 402 tctrl_setup_bitport_nop(void) 403 { 404 struct tctrl_softc *sc; 405 struct tctrl_req req; 406 int s; 407 408 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV]; 409 req.cmdbuf[0] = TS102_OP_CTL_BITPORT; 410 req.cmdbuf[1] = 0xff; 411 req.cmdbuf[2] = 0; 412 req.cmdlen = 3; 413 req.rsplen = 2; 414 req.p = NULL; 415 tadpole_request(&req, 1); 416 s = splts102(); 417 sc->sc_bitport = (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2]; 418 splx(s); 419 } 420 421 static void 422 tctrl_setup_bitport(void) 423 { 424 struct tctrl_softc *sc; 425 struct tctrl_req req; 426 int s; 427 428 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV]; 429 s = splts102(); 430 if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) 431 || (!sc->sc_tft_on)) { 432 req.cmdbuf[2] = TS102_BITPORT_TFTPWR; 433 } else { 434 req.cmdbuf[2] = 0; 435 } 436 req.cmdbuf[0] = TS102_OP_CTL_BITPORT; 437 req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR; 438 req.cmdlen = 3; 439 req.rsplen = 2; 440 req.p = NULL; 441 tadpole_request(&req, 1); 442 s = splts102(); 443 sc->sc_bitport = (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2]; 444 splx(s); 445 } 446 447 /* 448 * The tadpole microcontroller is not preprogrammed with icon 449 * representations. The machine boots with the DC-IN light as 450 * a blank (all 0x00) and the other lights, as 4 rows of horizontal 451 * bars. The below code initializes the icons in the system to 452 * sane values. Some of these icons could be used for any purpose 453 * desired, namely the pcmcia, LAN and WAN lights. For the disk spinner, 454 * only the backslash is unprogrammed. (sigh) 455 * 456 * programming the icons is simple. It is a 5x8 matrix, which each row a 457 * bitfield in the order 0x10 0x08 0x04 0x02 0x01. 458 */ 459 460 static void 461 tctrl_init_lcd(void) 462 { 463 struct tctrl_req req; 464 465 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR; 466 req.cmdlen = 11; 467 req.rsplen = 1; 468 req.cmdbuf[1] = 0x08; /*len*/ 469 req.cmdbuf[2] = TS102_BLK_OFF_DEF_DC_GOOD; 470 req.cmdbuf[3] = 0x00; /* ..... */ 471 req.cmdbuf[4] = 0x00; /* ..... */ 472 req.cmdbuf[5] = 0x1f; /* XXXXX */ 473 req.cmdbuf[6] = 0x00; /* ..... */ 474 req.cmdbuf[7] = 0x15; /* X.X.X */ 475 req.cmdbuf[8] = 0x00; /* ..... */ 476 req.cmdbuf[9] = 0x00; /* ..... */ 477 req.cmdbuf[10] = 0x00; /* ..... */ 478 req.p = NULL; 479 tadpole_request(&req, 1); 480 481 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR; 482 req.cmdlen = 11; 483 req.rsplen = 1; 484 req.cmdbuf[1] = 0x08; /*len*/ 485 req.cmdbuf[2] = TS102_BLK_OFF_DEF_BACKSLASH; 486 req.cmdbuf[3] = 0x00; /* ..... */ 487 req.cmdbuf[4] = 0x10; /* X.... */ 488 req.cmdbuf[5] = 0x08; /* .X... */ 489 req.cmdbuf[6] = 0x04; /* ..X.. */ 490 req.cmdbuf[7] = 0x02; /* ...X. */ 491 req.cmdbuf[8] = 0x01; /* ....X */ 492 req.cmdbuf[9] = 0x00; /* ..... */ 493 req.cmdbuf[10] = 0x00; /* ..... */ 494 req.p = NULL; 495 tadpole_request(&req, 1); 496 497 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR; 498 req.cmdlen = 11; 499 req.rsplen = 1; 500 req.cmdbuf[1] = 0x08; /*len*/ 501 req.cmdbuf[2] = TS102_BLK_OFF_DEF_WAN1; 502 req.cmdbuf[3] = 0x0c; /* .XXX. */ 503 req.cmdbuf[4] = 0x16; /* X.XX. */ 504 req.cmdbuf[5] = 0x10; /* X.... */ 505 req.cmdbuf[6] = 0x15; /* X.X.X */ 506 req.cmdbuf[7] = 0x10; /* X.... */ 507 req.cmdbuf[8] = 0x16; /* X.XX. */ 508 req.cmdbuf[9] = 0x0c; /* .XXX. */ 509 req.cmdbuf[10] = 0x00; /* ..... */ 510 req.p = NULL; 511 tadpole_request(&req, 1); 512 513 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR; 514 req.cmdlen = 11; 515 req.rsplen = 1; 516 req.cmdbuf[1] = 0x08; /*len*/ 517 req.cmdbuf[2] = TS102_BLK_OFF_DEF_WAN2; 518 req.cmdbuf[3] = 0x0c; /* .XXX. */ 519 req.cmdbuf[4] = 0x0d; /* .XX.X */ 520 req.cmdbuf[5] = 0x01; /* ....X */ 521 req.cmdbuf[6] = 0x15; /* X.X.X */ 522 req.cmdbuf[7] = 0x01; /* ....X */ 523 req.cmdbuf[8] = 0x0d; /* .XX.X */ 524 req.cmdbuf[9] = 0x0c; /* .XXX. */ 525 req.cmdbuf[10] = 0x00; /* ..... */ 526 req.p = NULL; 527 tadpole_request(&req, 1); 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_LAN1; 534 req.cmdbuf[3] = 0x00; /* ..... */ 535 req.cmdbuf[4] = 0x04; /* ..X.. */ 536 req.cmdbuf[5] = 0x08; /* .X... */ 537 req.cmdbuf[6] = 0x13; /* X..XX */ 538 req.cmdbuf[7] = 0x08; /* .X... */ 539 req.cmdbuf[8] = 0x04; /* ..X.. */ 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_LAN2; 550 req.cmdbuf[3] = 0x00; /* ..... */ 551 req.cmdbuf[4] = 0x04; /* ..X.. */ 552 req.cmdbuf[5] = 0x02; /* ...X. */ 553 req.cmdbuf[6] = 0x19; /* XX..X */ 554 req.cmdbuf[7] = 0x02; /* ...X. */ 555 req.cmdbuf[8] = 0x04; /* ..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_PCMCIA; 566 req.cmdbuf[3] = 0x00; /* ..... */ 567 req.cmdbuf[4] = 0x0c; /* .XXX. */ 568 req.cmdbuf[5] = 0x1f; /* XXXXX */ 569 req.cmdbuf[6] = 0x1f; /* XXXXX */ 570 req.cmdbuf[7] = 0x1f; /* XXXXX */ 571 req.cmdbuf[8] = 0x1f; /* XXXXX */ 572 req.cmdbuf[9] = 0x00; /* ..... */ 573 req.cmdbuf[10] = 0x00; /* ..... */ 574 req.p = NULL; 575 tadpole_request(&req, 1); 576 } 577 578 579 580 /* 581 * set the blinken-lights on the lcd. what: 582 * what = 0 off, what = 1 on, what = 2 toggle 583 */ 584 585 void 586 tctrl_set_lcd(what, which) 587 int what; 588 unsigned short which; 589 { 590 struct tctrl_softc *sc; 591 struct tctrl_req req; 592 int s; 593 594 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV]; 595 s = splts102(); 596 597 /* provide a quick exit to save cpu time */ 598 if ((what == 1 && sc->sc_lcdstate & which) || 599 (what == 0 && !(sc->sc_lcdstate & which))) { 600 splx(s); 601 return; 602 } 603 /* 604 * the mask setup on this particular command is *very* bizzare 605 * and totally undocumented. 606 */ 607 if ((what == 1) || (what == 2 && !(sc->sc_lcdstate & which))) { 608 req.cmdbuf[2] = (u_int8_t)(which&0xff); 609 req.cmdbuf[3] = (u_int8_t)(which>>8); 610 } else { 611 req.cmdbuf[2] = 0; 612 req.cmdbuf[3] = 0; 613 } 614 req.cmdbuf[0] = TS102_OP_CTL_LCD; 615 req.cmdbuf[4] = (u_int8_t)(~which>>8); 616 req.cmdbuf[1] = (u_int8_t)(~which&0xff); 617 618 /* XXX this thing is weird.... */ 619 req.cmdlen = 3; 620 req.rsplen = 2; 621 #if 0 622 req.cmdlen = 5; 623 req.rsplen = 4; 624 #endif 625 req.p = NULL; 626 tadpole_request(&req, 1); 627 s = splts102(); 628 sc->sc_lcdstate = (unsigned short)req.rspbuf[0]; 629 splx(s); 630 } 631 632 static void 633 tctrl_read_ext_status(void) 634 { 635 struct tctrl_softc *sc; 636 struct tctrl_req req; 637 int s; 638 639 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV]; 640 req.cmdbuf[0] = TS102_OP_RD_EXT_STATUS; 641 req.cmdlen = 1; 642 req.rsplen = 3; 643 req.p = NULL; 644 #ifdef TCTRLDEBUG 645 printf("pre read: sc->sc_ext_status = 0x%x\n", sc->sc_ext_status); 646 #endif 647 tadpole_request(&req, 1); 648 s = splts102(); 649 sc->sc_ext_status = req.rspbuf[0] * 256 + req.rspbuf[1]; 650 splx(s); 651 #ifdef TCTRLDEBUG 652 printf("post read: sc->sc_ext_status = 0x%x\n", sc->sc_ext_status); 653 #endif 654 } 655 656 /* 657 * return 0 if the user will notice and handle the event, 658 * return 1 if the kernel driver should do so. 659 */ 660 static int 661 tctrl_apm_record_event(sc, event_type) 662 struct tctrl_softc *sc; 663 u_int event_type; 664 { 665 struct apm_event_info *evp; 666 667 if ((sc->sc_flags & TCTRL_APM_CTLOPEN) && 668 (sc->sc_event_count < APM_NEVENTS)) { 669 evp = &sc->sc_event_list[sc->sc_event_ptr]; 670 sc->sc_event_count++; 671 sc->sc_event_ptr++; 672 sc->sc_event_ptr %= APM_NEVENTS; 673 evp->type = event_type; 674 evp->index = ++tctrl_apm_evindex; 675 selnotify(&sc->sc_rsel, 0); 676 return(sc->sc_flags & TCTRL_APM_CTLOPEN) ? 0 : 1; 677 } 678 return(1); 679 } 680 681 static void 682 tctrl_read_event_status(arg) 683 void *arg; 684 { 685 struct tctrl_softc *sc; 686 struct tctrl_req req; 687 int s; 688 unsigned int v; 689 690 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV]; 691 req.cmdbuf[0] = TS102_OP_RD_EVENT_STATUS; 692 req.cmdlen = 1; 693 req.rsplen = 3; 694 req.p = NULL; 695 tadpole_request(&req, 1); 696 s = splts102(); 697 v = req.rspbuf[0] * 256 + req.rspbuf[1]; 698 if (v & TS102_EVENT_STATUS_SHUTDOWN_REQUEST) { 699 printf("%s: SHUTDOWN REQUEST!\n", sc->sc_dev.dv_xname); 700 } 701 if (v & TS102_EVENT_STATUS_VERY_LOW_POWER_WARNING) { 702 /*printf("%s: VERY LOW POWER WARNING!\n", sc->sc_dev.dv_xname);*/ 703 /* according to a tadpole header, and observation */ 704 #ifdef TCTRLDEBUG 705 printf("%s: Battery charge level change\n", sc->sc_dev.dv_xname); 706 #endif 707 } 708 if (v & TS102_EVENT_STATUS_LOW_POWER_WARNING) { 709 if (tctrl_apm_record_event(sc, APM_BATTERY_LOW)) 710 printf("%s: LOW POWER WARNING!\n", sc->sc_dev.dv_xname); 711 } 712 if (v & TS102_EVENT_STATUS_DC_STATUS_CHANGE) { 713 splx(s); 714 tctrl_read_ext_status(); 715 s = splts102(); 716 if (tctrl_apm_record_event(sc, APM_POWER_CHANGE)) 717 printf("%s: main power %s\n", sc->sc_dev.dv_xname, 718 (sc->sc_ext_status & 719 TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ? 720 "restored" : "removed"); 721 } 722 if (v & TS102_EVENT_STATUS_LID_STATUS_CHANGE) { 723 splx(s); 724 tctrl_read_ext_status(); 725 tctrl_setup_bitport(); 726 #ifdef TCTRLDEBUG 727 printf("%s: lid %s\n", sc->sc_dev.dv_xname, 728 (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) 729 ? "closed" : "opened"); 730 #endif 731 } 732 splx(s); 733 } 734 735 void 736 tadpole_request(req, spin) 737 struct tctrl_req *req; 738 int spin; 739 { 740 struct tctrl_softc *sc; 741 int i, s; 742 743 if (tctrl_cd.cd_devs == NULL 744 || tctrl_cd.cd_ndevs == 0 745 || tctrl_cd.cd_devs[TCTRL_STD_DEV] == NULL) { 746 return; 747 } 748 749 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV]; 750 while (sc->sc_wantdata != 0) { 751 if (req->p != NULL) 752 tsleep(&sc->sc_wantdata, PLOCK, "tctrl_lock", 10); 753 else 754 DELAY(1); 755 } 756 if (spin) 757 s = splhigh(); 758 else 759 s = splts102(); 760 sc->sc_flags |= TCTRL_SEND_REQUEST; 761 memcpy(sc->sc_cmdbuf, req->cmdbuf, req->cmdlen); 762 sc->sc_wantdata = 1; 763 sc->sc_rsplen = req->rsplen; 764 sc->sc_cmdlen = req->cmdlen; 765 sc->sc_cmdoff = sc->sc_rspoff = 0; 766 767 /* we spin for certain commands, like poweroffs */ 768 if (spin) { 769 /* for (i = 0; i < 30000; i++) {*/ 770 while (sc->sc_wantdata == 1) { 771 tctrl_intr(sc); 772 DELAY(1); 773 } 774 } else { 775 tctrl_intr(sc); 776 i = 0; 777 while (((sc->sc_rspoff != sc->sc_rsplen) || 778 (sc->sc_cmdoff != sc->sc_cmdlen)) && 779 (i < (5 * sc->sc_rsplen + sc->sc_cmdlen))) 780 if (req->p != NULL) { 781 tsleep(sc, PWAIT, "tctrl_data", 15); 782 i++; 783 } 784 else 785 DELAY(1); 786 } 787 /* 788 * we give the user a reasonable amount of time for a command 789 * to complete. If it doesn't complete in time, we hand them 790 * garbage. This is here to stop things like setting the 791 * rsplen too long, and sleeping forever in a CMD_REQ ioctl. 792 */ 793 sc->sc_wantdata = 0; 794 memcpy(req->rspbuf, sc->sc_rspbuf, req->rsplen); 795 splx(s); 796 } 797 798 void 799 tadpole_powerdown(void) 800 { 801 struct tctrl_req req; 802 803 req.cmdbuf[0] = TS102_OP_ADMIN_POWER_OFF; 804 req.cmdlen = 1; 805 req.rsplen = 1; 806 req.p = NULL; 807 tadpole_request(&req, 1); 808 } 809 810 void 811 tadpole_set_video(enabled) 812 int enabled; 813 { 814 struct tctrl_softc *sc; 815 struct tctrl_req req; 816 int s; 817 818 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV]; 819 while (sc->sc_wantdata != 0) 820 DELAY(1); 821 s = splts102(); 822 req.p = NULL; 823 if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN && !enabled) 824 || (sc->sc_tft_on)) { 825 req.cmdbuf[2] = TS102_BITPORT_TFTPWR; 826 } else { 827 req.cmdbuf[2] = 0; 828 } 829 req.cmdbuf[0] = TS102_OP_CTL_BITPORT; 830 req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR; 831 req.cmdlen = 3; 832 req.rsplen = 2; 833 834 if ((sc->sc_tft_on && !enabled) || (!sc->sc_tft_on && enabled)) { 835 sc->sc_tft_on = enabled; 836 if (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) { 837 splx(s); 838 return; 839 } 840 tadpole_request(&req, 1); 841 sc->sc_bitport = 842 (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2]; 843 } 844 splx(s); 845 } 846 847 static void 848 tctrl_write_data(sc, v) 849 struct tctrl_softc *sc; 850 u_int8_t v; 851 { 852 unsigned int i; 853 854 for (i = 0; i < 100; i++) { 855 if (TS102_UCTRL_STS_TXNF_STA & tctrl_read(sc, TS102_REG_UCTRL_STS)) 856 break; 857 } 858 tctrl_write(sc, TS102_REG_UCTRL_DATA, v); 859 } 860 861 static u_int8_t 862 tctrl_read_data(sc) 863 struct tctrl_softc *sc; 864 { 865 unsigned int i, v; 866 867 for (i = 0; i < 100000; i++) { 868 if (TS102_UCTRL_STS_RXNE_STA & tctrl_read(sc, TS102_REG_UCTRL_STS)) 869 break; 870 DELAY(1); 871 } 872 873 v = tctrl_read(sc, TS102_REG_UCTRL_DATA); 874 tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA); 875 return v; 876 } 877 878 static u_int8_t 879 tctrl_read(sc, off) 880 struct tctrl_softc *sc; 881 bus_size_t off; 882 { 883 884 sc->sc_junk = bus_space_read_1(sc->sc_memt, sc->sc_memh, off); 885 return sc->sc_junk; 886 } 887 888 static void 889 tctrl_write(sc, off, v) 890 struct tctrl_softc *sc; 891 bus_size_t off; 892 u_int8_t v; 893 { 894 895 sc->sc_junk = v; 896 bus_space_write_1(sc->sc_memt, sc->sc_memh, off, v); 897 } 898 899 int 900 tctrlopen(dev, flags, mode, p) 901 dev_t dev; 902 int flags, mode; 903 struct proc *p; 904 { 905 int unit = (minor(dev)&0xf0); 906 int ctl = (minor(dev)&0x0f); 907 struct tctrl_softc *sc; 908 909 if (unit >= tctrl_cd.cd_ndevs) 910 return(ENXIO); 911 sc = tctrl_cd.cd_devs[TCTRL_STD_DEV]; 912 if (!sc) 913 return(ENXIO); 914 915 switch (ctl) { 916 case TCTRL_STD_DEV: 917 break; 918 case TCTRL_APMCTL_DEV: 919 if (!(flags & FWRITE)) 920 return(EINVAL); 921 if (sc->sc_flags & TCTRL_APM_CTLOPEN) 922 return(EBUSY); 923 sc->sc_flags |= TCTRL_APM_CTLOPEN; 924 break; 925 default: 926 return(ENXIO); 927 break; 928 } 929 930 return(0); 931 } 932 933 int 934 tctrlclose(dev, flags, mode, p) 935 dev_t dev; 936 int flags, mode; 937 struct proc *p; 938 { 939 int ctl = (minor(dev)&0x0f); 940 struct tctrl_softc *sc; 941 942 sc = tctrl_cd.cd_devs[TCTRL_STD_DEV]; 943 if (!sc) 944 return(ENXIO); 945 946 switch (ctl) { 947 case TCTRL_STD_DEV: 948 break; 949 case TCTRL_APMCTL_DEV: 950 sc->sc_flags &= ~TCTRL_APM_CTLOPEN; 951 break; 952 } 953 return(0); 954 } 955 956 int 957 tctrlioctl(dev, cmd, data, flags, p) 958 dev_t dev; 959 u_long cmd; 960 caddr_t data; 961 int flags; 962 struct proc *p; 963 { 964 struct tctrl_req req, *reqn; 965 struct tctrl_pwr *pwrreq; 966 envsys_range_t *envrange; 967 envsys_temp_data_t *envdata; 968 envsys_temp_info_t *envinfo; 969 struct apm_power_info *powerp; 970 struct apm_event_info *evp; 971 struct tctrl_softc *sc; 972 int i; 973 u_int j; 974 u_int16_t a; 975 u_int8_t c; 976 977 if (tctrl_cd.cd_devs == NULL 978 || tctrl_cd.cd_ndevs == 0 979 || tctrl_cd.cd_devs[TCTRL_STD_DEV] == NULL) { 980 return ENXIO; 981 } 982 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV]; 983 switch (cmd) { 984 985 case APM_IOC_STANDBY: 986 return(EOPNOTSUPP); /* for now */ 987 988 case APM_IOC_SUSPEND: 989 return(EOPNOTSUPP); /* for now */ 990 991 case OAPM_IOC_GETPOWER: 992 case APM_IOC_GETPOWER: 993 powerp = (struct apm_power_info *)data; 994 req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_RATE; 995 req.cmdlen = 1; 996 req.rsplen = 2; 997 req.p = p; 998 tadpole_request(&req, 0); 999 if (req.rspbuf[0] > 0x00) 1000 powerp->battery_state = APM_BATT_CHARGING; 1001 req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_LEVEL; 1002 req.cmdlen = 1; 1003 req.rsplen = 3; 1004 req.p = p; 1005 tadpole_request(&req, 0); 1006 c = req.rspbuf[0]; 1007 powerp->battery_life = c; 1008 if (c > 0x70) /* the tadpole sometimes dips below zero, and */ 1009 c = 0; /* into the 255 range. */ 1010 powerp->minutes_left = (45 * c) / 100; /* XXX based on 45 min */ 1011 if (powerp->battery_state != APM_BATT_CHARGING) { 1012 if (c < 0x20) 1013 powerp->battery_state = APM_BATT_CRITICAL; 1014 else if (c < 0x40) 1015 powerp->battery_state = APM_BATT_LOW; 1016 else if (c < 0x66) 1017 powerp->battery_state = APM_BATT_HIGH; 1018 else 1019 powerp->battery_state = APM_BATT_UNKNOWN; 1020 } 1021 req.cmdbuf[0] = TS102_OP_RD_EXT_STATUS; 1022 req.cmdlen = 1; 1023 req.rsplen = 3; 1024 req.p = p; 1025 tadpole_request(&req, 0); 1026 a = req.rspbuf[0] * 256 + req.rspbuf[1]; 1027 if (a & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) 1028 powerp->ac_state = APM_AC_ON; 1029 else 1030 powerp->ac_state = APM_AC_OFF; 1031 break; 1032 1033 case APM_IOC_NEXTEVENT: 1034 if (!sc->sc_event_count) 1035 return EAGAIN; 1036 1037 evp = (struct apm_event_info *)data; 1038 i = sc->sc_event_ptr + APM_NEVENTS - sc->sc_event_count; 1039 i %= APM_NEVENTS; 1040 *evp = sc->sc_event_list[i]; 1041 sc->sc_event_count--; 1042 return(0); 1043 1044 /* this ioctl assumes the caller knows exactly what he is doing */ 1045 case TCTRL_CMD_REQ: 1046 reqn = (struct tctrl_req *)data; 1047 if ((i = suser(p->p_ucred, &p->p_acflag)) != 0 && 1048 (reqn->cmdbuf[0] == TS102_OP_CTL_BITPORT || 1049 (reqn->cmdbuf[0] >= TS102_OP_CTL_WATCHDOG && 1050 reqn->cmdbuf[0] <= TS102_OP_CTL_SECURITY_KEY) || 1051 reqn->cmdbuf[0] == TS102_OP_CTL_TIMEZONE || 1052 reqn->cmdbuf[0] == TS102_OP_CTL_DIAGNOSTIC_MODE || 1053 reqn->cmdbuf[0] == TS102_OP_CMD_SOFTWARE_RESET || 1054 (reqn->cmdbuf[0] >= TS102_OP_CMD_SET_RTC && 1055 reqn->cmdbuf[0] < TS102_OP_RD_INT_CHARGE_LEVEL) || 1056 reqn->cmdbuf[0] > TS102_OP_RD_EXT_CHARGE_LEVEL)) 1057 return(i); 1058 reqn->p = p; 1059 tadpole_request(reqn, 0); 1060 break; 1061 1062 case ENVSYS_VERSION: 1063 *(int32_t *)data = 1000; 1064 break; 1065 1066 case ENVSYS_GRANGE: 1067 envrange = (envsys_range_t *)data; 1068 i = 0; 1069 envrange->high = envrange->low = 0; 1070 for (j=0; j < ENVSYS_NUMSENSORS; j++) { 1071 if (!i && envrange->units == sc->sc_esensors[j].units) { 1072 envrange->low = j; 1073 i++; 1074 } 1075 if (i && envrange->units == sc->sc_esensors[j].units) 1076 envrange->high = j; 1077 } 1078 if (!i) { 1079 envrange->high = 0; 1080 envrange->low = 1; 1081 } 1082 break; 1083 1084 case ENVSYS_GTREDATA: 1085 envdata = (envsys_temp_data_t *)data; 1086 if (envdata->sensor >= ENVSYS_NUMSENSORS) { 1087 envdata->validflags = 0; 1088 break; 1089 } 1090 envdata->warnflags = ENVSYS_WARN_OK; 1091 if (envdata->sensor == 0) { 1092 envdata->validflags |= ENVSYS_FVALID; 1093 req.cmdbuf[0] = TS102_OP_RD_CURRENT_TEMP; 1094 req.cmdlen = 1; 1095 req.rsplen = 2; 1096 req.p = p; 1097 tadpole_request(&req, 0); 1098 envdata->cur.data_us = /* 273160? */ 1099 (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000000/9+273150000); 1100 envdata->validflags |= ENVSYS_FCURVALID; 1101 req.cmdbuf[0] = TS102_OP_RD_MAX_TEMP; 1102 req.cmdlen = 1; 1103 req.rsplen = 2; 1104 req.p = p; 1105 tadpole_request(&req, 0); 1106 envdata->max.data_us = 1107 (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000000/9+273150000); 1108 envdata->validflags |= ENVSYS_FMAXVALID; 1109 req.cmdbuf[0] = TS102_OP_RD_MIN_TEMP; 1110 req.cmdlen = 1; 1111 req.rsplen = 2; 1112 req.p = p; 1113 tadpole_request(&req, 0); 1114 envdata->min.data_us = 1115 (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000000/9+273150000); 1116 envdata->validflags |= ENVSYS_FMINVALID; 1117 envdata->units = sc->sc_esensors[envdata->sensor].units; 1118 break; 1119 } else if (envdata->sensor == 1 || envdata->sensor == 2) { 1120 envdata->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID; 1121 envdata->units = sc->sc_esensors[envdata->sensor].units; 1122 if (envdata->sensor == 1) 1123 req.cmdbuf[0] = TS102_OP_RD_INT_BATT_VLT; 1124 else 1125 req.cmdbuf[0] = TS102_OP_RD_DC_IN_VLT; 1126 req.cmdlen = 1; 1127 req.rsplen = 2; 1128 req.p = p; 1129 tadpole_request(&req, 0); 1130 envdata->cur.data_s = (int32_t)req.rspbuf[0]*1000000/11; 1131 break; 1132 } 1133 break; 1134 1135 case ENVSYS_GTREINFO: 1136 envinfo = (envsys_temp_info_t *)data; 1137 if (envinfo->sensor >= ENVSYS_NUMSENSORS) { 1138 envinfo->validflags = 0; 1139 break; 1140 } 1141 envinfo->units = sc->sc_esensors[envinfo->sensor].units; 1142 memcpy(envinfo->desc, sc->sc_esensors[envinfo->sensor].desc, 1143 sizeof(sc->sc_esensors[envinfo->sensor].desc) > 1144 sizeof(envinfo->desc) ? sizeof(envinfo->desc) : 1145 sizeof(sc->sc_esensors[envinfo->sensor].desc)); 1146 if (envinfo->units == ENVSYS_STEMP) { 1147 envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID| 1148 ENVSYS_FMINVALID|ENVSYS_FMAXVALID; 1149 } else if (envinfo->units == ENVSYS_SVOLTS_DC) { 1150 envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID; 1151 } else 1152 envinfo->validflags = 0; 1153 break; 1154 1155 case ENVSYS_STREINFO: 1156 envinfo = (envsys_temp_info_t *)data; 1157 if (envinfo->sensor >= ENVSYS_NUMSENSORS) { 1158 envinfo->validflags = 0; 1159 break; 1160 } 1161 if (envinfo->units == sc->sc_esensors[envinfo->sensor].units) 1162 memcpy(sc->sc_esensors[envinfo->sensor].desc, 1163 envinfo->desc, 1164 sizeof(envinfo->desc) > sizeof(char)*32 ? 1165 sizeof(char)*32 : sizeof(envinfo->desc) ); 1166 if (envinfo->units == ENVSYS_STEMP) { 1167 envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID| 1168 ENVSYS_FMINVALID|ENVSYS_FMAXVALID; 1169 } else if (envinfo->units == ENVSYS_SVOLTS_DC) { 1170 envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID; 1171 } else 1172 envinfo->validflags = 0; 1173 break; 1174 1175 /* serial power mode (via auxiotwo) */ 1176 case TCTRL_SERIAL_PWR: 1177 pwrreq = (struct tctrl_pwr *)data; 1178 if (pwrreq->rw) 1179 pwrreq->state = auxiotwoserialgetapm(); 1180 else 1181 auxiotwoserialsetapm(pwrreq->state); 1182 break; 1183 1184 /* modem power mode (via auxio) */ 1185 case TCTRL_MODEM_PWR: 1186 return(EOPNOTSUPP); /* for now */ 1187 break; 1188 1189 1190 default: 1191 return (ENOTTY); 1192 } 1193 return (0); 1194 } 1195 1196 int 1197 tctrlpoll(dev, events, p) 1198 dev_t dev; 1199 int events; 1200 struct proc *p; 1201 { 1202 struct tctrl_softc *sc = tctrl_cd.cd_devs[TCTRL_STD_DEV]; 1203 int revents = 0; 1204 1205 if (events & (POLLIN | POLLRDNORM)) { 1206 if (sc->sc_event_count) 1207 revents |= events & (POLLIN | POLLRDNORM); 1208 else 1209 selrecord(p, &sc->sc_rsel); 1210 } 1211 1212 return (revents); 1213 } 1214 1215 static void 1216 filt_tctrlrdetach(struct knote *kn) 1217 { 1218 struct tctrl_softc *sc = kn->kn_hook; 1219 int s; 1220 1221 s = splts102(); 1222 SLIST_REMOVE(&sc->sc_rsel.sel_klist, kn, knote, kn_selnext); 1223 splx(s); 1224 } 1225 1226 static int 1227 filt_tctrlread(struct knote *kn, long hint) 1228 { 1229 struct tctrl_softc *sc = kn->kn_hook; 1230 1231 kn->kn_data = sc->sc_event_count; 1232 return (kn->kn_data > 0); 1233 } 1234 1235 static const struct filterops tctrlread_filtops = 1236 { 1, NULL, filt_tctrlrdetach, filt_tctrlread }; 1237 1238 int 1239 tctrlkqfilter(dev_t dev, struct knote *kn) 1240 { 1241 struct tctrl_softc *sc = tctrl_cd.cd_devs[TCTRL_STD_DEV]; 1242 struct klist *klist; 1243 int s; 1244 1245 switch (kn->kn_filter) { 1246 case EVFILT_READ: 1247 klist = &sc->sc_rsel.sel_klist; 1248 kn->kn_fop = &tctrlread_filtops; 1249 break; 1250 1251 default: 1252 return (1); 1253 } 1254 1255 kn->kn_hook = sc; 1256 1257 s = splts102(); 1258 SLIST_INSERT_HEAD(klist, kn, kn_selnext); 1259 splx(s); 1260 1261 return (0); 1262 } 1263 1264 /* DO NOT SET THIS OPTION */ 1265 #ifdef TADPOLE_BLINK 1266 void 1267 cpu_disk_unbusy(busy) 1268 int busy; 1269 { 1270 static struct timeval tctrl_ds_timestamp; 1271 struct timeval dv_time, diff_time; 1272 struct tctrl_softc *sc; 1273 1274 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV]; 1275 1276 /* quickly bail */ 1277 if (!(sc->sc_lcdstate & TS102_LCD_DISK_ACTIVE) || busy > 0) 1278 return; 1279 1280 /* we aren't terribly concerned with precision here */ 1281 dv_time = mono_time; 1282 timersub(&dv_time, &tctrl_ds_timestamp, &diff_time); 1283 1284 if (diff_time.tv_sec > 0) { 1285 tctrl_set_lcd(0, TS102_LCD_DISK_ACTIVE); 1286 tctrl_ds_timestamp = mono_time; 1287 } 1288 } 1289 #endif 1290