Annotation of src/sys/arch/sparc/dev/tctrl.c, revision 1.35
1.35 ! ad 1: /* $NetBSD: tctrl.c,v 1.34 2006/05/14 21:56:33 elad Exp $ */
1.1 matt 2:
3: /*-
1.30 macallan 4: * Copyright (c) 1998, 2005, 2006 The NetBSD Foundation, Inc.
1.1 matt 5: * All rights reserved.
6: *
7: * This code is derived from software contributed to The NetBSD Foundation
8: * by Matt Thomas.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: * 3. All advertising materials mentioning features or use of this software
19: * must display the following acknowledgement:
20: * This product includes software developed by the NetBSD
21: * Foundation, Inc. and its contributors.
22: * 4. Neither the name of The NetBSD Foundation nor the names of its
23: * contributors may be used to endorse or promote products derived
24: * from this software without specific prior written permission.
25: *
26: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36: * POSSIBILITY OF SUCH DAMAGE.
37: */
1.25 lukem 38:
39: #include <sys/cdefs.h>
1.35 ! ad 40: __KERNEL_RCSID(0, "$NetBSD: tctrl.c,v 1.34 2006/05/14 21:56:33 elad Exp $");
1.1 matt 41:
42: #include <sys/param.h>
43: #include <sys/systm.h>
44: #include <sys/ioctl.h>
45: #include <sys/select.h>
46: #include <sys/tty.h>
47: #include <sys/proc.h>
48: #include <sys/user.h>
49: #include <sys/conf.h>
50: #include <sys/file.h>
51: #include <sys/uio.h>
52: #include <sys/kernel.h>
1.30 macallan 53: #include <sys/kthread.h>
1.1 matt 54: #include <sys/syslog.h>
55: #include <sys/types.h>
56: #include <sys/device.h>
1.4 garbled 57: #include <sys/envsys.h>
58: #include <sys/poll.h>
1.34 elad 59: #include <sys/kauth.h>
1.1 matt 60:
1.4 garbled 61: #include <machine/apmvar.h>
1.1 matt 62: #include <machine/autoconf.h>
63: #include <machine/bus.h>
1.11 pk 64: #include <machine/intr.h>
1.4 garbled 65: #include <machine/tctrl.h>
1.1 matt 66:
67: #include <sparc/dev/ts102reg.h>
68: #include <sparc/dev/tctrlvar.h>
1.7 jdc 69: #include <sparc/sparc/auxiotwo.h>
1.27 macallan 70: #include <sparc/sparc/auxreg.h>
71:
72: #include <dev/sysmon/sysmonvar.h>
73: #include <dev/sysmon/sysmon_taskq.h>
1.30 macallan 74:
1.27 macallan 75: #include "sysmon_envsys.h"
1.1 matt 76:
1.30 macallan 77: /*#define TCTRLDEBUG*/
78:
79: /* disk spinner */
80: #include <sys/disk.h>
81: #include <dev/scsipi/sdvar.h>
82:
83: /* ethernet carrier */
84: #include <net/if.h>
85: #include <net/if_dl.h>
86: #include <net/if_ether.h>
87: #include <net/if_media.h>
88: #include <dev/ic/lancevar.h>
89:
1.15 gehenna 90: extern struct cfdriver tctrl_cd;
1.4 garbled 91:
1.15 gehenna 92: dev_type_open(tctrlopen);
93: dev_type_close(tctrlclose);
94: dev_type_ioctl(tctrlioctl);
95: dev_type_poll(tctrlpoll);
1.20 jdolecek 96: dev_type_kqfilter(tctrlkqfilter);
1.15 gehenna 97:
98: const struct cdevsw tctrl_cdevsw = {
99: tctrlopen, tctrlclose, noread, nowrite, tctrlioctl,
1.20 jdolecek 100: nostop, notty, tctrlpoll, nommap, tctrlkqfilter,
1.15 gehenna 101: };
1.4 garbled 102:
1.1 matt 103: static const char *tctrl_ext_statuses[16] = {
104: "main power available",
105: "internal battery attached",
106: "external battery attached",
107: "external VGA attached",
108: "external keyboard attached",
109: "external mouse attached",
110: "lid down",
111: "internal battery charging",
112: "external battery charging",
113: "internal battery discharging",
114: "external battery discharging",
115: };
116:
117: struct tctrl_softc {
1.4 garbled 118: struct device sc_dev;
119: bus_space_tag_t sc_memt;
120: bus_space_handle_t sc_memh;
121: unsigned int sc_junk;
122: unsigned int sc_ext_status;
123: unsigned int sc_flags;
124: #define TCTRL_SEND_REQUEST 0x0001
125: #define TCTRL_APM_CTLOPEN 0x0002
1.30 macallan 126: uint32_t sc_wantdata;
127: uint32_t sc_ext_pending;
128: volatile uint16_t sc_lcdstate;
129: uint16_t sc_lcdwanted;
130:
1.1 matt 131: enum { TCTRL_IDLE, TCTRL_ARGS,
132: TCTRL_ACK, TCTRL_DATA } sc_state;
1.28 uwe 133: uint8_t sc_cmdbuf[16];
134: uint8_t sc_rspbuf[16];
135: uint8_t sc_bitport;
136: uint8_t sc_tft_on;
137: uint8_t sc_op;
138: uint8_t sc_cmdoff;
139: uint8_t sc_cmdlen;
140: uint8_t sc_rspoff;
141: uint8_t sc_rsplen;
1.4 garbled 142: /* APM stuff */
143: #define APM_NEVENTS 16
144: struct apm_event_info sc_event_list[APM_NEVENTS];
145: int sc_event_count;
146: int sc_event_ptr;
147: struct selinfo sc_rsel;
1.27 macallan 148:
1.4 garbled 149: /* ENVSYS stuff */
150: #define ENVSYS_NUMSENSORS 3
151: struct evcnt sc_intrcnt; /* interrupt counting */
1.27 macallan 152: struct sysmon_envsys sc_sme;
153: struct envsys_tre_data sc_tre[ENVSYS_NUMSENSORS];
154: struct envsys_basic_info sc_binfo[ENVSYS_NUMSENSORS];
155: struct envsys_range sc_range[ENVSYS_NUMSENSORS];
1.28 uwe 156:
1.31 macallan 157: struct sysmon_pswitch sc_sm_pbutton; /* power button */
158: struct sysmon_pswitch sc_sm_lid; /* lid state */
159: struct sysmon_pswitch sc_sm_ac; /* AC adaptor presence */
1.27 macallan 160: int sc_powerpressed;
1.30 macallan 161:
162: /* hardware status stuff */
163: int sc_lid; /* 1 - open, 0 - closed */
164: int sc_power_state;
165: int sc_spl;
166:
167: /*
168: * we call this when we detect connection or removal of an external
169: * monitor. 0 for no monitor, !=0 for monitor present
170: */
171: void (*sc_video_callback)(void *, int);
172: void *sc_video_callback_cookie;
173: int sc_extvga;
174:
175: uint32_t sc_events;
176: struct proc *sc_thread; /* event thread */
177:
178: struct lock sc_requestlock;
1.1 matt 179: };
180:
1.4 garbled 181: #define TCTRL_STD_DEV 0
182: #define TCTRL_APMCTL_DEV 8
1.1 matt 183:
1.28 uwe 184: static int tctrl_match(struct device *, struct cfdata *, void *);
185: static void tctrl_attach(struct device *, struct device *, void *);
186: static void tctrl_write(struct tctrl_softc *, bus_size_t, uint8_t);
187: static uint8_t tctrl_read(struct tctrl_softc *, bus_size_t);
188: static void tctrl_write_data(struct tctrl_softc *, uint8_t);
189: static uint8_t tctrl_read_data(struct tctrl_softc *);
190: static int tctrl_intr(void *);
191: static void tctrl_setup_bitport(void);
192: static void tctrl_setup_bitport_nop(void);
193: static void tctrl_read_ext_status(void);
1.30 macallan 194: static void tctrl_read_event_status(struct tctrl_softc *);
1.28 uwe 195: static int tctrl_apm_record_event(struct tctrl_softc *, u_int);
196: static void tctrl_init_lcd(void);
1.1 matt 197:
1.27 macallan 198: static void tctrl_sensor_setup(struct tctrl_softc *);
199: static int tctrl_gtredata(struct sysmon_envsys *, struct envsys_tre_data *);
200: static int tctrl_streinfo(struct sysmon_envsys *, struct envsys_basic_info *);
201:
202: static void tctrl_power_button_pressed(void *);
1.31 macallan 203: static void tctrl_lid_state(struct tctrl_softc *);
204: static void tctrl_ac_state(struct tctrl_softc *);
205:
1.27 macallan 206: static int tctrl_powerfail(void *);
207:
1.30 macallan 208: static void tctrl_create_event_thread(void *);
209: static void tctrl_event_thread(void *);
210: void tctrl_update_lcd(struct tctrl_softc *);
211:
212: static void tctrl_lock(struct tctrl_softc *);
213: static void tctrl_unlock(struct tctrl_softc *);
214:
1.17 thorpej 215: CFATTACH_DECL(tctrl, sizeof(struct tctrl_softc),
1.18 thorpej 216: tctrl_match, tctrl_attach, NULL, NULL);
1.1 matt 217:
1.28 uwe 218:
1.4 garbled 219: /* XXX wtf is this? see i386/apm.c */
220: int tctrl_apm_evindex;
1.1 matt 221:
222: static int
1.28 uwe 223: tctrl_match(struct device *parent, struct cfdata *cf, void *aux)
1.1 matt 224: {
225: union obio_attach_args *uoba = aux;
226: struct sbus_attach_args *sa = &uoba->uoba_sbus;
227:
228: if (uoba->uoba_isobio4 != 0) {
229: return (0);
230: }
231:
232: /* Tadpole 3GX/3GS uses "uctrl" for the Tadpole Microcontroller
233: * (who's interface is off the TS102 PCMCIA controller but there
234: * exists a OpenProm for microcontroller interface).
235: */
236: return strcmp("uctrl", sa->sa_name) == 0;
237: }
238:
239: static void
1.28 uwe 240: tctrl_attach(struct device *parent, struct device *self, void *aux)
1.1 matt 241: {
242: struct tctrl_softc *sc = (void *)self;
243: union obio_attach_args *uoba = aux;
244: struct sbus_attach_args *sa = &uoba->uoba_sbus;
1.2 matt 245: unsigned int i, v;
1.1 matt 246:
247: /* We're living on a sbus slot that looks like an obio that
248: * looks like an sbus slot.
249: */
250: sc->sc_memt = sa->sa_bustag;
1.14 pk 251: if (sbus_bus_map(sc->sc_memt,
252: sa->sa_slot,
253: sa->sa_offset - TS102_REG_UCTRL_INT,
254: sa->sa_size,
255: BUS_SPACE_MAP_LINEAR, &sc->sc_memh) != 0) {
1.1 matt 256: printf(": can't map registers\n");
257: return;
258: }
259:
1.2 matt 260: printf("\n");
261:
1.1 matt 262: sc->sc_tft_on = 1;
1.2 matt 263:
1.1 matt 264: /* clear any pending data.
265: */
266: for (i = 0; i < 10000; i++) {
1.4 garbled 267: if ((TS102_UCTRL_STS_RXNE_STA &
268: tctrl_read(sc, TS102_REG_UCTRL_STS)) == 0) {
1.1 matt 269: break;
270: }
271: v = tctrl_read(sc, TS102_REG_UCTRL_DATA);
1.2 matt 272: tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA);
1.1 matt 273: }
274:
1.3 pk 275: if (sa->sa_nintr != 0) {
1.11 pk 276: (void)bus_intr_establish(sc->sc_memt, sa->sa_pri, IPL_NONE,
1.22 pk 277: tctrl_intr, sc);
1.10 cgd 278: evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, NULL,
1.22 pk 279: sc->sc_dev.dv_xname, "intr");
1.3 pk 280: }
1.2 matt 281:
1.27 macallan 282: /* See what the external status is */
1.30 macallan 283: sc->sc_ext_status = 0;
1.4 garbled 284: tctrl_read_ext_status();
1.2 matt 285: if (sc->sc_ext_status != 0) {
286: const char *sep;
1.1 matt 287:
288: printf("%s: ", sc->sc_dev.dv_xname);
1.2 matt 289: v = sc->sc_ext_status;
1.1 matt 290: for (i = 0, sep = ""; v != 0; i++, v >>= 1) {
291: if (v & 1) {
292: printf("%s%s", sep, tctrl_ext_statuses[i]);
293: sep = ", ";
294: }
295: }
296: printf("\n");
297: }
298:
1.27 macallan 299: /* Get a current of the control bitport */
1.4 garbled 300: tctrl_setup_bitport_nop();
1.2 matt 301: tctrl_write(sc, TS102_REG_UCTRL_INT,
302: TS102_UCTRL_INT_RXNE_REQ|TS102_UCTRL_INT_RXNE_MSK);
1.30 macallan 303: sc->sc_lid = (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) == 0;
304: sc->sc_power_state = PWR_RESUME;
305:
306: sc->sc_extvga = (sc->sc_ext_status &
307: TS102_EXT_STATUS_EXTERNAL_VGA_ATTACHED) != 0;
308: sc->sc_video_callback = NULL;
309:
310:
1.4 garbled 311: sc->sc_wantdata = 0;
312: sc->sc_event_count = 0;
1.30 macallan 313: sc->sc_ext_pending = 0;
314: sc->sc_ext_pending = 0;
1.4 garbled 315:
1.30 macallan 316: lockinit(&sc->sc_requestlock, PUSER, "tctrl_req", 0, 0);
1.27 macallan 317: /* setup sensors and register the power button */
318: tctrl_sensor_setup(sc);
1.31 macallan 319: tctrl_lid_state(sc);
320: tctrl_ac_state(sc);
1.28 uwe 321:
1.6 garbled 322: /* initialize the LCD */
323: tctrl_init_lcd();
324:
325: /* initialize sc_lcdstate */
326: sc->sc_lcdstate = 0;
1.30 macallan 327: sc->sc_lcdwanted = 0;
328: tadpole_set_lcd(2, 0);
329:
330: /* fire up the LCD event thread */
331: sc->sc_events = 0;
332: kthread_create(tctrl_create_event_thread, sc);
1.1 matt 333: }
334:
335: static int
1.28 uwe 336: tctrl_intr(void *arg)
1.1 matt 337: {
338: struct tctrl_softc *sc = arg;
339: unsigned int v, d;
340: int progress = 0;
341:
342: again:
343: /* find out the cause(s) of the interrupt */
1.12 toddpw 344: v = tctrl_read(sc, TS102_REG_UCTRL_STS) & TS102_UCTRL_STS_MASK;
1.1 matt 345:
346: /* clear the cause(s) of the interrupt */
347: tctrl_write(sc, TS102_REG_UCTRL_STS, v);
348:
1.2 matt 349: v &= ~(TS102_UCTRL_STS_RXO_STA|TS102_UCTRL_STS_TXE_STA);
1.1 matt 350: if (sc->sc_cmdoff >= sc->sc_cmdlen) {
1.2 matt 351: v &= ~TS102_UCTRL_STS_TXNF_STA;
1.28 uwe 352: if (tctrl_read(sc, TS102_REG_UCTRL_INT) &
1.27 macallan 353: TS102_UCTRL_INT_TXNF_REQ) {
1.4 garbled 354: tctrl_write(sc, TS102_REG_UCTRL_INT, 0);
355: progress = 1;
356: }
1.1 matt 357: }
1.4 garbled 358: if ((v == 0) && ((sc->sc_flags & TCTRL_SEND_REQUEST) == 0 ||
359: sc->sc_state != TCTRL_IDLE)) {
360: wakeup(sc);
1.1 matt 361: return progress;
362: }
363:
364: progress = 1;
1.2 matt 365: if (v & TS102_UCTRL_STS_RXNE_STA) {
1.1 matt 366: d = tctrl_read_data(sc);
367: switch (sc->sc_state) {
368: case TCTRL_IDLE:
1.2 matt 369: if (d == 0xfa) {
1.30 macallan 370: /*
371: * external event,
372: * set a flag and wakeup the event thread
373: */
374: sc->sc_ext_pending = 1;
1.2 matt 375: } else {
376: printf("%s: (op=0x%02x): unexpected data (0x%02x)\n",
377: sc->sc_dev.dv_xname, sc->sc_op, d);
1.1 matt 378: }
1.2 matt 379: goto again;
1.1 matt 380: case TCTRL_ACK:
381: if (d != 0xfe) {
1.2 matt 382: printf("%s: (op=0x%02x): unexpected ack value (0x%02x)\n",
1.1 matt 383: sc->sc_dev.dv_xname, sc->sc_op, d);
384: }
1.4 garbled 385: #ifdef TCTRLDEBUG
1.2 matt 386: printf(" ack=0x%02x", d);
387: #endif
388: sc->sc_rsplen--;
389: sc->sc_rspoff = 0;
1.1 matt 390: sc->sc_state = sc->sc_rsplen ? TCTRL_DATA : TCTRL_IDLE;
1.4 garbled 391: sc->sc_wantdata = sc->sc_rsplen ? 1 : 0;
392: #ifdef TCTRLDEBUG
1.2 matt 393: if (sc->sc_rsplen > 0) {
394: printf(" [data(%u)]", sc->sc_rsplen);
395: } else {
396: printf(" [idle]\n");
397: }
398: #endif
399: goto again;
1.1 matt 400: case TCTRL_DATA:
401: sc->sc_rspbuf[sc->sc_rspoff++] = d;
1.4 garbled 402: #ifdef TCTRLDEBUG
1.2 matt 403: printf(" [%d]=0x%02x", sc->sc_rspoff-1, d);
404: #endif
1.1 matt 405: if (sc->sc_rspoff == sc->sc_rsplen) {
1.4 garbled 406: #ifdef TCTRLDEBUG
1.2 matt 407: printf(" [idle]\n");
408: #endif
1.1 matt 409: sc->sc_state = TCTRL_IDLE;
1.4 garbled 410: sc->sc_wantdata = 0;
1.1 matt 411: }
1.2 matt 412: goto again;
1.1 matt 413: default:
414: printf("%s: (op=0x%02x): unexpected data (0x%02x) in state %d\n",
415: sc->sc_dev.dv_xname, sc->sc_op, d, sc->sc_state);
1.2 matt 416: goto again;
1.1 matt 417: }
418: }
1.4 garbled 419: if ((sc->sc_state == TCTRL_IDLE && sc->sc_wantdata == 0) ||
420: sc->sc_flags & TCTRL_SEND_REQUEST) {
421: if (sc->sc_flags & TCTRL_SEND_REQUEST) {
422: sc->sc_flags &= ~TCTRL_SEND_REQUEST;
423: sc->sc_wantdata = 1;
424: }
1.1 matt 425: if (sc->sc_cmdlen > 0) {
426: tctrl_write(sc, TS102_REG_UCTRL_INT,
427: tctrl_read(sc, TS102_REG_UCTRL_INT)
428: |TS102_UCTRL_INT_TXNF_MSK
429: |TS102_UCTRL_INT_TXNF_REQ);
430: v = tctrl_read(sc, TS102_REG_UCTRL_STS);
431: }
432: }
1.2 matt 433: if ((sc->sc_cmdoff < sc->sc_cmdlen) && (v & TS102_UCTRL_STS_TXNF_STA)) {
1.1 matt 434: tctrl_write_data(sc, sc->sc_cmdbuf[sc->sc_cmdoff++]);
1.4 garbled 435: #ifdef TCTRLDEBUG
1.2 matt 436: if (sc->sc_cmdoff == 1) {
437: printf("%s: op=0x%02x(l=%u)", sc->sc_dev.dv_xname,
438: sc->sc_cmdbuf[0], sc->sc_rsplen);
439: } else {
440: printf(" [%d]=0x%02x", sc->sc_cmdoff-1,
441: sc->sc_cmdbuf[sc->sc_cmdoff-1]);
442: }
443: #endif
1.1 matt 444: if (sc->sc_cmdoff == sc->sc_cmdlen) {
445: sc->sc_state = sc->sc_rsplen ? TCTRL_ACK : TCTRL_IDLE;
1.4 garbled 446: #ifdef TCTRLDEBUG
1.2 matt 447: printf(" %s", sc->sc_rsplen ? "[ack]" : "[idle]\n");
448: #endif
449: if (sc->sc_cmdoff == 1) {
450: sc->sc_op = sc->sc_cmdbuf[0];
451: }
1.1 matt 452: tctrl_write(sc, TS102_REG_UCTRL_INT,
453: tctrl_read(sc, TS102_REG_UCTRL_INT)
454: & (~TS102_UCTRL_INT_TXNF_MSK
455: |TS102_UCTRL_INT_TXNF_REQ));
456: } else if (sc->sc_state == TCTRL_IDLE) {
457: sc->sc_op = sc->sc_cmdbuf[0];
458: sc->sc_state = TCTRL_ARGS;
1.4 garbled 459: #ifdef TCTRLDEBUG
1.2 matt 460: printf(" [args]");
461: #endif
1.1 matt 462: }
463: }
464: goto again;
465: }
466:
467: static void
1.4 garbled 468: tctrl_setup_bitport_nop(void)
469: {
470: struct tctrl_softc *sc;
471: struct tctrl_req req;
472: int s;
1.28 uwe 473:
1.4 garbled 474: sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
475: req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
476: req.cmdbuf[1] = 0xff;
1.30 macallan 477: req.cmdbuf[2] = 0x00;
1.4 garbled 478: req.cmdlen = 3;
479: req.rsplen = 2;
480: req.p = NULL;
481: tadpole_request(&req, 1);
482: s = splts102();
483: sc->sc_bitport = (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
484: splx(s);
485: }
486:
487: static void
488: tctrl_setup_bitport(void)
1.1 matt 489: {
1.4 garbled 490: struct tctrl_softc *sc;
491: struct tctrl_req req;
492: int s;
1.28 uwe 493:
1.4 garbled 494: sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
495: s = splts102();
1.30 macallan 496: req.cmdbuf[2] = 0;
1.4 garbled 497: if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN)
498: || (!sc->sc_tft_on)) {
499: req.cmdbuf[2] = TS102_BITPORT_TFTPWR;
500: }
501: req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
502: req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR;
503: req.cmdlen = 3;
504: req.rsplen = 2;
505: req.p = NULL;
506: tadpole_request(&req, 1);
507: s = splts102();
508: sc->sc_bitport = (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
509: splx(s);
510: }
511:
1.6 garbled 512: /*
513: * The tadpole microcontroller is not preprogrammed with icon
514: * representations. The machine boots with the DC-IN light as
515: * a blank (all 0x00) and the other lights, as 4 rows of horizontal
516: * bars. The below code initializes the icons in the system to
517: * sane values. Some of these icons could be used for any purpose
518: * desired, namely the pcmcia, LAN and WAN lights. For the disk spinner,
519: * only the backslash is unprogrammed. (sigh)
520: *
521: * programming the icons is simple. It is a 5x8 matrix, which each row a
522: * bitfield in the order 0x10 0x08 0x04 0x02 0x01.
523: */
524:
525: static void
526: tctrl_init_lcd(void)
527: {
528: struct tctrl_req req;
529:
530: req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
531: req.cmdlen = 11;
532: req.rsplen = 1;
533: req.cmdbuf[1] = 0x08; /*len*/
534: req.cmdbuf[2] = TS102_BLK_OFF_DEF_DC_GOOD;
535: req.cmdbuf[3] = 0x00; /* ..... */
536: req.cmdbuf[4] = 0x00; /* ..... */
537: req.cmdbuf[5] = 0x1f; /* XXXXX */
538: req.cmdbuf[6] = 0x00; /* ..... */
539: req.cmdbuf[7] = 0x15; /* X.X.X */
540: req.cmdbuf[8] = 0x00; /* ..... */
541: req.cmdbuf[9] = 0x00; /* ..... */
542: req.cmdbuf[10] = 0x00; /* ..... */
543: req.p = NULL;
544: tadpole_request(&req, 1);
545:
546: req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
547: req.cmdlen = 11;
548: req.rsplen = 1;
549: req.cmdbuf[1] = 0x08; /*len*/
550: req.cmdbuf[2] = TS102_BLK_OFF_DEF_BACKSLASH;
551: req.cmdbuf[3] = 0x00; /* ..... */
552: req.cmdbuf[4] = 0x10; /* X.... */
553: req.cmdbuf[5] = 0x08; /* .X... */
554: req.cmdbuf[6] = 0x04; /* ..X.. */
555: req.cmdbuf[7] = 0x02; /* ...X. */
556: req.cmdbuf[8] = 0x01; /* ....X */
557: req.cmdbuf[9] = 0x00; /* ..... */
558: req.cmdbuf[10] = 0x00; /* ..... */
559: req.p = NULL;
560: tadpole_request(&req, 1);
561:
562: req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
563: req.cmdlen = 11;
564: req.rsplen = 1;
565: req.cmdbuf[1] = 0x08; /*len*/
566: req.cmdbuf[2] = TS102_BLK_OFF_DEF_WAN1;
567: req.cmdbuf[3] = 0x0c; /* .XXX. */
568: req.cmdbuf[4] = 0x16; /* X.XX. */
569: req.cmdbuf[5] = 0x10; /* X.... */
570: req.cmdbuf[6] = 0x15; /* X.X.X */
571: req.cmdbuf[7] = 0x10; /* X.... */
572: req.cmdbuf[8] = 0x16; /* X.XX. */
573: req.cmdbuf[9] = 0x0c; /* .XXX. */
574: req.cmdbuf[10] = 0x00; /* ..... */
575: req.p = NULL;
576: tadpole_request(&req, 1);
577:
578: req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
579: req.cmdlen = 11;
580: req.rsplen = 1;
581: req.cmdbuf[1] = 0x08; /*len*/
582: req.cmdbuf[2] = TS102_BLK_OFF_DEF_WAN2;
583: req.cmdbuf[3] = 0x0c; /* .XXX. */
584: req.cmdbuf[4] = 0x0d; /* .XX.X */
585: req.cmdbuf[5] = 0x01; /* ....X */
586: req.cmdbuf[6] = 0x15; /* X.X.X */
587: req.cmdbuf[7] = 0x01; /* ....X */
588: req.cmdbuf[8] = 0x0d; /* .XX.X */
589: req.cmdbuf[9] = 0x0c; /* .XXX. */
590: req.cmdbuf[10] = 0x00; /* ..... */
591: req.p = NULL;
592: tadpole_request(&req, 1);
593:
594: req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
595: req.cmdlen = 11;
596: req.rsplen = 1;
597: req.cmdbuf[1] = 0x08; /*len*/
598: req.cmdbuf[2] = TS102_BLK_OFF_DEF_LAN1;
599: req.cmdbuf[3] = 0x00; /* ..... */
600: req.cmdbuf[4] = 0x04; /* ..X.. */
601: req.cmdbuf[5] = 0x08; /* .X... */
602: req.cmdbuf[6] = 0x13; /* X..XX */
603: req.cmdbuf[7] = 0x08; /* .X... */
604: req.cmdbuf[8] = 0x04; /* ..X.. */
605: req.cmdbuf[9] = 0x00; /* ..... */
606: req.cmdbuf[10] = 0x00; /* ..... */
607: req.p = NULL;
608: tadpole_request(&req, 1);
609:
610: req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
611: req.cmdlen = 11;
612: req.rsplen = 1;
613: req.cmdbuf[1] = 0x08; /*len*/
614: req.cmdbuf[2] = TS102_BLK_OFF_DEF_LAN2;
615: req.cmdbuf[3] = 0x00; /* ..... */
616: req.cmdbuf[4] = 0x04; /* ..X.. */
617: req.cmdbuf[5] = 0x02; /* ...X. */
618: req.cmdbuf[6] = 0x19; /* XX..X */
619: req.cmdbuf[7] = 0x02; /* ...X. */
620: req.cmdbuf[8] = 0x04; /* ..X.. */
621: req.cmdbuf[9] = 0x00; /* ..... */
622: req.cmdbuf[10] = 0x00; /* ..... */
623: req.p = NULL;
624: tadpole_request(&req, 1);
625:
626: req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
627: req.cmdlen = 11;
628: req.rsplen = 1;
629: req.cmdbuf[1] = 0x08; /*len*/
630: req.cmdbuf[2] = TS102_BLK_OFF_DEF_PCMCIA;
631: req.cmdbuf[3] = 0x00; /* ..... */
632: req.cmdbuf[4] = 0x0c; /* .XXX. */
633: req.cmdbuf[5] = 0x1f; /* XXXXX */
634: req.cmdbuf[6] = 0x1f; /* XXXXX */
635: req.cmdbuf[7] = 0x1f; /* XXXXX */
636: req.cmdbuf[8] = 0x1f; /* XXXXX */
637: req.cmdbuf[9] = 0x00; /* ..... */
638: req.cmdbuf[10] = 0x00; /* ..... */
639: req.p = NULL;
640: tadpole_request(&req, 1);
641: }
642:
1.30 macallan 643: /* sc_lcdwanted -> lcd_state */
1.6 garbled 644: void
1.30 macallan 645: tctrl_update_lcd(struct tctrl_softc *sc)
1.6 garbled 646: {
647: struct tctrl_req req;
648: int s;
1.27 macallan 649:
1.30 macallan 650: s = splhigh();
651: if (sc->sc_lcdwanted == sc->sc_lcdstate) {
1.6 garbled 652: splx(s);
653: return;
654: }
1.30 macallan 655: sc->sc_lcdstate = sc->sc_lcdwanted;
656: splx(s);
657:
1.6 garbled 658: /*
659: * the mask setup on this particular command is *very* bizzare
660: * and totally undocumented.
661: */
662: req.cmdbuf[0] = TS102_OP_CTL_LCD;
1.28 uwe 663:
1.30 macallan 664: /* leave caps-lock alone */
665: req.cmdbuf[2] = (u_int8_t)(sc->sc_lcdstate & 0xfe);
666: req.cmdbuf[3] = (u_int8_t)((sc->sc_lcdstate & 0x100)>>8);
667:
668: req.cmdbuf[1] = 1;
669: req.cmdbuf[4] = 0;
670:
1.6 garbled 671:
1.13 wiz 672: /* XXX this thing is weird.... */
1.6 garbled 673: req.cmdlen = 3;
674: req.rsplen = 2;
1.30 macallan 675:
1.27 macallan 676: /* below are the values one would expect but which won't work */
1.6 garbled 677: #if 0
678: req.cmdlen = 5;
679: req.rsplen = 4;
680: #endif
681: req.p = NULL;
682: tadpole_request(&req, 1);
1.30 macallan 683: }
1.27 macallan 684:
1.30 macallan 685:
686: /*
687: * set the blinken-lights on the lcd. what:
688: * what = 0 off, what = 1 on, what = 2 toggle
689: */
690:
691: void
692: tadpole_set_lcd(int what, unsigned short which)
693: {
694: struct tctrl_softc *sc;
695: int s;
696:
697: sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
698:
699: s = splhigh();
700: switch (what) {
701: case 0:
702: sc->sc_lcdwanted &= ~which;
703: break;
704: case 1:
705: sc->sc_lcdwanted |= which;
706: break;
707: case 2:
708: sc->sc_lcdwanted ^= which;
709: break;
710: }
1.6 garbled 711: splx(s);
712: }
713:
1.4 garbled 714: static void
715: tctrl_read_ext_status(void)
716: {
717: struct tctrl_softc *sc;
718: struct tctrl_req req;
719: int s;
1.28 uwe 720:
1.4 garbled 721: sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
722: req.cmdbuf[0] = TS102_OP_RD_EXT_STATUS;
723: req.cmdlen = 1;
724: req.rsplen = 3;
725: req.p = NULL;
726: #ifdef TCTRLDEBUG
727: printf("pre read: sc->sc_ext_status = 0x%x\n", sc->sc_ext_status);
728: #endif
729: tadpole_request(&req, 1);
730: s = splts102();
1.30 macallan 731: sc->sc_ext_status = (req.rspbuf[0] << 8) + req.rspbuf[1];
1.4 garbled 732: splx(s);
733: #ifdef TCTRLDEBUG
734: printf("post read: sc->sc_ext_status = 0x%x\n", sc->sc_ext_status);
735: #endif
736: }
737:
738: /*
739: * return 0 if the user will notice and handle the event,
740: * return 1 if the kernel driver should do so.
741: */
742: static int
1.28 uwe 743: tctrl_apm_record_event(struct tctrl_softc *sc, u_int event_type)
1.4 garbled 744: {
745: struct apm_event_info *evp;
746:
747: if ((sc->sc_flags & TCTRL_APM_CTLOPEN) &&
748: (sc->sc_event_count < APM_NEVENTS)) {
749: evp = &sc->sc_event_list[sc->sc_event_ptr];
750: sc->sc_event_count++;
751: sc->sc_event_ptr++;
752: sc->sc_event_ptr %= APM_NEVENTS;
753: evp->type = event_type;
754: evp->index = ++tctrl_apm_evindex;
1.20 jdolecek 755: selnotify(&sc->sc_rsel, 0);
1.4 garbled 756: return(sc->sc_flags & TCTRL_APM_CTLOPEN) ? 0 : 1;
1.1 matt 757: }
1.4 garbled 758: return(1);
1.1 matt 759: }
760:
761: static void
1.30 macallan 762: tctrl_read_event_status(struct tctrl_softc *sc)
1.1 matt 763: {
1.4 garbled 764: struct tctrl_req req;
1.30 macallan 765: int s, lid;
766: uint32_t v;
1.28 uwe 767:
1.4 garbled 768: req.cmdbuf[0] = TS102_OP_RD_EVENT_STATUS;
769: req.cmdlen = 1;
770: req.rsplen = 3;
771: req.p = NULL;
772: tadpole_request(&req, 1);
773: s = splts102();
774: v = req.rspbuf[0] * 256 + req.rspbuf[1];
1.27 macallan 775: #ifdef TCTRLDEBUG
776: printf("event: %x\n",v);
777: #endif
1.28 uwe 778: if (v & TS102_EVENT_STATUS_POWERON_BTN_PRESSED) {
1.27 macallan 779: printf("%s: Power button pressed\n",sc->sc_dev.dv_xname);
780: tctrl_powerfail(sc);
781: }
1.4 garbled 782: if (v & TS102_EVENT_STATUS_SHUTDOWN_REQUEST) {
783: printf("%s: SHUTDOWN REQUEST!\n", sc->sc_dev.dv_xname);
1.30 macallan 784: tctrl_powerfail(sc);
1.4 garbled 785: }
786: if (v & TS102_EVENT_STATUS_VERY_LOW_POWER_WARNING) {
787: /*printf("%s: VERY LOW POWER WARNING!\n", sc->sc_dev.dv_xname);*/
788: /* according to a tadpole header, and observation */
789: #ifdef TCTRLDEBUG
1.28 uwe 790: printf("%s: Battery charge level change\n",
1.27 macallan 791: sc->sc_dev.dv_xname);
1.4 garbled 792: #endif
1.1 matt 793: }
1.4 garbled 794: if (v & TS102_EVENT_STATUS_LOW_POWER_WARNING) {
795: if (tctrl_apm_record_event(sc, APM_BATTERY_LOW))
1.1 matt 796: printf("%s: LOW POWER WARNING!\n", sc->sc_dev.dv_xname);
1.4 garbled 797: }
798: if (v & TS102_EVENT_STATUS_DC_STATUS_CHANGE) {
799: splx(s);
800: tctrl_read_ext_status();
1.31 macallan 801: tctrl_ac_state(sc);
1.4 garbled 802: s = splts102();
803: if (tctrl_apm_record_event(sc, APM_POWER_CHANGE))
1.1 matt 804: printf("%s: main power %s\n", sc->sc_dev.dv_xname,
1.4 garbled 805: (sc->sc_ext_status &
806: TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ?
807: "restored" : "removed");
808: }
809: if (v & TS102_EVENT_STATUS_LID_STATUS_CHANGE) {
810: splx(s);
811: tctrl_read_ext_status();
1.31 macallan 812: tctrl_lid_state(sc);
1.4 garbled 813: tctrl_setup_bitport();
814: #ifdef TCTRLDEBUG
815: printf("%s: lid %s\n", sc->sc_dev.dv_xname,
816: (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN)
817: ? "closed" : "opened");
1.2 matt 818: #endif
1.30 macallan 819: lid = (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) == 0;
820: }
821: if (v & TS102_EVENT_STATUS_EXTERNAL_VGA_STATUS_CHANGE) {
822: int vga;
823: splx(s);
824: tctrl_read_ext_status();
825: vga = (sc->sc_ext_status &
826: TS102_EXT_STATUS_EXTERNAL_VGA_ATTACHED) != 0;
827: if (vga != sc->sc_extvga) {
828: sc->sc_extvga = vga;
829: if (sc->sc_video_callback != NULL) {
830: sc->sc_video_callback(
831: sc->sc_video_callback_cookie,
832: sc->sc_extvga);
833: }
834: }
835: }
836: #ifdef DIAGNOSTIC
837: if (v & TS102_EVENT_STATUS_EXT_MOUSE_STATUS_CHANGE) {
838: splx(s);
839: tctrl_read_ext_status();
840: if (sc->sc_ext_status &
841: TS102_EXT_STATUS_EXTERNAL_MOUSE_ATTACHED) {
842: printf("tctrl: external mouse detected\n");
843: }
1.1 matt 844: }
1.30 macallan 845: #endif
846: sc->sc_ext_pending = 0;
1.4 garbled 847: splx(s);
1.1 matt 848: }
849:
1.30 macallan 850: static void
851: tctrl_lock(struct tctrl_softc *sc)
852: {
853:
854: lockmgr(&sc->sc_requestlock, LK_EXCLUSIVE, NULL);
855: }
856:
857: static void
858: tctrl_unlock(struct tctrl_softc *sc)
859: {
860:
861: lockmgr(&sc->sc_requestlock, LK_RELEASE, NULL);
862: }
863:
864: int
1.28 uwe 865: tadpole_request(struct tctrl_req *req, int spin)
1.1 matt 866: {
867: struct tctrl_softc *sc;
868: int i, s;
869:
870: if (tctrl_cd.cd_devs == NULL
871: || tctrl_cd.cd_ndevs == 0
1.4 garbled 872: || tctrl_cd.cd_devs[TCTRL_STD_DEV] == NULL) {
1.30 macallan 873: return ENODEV;
1.1 matt 874: }
875:
1.4 garbled 876: sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
1.30 macallan 877: tctrl_lock(sc);
878:
1.4 garbled 879: if (spin)
880: s = splhigh();
881: else
882: s = splts102();
883: sc->sc_flags |= TCTRL_SEND_REQUEST;
884: memcpy(sc->sc_cmdbuf, req->cmdbuf, req->cmdlen);
1.30 macallan 885: #ifdef DIAGNOSTIC
886: if (sc->sc_wantdata != 0) {
887: splx(s);
888: printf("tctrl: we lost the race\n");
889: tctrl_unlock(sc);
890: return EAGAIN;
891: }
892: #endif
1.4 garbled 893: sc->sc_wantdata = 1;
894: sc->sc_rsplen = req->rsplen;
895: sc->sc_cmdlen = req->cmdlen;
896: sc->sc_cmdoff = sc->sc_rspoff = 0;
897:
898: /* we spin for certain commands, like poweroffs */
899: if (spin) {
1.6 garbled 900: /* for (i = 0; i < 30000; i++) {*/
1.30 macallan 901: i = 0;
902: while ((sc->sc_wantdata == 1) && (i < 30000)) {
1.4 garbled 903: tctrl_intr(sc);
904: DELAY(1);
1.30 macallan 905: i++;
1.4 garbled 906: }
1.30 macallan 907: #ifdef DIAGNOSTIC
908: if (i >= 30000) {
909: printf("tctrl: timeout busy waiting for micro controller request!\n");
910: sc->sc_wantdata = 0;
911: splx(s);
912: tctrl_unlock(sc);
913: return EAGAIN;
914: }
915: #endif
1.4 garbled 916: } else {
1.30 macallan 917: int timeout = 5 * (sc->sc_rsplen + sc->sc_cmdlen);
1.1 matt 918: tctrl_intr(sc);
1.5 garbled 919: i = 0;
920: while (((sc->sc_rspoff != sc->sc_rsplen) ||
921: (sc->sc_cmdoff != sc->sc_cmdlen)) &&
1.30 macallan 922: (i < timeout))
1.5 garbled 923: if (req->p != NULL) {
924: tsleep(sc, PWAIT, "tctrl_data", 15);
925: i++;
1.30 macallan 926: } else
1.4 garbled 927: DELAY(1);
1.30 macallan 928: #ifdef DIAGNOSTIC
929: if (i >= timeout) {
930: printf("tctrl: timeout waiting for microcontroller request\n");
931: sc->sc_wantdata = 0;
932: splx(s);
933: tctrl_unlock(sc);
934: return EAGAIN;
935: }
936: #endif
1.1 matt 937: }
1.5 garbled 938: /*
939: * we give the user a reasonable amount of time for a command
940: * to complete. If it doesn't complete in time, we hand them
941: * garbage. This is here to stop things like setting the
942: * rsplen too long, and sleeping forever in a CMD_REQ ioctl.
943: */
944: sc->sc_wantdata = 0;
1.4 garbled 945: memcpy(req->rspbuf, sc->sc_rspbuf, req->rsplen);
1.1 matt 946: splx(s);
1.30 macallan 947:
948: tctrl_unlock(sc);
949: return 0;
1.1 matt 950: }
951:
952: void
1.4 garbled 953: tadpole_powerdown(void)
954: {
955: struct tctrl_req req;
1.28 uwe 956:
1.4 garbled 957: req.cmdbuf[0] = TS102_OP_ADMIN_POWER_OFF;
958: req.cmdlen = 1;
959: req.rsplen = 1;
960: req.p = NULL;
961: tadpole_request(&req, 1);
962: }
963:
964: void
1.28 uwe 965: tadpole_set_video(int enabled)
1.1 matt 966: {
967: struct tctrl_softc *sc;
1.4 garbled 968: struct tctrl_req req;
1.1 matt 969: int s;
970:
1.4 garbled 971: sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
972: while (sc->sc_wantdata != 0)
973: DELAY(1);
974: s = splts102();
975: req.p = NULL;
976: if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN && !enabled)
977: || (sc->sc_tft_on)) {
978: req.cmdbuf[2] = TS102_BITPORT_TFTPWR;
979: } else {
980: req.cmdbuf[2] = 0;
1.1 matt 981: }
1.4 garbled 982: req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
983: req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR;
984: req.cmdlen = 3;
985: req.rsplen = 2;
1.1 matt 986:
987: if ((sc->sc_tft_on && !enabled) || (!sc->sc_tft_on && enabled)) {
988: sc->sc_tft_on = enabled;
989: if (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) {
990: splx(s);
991: return;
992: }
1.4 garbled 993: tadpole_request(&req, 1);
994: sc->sc_bitport =
995: (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
1.1 matt 996: }
997: splx(s);
998: }
999:
1000: static void
1.28 uwe 1001: tctrl_write_data(struct tctrl_softc *sc, uint8_t v)
1.1 matt 1002: {
1003: unsigned int i;
1.4 garbled 1004:
1.1 matt 1005: for (i = 0; i < 100; i++) {
1.28 uwe 1006: if (TS102_UCTRL_STS_TXNF_STA &
1.27 macallan 1007: tctrl_read(sc, TS102_REG_UCTRL_STS))
1.1 matt 1008: break;
1009: }
1010: tctrl_write(sc, TS102_REG_UCTRL_DATA, v);
1011: }
1012:
1.28 uwe 1013: static uint8_t
1014: tctrl_read_data(struct tctrl_softc *sc)
1.4 garbled 1015: {
1.1 matt 1016: unsigned int i, v;
1017:
1018: for (i = 0; i < 100000; i++) {
1.28 uwe 1019: if (TS102_UCTRL_STS_RXNE_STA &
1.27 macallan 1020: tctrl_read(sc, TS102_REG_UCTRL_STS))
1.1 matt 1021: break;
1022: DELAY(1);
1023: }
1024:
1025: v = tctrl_read(sc, TS102_REG_UCTRL_DATA);
1.2 matt 1026: tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA);
1.1 matt 1027: return v;
1028: }
1029:
1.28 uwe 1030: static uint8_t
1031: tctrl_read(struct tctrl_softc *sc, bus_size_t off)
1.1 matt 1032: {
1.4 garbled 1033:
1.2 matt 1034: sc->sc_junk = bus_space_read_1(sc->sc_memt, sc->sc_memh, off);
1.1 matt 1035: return sc->sc_junk;
1036: }
1037:
1038: static void
1.28 uwe 1039: tctrl_write(struct tctrl_softc *sc, bus_size_t off, uint8_t v)
1.1 matt 1040: {
1.4 garbled 1041:
1.1 matt 1042: sc->sc_junk = v;
1.2 matt 1043: bus_space_write_1(sc->sc_memt, sc->sc_memh, off, v);
1.4 garbled 1044: }
1045:
1046: int
1.29 christos 1047: tctrlopen(dev_t dev, int flags, int mode, struct lwp *l)
1.4 garbled 1048: {
1049: int unit = (minor(dev)&0xf0);
1050: int ctl = (minor(dev)&0x0f);
1051: struct tctrl_softc *sc;
1052:
1053: if (unit >= tctrl_cd.cd_ndevs)
1054: return(ENXIO);
1055: sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
1056: if (!sc)
1057: return(ENXIO);
1.28 uwe 1058:
1.4 garbled 1059: switch (ctl) {
1060: case TCTRL_STD_DEV:
1061: break;
1062: case TCTRL_APMCTL_DEV:
1063: if (!(flags & FWRITE))
1064: return(EINVAL);
1065: if (sc->sc_flags & TCTRL_APM_CTLOPEN)
1066: return(EBUSY);
1067: sc->sc_flags |= TCTRL_APM_CTLOPEN;
1068: break;
1069: default:
1070: return(ENXIO);
1071: break;
1072: }
1073:
1074: return(0);
1075: }
1076:
1077: int
1.29 christos 1078: tctrlclose(dev_t dev, int flags, int mode, struct lwp *l)
1.4 garbled 1079: {
1080: int ctl = (minor(dev)&0x0f);
1081: struct tctrl_softc *sc;
1082:
1083: sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
1084: if (!sc)
1085: return(ENXIO);
1086:
1087: switch (ctl) {
1088: case TCTRL_STD_DEV:
1089: break;
1090: case TCTRL_APMCTL_DEV:
1091: sc->sc_flags &= ~TCTRL_APM_CTLOPEN;
1092: break;
1093: }
1094: return(0);
1095: }
1096:
1097: int
1.29 christos 1098: tctrlioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct lwp *l)
1.4 garbled 1099: {
1100: struct tctrl_req req, *reqn;
1.28 uwe 1101: struct tctrl_pwr *pwrreq;
1.4 garbled 1102: struct apm_power_info *powerp;
1103: struct apm_event_info *evp;
1104: struct tctrl_softc *sc;
1105: int i;
1.28 uwe 1106: uint8_t c;
1.4 garbled 1107:
1108: if (tctrl_cd.cd_devs == NULL
1109: || tctrl_cd.cd_ndevs == 0
1110: || tctrl_cd.cd_devs[TCTRL_STD_DEV] == NULL) {
1111: return ENXIO;
1112: }
1113: sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
1114: switch (cmd) {
1115:
1116: case APM_IOC_STANDBY:
1.30 macallan 1117: /* turn off backlight and so on ? */
1118:
1119: return 0; /* for now */
1.4 garbled 1120:
1121: case APM_IOC_SUSPEND:
1.30 macallan 1122: /* not sure what to do here - we can't really suspend */
1123:
1124: return 0; /* for now */
1.4 garbled 1125:
1.19 takemura 1126: case OAPM_IOC_GETPOWER:
1.4 garbled 1127: case APM_IOC_GETPOWER:
1128: powerp = (struct apm_power_info *)data;
1129: req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_RATE;
1130: req.cmdlen = 1;
1131: req.rsplen = 2;
1.29 christos 1132: req.p = l->l_proc;
1.4 garbled 1133: tadpole_request(&req, 0);
1134: if (req.rspbuf[0] > 0x00)
1135: powerp->battery_state = APM_BATT_CHARGING;
1136: req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_LEVEL;
1137: req.cmdlen = 1;
1138: req.rsplen = 3;
1.29 christos 1139: req.p = l->l_proc;
1.4 garbled 1140: tadpole_request(&req, 0);
1141: c = req.rspbuf[0];
1142: powerp->battery_life = c;
1.6 garbled 1143: if (c > 0x70) /* the tadpole sometimes dips below zero, and */
1144: c = 0; /* into the 255 range. */
1.4 garbled 1145: powerp->minutes_left = (45 * c) / 100; /* XXX based on 45 min */
1146: if (powerp->battery_state != APM_BATT_CHARGING) {
1147: if (c < 0x20)
1148: powerp->battery_state = APM_BATT_CRITICAL;
1149: else if (c < 0x40)
1150: powerp->battery_state = APM_BATT_LOW;
1151: else if (c < 0x66)
1152: powerp->battery_state = APM_BATT_HIGH;
1153: else
1154: powerp->battery_state = APM_BATT_UNKNOWN;
1155: }
1.31 macallan 1156:
1157: if (sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE)
1.4 garbled 1158: powerp->ac_state = APM_AC_ON;
1159: else
1160: powerp->ac_state = APM_AC_OFF;
1161: break;
1162:
1163: case APM_IOC_NEXTEVENT:
1164: if (!sc->sc_event_count)
1165: return EAGAIN;
1166:
1167: evp = (struct apm_event_info *)data;
1168: i = sc->sc_event_ptr + APM_NEVENTS - sc->sc_event_count;
1169: i %= APM_NEVENTS;
1170: *evp = sc->sc_event_list[i];
1171: sc->sc_event_count--;
1172: return(0);
1173:
1174: /* this ioctl assumes the caller knows exactly what he is doing */
1175: case TCTRL_CMD_REQ:
1176: reqn = (struct tctrl_req *)data;
1.35 ! ad 1177: if ((i = kauth_authorize_generic(l->l_cred,
! 1178: KAUTH_GENERIC_ISSUSER, &l->l_acflag)) != 0 &&
1.4 garbled 1179: (reqn->cmdbuf[0] == TS102_OP_CTL_BITPORT ||
1180: (reqn->cmdbuf[0] >= TS102_OP_CTL_WATCHDOG &&
1181: reqn->cmdbuf[0] <= TS102_OP_CTL_SECURITY_KEY) ||
1182: reqn->cmdbuf[0] == TS102_OP_CTL_TIMEZONE ||
1183: reqn->cmdbuf[0] == TS102_OP_CTL_DIAGNOSTIC_MODE ||
1184: reqn->cmdbuf[0] == TS102_OP_CMD_SOFTWARE_RESET ||
1185: (reqn->cmdbuf[0] >= TS102_OP_CMD_SET_RTC &&
1186: reqn->cmdbuf[0] < TS102_OP_RD_INT_CHARGE_LEVEL) ||
1187: reqn->cmdbuf[0] > TS102_OP_RD_EXT_CHARGE_LEVEL))
1188: return(i);
1.29 christos 1189: reqn->p = l->l_proc;
1.4 garbled 1190: tadpole_request(reqn, 0);
1191: break;
1.7 jdc 1192: /* serial power mode (via auxiotwo) */
1193: case TCTRL_SERIAL_PWR:
1.28 uwe 1194: pwrreq = (struct tctrl_pwr *)data;
1.7 jdc 1195: if (pwrreq->rw)
1196: pwrreq->state = auxiotwoserialgetapm();
1197: else
1198: auxiotwoserialsetapm(pwrreq->state);
1199: break;
1200:
1201: /* modem power mode (via auxio) */
1202: case TCTRL_MODEM_PWR:
1203: return(EOPNOTSUPP); /* for now */
1204: break;
1.4 garbled 1205:
1206:
1207: default:
1208: return (ENOTTY);
1209: }
1210: return (0);
1211: }
1212:
1213: int
1.29 christos 1214: tctrlpoll(dev_t dev, int events, struct lwp *l)
1.4 garbled 1215: {
1216: struct tctrl_softc *sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
1217: int revents = 0;
1218:
1219: if (events & (POLLIN | POLLRDNORM)) {
1220: if (sc->sc_event_count)
1221: revents |= events & (POLLIN | POLLRDNORM);
1222: else
1.29 christos 1223: selrecord(l, &sc->sc_rsel);
1.4 garbled 1224: }
1225:
1226: return (revents);
1.1 matt 1227: }
1.20 jdolecek 1228:
1229: static void
1230: filt_tctrlrdetach(struct knote *kn)
1231: {
1232: struct tctrl_softc *sc = kn->kn_hook;
1233: int s;
1234:
1235: s = splts102();
1.21 christos 1236: SLIST_REMOVE(&sc->sc_rsel.sel_klist, kn, knote, kn_selnext);
1.20 jdolecek 1237: splx(s);
1238: }
1239:
1240: static int
1241: filt_tctrlread(struct knote *kn, long hint)
1242: {
1243: struct tctrl_softc *sc = kn->kn_hook;
1244:
1245: kn->kn_data = sc->sc_event_count;
1246: return (kn->kn_data > 0);
1247: }
1248:
1249: static const struct filterops tctrlread_filtops =
1250: { 1, NULL, filt_tctrlrdetach, filt_tctrlread };
1251:
1252: int
1253: tctrlkqfilter(dev_t dev, struct knote *kn)
1254: {
1255: struct tctrl_softc *sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
1256: struct klist *klist;
1257: int s;
1258:
1259: switch (kn->kn_filter) {
1260: case EVFILT_READ:
1.21 christos 1261: klist = &sc->sc_rsel.sel_klist;
1.20 jdolecek 1262: kn->kn_fop = &tctrlread_filtops;
1263: break;
1264:
1265: default:
1266: return (1);
1267: }
1268:
1269: kn->kn_hook = sc;
1270:
1271: s = splts102();
1272: SLIST_INSERT_HEAD(klist, kn, kn_selnext);
1273: splx(s);
1274:
1275: return (0);
1276: }
1277:
1.27 macallan 1278: static void
1279: tctrl_sensor_setup(struct tctrl_softc *sc)
1280: {
1281: int error;
1.28 uwe 1282:
1.27 macallan 1283: /* case temperature */
1284: strcpy(sc->sc_binfo[0].desc, "Case temperature");
1285: sc->sc_binfo[0].sensor = 0;
1286: sc->sc_binfo[0].units = ENVSYS_STEMP;
1287: sc->sc_binfo[0].validflags = ENVSYS_FVALID | ENVSYS_FCURVALID;
1288: sc->sc_range[0].low = 0;
1289: sc->sc_range[0].high = 0;
1290: sc->sc_range[0].units = ENVSYS_STEMP;
1291: sc->sc_tre[0].sensor = 0;
1292: sc->sc_tre[0].warnflags = ENVSYS_WARN_OK;
1293: sc->sc_tre[0].validflags = ENVSYS_FVALID | ENVSYS_FCURVALID;
1294: sc->sc_tre[0].units = ENVSYS_STEMP;
1.28 uwe 1295:
1.27 macallan 1296: /* battery voltage */
1297: strcpy(sc->sc_binfo[1].desc, "Internal battery voltage");
1298: sc->sc_binfo[1].sensor = 1;
1299: sc->sc_binfo[1].units = ENVSYS_SVOLTS_DC;
1300: sc->sc_binfo[1].validflags = ENVSYS_FVALID | ENVSYS_FCURVALID;
1301: sc->sc_range[1].low = 0;
1302: sc->sc_range[1].high = 0;
1303: sc->sc_range[1].units = ENVSYS_SVOLTS_DC;
1304: sc->sc_tre[1].sensor = 0;
1305: sc->sc_tre[1].warnflags = ENVSYS_WARN_OK;
1306: sc->sc_tre[1].validflags = ENVSYS_FVALID | ENVSYS_FCURVALID;
1307: sc->sc_tre[1].units = ENVSYS_SVOLTS_DC;
1.28 uwe 1308:
1.27 macallan 1309: /* DC voltage */
1310: strcpy(sc->sc_binfo[2].desc, "DC-In voltage");
1311: sc->sc_binfo[2].sensor = 2;
1312: sc->sc_binfo[2].units = ENVSYS_SVOLTS_DC;
1313: sc->sc_binfo[2].validflags = ENVSYS_FVALID | ENVSYS_FCURVALID;
1314: sc->sc_range[2].low = 0;
1315: sc->sc_range[2].high = 0;
1316: sc->sc_range[2].units = ENVSYS_SVOLTS_DC;
1317: sc->sc_tre[2].sensor = 0;
1318: sc->sc_tre[2].warnflags = ENVSYS_WARN_OK;
1319: sc->sc_tre[2].validflags = ENVSYS_FVALID | ENVSYS_FCURVALID;
1320: sc->sc_tre[2].units = ENVSYS_SVOLTS_DC;
1.28 uwe 1321:
1.27 macallan 1322: sc->sc_sme.sme_nsensors = ENVSYS_NUMSENSORS;
1323: sc->sc_sme.sme_envsys_version = 1000;
1324: sc->sc_sme.sme_ranges = sc->sc_range;
1325: sc->sc_sme.sme_sensor_info = sc->sc_binfo;
1326: sc->sc_sme.sme_sensor_data = sc->sc_tre;
1327: sc->sc_sme.sme_cookie = sc;
1328: sc->sc_sme.sme_gtredata = tctrl_gtredata;
1329: sc->sc_sme.sme_streinfo = tctrl_streinfo;
1330: sc->sc_sme.sme_flags = 0;
1.28 uwe 1331:
1.27 macallan 1332: if ((error = sysmon_envsys_register(&sc->sc_sme)) != 0) {
1.28 uwe 1333: printf("%s: couldn't register sensors (%d)\n",
1.27 macallan 1334: sc->sc_dev.dv_xname, error);
1335: }
1.28 uwe 1336:
1.27 macallan 1337: /* now register the power button */
1.28 uwe 1338:
1.27 macallan 1339: sysmon_task_queue_init();
1340:
1341: sc->sc_powerpressed = 0;
1.31 macallan 1342: memset(&sc->sc_sm_pbutton, 0, sizeof(struct sysmon_pswitch));
1343: sc->sc_sm_pbutton.smpsw_name = sc->sc_dev.dv_xname;
1344: sc->sc_sm_pbutton.smpsw_type = PSWITCH_TYPE_POWER;
1345: if (sysmon_pswitch_register(&sc->sc_sm_pbutton) != 0)
1.28 uwe 1346: printf("%s: unable to register power button with sysmon\n",
1.27 macallan 1347: sc->sc_dev.dv_xname);
1.31 macallan 1348:
1349: memset(&sc->sc_sm_lid, 0, sizeof(struct sysmon_pswitch));
1350: sc->sc_sm_lid.smpsw_name = sc->sc_dev.dv_xname;
1351: sc->sc_sm_lid.smpsw_type = PSWITCH_TYPE_LID;
1352: if (sysmon_pswitch_register(&sc->sc_sm_lid) != 0)
1353: printf("%s: unable to register lid switch with sysmon\n",
1354: sc->sc_dev.dv_xname);
1355:
1356: memset(&sc->sc_sm_ac, 0, sizeof(struct sysmon_pswitch));
1357: sc->sc_sm_ac.smpsw_name = sc->sc_dev.dv_xname;
1358: sc->sc_sm_ac.smpsw_type = PSWITCH_TYPE_ACADAPTER;
1359: if (sysmon_pswitch_register(&sc->sc_sm_ac) != 0)
1360: printf("%s: unable to register AC adaptor with sysmon\n",
1361: sc->sc_dev.dv_xname);
1.27 macallan 1362: }
1363:
1364: static void
1365: tctrl_power_button_pressed(void *arg)
1366: {
1367: struct tctrl_softc *sc = arg;
1368:
1.31 macallan 1369: sysmon_pswitch_event(&sc->sc_sm_pbutton, PSWITCH_EVENT_PRESSED);
1.27 macallan 1370: sc->sc_powerpressed = 0;
1371: }
1372:
1.31 macallan 1373: static void
1374: tctrl_lid_state(struct tctrl_softc *sc)
1375: {
1376: int state;
1377:
1378: state = (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) ?
1379: PSWITCH_STATE_PRESSED : PSWITCH_STATE_RELEASED;
1380: sysmon_pswitch_event(&sc->sc_sm_lid, state);
1381: }
1382:
1383: static void
1384: tctrl_ac_state(struct tctrl_softc *sc)
1385: {
1386: int state;
1387:
1388: state = (sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ?
1389: PSWITCH_STATE_PRESSED : PSWITCH_STATE_RELEASED;
1390: sysmon_pswitch_event(&sc->sc_sm_ac, state);
1391: }
1392:
1.28 uwe 1393: static int
1.27 macallan 1394: tctrl_powerfail(void *arg)
1395: {
1396: struct tctrl_softc *sc = (struct tctrl_softc *)arg;
1397:
1398: /*
1399: * We lost power. Queue a callback with thread context to
1400: * handle all the real work.
1401: */
1402: if (sc->sc_powerpressed == 0) {
1403: sc->sc_powerpressed = 1;
1404: sysmon_task_queue_sched(0, tctrl_power_button_pressed, sc);
1405: }
1406: return (1);
1407: }
1408:
1409: static int
1410: tctrl_gtredata(struct sysmon_envsys *sme, struct envsys_tre_data *tred)
1411: {
1412: /*struct tctrl_softc *sc = sme->sme_cookie;*/
1413: struct envsys_tre_data *cur_tre;
1414: struct envsys_basic_info *cur_i;
1415: struct tctrl_req req;
1416: struct proc *p;
1417: int i;
1.28 uwe 1418:
1.27 macallan 1419: i = tred->sensor;
1420: cur_tre = &sme->sme_sensor_data[i];
1421: cur_i = &sme->sme_sensor_info[i];
1422: p = __curproc();
1.28 uwe 1423:
1.27 macallan 1424: switch (i)
1425: {
1426: case 0: /* case temperature */
1427: req.cmdbuf[0] = TS102_OP_RD_CURRENT_TEMP;
1428: req.cmdlen = 1;
1429: req.rsplen = 2;
1430: req.p = p;
1431: tadpole_request(&req, 0);
1432: cur_tre->cur.data_us = /* 273160? */
1.28 uwe 1433: (uint32_t)((int)((int)req.rspbuf[0] - 32) * 5000000
1.27 macallan 1434: / 9 + 273150000);
1435: cur_tre->validflags |= ENVSYS_FCURVALID;
1436: req.cmdbuf[0] = TS102_OP_RD_MAX_TEMP;
1437: req.cmdlen = 1;
1438: req.rsplen = 2;
1439: req.p = p;
1440: tadpole_request(&req, 0);
1441: cur_tre->max.data_us =
1.28 uwe 1442: (uint32_t)((int)((int)req.rspbuf[0] - 32) * 5000000
1.27 macallan 1443: / 9 + 273150000);
1444: cur_tre->validflags |= ENVSYS_FMAXVALID;
1445: req.cmdbuf[0] = TS102_OP_RD_MIN_TEMP;
1446: req.cmdlen = 1;
1447: req.rsplen = 2;
1448: req.p = p;
1449: tadpole_request(&req, 0);
1450: cur_tre->min.data_us =
1.28 uwe 1451: (uint32_t)((int)((int)req.rspbuf[0] - 32) * 5000000
1.27 macallan 1452: / 9 + 273150000);
1453: cur_tre->validflags |= ENVSYS_FMINVALID;
1454: cur_tre->units = ENVSYS_STEMP;
1455: break;
1.28 uwe 1456:
1.27 macallan 1457: case 1: /* battery voltage */
1458: {
1.28 uwe 1459: cur_tre->validflags =
1.27 macallan 1460: ENVSYS_FVALID|ENVSYS_FCURVALID;
1461: cur_tre->units = ENVSYS_SVOLTS_DC;
1462: req.cmdbuf[0] = TS102_OP_RD_INT_BATT_VLT;
1463: req.cmdlen = 1;
1464: req.rsplen = 2;
1465: req.p = p;
1466: tadpole_request(&req, 0);
1.28 uwe 1467: cur_tre->cur.data_s = (int32_t)req.rspbuf[0] *
1.27 macallan 1468: 1000000 / 11;
1469: }
1470: break;
1471: case 2: /* DC voltage */
1472: {
1.28 uwe 1473: cur_tre->validflags =
1.27 macallan 1474: ENVSYS_FVALID|ENVSYS_FCURVALID;
1475: cur_tre->units = ENVSYS_SVOLTS_DC;
1476: req.cmdbuf[0] = TS102_OP_RD_DC_IN_VLT;
1477: req.cmdlen = 1;
1478: req.rsplen = 2;
1479: req.p = p;
1480: tadpole_request(&req, 0);
1.28 uwe 1481: cur_tre->cur.data_s = (int32_t)req.rspbuf[0] *
1.27 macallan 1482: 1000000 / 11;
1483: }
1484: break;
1485: }
1486: cur_tre->validflags |= ENVSYS_FVALID;
1487: *tred = sme->sme_sensor_data[i];
1488: return 0;
1489: }
1490:
1491:
1492: static int
1493: tctrl_streinfo(struct sysmon_envsys *sme, struct envsys_basic_info *binfo)
1494: {
1.28 uwe 1495:
1.27 macallan 1496: /* There is nothing to set here. */
1497: return (EINVAL);
1498: }
1.30 macallan 1499:
1500: static void
1501: tctrl_create_event_thread(void *v)
1502: {
1503: struct tctrl_softc *sc = v;
1504: const char *name = sc->sc_dev.dv_xname;
1505:
1506: if (kthread_create1(tctrl_event_thread, sc, &sc->sc_thread, "%s",
1507: name) != 0) {
1508: printf("%s: unable to create event kthread", name);
1509: }
1510: }
1511:
1512: static void
1513: tctrl_event_thread(void *v)
1514: {
1515: struct tctrl_softc *sc = v;
1516: struct device *dv;
1517: struct sd_softc *sd = NULL;
1518: struct lance_softc *le = NULL;
1519: int ticks = hz/2;
1520: int rcount, wcount;
1521: int s;
1522:
1523: while (sd == NULL) {
1524: for (dv = alldevs.tqh_first; dv; dv = dv->dv_list.tqe_next) {
1525: if (strcmp(dv->dv_xname, "sd0") == 0) {
1526: sd = (struct sd_softc *)dv;
1527: }
1528: if (le == NULL) {
1529: if (strcmp(dv->dv_xname, "le0") == 0)
1530: le = (struct lance_softc *)dv;
1531: }
1532: }
1533: if (sd == NULL)
1534: tsleep(&sc->sc_events, PWAIT, "probe_disk", hz);
1535: }
1536: printf("found %s\n", sd->sc_dev.dv_xname);
1.33 blymn 1537: rcount = sd->sc_dk.dk_stats->io_rxfer;
1538: wcount = sd->sc_dk.dk_stats->io_wxfer;
1.30 macallan 1539:
1540: tctrl_read_event_status(sc);
1541:
1542: while (1) {
1543: tsleep(&sc->sc_events, PWAIT, "tctrl_event", ticks);
1544: s = splhigh();
1.33 blymn 1545: if ((rcount != sd->sc_dk.dk_stats->io_rxfer) ||
1546: (wcount != sd->sc_dk.dk_stats->io_wxfer)) {
1547: rcount = sd->sc_dk.dk_stats->io_rxfer;
1548: wcount = sd->sc_dk.dk_stats->io_wxfer;
1.30 macallan 1549: sc->sc_lcdwanted |= TS102_LCD_DISK_ACTIVE;
1550: } else
1551: sc->sc_lcdwanted &= ~TS102_LCD_DISK_ACTIVE;
1552: if (le != NULL) {
1553: if (le->sc_havecarrier != 0) {
1554: sc->sc_lcdwanted |= TS102_LCD_LAN_ACTIVE;
1555: } else
1556: sc->sc_lcdwanted &= ~TS102_LCD_LAN_ACTIVE;
1557: }
1558: splx(s);
1559: tctrl_update_lcd(sc);
1560: if (sc->sc_ext_pending)
1561: tctrl_read_event_status(sc);
1562: }
1563: }
1564:
1565: void
1566: tadpole_register_callback(void (*callback)(void *, int), void *cookie)
1567: {
1568: struct tctrl_softc *sc;
1569:
1570: sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
1571: sc->sc_video_callback = callback;
1572: sc->sc_video_callback_cookie = cookie;
1573: if (sc->sc_video_callback != NULL) {
1574: sc->sc_video_callback(sc->sc_video_callback_cookie,
1575: sc->sc_extvga);
1576: }
1577: }
CVSweb <webmaster@jp.NetBSD.org>