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