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