Annotation of sys/arch/sparc/dev/tctrl.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: tctrl.c,v 1.18 2006/10/27 17:52:38 miod Exp $ */
! 2: /* $NetBSD: tctrl.c,v 1.2 1999/08/11 00:46:06 matt Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 1998 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by Matt Thomas.
! 10: *
! 11: * Redistribution and use in source and binary forms, with or without
! 12: * modification, are permitted provided that the following conditions
! 13: * are met:
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions and the following disclaimer.
! 16: * 2. Redistributions in binary form must reproduce the above copyright
! 17: * notice, this list of conditions and the following disclaimer in the
! 18: * documentation and/or other materials provided with the distribution.
! 19: * 3. All advertising materials mentioning features or use of this software
! 20: * must display the following acknowledgement:
! 21: * This product includes software developed by the NetBSD
! 22: * Foundation, Inc. and its contributors.
! 23: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 24: * contributors may be used to endorse or promote products derived
! 25: * from this software without specific prior written permission.
! 26: *
! 27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 37: * POSSIBILITY OF SUCH DAMAGE.
! 38: */
! 39: /*
! 40: * The /dev/apm{,ctl} interface code falls under the following license
! 41: * terms:
! 42: *
! 43: * Copyright (c) 1998-2001 Michael Shalayeff. All rights reserved.
! 44: * Copyright (c) 1995 John T. Kohl. All rights reserved.
! 45: *
! 46: * Redistribution and use in source and binary forms, with or without
! 47: * modification, are permitted provided that the following conditions
! 48: * are met:
! 49: * 1. Redistributions of source code must retain the above copyright
! 50: * notice, this list of conditions and the following disclaimer.
! 51: * 2. Redistributions in binary form must reproduce the above copyright
! 52: * notice, this list of conditions and the following disclaimer in the
! 53: * documentation and/or other materials provided with the distribution.
! 54: * 3. All advertising materials mentioning features or use of this software
! 55: * must display the following acknowledgement:
! 56: * This product includes software developed by the University of
! 57: * California, Berkeley and its contributors.
! 58: * 4. Neither the name of the University nor the names of its contributors
! 59: * may be used to endorse or promote products derived from this software
! 60: * without specific prior written permission.
! 61: *
! 62: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 63: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 64: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 65: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 66: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 67: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 68: * OR SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 69: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 70: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 71: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 72: * SUCH DAMAGE.
! 73: */
! 74:
! 75: #include <sys/param.h>
! 76: #include <sys/systm.h>
! 77: #include <sys/conf.h>
! 78: #include <sys/kernel.h>
! 79: #include <sys/device.h>
! 80: #include <sys/event.h>
! 81: #include <sys/fcntl.h>
! 82: #include <sys/ioctl.h>
! 83: #include <sys/proc.h>
! 84: #include <sys/timeout.h>
! 85:
! 86: #include <machine/apmvar.h>
! 87: #include <machine/autoconf.h>
! 88: #include <machine/conf.h>
! 89: #include <machine/cpu.h>
! 90:
! 91: #include <sparc/sparc/auxioreg.h>
! 92:
! 93: #include <sparc/dev/ts102reg.h>
! 94: #include <sparc/dev/tctrlvar.h>
! 95:
! 96: /*
! 97: * Flags to control kernel display
! 98: * SCFLAG_NOPRINT: do not output APM power messages due to
! 99: * a power change event.
! 100: *
! 101: * SCFLAG_PCTPRINT: do not output APM power messages due to
! 102: * to a power change event unless the battery
! 103: * percentage changes.
! 104: */
! 105:
! 106: #define SCFLAG_NOPRINT 0x0008000
! 107: #define SCFLAG_PCTPRINT 0x0004000
! 108: #define SCFLAG_PRINT (SCFLAG_NOPRINT|SCFLAG_PCTPRINT)
! 109:
! 110: const char *tctrl_ext_status[16] = {
! 111: "main power available",
! 112: "internal battery attached",
! 113: "external battery attached",
! 114: "external VGA attached",
! 115: "external keyboard attached",
! 116: "external mouse attached",
! 117: "lid down",
! 118: "internal battery charging",
! 119: "external battery charging",
! 120: "internal battery discharging",
! 121: "external battery discharging",
! 122: };
! 123:
! 124: /* Request "packet" */
! 125: struct tctrl_req {
! 126: u_int8_t cmdbuf[16];
! 127: u_int cmdlen;
! 128: u_int8_t rspbuf[16];
! 129: u_int rsplen;
! 130: };
! 131:
! 132: struct tctrl_softc {
! 133: struct device sc_dev;
! 134: struct uctrl_regs *sc_regs;
! 135: struct intrhand sc_ih;
! 136: u_int sc_ext_status;
! 137: u_int sc_flags;
! 138: #define TCTRL_SEND_REQUEST 0x0001
! 139: #define TCTRL_ISXT 0x0002
! 140: u_int sc_wantdata;
! 141: enum { TCTRL_IDLE, TCTRL_ARGS,
! 142: TCTRL_ACK, TCTRL_DATA } sc_state;
! 143: u_int8_t sc_cmdbuf[16];
! 144: u_int8_t sc_rspbuf[16];
! 145: u_int8_t sc_tft_on;
! 146: u_int8_t sc_pcmcia_on;
! 147: u_int8_t sc_brightness;
! 148: u_int8_t sc_op;
! 149: u_int sc_cmdoff;
! 150: u_int sc_cmdlen;
! 151: u_int sc_rspoff;
! 152: u_int sc_rsplen;
! 153: u_int sc_rspack;
! 154: u_int sc_bellfreq;
! 155: u_int sc_bellvol;
! 156:
! 157: struct timeout sc_tmo;
! 158:
! 159: /* /dev/apm{,ctl} fields */
! 160: struct klist sc_note;
! 161: u_int sc_apmflags;
! 162:
! 163: /* external video control callback */
! 164: void (*sc_evcb)(void *, int);
! 165: void *sc_evdata;
! 166: };
! 167:
! 168: int tctrl_match(struct device *, void *, void *);
! 169: void tctrl_attach(struct device *, struct device *, void *);
! 170:
! 171: void tctrl_bell(struct tctrl_softc *, int, int);
! 172: void tctrl_brightness(struct tctrl_softc *, int, int);
! 173: void tctrl_init_lcd(struct tctrl_softc *);
! 174: int tctrl_intr(void *);
! 175: void tctrl_lcd(struct tctrl_softc *, int, int);
! 176: u_int8_t tctrl_read_data(struct tctrl_softc *);
! 177: void tctrl_read_event_status(void *);
! 178: void tctrl_read_ext_status(struct tctrl_softc *);
! 179: int tctrl_request(struct tctrl_softc *, struct tctrl_req *);
! 180: void tctrl_tft(struct tctrl_softc *);
! 181: void tctrl_write_data(struct tctrl_softc *, u_int8_t);
! 182:
! 183: int apm_record_event(struct tctrl_softc *, u_int);
! 184:
! 185: struct cfattach tctrl_ca = {
! 186: sizeof(struct tctrl_softc), tctrl_match, tctrl_attach
! 187: };
! 188:
! 189: struct cfdriver tctrl_cd = {
! 190: NULL, "tctrl", DV_DULL
! 191: };
! 192:
! 193: int
! 194: tctrl_match(parent, vcf, aux)
! 195: struct device *parent;
! 196: void *vcf;
! 197: void *aux;
! 198: {
! 199: struct confargs *ca = aux;
! 200: struct romaux *ra = &ca->ca_ra;
! 201:
! 202: /*
! 203: * Tadpole 3GX/3GS uses "uctrl" for the Tadpole Microcontroller
! 204: * (which is really part of the TS102 PCMCIA controller, but there
! 205: * exists a distinct OpenProm node for the microcontroller interface).
! 206: */
! 207: if (strcmp("uctrl", ra->ra_name))
! 208: return (0);
! 209:
! 210: return (1);
! 211: }
! 212:
! 213: void
! 214: tctrl_attach(parent, self, aux)
! 215: struct device *parent, *self;
! 216: void *aux;
! 217: {
! 218: struct confargs *ca = aux;
! 219: struct tctrl_softc *sc = (void *)self;
! 220: u_int i, v;
! 221: int pri;
! 222:
! 223: if (ca->ca_ra.ra_nintr != 1) {
! 224: printf(": expected 1 interrupt, got %d\n",
! 225: ca->ca_ra.ra_nintr);
! 226: return;
! 227: }
! 228: pri = ca->ca_ra.ra_intr[0].int_pri;
! 229:
! 230: if (ca->ca_ra.ra_nreg != 1) {
! 231: printf(": expected 1 register, got %d\n",
! 232: ca->ca_ra.ra_nreg);
! 233: return;
! 234: }
! 235: sc->sc_regs = mapiodev(&(ca->ca_ra.ra_reg[0]), 0,
! 236: ca->ca_ra.ra_reg[0].rr_len);
! 237:
! 238: printf(" pri %d\n", pri);
! 239:
! 240: /*
! 241: * We need to check if we are running on the SPARCbook S3XT, which
! 242: * needs extra work to control the TFT power.
! 243: */
! 244: sc->sc_flags = 0;
! 245: if (strcmp(mainbus_model, "Tadpole_S3000XT") == 0)
! 246: sc->sc_flags |= TCTRL_ISXT;
! 247: sc->sc_tft_on = 1;
! 248:
! 249: /* clear any pending data */
! 250: for (i = 0; i < 10000; i++) {
! 251: if ((TS102_UCTRL_STS_RXNE_STA & sc->sc_regs->stat) == 0)
! 252: break;
! 253: v = sc->sc_regs->data;
! 254: sc->sc_regs->stat = TS102_UCTRL_STS_RXNE_STA;
! 255: }
! 256:
! 257: sc->sc_ih.ih_fun = tctrl_intr;
! 258: sc->sc_ih.ih_arg = sc;
! 259: intr_establish(pri, &sc->sc_ih, -1, self->dv_xname);
! 260:
! 261: timeout_set(&sc->sc_tmo, tctrl_read_event_status, sc);
! 262:
! 263: /* See what the external status is */
! 264: tctrl_read_ext_status(sc);
! 265: if (sc->sc_ext_status != 0) {
! 266: const char *sep;
! 267: u_int len;
! 268:
! 269: v = sc->sc_ext_status;
! 270: len = 0;
! 271: sep = "";
! 272: for (i = 0; v != 0; i++, v >>= 1) {
! 273: if ((v & 1) == 0)
! 274: continue;
! 275: /* wrap to next line if necessary */
! 276: if (len != 0 && len + strlen(sep) +
! 277: strlen(tctrl_ext_status[i]) > 80) {
! 278: printf("\n");
! 279: len = 0;
! 280: }
! 281: if (len == 0) {
! 282: printf("%s: ", sc->sc_dev.dv_xname);
! 283: len = 2 + strlen(sc->sc_dev.dv_xname);
! 284: sep = "";
! 285: }
! 286: printf("%s%s", sep, tctrl_ext_status[i]);
! 287: len += strlen(sep) + strlen(tctrl_ext_status[i]);
! 288: sep = ", ";
! 289: }
! 290: if (len != 0)
! 291: printf("\n");
! 292: }
! 293:
! 294: /* Get a few status values */
! 295: tctrl_bell(sc, 0xff, 0);
! 296: tctrl_brightness(sc, 0xff, 0);
! 297:
! 298: /* Blank video if lid is closed during boot */
! 299: if (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN)
! 300: tctrl_tft(sc);
! 301:
! 302: sc->sc_regs->intr = TS102_UCTRL_INT_RXNE_REQ|TS102_UCTRL_INT_RXNE_MSK;
! 303:
! 304: sc->sc_wantdata = 0;
! 305:
! 306: /* Initialize the LCD icons */
! 307: tctrl_init_lcd(sc);
! 308: }
! 309:
! 310: int
! 311: tctrl_intr(void *arg)
! 312: {
! 313: struct tctrl_softc *sc = arg;
! 314: unsigned int v, d;
! 315: int progress = 0;
! 316:
! 317: again:
! 318: /* find out the cause(s) of the interrupt */
! 319: v = sc->sc_regs->stat & TS102_UCTRL_STS_MASK;
! 320:
! 321: /* clear the cause(s) of the interrupt */
! 322: sc->sc_regs->stat = v;
! 323:
! 324: v &= ~(TS102_UCTRL_STS_RXO_STA|TS102_UCTRL_STS_TXE_STA);
! 325: if (sc->sc_cmdoff >= sc->sc_cmdlen) {
! 326: v &= ~TS102_UCTRL_STS_TXNF_STA;
! 327: if (sc->sc_regs->intr & TS102_UCTRL_INT_TXNF_REQ) {
! 328: sc->sc_regs->intr = 0;
! 329: progress = 1;
! 330: }
! 331: }
! 332: if (v == 0 && ((sc->sc_flags & TCTRL_SEND_REQUEST) == 0 ||
! 333: sc->sc_state != TCTRL_IDLE)) {
! 334: return (progress);
! 335: }
! 336:
! 337: progress = 1;
! 338: if (v & TS102_UCTRL_STS_RXNE_STA) {
! 339: d = tctrl_read_data(sc);
! 340: switch (sc->sc_state) {
! 341: case TCTRL_IDLE:
! 342: if (d == TS102_UCTRL_INTR) {
! 343: /* external event */
! 344: timeout_add(&sc->sc_tmo, 1);
! 345: } else {
! 346: printf("%s: (op=0x%02x): unexpected data (0x%02x)\n",
! 347: sc->sc_dev.dv_xname, sc->sc_op, d);
! 348: }
! 349: goto again;
! 350: case TCTRL_ACK:
! 351: #ifdef TCTRLDEBUG
! 352: printf(" ack=0x%02x", d);
! 353: #endif
! 354: switch (d) {
! 355: case TS102_UCTRL_ACK:
! 356: sc->sc_rspack = 1;
! 357: sc->sc_rsplen--;
! 358: sc->sc_rspoff = 0;
! 359: sc->sc_state =
! 360: sc->sc_rsplen ? TCTRL_DATA : TCTRL_IDLE;
! 361: sc->sc_wantdata = sc->sc_rsplen ? 1 : 0;
! 362: #ifdef TCTRLDEBUG
! 363: if (sc->sc_rsplen > 0) {
! 364: printf(" [data(%u)]", sc->sc_rsplen);
! 365: } else {
! 366: printf(" [idle]\n");
! 367: }
! 368: #endif
! 369: goto again;
! 370: default:
! 371: printf("%s: (op=0x%02x): unexpected return value (0x%02x)\n",
! 372: sc->sc_dev.dv_xname, sc->sc_op, d);
! 373: /* FALLTHROUGH */
! 374: case TS102_UCTRL_NACK:
! 375: printf("%s: command %x failed\n",
! 376: sc->sc_dev.dv_xname, sc->sc_op);
! 377: sc->sc_rspack = 0;
! 378: sc->sc_wantdata = 0;
! 379: sc->sc_state = TCTRL_IDLE;
! 380: break;
! 381: }
! 382: break;
! 383: case TCTRL_DATA:
! 384: sc->sc_rspbuf[sc->sc_rspoff++] = d;
! 385: #ifdef TCTRLDEBUG
! 386: printf(" [%d]=0x%02x", sc->sc_rspoff-1, d);
! 387: #endif
! 388: if (sc->sc_rspoff == sc->sc_rsplen) {
! 389: #ifdef TCTRLDEBUG
! 390: printf(" [idle]\n");
! 391: #endif
! 392: sc->sc_state = TCTRL_IDLE;
! 393: sc->sc_wantdata = 0;
! 394: }
! 395: goto again;
! 396: default:
! 397: printf("%s: (op=0x%02x): unexpected data (0x%02x) in state %d\n",
! 398: sc->sc_dev.dv_xname, sc->sc_op, d, sc->sc_state);
! 399: goto again;
! 400: }
! 401: }
! 402: if ((sc->sc_state == TCTRL_IDLE && sc->sc_wantdata == 0) ||
! 403: (sc->sc_flags & TCTRL_SEND_REQUEST)) {
! 404: if (sc->sc_flags & TCTRL_SEND_REQUEST) {
! 405: sc->sc_flags &= ~TCTRL_SEND_REQUEST;
! 406: sc->sc_wantdata = 1;
! 407: }
! 408: if (sc->sc_cmdlen > 0) {
! 409: sc->sc_regs->intr =
! 410: sc->sc_regs->intr | TS102_UCTRL_INT_TXNF_MSK
! 411: |TS102_UCTRL_INT_TXNF_REQ;
! 412: v = sc->sc_regs->stat;
! 413: }
! 414: }
! 415: if ((sc->sc_cmdoff < sc->sc_cmdlen) && (v & TS102_UCTRL_STS_TXNF_STA)) {
! 416: tctrl_write_data(sc, sc->sc_cmdbuf[sc->sc_cmdoff++]);
! 417: #ifdef TCTRLDEBUG
! 418: if (sc->sc_cmdoff == 1) {
! 419: printf("%s: op=0x%02x(l=%u)", sc->sc_dev.dv_xname,
! 420: sc->sc_cmdbuf[0], sc->sc_rsplen);
! 421: } else {
! 422: printf(" [%d]=0x%02x", sc->sc_cmdoff-1,
! 423: sc->sc_cmdbuf[sc->sc_cmdoff-1]);
! 424: }
! 425: #endif
! 426: if (sc->sc_cmdoff == sc->sc_cmdlen) {
! 427: sc->sc_state = sc->sc_rsplen ? TCTRL_ACK : TCTRL_IDLE;
! 428: #ifdef TCTRLDEBUG
! 429: printf(" %s", sc->sc_rsplen ? "[ack]" : "[idle]\n");
! 430: #endif
! 431: if (sc->sc_cmdoff == 1) {
! 432: sc->sc_op = sc->sc_cmdbuf[0];
! 433: }
! 434: sc->sc_regs->intr =
! 435: sc->sc_regs->intr & (~TS102_UCTRL_INT_TXNF_MSK
! 436: |TS102_UCTRL_INT_TXNF_REQ);
! 437: } else if (sc->sc_state == TCTRL_IDLE) {
! 438: sc->sc_op = sc->sc_cmdbuf[0];
! 439: sc->sc_state = TCTRL_ARGS;
! 440: #ifdef TCTRLDEBUG
! 441: printf(" [args]");
! 442: #endif
! 443: }
! 444: }
! 445: goto again;
! 446: }
! 447:
! 448: /*
! 449: * The Tadpole microcontroller is not preprogrammed with icon
! 450: * representations. The machine boots with the DC-IN light as
! 451: * a blank (all 0x00) and the other lights, as 4 rows of horizontal
! 452: * bars. The below code initializes the few icons the system will use
! 453: * to sane values.
! 454: *
! 455: * Programming the icons is simple. It is a 5x8 matrix, with each row a
! 456: * bitfield in the order 0x10 0x08 0x04 0x02 0x01.
! 457: */
! 458:
! 459: static void tctrl_set_glyph(struct tctrl_softc *, u_int, const u_int8_t *);
! 460:
! 461: static const u_int8_t
! 462: tctrl_glyph_dc[] = { 0x00, 0x00, 0x1f, 0x00, 0x15, 0x00, 0x00, 0x00 },
! 463: #if 0
! 464: tctrl_glyph_bs[] = { 0x00, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, 0x00 },
! 465: tctrl_glyph_w1[] = { 0x0c, 0x16, 0x10, 0x15, 0x10, 0x16, 0x0c, 0x00 },
! 466: tctrl_glyph_w2[] = { 0x0c, 0x0d, 0x01, 0x15, 0x01, 0x0d, 0x0c, 0x00 },
! 467: tctrl_glyph_l1[] = { 0x00, 0x04, 0x08, 0x13, 0x08, 0x04, 0x00, 0x00 },
! 468: tctrl_glyph_l2[] = { 0x00, 0x04, 0x02, 0x19, 0x02, 0x04, 0x00, 0x00 },
! 469: #endif
! 470: tctrl_glyph_pc[] = { 0x00, 0x0e, 0x0e, 0x1f, 0x1f, 0x1f, 0x1f, 0x00 };
! 471:
! 472: void
! 473: tctrl_init_lcd(struct tctrl_softc *sc)
! 474: {
! 475: tctrl_set_glyph(sc, TS102_BLK_OFF_DEF_DC_GOOD, tctrl_glyph_dc);
! 476: #if 0
! 477: tctrl_set_glyph(sc, TS102_BLK_OFF_DEF_BACKSLASH, tctrl_glyph_bs);
! 478: tctrl_set_glyph(sc, TS102_BLK_OFF_DEF_WAN1, tctrl_glyph_w1);
! 479: tctrl_set_glyph(sc, TS102_BLK_OFF_DEF_WAN2, tctrl_glyph_w2);
! 480: tctrl_set_glyph(sc, TS102_BLK_OFF_DEF_LAN1, tctrl_glyph_l1);
! 481: tctrl_set_glyph(sc, TS102_BLK_OFF_DEF_LAN2, tctrl_glyph_l2);
! 482: #endif
! 483: tctrl_set_glyph(sc, TS102_BLK_OFF_DEF_PCMCIA, tctrl_glyph_pc);
! 484: }
! 485:
! 486: static void
! 487: tctrl_set_glyph(struct tctrl_softc *sc, u_int glyph, const u_int8_t *data)
! 488: {
! 489: struct tctrl_req req;
! 490:
! 491: req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
! 492: req.cmdbuf[1] = 8;
! 493: req.cmdbuf[2] = glyph;
! 494: bcopy(data, req.cmdbuf + 3, 8);
! 495: req.cmdlen = 3 + 8;
! 496: req.rsplen = 1;
! 497:
! 498: tctrl_request(sc, &req);
! 499: }
! 500:
! 501: void
! 502: tctrl_read_event_status(void *arg)
! 503: {
! 504: struct tctrl_softc *sc = (struct tctrl_softc *)arg;
! 505: struct tctrl_req req;
! 506: unsigned int v;
! 507:
! 508: req.cmdbuf[0] = TS102_OP_RD_EVENT_STATUS;
! 509: req.cmdlen = 1;
! 510: req.rsplen = 3;
! 511:
! 512: tctrl_request(sc, &req);
! 513:
! 514: v = req.rspbuf[0] * 256 + req.rspbuf[1];
! 515:
! 516: /*
! 517: * Read the new external status value if necessary
! 518: */
! 519: if (v & (TS102_EVENT_STATUS_DC_STATUS_CHANGE |
! 520: TS102_EVENT_STATUS_LID_STATUS_CHANGE |
! 521: TS102_EVENT_STATUS_EXTERNAL_VGA_STATUS_CHANGE))
! 522: tctrl_read_ext_status(sc);
! 523:
! 524: if (v & TS102_EVENT_STATUS_SHUTDOWN_REQUEST) {
! 525: printf("%s: SHUTDOWN REQUEST!\n", sc->sc_dev.dv_xname);
! 526: }
! 527: #ifdef TCTRLDEBUG
! 528: /* Obviously status change */
! 529: if (v & TS102_EVENT_STATUS_VERY_LOW_POWER_WARNING) {
! 530: if (sc->sc_apmflags & SCFLAG_PCTPRINT)
! 531: printf("%s: Battery level change\n",
! 532: sc->sc_dev.dv_xname);
! 533: }
! 534: #endif
! 535: if (v & TS102_EVENT_STATUS_LOW_POWER_WARNING) {
! 536: if ((sc->sc_apmflags & SCFLAG_NOPRINT) == 0)
! 537: printf("%s: LOW POWER WARNING!\n", sc->sc_dev.dv_xname);
! 538: apm_record_event(sc, APM_BATTERY_LOW);
! 539: }
! 540: if (v & TS102_EVENT_STATUS_DC_STATUS_CHANGE) {
! 541: if ((sc->sc_apmflags & SCFLAG_NOPRINT) == 0)
! 542: printf("%s: main power %s\n", sc->sc_dev.dv_xname,
! 543: (sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ?
! 544: "restored" : "removed");
! 545: apm_record_event(sc, APM_POWER_CHANGE);
! 546: #if 0 /* automatically done for us */
! 547: tctrl_lcd(sc, ~TS102_LCD_DC_OK,
! 548: sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE ?
! 549: TS102_LCD_DC_OK : 0);
! 550: #endif
! 551: }
! 552: if (v & TS102_EVENT_STATUS_LID_STATUS_CHANGE) {
! 553: /* blank or restore video if necessary */
! 554: if (sc->sc_tft_on)
! 555: tctrl_tft(sc);
! 556: #ifdef TCTRLDEBUG
! 557: printf("%s: lid %s\n", sc->sc_dev.dv_xname,
! 558: (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) ?
! 559: "closed" : "opened");
! 560: #endif
! 561: }
! 562: if (v & TS102_EVENT_STATUS_EXTERNAL_VGA_STATUS_CHANGE) {
! 563: printf("%s: external vga %s\n", sc->sc_dev.dv_xname,
! 564: sc->sc_ext_status & TS102_EXT_STATUS_EXTERNAL_VGA_ATTACHED ?
! 565: "attached" : "detached");
! 566: #ifdef TCTRLDEBUG
! 567: req.cmdbuf[0] = TS102_OP_RD_EXT_VGA_PORT;
! 568: req.cmdlen = 1;
! 569: req.rsplen = 2;
! 570: tctrl_request(sc, &req);
! 571: printf("%s: vga status %x\n", sc->sc_dev.dv_xname,
! 572: req.rspbuf[0]);
! 573: #endif
! 574: if (sc->sc_evcb != NULL)
! 575: (*sc->sc_evcb)(sc->sc_evdata, sc->sc_ext_status &
! 576: TS102_EXT_STATUS_EXTERNAL_VGA_ATTACHED);
! 577: }
! 578: }
! 579:
! 580: void
! 581: tctrl_read_ext_status(struct tctrl_softc *sc)
! 582: {
! 583: struct tctrl_req req;
! 584:
! 585: req.cmdbuf[0] = TS102_OP_RD_EXT_STATUS;
! 586: req.cmdlen = 1;
! 587: req.rsplen = 3;
! 588: #ifdef TCTRLDEBUG
! 589: printf("tctrl_read_ext_status: before, ext_status = %x\n",
! 590: sc->sc_ext_status);
! 591: #endif
! 592:
! 593: tctrl_request(sc, &req);
! 594:
! 595: sc->sc_ext_status = req.rspbuf[0] * 256 + req.rspbuf[1];
! 596:
! 597: #ifdef TCTRLDEBUG
! 598: printf("tctrl_read_ext_status: after, ext_status = %x\n",
! 599: sc->sc_ext_status);
! 600: #endif
! 601: }
! 602:
! 603: void
! 604: tctrl_bell(struct tctrl_softc *sc, int mask, int value)
! 605: {
! 606: struct tctrl_req req;
! 607:
! 608: req.cmdbuf[0] = TS102_OP_CTL_SPEAKER_VOLUME;
! 609: req.cmdbuf[1] = mask;
! 610: req.cmdbuf[2] = value;
! 611: req.cmdlen = 3;
! 612: req.rsplen = 2;
! 613:
! 614: tctrl_request(sc, &req);
! 615:
! 616: /*
! 617: * Note that rspbuf[0] returns the previous value, before any
! 618: * adjustment happened.
! 619: */
! 620: if (mask == 0)
! 621: sc->sc_bellvol = value;
! 622: else
! 623: sc->sc_bellvol = req.rspbuf[0];
! 624: }
! 625:
! 626: void
! 627: tctrl_brightness(struct tctrl_softc *sc, int mask, int value)
! 628: {
! 629: struct tctrl_req req;
! 630:
! 631: req.cmdbuf[0] = TS102_OP_CTL_TFT_BRIGHTNESS;
! 632: req.cmdbuf[1] = mask;
! 633: req.cmdbuf[2] = value;
! 634: req.cmdlen = 3;
! 635: req.rsplen = 2;
! 636:
! 637: tctrl_request(sc, &req);
! 638:
! 639: /*
! 640: * Note that rspbuf[0] returns the previous value, before any
! 641: * adjustment happened.
! 642: */
! 643: if (mask == 0)
! 644: sc->sc_brightness = value;
! 645: else
! 646: sc->sc_brightness = req.rspbuf[0];
! 647: }
! 648:
! 649: void
! 650: tctrl_tft(struct tctrl_softc *sc)
! 651: {
! 652: struct tctrl_req req;
! 653: int enable;
! 654:
! 655: enable = (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) == 0 &&
! 656: sc->sc_tft_on;
! 657:
! 658: req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
! 659: req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR;
! 660: req.cmdbuf[2] = enable ? 0 : TS102_BITPORT_TFTPWR;
! 661: req.cmdlen = 3;
! 662: req.rsplen = 2;
! 663:
! 664: if ((sc->sc_flags & TCTRL_ISXT) != 0 && enable) {
! 665: sb_auxregbisc(0, AUXIO_TFT, 0);
! 666: delay(100000); /* XXX is such a long delay really necessary? */
! 667: }
! 668:
! 669: tctrl_request(sc, &req);
! 670:
! 671: if ((sc->sc_flags & TCTRL_ISXT) != 0 && !enable) {
! 672: delay(100000); /* XXX is such a long delay really necessary? */
! 673: sb_auxregbisc(0, 0, AUXIO_TFT);
! 674: }
! 675: }
! 676:
! 677: void
! 678: tctrl_lcd(struct tctrl_softc *sc, int mask, int value)
! 679: {
! 680: struct tctrl_req req;
! 681:
! 682: req.cmdbuf[0] = TS102_OP_CTL_LCD;
! 683:
! 684: /*
! 685: * The mask setup for this particular command is *very* bizarre
! 686: * and totally undocumented.
! 687: * One would expect the cmdlen and rsplen to be 5 and 3,
! 688: * respectively, as well. Though luck, they are not...
! 689: */
! 690:
! 691: req.cmdbuf[1] = mask & 0xff;
! 692: req.cmdbuf[4] = (mask >> 8) & 0x01;
! 693:
! 694: req.cmdbuf[2] = value & 0xff;
! 695: req.cmdbuf[3] = (value >> 8 & 0x01);
! 696:
! 697: req.cmdlen = 3;
! 698: req.rsplen = 2;
! 699:
! 700: tctrl_request(sc, &req);
! 701: }
! 702:
! 703: int
! 704: tctrl_request(struct tctrl_softc *sc, struct tctrl_req *req)
! 705: {
! 706: int s, rv;
! 707:
! 708: while (sc->sc_wantdata != 0) {
! 709: DELAY(1);
! 710: }
! 711:
! 712: s = splhigh();
! 713: sc->sc_flags |= TCTRL_SEND_REQUEST;
! 714: bcopy(req->cmdbuf, sc->sc_cmdbuf, req->cmdlen);
! 715: sc->sc_wantdata = 1;
! 716: sc->sc_rsplen = req->rsplen;
! 717: sc->sc_cmdlen = req->cmdlen;
! 718: sc->sc_cmdoff = sc->sc_rspoff = 0;
! 719:
! 720: do {
! 721: tctrl_intr(sc);
! 722: } while (sc->sc_state != TCTRL_IDLE);
! 723:
! 724: sc->sc_wantdata = 0; /* just in case... */
! 725:
! 726: rv = sc->sc_rspack;
! 727: if (rv != 0)
! 728: bcopy(sc->sc_rspbuf, req->rspbuf, sc->sc_rsplen);
! 729: else
! 730: bzero(req->rspbuf, req->rsplen); /* safety */
! 731: splx(s);
! 732:
! 733: return (rv);
! 734: }
! 735:
! 736: void
! 737: tctrl_write_data(sc, v)
! 738: struct tctrl_softc *sc;
! 739: u_int8_t v;
! 740: {
! 741: unsigned int i;
! 742:
! 743: for (i = 0; i < 100; i++) {
! 744: if (sc->sc_regs->stat & TS102_UCTRL_STS_TXNF_STA)
! 745: break;
! 746: }
! 747: sc->sc_regs->data = v;
! 748: }
! 749:
! 750: u_int8_t
! 751: tctrl_read_data(sc)
! 752: struct tctrl_softc *sc;
! 753: {
! 754: unsigned int i, v;
! 755:
! 756: for (i = 0; i < 100000; i++) {
! 757: if (sc->sc_regs->stat & TS102_UCTRL_STS_RXNE_STA)
! 758: break;
! 759: DELAY(1);
! 760: }
! 761:
! 762: v = sc->sc_regs->data;
! 763: sc->sc_regs->stat = TS102_UCTRL_STS_RXNE_STA;
! 764: return v;
! 765: }
! 766:
! 767: /*
! 768: * External interfaces, used by the display and pcmcia drivers, as well
! 769: * as the powerdown code.
! 770: */
! 771:
! 772: void
! 773: tadpole_powerdown(void)
! 774: {
! 775: struct tctrl_softc *sc;
! 776: struct tctrl_req req;
! 777:
! 778: if (tctrl_cd.cd_ndevs == 0 || tctrl_cd.cd_devs[0] == NULL) {
! 779: return;
! 780: }
! 781:
! 782: sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0];
! 783: req.cmdbuf[0] = TS102_OP_ADMIN_POWER_OFF;
! 784: req.cmdlen = 1;
! 785: req.rsplen = 1;
! 786:
! 787: tctrl_request(sc, &req);
! 788: }
! 789:
! 790: void
! 791: tadpole_set_brightness(int value)
! 792: {
! 793: struct tctrl_softc *sc;
! 794:
! 795: if (tctrl_cd.cd_ndevs == 0 || tctrl_cd.cd_devs[0] == NULL) {
! 796: return;
! 797: }
! 798:
! 799: sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0];
! 800: if (value != sc->sc_brightness)
! 801: tctrl_brightness(sc, 0, value);
! 802: }
! 803:
! 804: int
! 805: tadpole_get_brightness()
! 806: {
! 807: struct tctrl_softc *sc;
! 808:
! 809: if (tctrl_cd.cd_ndevs == 0 || tctrl_cd.cd_devs[0] == NULL) {
! 810: return 0;
! 811: }
! 812:
! 813: sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0];
! 814: return sc->sc_brightness;
! 815: }
! 816:
! 817: void
! 818: tadpole_set_video(int enabled)
! 819: {
! 820: struct tctrl_softc *sc;
! 821:
! 822: if (tctrl_cd.cd_ndevs == 0 || tctrl_cd.cd_devs[0] == NULL) {
! 823: return;
! 824: }
! 825:
! 826: sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0];
! 827: if (sc->sc_tft_on ^ enabled) {
! 828: sc->sc_tft_on = enabled;
! 829: /* nothing to do if the lid is down */
! 830: if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) == 0)
! 831: tctrl_tft(sc);
! 832: }
! 833: }
! 834:
! 835: u_int
! 836: tadpole_get_video()
! 837: {
! 838: struct tctrl_softc *sc;
! 839: unsigned int status;
! 840:
! 841: if (tctrl_cd.cd_ndevs == 0 || tctrl_cd.cd_devs[0] == NULL) {
! 842: return 0;
! 843: }
! 844:
! 845: sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0];
! 846: status = sc->sc_tft_on ? TV_ON : 0;
! 847:
! 848: return status;
! 849: }
! 850:
! 851: void
! 852: tadpole_register_extvideo(void (*cb)(void *, int), void *data)
! 853: {
! 854: struct tctrl_softc *sc;
! 855:
! 856: if (tctrl_cd.cd_ndevs == 0 || tctrl_cd.cd_devs[0] == NULL) {
! 857: return;
! 858: }
! 859:
! 860: sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0];
! 861: sc->sc_evcb = cb;
! 862: sc->sc_evdata = data;
! 863:
! 864: (*cb)(data, sc->sc_ext_status & TS102_EXT_STATUS_EXTERNAL_VGA_ATTACHED);
! 865: }
! 866:
! 867: void
! 868: tadpole_set_pcmcia(int slot, int enabled)
! 869: {
! 870: struct tctrl_softc *sc;
! 871: int mask;
! 872:
! 873: if (tctrl_cd.cd_ndevs == 0 || tctrl_cd.cd_devs[0] == NULL) {
! 874: return;
! 875: }
! 876:
! 877: sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0];
! 878: mask = 1 << slot;
! 879: enabled = enabled ? mask : 0;
! 880: if ((sc->sc_pcmcia_on ^ enabled) & mask) {
! 881: sc->sc_pcmcia_on ^= mask;
! 882: tctrl_lcd(sc, ~TS102_LCD_PCMCIA_ACTIVE,
! 883: sc->sc_pcmcia_on ? TS102_LCD_PCMCIA_ACTIVE : 0);
! 884: }
! 885: }
! 886:
! 887: int
! 888: tadpole_bell(u_int duration, u_int freq, u_int volume)
! 889: {
! 890: struct tctrl_softc *sc;
! 891: struct tctrl_req req;
! 892:
! 893: if (tctrl_cd.cd_ndevs == 0 || tctrl_cd.cd_devs[0] == NULL) {
! 894: return (0);
! 895: }
! 896:
! 897: sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0];
! 898:
! 899: /* Adjust frequency if necessary (first time or frequence change) */
! 900: if (freq > 0 && freq <= 0xffff && freq != sc->sc_bellfreq) {
! 901: req.cmdbuf[0] = TS102_OP_CMD_SET_BELL_FREQ;
! 902: req.cmdbuf[1] = (freq >> 8) & 0xff;
! 903: req.cmdbuf[2] = freq & 0xff;
! 904: req.cmdlen = 3;
! 905: req.rsplen = 1;
! 906:
! 907: tctrl_request(sc, &req);
! 908:
! 909: sc->sc_bellfreq = freq;
! 910: }
! 911:
! 912: /* Adjust volume if necessary */
! 913: if (volume >= 0 && volume <= 100) {
! 914: volume = (volume * 255) / 100;
! 915: if (volume != sc->sc_bellvol)
! 916: tctrl_bell(sc, 0, volume);
! 917:
! 918: }
! 919:
! 920: req.cmdbuf[0] = TS102_OP_CMD_RING_BELL;
! 921: req.cmdbuf[1] = (duration >> 8) & 0xff;
! 922: req.cmdbuf[2] = duration & 0xff;
! 923: req.cmdlen = 3;
! 924: req.rsplen = 1;
! 925:
! 926: tctrl_request(sc, &req);
! 927:
! 928: return (1);
! 929: }
! 930:
! 931: /*
! 932: * /dev/apm{,ctl} interface code
! 933: */
! 934:
! 935: #define APMUNIT(dev) (minor(dev)&0xf0)
! 936: #define APMDEV(dev) (minor(dev)&0x0f)
! 937: #define APMDEV_NORMAL 0
! 938: #define APMDEV_CTL 8
! 939:
! 940: int apmkqfilter(dev_t dev, struct knote *kn);
! 941: void filt_apmrdetach(struct knote *kn);
! 942: int filt_apmread(struct knote *kn, long hint);
! 943:
! 944: struct filterops apmread_filtops =
! 945: { 1, NULL, filt_apmrdetach, filt_apmread};
! 946:
! 947: #define SCFLAG_OREAD (1 << 0)
! 948: #define SCFLAG_OWRITE (1 << 1)
! 949: #define SCFLAG_OPEN (SCFLAG_OREAD|SCFLAG_OWRITE)
! 950:
! 951: int
! 952: apmopen(dev_t dev, int flag, int mode, struct proc *p)
! 953: {
! 954: struct tctrl_softc *sc;
! 955: int error = 0;
! 956:
! 957: if (tctrl_cd.cd_ndevs == 0 || tctrl_cd.cd_devs[0] == NULL) {
! 958: return (ENXIO);
! 959: }
! 960:
! 961: /* apm0 only */
! 962: if (APMUNIT(dev) != 0)
! 963: return (ENODEV);
! 964:
! 965: sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0];
! 966:
! 967: switch (APMDEV(dev)) {
! 968: case APMDEV_CTL:
! 969: if (!(flag & FWRITE)) {
! 970: error = EINVAL;
! 971: break;
! 972: }
! 973: if (sc->sc_apmflags & SCFLAG_OWRITE) {
! 974: error = EBUSY;
! 975: break;
! 976: }
! 977: sc->sc_apmflags |= SCFLAG_OWRITE;
! 978: break;
! 979: case APMDEV_NORMAL:
! 980: if (!(flag & FREAD) || (flag & FWRITE)) {
! 981: error = EINVAL;
! 982: break;
! 983: }
! 984: sc->sc_apmflags |= SCFLAG_OREAD;
! 985: break;
! 986: default:
! 987: error = ENXIO;
! 988: break;
! 989: }
! 990: return (error);
! 991: }
! 992:
! 993: int
! 994: apmclose(dev_t dev, int flag, int mode, struct proc *p)
! 995: {
! 996: struct tctrl_softc *sc;
! 997:
! 998: if (tctrl_cd.cd_ndevs == 0 || tctrl_cd.cd_devs[0] == NULL) {
! 999: return (ENXIO);
! 1000: }
! 1001:
! 1002: /* apm0 only */
! 1003: if (APMUNIT(dev) != 0)
! 1004: return (ENODEV);
! 1005:
! 1006: sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0];
! 1007:
! 1008: switch (APMDEV(dev)) {
! 1009: case APMDEV_CTL:
! 1010: sc->sc_apmflags &= ~SCFLAG_OWRITE;
! 1011: break;
! 1012: case APMDEV_NORMAL:
! 1013: sc->sc_apmflags &= ~SCFLAG_OREAD;
! 1014: break;
! 1015: }
! 1016: return (0);
! 1017: }
! 1018:
! 1019: int
! 1020: apmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
! 1021: {
! 1022: struct tctrl_softc *sc;
! 1023: struct tctrl_req req;
! 1024: struct apm_power_info *power;
! 1025: u_int8_t c;
! 1026: int error = 0;
! 1027:
! 1028: if (tctrl_cd.cd_ndevs == 0 || tctrl_cd.cd_devs[0] == NULL) {
! 1029: return (ENXIO);
! 1030: }
! 1031:
! 1032: /* apm0 only */
! 1033: if (APMUNIT(dev) != 0)
! 1034: return (ENODEV);
! 1035:
! 1036: sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0];
! 1037:
! 1038: switch (cmd) {
! 1039: /* some ioctl names from linux */
! 1040: case APM_IOC_STANDBY:
! 1041: if ((flag & FWRITE) == 0)
! 1042: error = EBADF;
! 1043: else
! 1044: error = EOPNOTSUPP; /* XXX */
! 1045: break;
! 1046: case APM_IOC_SUSPEND:
! 1047: if ((flag & FWRITE) == 0)
! 1048: error = EBADF;
! 1049: else
! 1050: error = EOPNOTSUPP; /* XXX */
! 1051: break;
! 1052: case APM_IOC_PRN_CTL:
! 1053: if ((flag & FWRITE) == 0)
! 1054: error = EBADF;
! 1055: else {
! 1056: int flag = *(int *)data;
! 1057: switch (flag) {
! 1058: case APM_PRINT_ON: /* enable printing */
! 1059: sc->sc_apmflags &= ~SCFLAG_PRINT;
! 1060: break;
! 1061: case APM_PRINT_OFF: /* disable printing */
! 1062: sc->sc_apmflags &= ~SCFLAG_PRINT;
! 1063: sc->sc_apmflags |= SCFLAG_NOPRINT;
! 1064: break;
! 1065: case APM_PRINT_PCT: /* disable some printing */
! 1066: sc->sc_apmflags &= ~SCFLAG_PRINT;
! 1067: sc->sc_apmflags |= SCFLAG_PCTPRINT;
! 1068: break;
! 1069: default:
! 1070: error = EINVAL;
! 1071: break;
! 1072: }
! 1073: }
! 1074: break;
! 1075: case APM_IOC_GETPOWER:
! 1076: power = (struct apm_power_info *)data;
! 1077:
! 1078: if (sc->sc_ext_status &
! 1079: TS102_EXT_STATUS_INTERNAL_BATTERY_ATTACHED) {
! 1080: req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_RATE;
! 1081: req.cmdlen = 1;
! 1082: req.rsplen = 2;
! 1083: tctrl_request(sc, &req);
! 1084: if (req.rspbuf[0] != 0)
! 1085: power->battery_state = APM_BATT_CHARGING;
! 1086: else
! 1087: power->battery_state = APM_BATT_UNKNOWN;
! 1088:
! 1089: req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_LEVEL;
! 1090: req.cmdlen = 1;
! 1091: req.rsplen = 3;
! 1092: tctrl_request(sc, &req);
! 1093:
! 1094: c = req.rspbuf[0];
! 1095: if (c >= TS102_CHARGE_UNKNOWN)
! 1096: power->battery_life = 0;
! 1097: else {
! 1098: power->battery_life = c;
! 1099: if (power->battery_state != APM_BATT_CHARGING) {
! 1100: if (c < 0x20)
! 1101: power->battery_state =
! 1102: APM_BATT_CRITICAL;
! 1103: else if (c < 0x40)
! 1104: power->battery_state =
! 1105: APM_BATT_HIGH;
! 1106: else if (c < 0x66)
! 1107: power->battery_state =
! 1108: APM_BATT_HIGH;
! 1109: }
! 1110: }
! 1111: } else {
! 1112: power->battery_state = APM_BATTERY_ABSENT;
! 1113: power->battery_life = 0;
! 1114: }
! 1115: power->minutes_left = (u_int)-1; /* unknown */
! 1116:
! 1117: if (sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE)
! 1118: power->ac_state = APM_AC_ON;
! 1119: else
! 1120: power->ac_state = APM_AC_OFF;
! 1121: break;
! 1122:
! 1123: default:
! 1124: error = ENOTTY;
! 1125: }
! 1126:
! 1127: return (error);
! 1128: }
! 1129:
! 1130: int
! 1131: apm_record_event(struct tctrl_softc *sc, u_int type)
! 1132: {
! 1133: static int apm_evindex;
! 1134:
! 1135: /* skip if no user waiting */
! 1136: if ((sc->sc_apmflags & SCFLAG_OPEN) == 0)
! 1137: return (1);
! 1138:
! 1139: apm_evindex++;
! 1140: KNOTE(&sc->sc_note, APM_EVENT_COMPOSE(type, apm_evindex));
! 1141:
! 1142: return (0);
! 1143: }
! 1144:
! 1145: void
! 1146: filt_apmrdetach(struct knote *kn)
! 1147: {
! 1148: struct tctrl_softc *sc = (struct tctrl_softc *)kn->kn_hook;
! 1149:
! 1150: SLIST_REMOVE(&sc->sc_note, kn, knote, kn_selnext);
! 1151: }
! 1152:
! 1153: int
! 1154: filt_apmread(struct knote *kn, long hint)
! 1155: {
! 1156: /* XXX weird kqueue_scan() semantics */
! 1157: if (hint && !kn->kn_data)
! 1158: kn->kn_data = (int)hint;
! 1159:
! 1160: return (1);
! 1161: }
! 1162:
! 1163: int
! 1164: apmkqfilter(dev_t dev, struct knote *kn)
! 1165: {
! 1166: struct tctrl_softc *sc;
! 1167:
! 1168: if (tctrl_cd.cd_ndevs == 0 || tctrl_cd.cd_devs[0] == NULL) {
! 1169: return (ENXIO);
! 1170: }
! 1171:
! 1172: /* apm0 only */
! 1173: if (APMUNIT(dev) != 0)
! 1174: return (ENODEV);
! 1175:
! 1176: sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0];
! 1177:
! 1178: switch (kn->kn_filter) {
! 1179: case EVFILT_READ:
! 1180: kn->kn_fop = &apmread_filtops;
! 1181: break;
! 1182: default:
! 1183: return (1);
! 1184: }
! 1185:
! 1186: kn->kn_hook = (caddr_t)sc;
! 1187: SLIST_INSERT_HEAD(&sc->sc_note, kn, kn_selnext);
! 1188:
! 1189: return (0);
! 1190: }
CVSweb