tctrl.c revision 1.19
1/* $NetBSD: tctrl.c,v 1.19 2002/10/14 02:08:39 takemura 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 67extern struct cfdriver tctrl_cd; 68 69dev_type_open(tctrlopen); 70dev_type_close(tctrlclose); 71dev_type_ioctl(tctrlioctl); 72dev_type_poll(tctrlpoll); 73 74const struct cdevsw tctrl_cdevsw = { 75 tctrlopen, tctrlclose, noread, nowrite, tctrlioctl, 76 nostop, notty, tctrlpoll, nommap, 77}; 78 79static 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 93struct 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 131static struct callout tctrl_event_ch = CALLOUT_INITIALIZER; 132 133static int tctrl_match __P((struct device *parent, struct cfdata *cf, 134 void *aux)); 135static void tctrl_attach __P((struct device *parent, struct device *self, 136 void *aux)); 137static void tctrl_write __P((struct tctrl_softc *sc, bus_size_t off, 138 u_int8_t v)); 139static u_int8_t tctrl_read __P((struct tctrl_softc *sc, bus_size_t off)); 140static void tctrl_write_data __P((struct tctrl_softc *sc, u_int8_t v)); 141static u_int8_t tctrl_read_data __P((struct tctrl_softc *sc)); 142static int tctrl_intr __P((void *arg)); 143static void tctrl_setup_bitport __P((void)); 144static void tctrl_setup_bitport_nop __P((void)); 145static void tctrl_read_ext_status __P((void)); 146static void tctrl_read_event_status __P((void *arg)); 147static int tctrl_apm_record_event __P((struct tctrl_softc *sc, 148 u_int event_type)); 149static void tctrl_init_lcd __P((void)); 150 151CFATTACH_DECL(tctrl, sizeof(struct tctrl_softc), 152 tctrl_match, tctrl_attach, NULL, NULL); 153 154extern struct cfdriver tctrl_cd; 155/* XXX wtf is this? see i386/apm.c */ 156int tctrl_apm_evindex; 157 158static int 159tctrl_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 178static void 179tctrl_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 270static int 271tctrl_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 400static void 401tctrl_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 420static void 421tctrl_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 459static void 460tctrl_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 584void 585tctrl_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 631static void 632tctrl_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 */ 659static int 660tctrl_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 680static void 681tctrl_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 734void 735tadpole_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 797void 798tadpole_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 809void 810tadpole_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 846static void 847tctrl_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 860static u_int8_t 861tctrl_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 877static u_int8_t 878tctrl_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 887static void 888tctrl_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 898int 899tctrlopen(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 932int 933tctrlclose(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 955int 956tctrlioctl(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 OAPM_IOC_GETPOWER: 991 case APM_IOC_GETPOWER: 992 powerp = (struct apm_power_info *)data; 993 req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_RATE; 994 req.cmdlen = 1; 995 req.rsplen = 2; 996 req.p = p; 997 tadpole_request(&req, 0); 998 if (req.rspbuf[0] > 0x00) 999 powerp->battery_state = APM_BATT_CHARGING; 1000 req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_LEVEL; 1001 req.cmdlen = 1; 1002 req.rsplen = 3; 1003 req.p = p; 1004 tadpole_request(&req, 0); 1005 c = req.rspbuf[0]; 1006 powerp->battery_life = c; 1007 if (c > 0x70) /* the tadpole sometimes dips below zero, and */ 1008 c = 0; /* into the 255 range. */ 1009 powerp->minutes_left = (45 * c) / 100; /* XXX based on 45 min */ 1010 if (powerp->battery_state != APM_BATT_CHARGING) { 1011 if (c < 0x20) 1012 powerp->battery_state = APM_BATT_CRITICAL; 1013 else if (c < 0x40) 1014 powerp->battery_state = APM_BATT_LOW; 1015 else if (c < 0x66) 1016 powerp->battery_state = APM_BATT_HIGH; 1017 else 1018 powerp->battery_state = APM_BATT_UNKNOWN; 1019 } 1020 req.cmdbuf[0] = TS102_OP_RD_EXT_STATUS; 1021 req.cmdlen = 1; 1022 req.rsplen = 3; 1023 req.p = p; 1024 tadpole_request(&req, 0); 1025 a = req.rspbuf[0] * 256 + req.rspbuf[1]; 1026 if (a & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) 1027 powerp->ac_state = APM_AC_ON; 1028 else 1029 powerp->ac_state = APM_AC_OFF; 1030 break; 1031 1032 case APM_IOC_NEXTEVENT: 1033 if (!sc->sc_event_count) 1034 return EAGAIN; 1035 1036 evp = (struct apm_event_info *)data; 1037 i = sc->sc_event_ptr + APM_NEVENTS - sc->sc_event_count; 1038 i %= APM_NEVENTS; 1039 *evp = sc->sc_event_list[i]; 1040 sc->sc_event_count--; 1041 return(0); 1042 1043 /* this ioctl assumes the caller knows exactly what he is doing */ 1044 case TCTRL_CMD_REQ: 1045 reqn = (struct tctrl_req *)data; 1046 if ((i = suser(p->p_ucred, &p->p_acflag)) != 0 && 1047 (reqn->cmdbuf[0] == TS102_OP_CTL_BITPORT || 1048 (reqn->cmdbuf[0] >= TS102_OP_CTL_WATCHDOG && 1049 reqn->cmdbuf[0] <= TS102_OP_CTL_SECURITY_KEY) || 1050 reqn->cmdbuf[0] == TS102_OP_CTL_TIMEZONE || 1051 reqn->cmdbuf[0] == TS102_OP_CTL_DIAGNOSTIC_MODE || 1052 reqn->cmdbuf[0] == TS102_OP_CMD_SOFTWARE_RESET || 1053 (reqn->cmdbuf[0] >= TS102_OP_CMD_SET_RTC && 1054 reqn->cmdbuf[0] < TS102_OP_RD_INT_CHARGE_LEVEL) || 1055 reqn->cmdbuf[0] > TS102_OP_RD_EXT_CHARGE_LEVEL)) 1056 return(i); 1057 reqn->p = p; 1058 tadpole_request(reqn, 0); 1059 break; 1060 1061 case ENVSYS_VERSION: 1062 *(int32_t *)data = 1000; 1063 break; 1064 1065 case ENVSYS_GRANGE: 1066 envrange = (envsys_range_t *)data; 1067 i = 0; 1068 envrange->high = envrange->low = 0; 1069 for (j=0; j < ENVSYS_NUMSENSORS; j++) { 1070 if (!i && envrange->units == sc->sc_esensors[j].units) { 1071 envrange->low = j; 1072 i++; 1073 } 1074 if (i && envrange->units == sc->sc_esensors[j].units) 1075 envrange->high = j; 1076 } 1077 if (!i) { 1078 envrange->high = 0; 1079 envrange->low = 1; 1080 } 1081 break; 1082 1083 case ENVSYS_GTREDATA: 1084 envdata = (envsys_temp_data_t *)data; 1085 if (envdata->sensor >= ENVSYS_NUMSENSORS) { 1086 envdata->validflags = 0; 1087 break; 1088 } 1089 envdata->warnflags = ENVSYS_WARN_OK; 1090 if (envdata->sensor == 0) { 1091 envdata->validflags |= ENVSYS_FVALID; 1092 req.cmdbuf[0] = TS102_OP_RD_CURRENT_TEMP; 1093 req.cmdlen = 1; 1094 req.rsplen = 2; 1095 req.p = p; 1096 tadpole_request(&req, 0); 1097 envdata->cur.data_us = /* 273160? */ 1098 (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000000/9+273150000); 1099 envdata->validflags |= ENVSYS_FCURVALID; 1100 req.cmdbuf[0] = TS102_OP_RD_MAX_TEMP; 1101 req.cmdlen = 1; 1102 req.rsplen = 2; 1103 req.p = p; 1104 tadpole_request(&req, 0); 1105 envdata->max.data_us = 1106 (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000000/9+273150000); 1107 envdata->validflags |= ENVSYS_FMAXVALID; 1108 req.cmdbuf[0] = TS102_OP_RD_MIN_TEMP; 1109 req.cmdlen = 1; 1110 req.rsplen = 2; 1111 req.p = p; 1112 tadpole_request(&req, 0); 1113 envdata->min.data_us = 1114 (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000000/9+273150000); 1115 envdata->validflags |= ENVSYS_FMINVALID; 1116 envdata->units = sc->sc_esensors[envdata->sensor].units; 1117 break; 1118 } else if (envdata->sensor == 1 || envdata->sensor == 2) { 1119 envdata->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID; 1120 envdata->units = sc->sc_esensors[envdata->sensor].units; 1121 if (envdata->sensor == 1) 1122 req.cmdbuf[0] = TS102_OP_RD_INT_BATT_VLT; 1123 else 1124 req.cmdbuf[0] = TS102_OP_RD_DC_IN_VLT; 1125 req.cmdlen = 1; 1126 req.rsplen = 2; 1127 req.p = p; 1128 tadpole_request(&req, 0); 1129 envdata->cur.data_s = (int32_t)req.rspbuf[0]*1000000/11; 1130 break; 1131 } 1132 break; 1133 1134 case ENVSYS_GTREINFO: 1135 envinfo = (envsys_temp_info_t *)data; 1136 if (envinfo->sensor >= ENVSYS_NUMSENSORS) { 1137 envinfo->validflags = 0; 1138 break; 1139 } 1140 envinfo->units = sc->sc_esensors[envinfo->sensor].units; 1141 memcpy(envinfo->desc, sc->sc_esensors[envinfo->sensor].desc, 1142 sizeof(sc->sc_esensors[envinfo->sensor].desc) > 1143 sizeof(envinfo->desc) ? sizeof(envinfo->desc) : 1144 sizeof(sc->sc_esensors[envinfo->sensor].desc)); 1145 if (envinfo->units == ENVSYS_STEMP) { 1146 envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID| 1147 ENVSYS_FMINVALID|ENVSYS_FMAXVALID; 1148 } else if (envinfo->units == ENVSYS_SVOLTS_DC) { 1149 envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID; 1150 } else 1151 envinfo->validflags = 0; 1152 break; 1153 1154 case ENVSYS_STREINFO: 1155 envinfo = (envsys_temp_info_t *)data; 1156 if (envinfo->sensor >= ENVSYS_NUMSENSORS) { 1157 envinfo->validflags = 0; 1158 break; 1159 } 1160 if (envinfo->units == sc->sc_esensors[envinfo->sensor].units) 1161 memcpy(sc->sc_esensors[envinfo->sensor].desc, 1162 envinfo->desc, 1163 sizeof(envinfo->desc) > sizeof(char)*32 ? 1164 sizeof(char)*32 : sizeof(envinfo->desc) ); 1165 if (envinfo->units == ENVSYS_STEMP) { 1166 envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID| 1167 ENVSYS_FMINVALID|ENVSYS_FMAXVALID; 1168 } else if (envinfo->units == ENVSYS_SVOLTS_DC) { 1169 envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID; 1170 } else 1171 envinfo->validflags = 0; 1172 break; 1173 1174 /* serial power mode (via auxiotwo) */ 1175 case TCTRL_SERIAL_PWR: 1176 pwrreq = (struct tctrl_pwr *)data; 1177 if (pwrreq->rw) 1178 pwrreq->state = auxiotwoserialgetapm(); 1179 else 1180 auxiotwoserialsetapm(pwrreq->state); 1181 break; 1182 1183 /* modem power mode (via auxio) */ 1184 case TCTRL_MODEM_PWR: 1185 return(EOPNOTSUPP); /* for now */ 1186 break; 1187 1188 1189 default: 1190 return (ENOTTY); 1191 } 1192 return (0); 1193} 1194 1195int 1196tctrlpoll(dev, events, p) 1197 dev_t dev; 1198 int events; 1199 struct proc *p; 1200{ 1201 struct tctrl_softc *sc = tctrl_cd.cd_devs[TCTRL_STD_DEV]; 1202 int revents = 0; 1203 1204 if (events & (POLLIN | POLLRDNORM)) { 1205 if (sc->sc_event_count) 1206 revents |= events & (POLLIN | POLLRDNORM); 1207 else 1208 selrecord(p, &sc->sc_rsel); 1209 } 1210 1211 return (revents); 1212} 1213/* DO NOT SET THIS OPTION */ 1214#ifdef TADPOLE_BLINK 1215void 1216cpu_disk_unbusy(busy) 1217 int busy; 1218{ 1219 static struct timeval tctrl_ds_timestamp; 1220 struct timeval dv_time, diff_time; 1221 struct tctrl_softc *sc; 1222 1223 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV]; 1224 1225 /* quickly bail */ 1226 if (!(sc->sc_lcdstate & TS102_LCD_DISK_ACTIVE) || busy > 0) 1227 return; 1228 1229 /* we aren't terribly concerned with precision here */ 1230 dv_time = mono_time; 1231 timersub(&dv_time, &tctrl_ds_timestamp, &diff_time); 1232 1233 if (diff_time.tv_sec > 0) { 1234 tctrl_set_lcd(0, TS102_LCD_DISK_ACTIVE); 1235 tctrl_ds_timestamp = mono_time; 1236 } 1237} 1238#endif 1239