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