tctrl.c revision 1.16
1/* $NetBSD: tctrl.c,v 1.16 2002/09/27 20:35:53 thorpej Exp $ */ 2 3/*- 4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Matt Thomas. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39#include <sys/param.h> 40#include <sys/systm.h> 41#include <sys/callout.h> 42#include <sys/ioctl.h> 43#include <sys/select.h> 44#include <sys/tty.h> 45#include <sys/proc.h> 46#include <sys/user.h> 47#include <sys/conf.h> 48#include <sys/file.h> 49#include <sys/uio.h> 50#include <sys/kernel.h> 51#include <sys/syslog.h> 52#include <sys/types.h> 53#include <sys/device.h> 54#include <sys/envsys.h> 55#include <sys/poll.h> 56 57#include <machine/apmvar.h> 58#include <machine/autoconf.h> 59#include <machine/bus.h> 60#include <machine/intr.h> 61#include <machine/tctrl.h> 62 63#include <sparc/dev/ts102reg.h> 64#include <sparc/dev/tctrlvar.h> 65#include <sparc/sparc/auxiotwo.h> 66 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 151const struct cfattach tctrl_ca = { 152 sizeof(struct tctrl_softc), tctrl_match, tctrl_attach 153}; 154 155extern struct cfdriver tctrl_cd; 156/* XXX wtf is this? see i386/apm.c */ 157int tctrl_apm_evindex; 158 159static int 160tctrl_match(parent, cf, aux) 161 struct device *parent; 162 struct cfdata *cf; 163 void *aux; 164{ 165 union obio_attach_args *uoba = aux; 166 struct sbus_attach_args *sa = &uoba->uoba_sbus; 167 168 if (uoba->uoba_isobio4 != 0) { 169 return (0); 170 } 171 172 /* Tadpole 3GX/3GS uses "uctrl" for the Tadpole Microcontroller 173 * (who's interface is off the TS102 PCMCIA controller but there 174 * exists a OpenProm for microcontroller interface). 175 */ 176 return strcmp("uctrl", sa->sa_name) == 0; 177} 178 179static void 180tctrl_attach(parent, self, aux) 181 struct device *parent; 182 struct device *self; 183 void *aux; 184{ 185 struct tctrl_softc *sc = (void *)self; 186 union obio_attach_args *uoba = aux; 187 struct sbus_attach_args *sa = &uoba->uoba_sbus; 188 unsigned int i, v; 189#if 0 190 unsigned int ack, msb, lsb; 191#endif 192 193 /* We're living on a sbus slot that looks like an obio that 194 * looks like an sbus slot. 195 */ 196 sc->sc_memt = sa->sa_bustag; 197 if (sbus_bus_map(sc->sc_memt, 198 sa->sa_slot, 199 sa->sa_offset - TS102_REG_UCTRL_INT, 200 sa->sa_size, 201 BUS_SPACE_MAP_LINEAR, &sc->sc_memh) != 0) { 202 printf(": can't map registers\n"); 203 return; 204 } 205 206 printf("\n"); 207 208 sc->sc_tft_on = 1; 209 210 /* clear any pending data. 211 */ 212 for (i = 0; i < 10000; i++) { 213 if ((TS102_UCTRL_STS_RXNE_STA & 214 tctrl_read(sc, TS102_REG_UCTRL_STS)) == 0) { 215 break; 216 } 217 v = tctrl_read(sc, TS102_REG_UCTRL_DATA); 218 tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA); 219 } 220 221 if (sa->sa_nintr != 0) { 222 (void)bus_intr_establish(sc->sc_memt, sa->sa_pri, IPL_NONE, 223 0, tctrl_intr, sc); 224 evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, NULL, 225 sc->sc_dev.dv_xname, "intr"); 226 } 227 228 /* See what the external status is 229 */ 230 231 tctrl_read_ext_status(); 232 if (sc->sc_ext_status != 0) { 233 const char *sep; 234 235 printf("%s: ", sc->sc_dev.dv_xname); 236 v = sc->sc_ext_status; 237 for (i = 0, sep = ""; v != 0; i++, v >>= 1) { 238 if (v & 1) { 239 printf("%s%s", sep, tctrl_ext_statuses[i]); 240 sep = ", "; 241 } 242 } 243 printf("\n"); 244 } 245 246 /* Get a current of the control bitport; 247 */ 248 tctrl_setup_bitport_nop(); 249 tctrl_write(sc, TS102_REG_UCTRL_INT, 250 TS102_UCTRL_INT_RXNE_REQ|TS102_UCTRL_INT_RXNE_MSK); 251 252 sc->sc_wantdata = 0; 253 sc->sc_event_count = 0; 254 255 /* prime the sensor data */ 256 sprintf(sc->sc_esensors[0].desc, "%s", "Internal Unit Temperature"); 257 sc->sc_esensors[0].units = ENVSYS_STEMP; 258 sprintf(sc->sc_esensors[1].desc, "%s", "Internal Battery Voltage"); 259 sc->sc_esensors[1].units = ENVSYS_SVOLTS_DC; 260 sprintf(sc->sc_esensors[2].desc, "%s", "DC-In Voltage"); 261 sc->sc_esensors[2].units = ENVSYS_SVOLTS_DC; 262 263 /* initialize the LCD */ 264 tctrl_init_lcd(); 265 266 /* initialize sc_lcdstate */ 267 sc->sc_lcdstate = 0; 268 tctrl_set_lcd(2, 0); 269} 270 271static int 272tctrl_intr(arg) 273 void *arg; 274{ 275 struct tctrl_softc *sc = arg; 276 unsigned int v, d; 277 int progress = 0; 278 279 again: 280 /* find out the cause(s) of the interrupt */ 281 v = tctrl_read(sc, TS102_REG_UCTRL_STS) & TS102_UCTRL_STS_MASK; 282 283 /* clear the cause(s) of the interrupt */ 284 tctrl_write(sc, TS102_REG_UCTRL_STS, v); 285 286 v &= ~(TS102_UCTRL_STS_RXO_STA|TS102_UCTRL_STS_TXE_STA); 287 if (sc->sc_cmdoff >= sc->sc_cmdlen) { 288 v &= ~TS102_UCTRL_STS_TXNF_STA; 289 if (tctrl_read(sc, TS102_REG_UCTRL_INT) & TS102_UCTRL_INT_TXNF_REQ) { 290 tctrl_write(sc, TS102_REG_UCTRL_INT, 0); 291 progress = 1; 292 } 293 } 294 if ((v == 0) && ((sc->sc_flags & TCTRL_SEND_REQUEST) == 0 || 295 sc->sc_state != TCTRL_IDLE)) { 296 wakeup(sc); 297 return progress; 298 } 299 300 progress = 1; 301 if (v & TS102_UCTRL_STS_RXNE_STA) { 302 d = tctrl_read_data(sc); 303 switch (sc->sc_state) { 304 case TCTRL_IDLE: 305 if (d == 0xfa) { 306 /* external event */ 307 callout_reset(&tctrl_event_ch, 1, 308 tctrl_read_event_status, NULL); 309 } else { 310 printf("%s: (op=0x%02x): unexpected data (0x%02x)\n", 311 sc->sc_dev.dv_xname, sc->sc_op, d); 312 } 313 goto again; 314 case TCTRL_ACK: 315 if (d != 0xfe) { 316 printf("%s: (op=0x%02x): unexpected ack value (0x%02x)\n", 317 sc->sc_dev.dv_xname, sc->sc_op, d); 318 } 319#ifdef TCTRLDEBUG 320 printf(" ack=0x%02x", d); 321#endif 322 sc->sc_rsplen--; 323 sc->sc_rspoff = 0; 324 sc->sc_state = sc->sc_rsplen ? TCTRL_DATA : TCTRL_IDLE; 325 sc->sc_wantdata = sc->sc_rsplen ? 1 : 0; 326#ifdef TCTRLDEBUG 327 if (sc->sc_rsplen > 0) { 328 printf(" [data(%u)]", sc->sc_rsplen); 329 } else { 330 printf(" [idle]\n"); 331 } 332#endif 333 goto again; 334 case TCTRL_DATA: 335 sc->sc_rspbuf[sc->sc_rspoff++] = d; 336#ifdef TCTRLDEBUG 337 printf(" [%d]=0x%02x", sc->sc_rspoff-1, d); 338#endif 339 if (sc->sc_rspoff == sc->sc_rsplen) { 340#ifdef TCTRLDEBUG 341 printf(" [idle]\n"); 342#endif 343 sc->sc_state = TCTRL_IDLE; 344 sc->sc_wantdata = 0; 345 } 346 goto again; 347 default: 348 printf("%s: (op=0x%02x): unexpected data (0x%02x) in state %d\n", 349 sc->sc_dev.dv_xname, sc->sc_op, d, sc->sc_state); 350 goto again; 351 } 352 } 353 if ((sc->sc_state == TCTRL_IDLE && sc->sc_wantdata == 0) || 354 sc->sc_flags & TCTRL_SEND_REQUEST) { 355 if (sc->sc_flags & TCTRL_SEND_REQUEST) { 356 sc->sc_flags &= ~TCTRL_SEND_REQUEST; 357 sc->sc_wantdata = 1; 358 } 359 if (sc->sc_cmdlen > 0) { 360 tctrl_write(sc, TS102_REG_UCTRL_INT, 361 tctrl_read(sc, TS102_REG_UCTRL_INT) 362 |TS102_UCTRL_INT_TXNF_MSK 363 |TS102_UCTRL_INT_TXNF_REQ); 364 v = tctrl_read(sc, TS102_REG_UCTRL_STS); 365 } 366 } 367 if ((sc->sc_cmdoff < sc->sc_cmdlen) && (v & TS102_UCTRL_STS_TXNF_STA)) { 368 tctrl_write_data(sc, sc->sc_cmdbuf[sc->sc_cmdoff++]); 369#ifdef TCTRLDEBUG 370 if (sc->sc_cmdoff == 1) { 371 printf("%s: op=0x%02x(l=%u)", sc->sc_dev.dv_xname, 372 sc->sc_cmdbuf[0], sc->sc_rsplen); 373 } else { 374 printf(" [%d]=0x%02x", sc->sc_cmdoff-1, 375 sc->sc_cmdbuf[sc->sc_cmdoff-1]); 376 } 377#endif 378 if (sc->sc_cmdoff == sc->sc_cmdlen) { 379 sc->sc_state = sc->sc_rsplen ? TCTRL_ACK : TCTRL_IDLE; 380#ifdef TCTRLDEBUG 381 printf(" %s", sc->sc_rsplen ? "[ack]" : "[idle]\n"); 382#endif 383 if (sc->sc_cmdoff == 1) { 384 sc->sc_op = sc->sc_cmdbuf[0]; 385 } 386 tctrl_write(sc, TS102_REG_UCTRL_INT, 387 tctrl_read(sc, TS102_REG_UCTRL_INT) 388 & (~TS102_UCTRL_INT_TXNF_MSK 389 |TS102_UCTRL_INT_TXNF_REQ)); 390 } else if (sc->sc_state == TCTRL_IDLE) { 391 sc->sc_op = sc->sc_cmdbuf[0]; 392 sc->sc_state = TCTRL_ARGS; 393#ifdef TCTRLDEBUG 394 printf(" [args]"); 395#endif 396 } 397 } 398 goto again; 399} 400 401static void 402tctrl_setup_bitport_nop(void) 403{ 404 struct tctrl_softc *sc; 405 struct tctrl_req req; 406 int s; 407 408 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV]; 409 req.cmdbuf[0] = TS102_OP_CTL_BITPORT; 410 req.cmdbuf[1] = 0xff; 411 req.cmdbuf[2] = 0; 412 req.cmdlen = 3; 413 req.rsplen = 2; 414 req.p = NULL; 415 tadpole_request(&req, 1); 416 s = splts102(); 417 sc->sc_bitport = (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2]; 418 splx(s); 419} 420 421static void 422tctrl_setup_bitport(void) 423{ 424 struct tctrl_softc *sc; 425 struct tctrl_req req; 426 int s; 427 428 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV]; 429 s = splts102(); 430 if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) 431 || (!sc->sc_tft_on)) { 432 req.cmdbuf[2] = TS102_BITPORT_TFTPWR; 433 } else { 434 req.cmdbuf[2] = 0; 435 } 436 req.cmdbuf[0] = TS102_OP_CTL_BITPORT; 437 req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR; 438 req.cmdlen = 3; 439 req.rsplen = 2; 440 req.p = NULL; 441 tadpole_request(&req, 1); 442 s = splts102(); 443 sc->sc_bitport = (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2]; 444 splx(s); 445} 446 447/* 448 * The tadpole microcontroller is not preprogrammed with icon 449 * representations. The machine boots with the DC-IN light as 450 * a blank (all 0x00) and the other lights, as 4 rows of horizontal 451 * bars. The below code initializes the icons in the system to 452 * sane values. Some of these icons could be used for any purpose 453 * desired, namely the pcmcia, LAN and WAN lights. For the disk spinner, 454 * only the backslash is unprogrammed. (sigh) 455 * 456 * programming the icons is simple. It is a 5x8 matrix, which each row a 457 * bitfield in the order 0x10 0x08 0x04 0x02 0x01. 458 */ 459 460static void 461tctrl_init_lcd(void) 462{ 463 struct tctrl_req req; 464 465 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR; 466 req.cmdlen = 11; 467 req.rsplen = 1; 468 req.cmdbuf[1] = 0x08; /*len*/ 469 req.cmdbuf[2] = TS102_BLK_OFF_DEF_DC_GOOD; 470 req.cmdbuf[3] = 0x00; /* ..... */ 471 req.cmdbuf[4] = 0x00; /* ..... */ 472 req.cmdbuf[5] = 0x1f; /* XXXXX */ 473 req.cmdbuf[6] = 0x00; /* ..... */ 474 req.cmdbuf[7] = 0x15; /* X.X.X */ 475 req.cmdbuf[8] = 0x00; /* ..... */ 476 req.cmdbuf[9] = 0x00; /* ..... */ 477 req.cmdbuf[10] = 0x00; /* ..... */ 478 req.p = NULL; 479 tadpole_request(&req, 1); 480 481 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR; 482 req.cmdlen = 11; 483 req.rsplen = 1; 484 req.cmdbuf[1] = 0x08; /*len*/ 485 req.cmdbuf[2] = TS102_BLK_OFF_DEF_BACKSLASH; 486 req.cmdbuf[3] = 0x00; /* ..... */ 487 req.cmdbuf[4] = 0x10; /* X.... */ 488 req.cmdbuf[5] = 0x08; /* .X... */ 489 req.cmdbuf[6] = 0x04; /* ..X.. */ 490 req.cmdbuf[7] = 0x02; /* ...X. */ 491 req.cmdbuf[8] = 0x01; /* ....X */ 492 req.cmdbuf[9] = 0x00; /* ..... */ 493 req.cmdbuf[10] = 0x00; /* ..... */ 494 req.p = NULL; 495 tadpole_request(&req, 1); 496 497 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR; 498 req.cmdlen = 11; 499 req.rsplen = 1; 500 req.cmdbuf[1] = 0x08; /*len*/ 501 req.cmdbuf[2] = TS102_BLK_OFF_DEF_WAN1; 502 req.cmdbuf[3] = 0x0c; /* .XXX. */ 503 req.cmdbuf[4] = 0x16; /* X.XX. */ 504 req.cmdbuf[5] = 0x10; /* X.... */ 505 req.cmdbuf[6] = 0x15; /* X.X.X */ 506 req.cmdbuf[7] = 0x10; /* X.... */ 507 req.cmdbuf[8] = 0x16; /* X.XX. */ 508 req.cmdbuf[9] = 0x0c; /* .XXX. */ 509 req.cmdbuf[10] = 0x00; /* ..... */ 510 req.p = NULL; 511 tadpole_request(&req, 1); 512 513 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR; 514 req.cmdlen = 11; 515 req.rsplen = 1; 516 req.cmdbuf[1] = 0x08; /*len*/ 517 req.cmdbuf[2] = TS102_BLK_OFF_DEF_WAN2; 518 req.cmdbuf[3] = 0x0c; /* .XXX. */ 519 req.cmdbuf[4] = 0x0d; /* .XX.X */ 520 req.cmdbuf[5] = 0x01; /* ....X */ 521 req.cmdbuf[6] = 0x15; /* X.X.X */ 522 req.cmdbuf[7] = 0x01; /* ....X */ 523 req.cmdbuf[8] = 0x0d; /* .XX.X */ 524 req.cmdbuf[9] = 0x0c; /* .XXX. */ 525 req.cmdbuf[10] = 0x00; /* ..... */ 526 req.p = NULL; 527 tadpole_request(&req, 1); 528 529 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR; 530 req.cmdlen = 11; 531 req.rsplen = 1; 532 req.cmdbuf[1] = 0x08; /*len*/ 533 req.cmdbuf[2] = TS102_BLK_OFF_DEF_LAN1; 534 req.cmdbuf[3] = 0x00; /* ..... */ 535 req.cmdbuf[4] = 0x04; /* ..X.. */ 536 req.cmdbuf[5] = 0x08; /* .X... */ 537 req.cmdbuf[6] = 0x13; /* X..XX */ 538 req.cmdbuf[7] = 0x08; /* .X... */ 539 req.cmdbuf[8] = 0x04; /* ..X.. */ 540 req.cmdbuf[9] = 0x00; /* ..... */ 541 req.cmdbuf[10] = 0x00; /* ..... */ 542 req.p = NULL; 543 tadpole_request(&req, 1); 544 545 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR; 546 req.cmdlen = 11; 547 req.rsplen = 1; 548 req.cmdbuf[1] = 0x08; /*len*/ 549 req.cmdbuf[2] = TS102_BLK_OFF_DEF_LAN2; 550 req.cmdbuf[3] = 0x00; /* ..... */ 551 req.cmdbuf[4] = 0x04; /* ..X.. */ 552 req.cmdbuf[5] = 0x02; /* ...X. */ 553 req.cmdbuf[6] = 0x19; /* XX..X */ 554 req.cmdbuf[7] = 0x02; /* ...X. */ 555 req.cmdbuf[8] = 0x04; /* ..X.. */ 556 req.cmdbuf[9] = 0x00; /* ..... */ 557 req.cmdbuf[10] = 0x00; /* ..... */ 558 req.p = NULL; 559 tadpole_request(&req, 1); 560 561 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR; 562 req.cmdlen = 11; 563 req.rsplen = 1; 564 req.cmdbuf[1] = 0x08; /*len*/ 565 req.cmdbuf[2] = TS102_BLK_OFF_DEF_PCMCIA; 566 req.cmdbuf[3] = 0x00; /* ..... */ 567 req.cmdbuf[4] = 0x0c; /* .XXX. */ 568 req.cmdbuf[5] = 0x1f; /* XXXXX */ 569 req.cmdbuf[6] = 0x1f; /* XXXXX */ 570 req.cmdbuf[7] = 0x1f; /* XXXXX */ 571 req.cmdbuf[8] = 0x1f; /* XXXXX */ 572 req.cmdbuf[9] = 0x00; /* ..... */ 573 req.cmdbuf[10] = 0x00; /* ..... */ 574 req.p = NULL; 575 tadpole_request(&req, 1); 576} 577 578 579 580/* 581 * set the blinken-lights on the lcd. what: 582 * what = 0 off, what = 1 on, what = 2 toggle 583 */ 584 585void 586tctrl_set_lcd(what, which) 587 int what; 588 unsigned short which; 589{ 590 struct tctrl_softc *sc; 591 struct tctrl_req req; 592 int s; 593 594 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV]; 595 s = splts102(); 596 597 /* provide a quick exit to save cpu time */ 598 if ((what == 1 && sc->sc_lcdstate & which) || 599 (what == 0 && !(sc->sc_lcdstate & which))) { 600 splx(s); 601 return; 602 } 603 /* 604 * the mask setup on this particular command is *very* bizzare 605 * and totally undocumented. 606 */ 607 if ((what == 1) || (what == 2 && !(sc->sc_lcdstate & which))) { 608 req.cmdbuf[2] = (u_int8_t)(which&0xff); 609 req.cmdbuf[3] = (u_int8_t)(which>>8); 610 } else { 611 req.cmdbuf[2] = 0; 612 req.cmdbuf[3] = 0; 613 } 614 req.cmdbuf[0] = TS102_OP_CTL_LCD; 615 req.cmdbuf[4] = (u_int8_t)(~which>>8); 616 req.cmdbuf[1] = (u_int8_t)(~which&0xff); 617 618 /* XXX this thing is weird.... */ 619 req.cmdlen = 3; 620 req.rsplen = 2; 621#if 0 622 req.cmdlen = 5; 623 req.rsplen = 4; 624#endif 625 req.p = NULL; 626 tadpole_request(&req, 1); 627 s = splts102(); 628 sc->sc_lcdstate = (unsigned short)req.rspbuf[0]; 629 splx(s); 630} 631 632static void 633tctrl_read_ext_status(void) 634{ 635 struct tctrl_softc *sc; 636 struct tctrl_req req; 637 int s; 638 639 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV]; 640 req.cmdbuf[0] = TS102_OP_RD_EXT_STATUS; 641 req.cmdlen = 1; 642 req.rsplen = 3; 643 req.p = NULL; 644#ifdef TCTRLDEBUG 645 printf("pre read: sc->sc_ext_status = 0x%x\n", sc->sc_ext_status); 646#endif 647 tadpole_request(&req, 1); 648 s = splts102(); 649 sc->sc_ext_status = req.rspbuf[0] * 256 + req.rspbuf[1]; 650 splx(s); 651#ifdef TCTRLDEBUG 652 printf("post read: sc->sc_ext_status = 0x%x\n", sc->sc_ext_status); 653#endif 654} 655 656/* 657 * return 0 if the user will notice and handle the event, 658 * return 1 if the kernel driver should do so. 659 */ 660static int 661tctrl_apm_record_event(sc, event_type) 662 struct tctrl_softc *sc; 663 u_int event_type; 664{ 665 struct apm_event_info *evp; 666 667 if ((sc->sc_flags & TCTRL_APM_CTLOPEN) && 668 (sc->sc_event_count < APM_NEVENTS)) { 669 evp = &sc->sc_event_list[sc->sc_event_ptr]; 670 sc->sc_event_count++; 671 sc->sc_event_ptr++; 672 sc->sc_event_ptr %= APM_NEVENTS; 673 evp->type = event_type; 674 evp->index = ++tctrl_apm_evindex; 675 selwakeup(&sc->sc_rsel); 676 return(sc->sc_flags & TCTRL_APM_CTLOPEN) ? 0 : 1; 677 } 678 return(1); 679} 680 681static void 682tctrl_read_event_status(arg) 683 void *arg; 684{ 685 struct tctrl_softc *sc; 686 struct tctrl_req req; 687 int s; 688 unsigned int v; 689 690 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV]; 691 req.cmdbuf[0] = TS102_OP_RD_EVENT_STATUS; 692 req.cmdlen = 1; 693 req.rsplen = 3; 694 req.p = NULL; 695 tadpole_request(&req, 1); 696 s = splts102(); 697 v = req.rspbuf[0] * 256 + req.rspbuf[1]; 698 if (v & TS102_EVENT_STATUS_SHUTDOWN_REQUEST) { 699 printf("%s: SHUTDOWN REQUEST!\n", sc->sc_dev.dv_xname); 700 } 701 if (v & TS102_EVENT_STATUS_VERY_LOW_POWER_WARNING) { 702/*printf("%s: VERY LOW POWER WARNING!\n", sc->sc_dev.dv_xname);*/ 703/* according to a tadpole header, and observation */ 704#ifdef TCTRLDEBUG 705 printf("%s: Battery charge level change\n", sc->sc_dev.dv_xname); 706#endif 707 } 708 if (v & TS102_EVENT_STATUS_LOW_POWER_WARNING) { 709 if (tctrl_apm_record_event(sc, APM_BATTERY_LOW)) 710 printf("%s: LOW POWER WARNING!\n", sc->sc_dev.dv_xname); 711 } 712 if (v & TS102_EVENT_STATUS_DC_STATUS_CHANGE) { 713 splx(s); 714 tctrl_read_ext_status(); 715 s = splts102(); 716 if (tctrl_apm_record_event(sc, APM_POWER_CHANGE)) 717 printf("%s: main power %s\n", sc->sc_dev.dv_xname, 718 (sc->sc_ext_status & 719 TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ? 720 "restored" : "removed"); 721 } 722 if (v & TS102_EVENT_STATUS_LID_STATUS_CHANGE) { 723 splx(s); 724 tctrl_read_ext_status(); 725 tctrl_setup_bitport(); 726#ifdef TCTRLDEBUG 727 printf("%s: lid %s\n", sc->sc_dev.dv_xname, 728 (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) 729 ? "closed" : "opened"); 730#endif 731 } 732 splx(s); 733} 734 735void 736tadpole_request(req, spin) 737 struct tctrl_req *req; 738 int spin; 739{ 740 struct tctrl_softc *sc; 741 int i, s; 742 743 if (tctrl_cd.cd_devs == NULL 744 || tctrl_cd.cd_ndevs == 0 745 || tctrl_cd.cd_devs[TCTRL_STD_DEV] == NULL) { 746 return; 747 } 748 749 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV]; 750 while (sc->sc_wantdata != 0) { 751 if (req->p != NULL) 752 tsleep(&sc->sc_wantdata, PLOCK, "tctrl_lock", 10); 753 else 754 DELAY(1); 755 } 756 if (spin) 757 s = splhigh(); 758 else 759 s = splts102(); 760 sc->sc_flags |= TCTRL_SEND_REQUEST; 761 memcpy(sc->sc_cmdbuf, req->cmdbuf, req->cmdlen); 762 sc->sc_wantdata = 1; 763 sc->sc_rsplen = req->rsplen; 764 sc->sc_cmdlen = req->cmdlen; 765 sc->sc_cmdoff = sc->sc_rspoff = 0; 766 767 /* we spin for certain commands, like poweroffs */ 768 if (spin) { 769/* for (i = 0; i < 30000; i++) {*/ 770 while (sc->sc_wantdata == 1) { 771 tctrl_intr(sc); 772 DELAY(1); 773 } 774 } else { 775 tctrl_intr(sc); 776 i = 0; 777 while (((sc->sc_rspoff != sc->sc_rsplen) || 778 (sc->sc_cmdoff != sc->sc_cmdlen)) && 779 (i < (5 * sc->sc_rsplen + sc->sc_cmdlen))) 780 if (req->p != NULL) { 781 tsleep(sc, PWAIT, "tctrl_data", 15); 782 i++; 783 } 784 else 785 DELAY(1); 786 } 787 /* 788 * we give the user a reasonable amount of time for a command 789 * to complete. If it doesn't complete in time, we hand them 790 * garbage. This is here to stop things like setting the 791 * rsplen too long, and sleeping forever in a CMD_REQ ioctl. 792 */ 793 sc->sc_wantdata = 0; 794 memcpy(req->rspbuf, sc->sc_rspbuf, req->rsplen); 795 splx(s); 796} 797 798void 799tadpole_powerdown(void) 800{ 801 struct tctrl_req req; 802 803 req.cmdbuf[0] = TS102_OP_ADMIN_POWER_OFF; 804 req.cmdlen = 1; 805 req.rsplen = 1; 806 req.p = NULL; 807 tadpole_request(&req, 1); 808} 809 810void 811tadpole_set_video(enabled) 812 int enabled; 813{ 814 struct tctrl_softc *sc; 815 struct tctrl_req req; 816 int s; 817 818 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV]; 819 while (sc->sc_wantdata != 0) 820 DELAY(1); 821 s = splts102(); 822 req.p = NULL; 823 if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN && !enabled) 824 || (sc->sc_tft_on)) { 825 req.cmdbuf[2] = TS102_BITPORT_TFTPWR; 826 } else { 827 req.cmdbuf[2] = 0; 828 } 829 req.cmdbuf[0] = TS102_OP_CTL_BITPORT; 830 req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR; 831 req.cmdlen = 3; 832 req.rsplen = 2; 833 834 if ((sc->sc_tft_on && !enabled) || (!sc->sc_tft_on && enabled)) { 835 sc->sc_tft_on = enabled; 836 if (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) { 837 splx(s); 838 return; 839 } 840 tadpole_request(&req, 1); 841 sc->sc_bitport = 842 (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2]; 843 } 844 splx(s); 845} 846 847static void 848tctrl_write_data(sc, v) 849 struct tctrl_softc *sc; 850 u_int8_t v; 851{ 852 unsigned int i; 853 854 for (i = 0; i < 100; i++) { 855 if (TS102_UCTRL_STS_TXNF_STA & tctrl_read(sc, TS102_REG_UCTRL_STS)) 856 break; 857 } 858 tctrl_write(sc, TS102_REG_UCTRL_DATA, v); 859} 860 861static u_int8_t 862tctrl_read_data(sc) 863 struct tctrl_softc *sc; 864{ 865 unsigned int i, v; 866 867 for (i = 0; i < 100000; i++) { 868 if (TS102_UCTRL_STS_RXNE_STA & tctrl_read(sc, TS102_REG_UCTRL_STS)) 869 break; 870 DELAY(1); 871 } 872 873 v = tctrl_read(sc, TS102_REG_UCTRL_DATA); 874 tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA); 875 return v; 876} 877 878static u_int8_t 879tctrl_read(sc, off) 880 struct tctrl_softc *sc; 881 bus_size_t off; 882{ 883 884 sc->sc_junk = bus_space_read_1(sc->sc_memt, sc->sc_memh, off); 885 return sc->sc_junk; 886} 887 888static void 889tctrl_write(sc, off, v) 890 struct tctrl_softc *sc; 891 bus_size_t off; 892 u_int8_t v; 893{ 894 895 sc->sc_junk = v; 896 bus_space_write_1(sc->sc_memt, sc->sc_memh, off, v); 897} 898 899int 900tctrlopen(dev, flags, mode, p) 901 dev_t dev; 902 int flags, mode; 903 struct proc *p; 904{ 905 int unit = (minor(dev)&0xf0); 906 int ctl = (minor(dev)&0x0f); 907 struct tctrl_softc *sc; 908 909 if (unit >= tctrl_cd.cd_ndevs) 910 return(ENXIO); 911 sc = tctrl_cd.cd_devs[TCTRL_STD_DEV]; 912 if (!sc) 913 return(ENXIO); 914 915 switch (ctl) { 916 case TCTRL_STD_DEV: 917 break; 918 case TCTRL_APMCTL_DEV: 919 if (!(flags & FWRITE)) 920 return(EINVAL); 921 if (sc->sc_flags & TCTRL_APM_CTLOPEN) 922 return(EBUSY); 923 sc->sc_flags |= TCTRL_APM_CTLOPEN; 924 break; 925 default: 926 return(ENXIO); 927 break; 928 } 929 930 return(0); 931} 932 933int 934tctrlclose(dev, flags, mode, p) 935 dev_t dev; 936 int flags, mode; 937 struct proc *p; 938{ 939 int ctl = (minor(dev)&0x0f); 940 struct tctrl_softc *sc; 941 942 sc = tctrl_cd.cd_devs[TCTRL_STD_DEV]; 943 if (!sc) 944 return(ENXIO); 945 946 switch (ctl) { 947 case TCTRL_STD_DEV: 948 break; 949 case TCTRL_APMCTL_DEV: 950 sc->sc_flags &= ~TCTRL_APM_CTLOPEN; 951 break; 952 } 953 return(0); 954} 955 956int 957tctrlioctl(dev, cmd, data, flags, p) 958 dev_t dev; 959 u_long cmd; 960 caddr_t data; 961 int flags; 962 struct proc *p; 963{ 964 struct tctrl_req req, *reqn; 965 struct tctrl_pwr *pwrreq; 966 envsys_range_t *envrange; 967 envsys_temp_data_t *envdata; 968 envsys_temp_info_t *envinfo; 969 struct apm_power_info *powerp; 970 struct apm_event_info *evp; 971 struct tctrl_softc *sc; 972 int i; 973 u_int j; 974 u_int16_t a; 975 u_int8_t c; 976 977 if (tctrl_cd.cd_devs == NULL 978 || tctrl_cd.cd_ndevs == 0 979 || tctrl_cd.cd_devs[TCTRL_STD_DEV] == NULL) { 980 return ENXIO; 981 } 982 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV]; 983 switch (cmd) { 984 985 case APM_IOC_STANDBY: 986 return(EOPNOTSUPP); /* for now */ 987 988 case APM_IOC_SUSPEND: 989 return(EOPNOTSUPP); /* for now */ 990 991 case 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