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