Annotation of sys/arch/sparc/dev/tctrl.c, Revision 1.1.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