No empty .Rs/.Re
[netbsd-mini2440.git] / sys / arch / sparc / dev / tctrl.c
blobe6fb0685f8a0e18aa9e85200348567091a68b101
1 /* $NetBSD: tctrl.c,v 1.49 2008/07/17 14:43:38 cegger Exp $ */
3 /*-
4 * Copyright (c) 1998, 2005, 2006 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Matt Thomas.
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: tctrl.c,v 1.49 2008/07/17 14:43:38 cegger Exp $");
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/ioctl.h>
38 #include <sys/select.h>
39 #include <sys/tty.h>
40 #include <sys/proc.h>
41 #include <sys/conf.h>
42 #include <sys/file.h>
43 #include <sys/uio.h>
44 #include <sys/kernel.h>
45 #include <sys/kthread.h>
46 #include <sys/syslog.h>
47 #include <sys/types.h>
48 #include <sys/device.h>
49 #include <sys/envsys.h>
50 #include <sys/poll.h>
51 #include <sys/kauth.h>
53 #include <machine/apmvar.h>
54 #include <machine/autoconf.h>
55 #include <machine/bus.h>
56 #include <machine/intr.h>
57 #include <machine/tctrl.h>
59 #include <sparc/dev/ts102reg.h>
60 #include <sparc/dev/tctrlvar.h>
61 #include <sparc/sparc/auxiotwo.h>
62 #include <sparc/sparc/auxreg.h>
64 #include <dev/sysmon/sysmonvar.h>
65 #include <dev/sysmon/sysmon_taskq.h>
67 #include "sysmon_envsys.h"
69 /*#define TCTRLDEBUG*/
71 /* disk spinner */
72 #include <sys/disk.h>
73 #include <dev/scsipi/sdvar.h>
75 /* ethernet carrier */
76 #include <net/if.h>
77 #include <net/if_dl.h>
78 #include <net/if_ether.h>
79 #include <net/if_media.h>
80 #include <dev/ic/lancevar.h>
82 extern struct cfdriver tctrl_cd;
84 dev_type_open(tctrlopen);
85 dev_type_close(tctrlclose);
86 dev_type_ioctl(tctrlioctl);
87 dev_type_poll(tctrlpoll);
88 dev_type_kqfilter(tctrlkqfilter);
90 const struct cdevsw tctrl_cdevsw = {
91 tctrlopen, tctrlclose, noread, nowrite, tctrlioctl,
92 nostop, notty, tctrlpoll, nommap, tctrlkqfilter,
95 static const char *tctrl_ext_statuses[16] = {
96 "main power available",
97 "internal battery attached",
98 "external battery attached",
99 "external VGA attached",
100 "external keyboard attached",
101 "external mouse attached",
102 "lid down",
103 "internal battery charging",
104 "external battery charging",
105 "internal battery discharging",
106 "external battery discharging",
109 struct tctrl_softc {
110 struct device sc_dev;
111 bus_space_tag_t sc_memt;
112 bus_space_handle_t sc_memh;
113 unsigned int sc_junk;
114 unsigned int sc_ext_status;
115 unsigned int sc_flags;
116 #define TCTRL_SEND_REQUEST 0x0001
117 #define TCTRL_APM_CTLOPEN 0x0002
118 uint32_t sc_wantdata;
119 uint32_t sc_ext_pending;
120 volatile uint16_t sc_lcdstate;
121 uint16_t sc_lcdwanted;
123 enum { TCTRL_IDLE, TCTRL_ARGS,
124 TCTRL_ACK, TCTRL_DATA } sc_state;
125 uint8_t sc_cmdbuf[16];
126 uint8_t sc_rspbuf[16];
127 uint8_t sc_bitport;
128 uint8_t sc_tft_on;
129 uint8_t sc_op;
130 uint8_t sc_cmdoff;
131 uint8_t sc_cmdlen;
132 uint8_t sc_rspoff;
133 uint8_t sc_rsplen;
134 /* APM stuff */
135 #define APM_NEVENTS 16
136 struct apm_event_info sc_event_list[APM_NEVENTS];
137 int sc_event_count;
138 int sc_event_ptr;
139 struct selinfo sc_rsel;
141 /* ENVSYS stuff */
142 #define ENVSYS_NUMSENSORS 3
143 struct evcnt sc_intrcnt; /* interrupt counting */
144 struct sysmon_envsys *sc_sme;
145 envsys_data_t sc_sensor[ENVSYS_NUMSENSORS];
147 struct sysmon_pswitch sc_sm_pbutton; /* power button */
148 struct sysmon_pswitch sc_sm_lid; /* lid state */
149 struct sysmon_pswitch sc_sm_ac; /* AC adaptor presence */
150 int sc_powerpressed;
152 /* hardware status stuff */
153 int sc_lid; /* 1 - open, 0 - closed */
154 int sc_power_state;
155 int sc_spl;
158 * we call this when we detect connection or removal of an external
159 * monitor. 0 for no monitor, !=0 for monitor present
161 void (*sc_video_callback)(void *, int);
162 void *sc_video_callback_cookie;
163 int sc_extvga;
165 uint32_t sc_events;
166 lwp_t *sc_thread; /* event thread */
167 kmutex_t sc_requestlock;
170 #define TCTRL_STD_DEV 0
171 #define TCTRL_APMCTL_DEV 8
173 static int tctrl_match(struct device *, struct cfdata *, void *);
174 static void tctrl_attach(struct device *, struct device *, void *);
175 static void tctrl_write(struct tctrl_softc *, bus_size_t, uint8_t);
176 static uint8_t tctrl_read(struct tctrl_softc *, bus_size_t);
177 static void tctrl_write_data(struct tctrl_softc *, uint8_t);
178 static uint8_t tctrl_read_data(struct tctrl_softc *);
179 static int tctrl_intr(void *);
180 static void tctrl_setup_bitport(void);
181 static void tctrl_setup_bitport_nop(void);
182 static void tctrl_read_ext_status(void);
183 static void tctrl_read_event_status(struct tctrl_softc *);
184 static int tctrl_apm_record_event(struct tctrl_softc *, u_int);
185 static void tctrl_init_lcd(void);
187 static void tctrl_sensor_setup(struct tctrl_softc *);
188 static void tctrl_refresh(struct sysmon_envsys *, envsys_data_t *);
190 static void tctrl_power_button_pressed(void *);
191 static void tctrl_lid_state(struct tctrl_softc *);
192 static void tctrl_ac_state(struct tctrl_softc *);
194 static int tctrl_powerfail(void *);
196 static void tctrl_event_thread(void *);
197 void tctrl_update_lcd(struct tctrl_softc *);
199 static void tctrl_lock(struct tctrl_softc *);
200 static void tctrl_unlock(struct tctrl_softc *);
202 CFATTACH_DECL(tctrl, sizeof(struct tctrl_softc),
203 tctrl_match, tctrl_attach, NULL, NULL);
205 static int tadpole_request(struct tctrl_req *, int, int);
207 /* XXX wtf is this? see i386/apm.c */
208 int tctrl_apm_evindex;
210 static int
211 tctrl_match(struct device *parent, struct cfdata *cf, void *aux)
213 union obio_attach_args *uoba = aux;
214 struct sbus_attach_args *sa = &uoba->uoba_sbus;
216 if (uoba->uoba_isobio4 != 0) {
217 return (0);
220 /* Tadpole 3GX/3GS uses "uctrl" for the Tadpole Microcontroller
221 * (who's interface is off the TS102 PCMCIA controller but there
222 * exists a OpenProm for microcontroller interface).
224 return strcmp("uctrl", sa->sa_name) == 0;
227 static void
228 tctrl_attach(struct device *parent, struct device *self, void *aux)
230 struct tctrl_softc *sc = device_private(self);
231 union obio_attach_args *uoba = aux;
232 struct sbus_attach_args *sa = &uoba->uoba_sbus;
233 unsigned int i, v;
235 /* We're living on a sbus slot that looks like an obio that
236 * looks like an sbus slot.
238 sc->sc_memt = sa->sa_bustag;
239 if (sbus_bus_map(sc->sc_memt,
240 sa->sa_slot,
241 sa->sa_offset - TS102_REG_UCTRL_INT,
242 sa->sa_size,
243 BUS_SPACE_MAP_LINEAR, &sc->sc_memh) != 0) {
244 printf(": can't map registers\n");
245 return;
248 printf("\n");
250 sc->sc_tft_on = 1;
252 /* clear any pending data.
254 for (i = 0; i < 10000; i++) {
255 if ((TS102_UCTRL_STS_RXNE_STA &
256 tctrl_read(sc, TS102_REG_UCTRL_STS)) == 0) {
257 break;
259 v = tctrl_read(sc, TS102_REG_UCTRL_DATA);
260 tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA);
263 if (sa->sa_nintr != 0) {
264 (void)bus_intr_establish(sc->sc_memt, sa->sa_pri, IPL_NONE,
265 tctrl_intr, sc);
266 evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, NULL,
267 sc->sc_dev.dv_xname, "intr");
270 /* See what the external status is */
271 sc->sc_ext_status = 0;
272 tctrl_read_ext_status();
273 if (sc->sc_ext_status != 0) {
274 const char *sep;
276 printf("%s: ", sc->sc_dev.dv_xname);
277 v = sc->sc_ext_status;
278 for (i = 0, sep = ""; v != 0; i++, v >>= 1) {
279 if (v & 1) {
280 printf("%s%s", sep, tctrl_ext_statuses[i]);
281 sep = ", ";
284 printf("\n");
287 /* Get a current of the control bitport */
288 tctrl_setup_bitport_nop();
289 tctrl_write(sc, TS102_REG_UCTRL_INT,
290 TS102_UCTRL_INT_RXNE_REQ|TS102_UCTRL_INT_RXNE_MSK);
291 sc->sc_lid = (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) == 0;
292 sc->sc_power_state = PWR_RESUME;
294 sc->sc_extvga = (sc->sc_ext_status &
295 TS102_EXT_STATUS_EXTERNAL_VGA_ATTACHED) != 0;
296 sc->sc_video_callback = NULL;
299 sc->sc_wantdata = 0;
300 sc->sc_event_count = 0;
301 sc->sc_ext_pending = 0;
302 sc->sc_ext_pending = 0;
304 mutex_init(&sc->sc_requestlock, MUTEX_DEFAULT, IPL_NONE);
305 selinit(&sc->sc_rsel);
307 /* setup sensors and register the power button */
308 tctrl_sensor_setup(sc);
309 tctrl_lid_state(sc);
310 tctrl_ac_state(sc);
312 /* initialize the LCD */
313 tctrl_init_lcd();
315 /* initialize sc_lcdstate */
316 sc->sc_lcdstate = 0;
317 sc->sc_lcdwanted = 0;
318 tadpole_set_lcd(2, 0);
320 /* fire up the LCD event thread */
321 sc->sc_events = 0;
323 if (kthread_create(PRI_NONE, 0, NULL, tctrl_event_thread, sc,
324 &sc->sc_thread, "%s", sc->sc_dev.dv_xname) != 0) {
325 printf("%s: unable to create event kthread",
326 sc->sc_dev.dv_xname);
330 static int
331 tctrl_intr(void *arg)
333 struct tctrl_softc *sc = arg;
334 unsigned int v, d;
335 int progress = 0;
337 again:
338 /* find out the cause(s) of the interrupt */
339 v = tctrl_read(sc, TS102_REG_UCTRL_STS) & TS102_UCTRL_STS_MASK;
341 /* clear the cause(s) of the interrupt */
342 tctrl_write(sc, TS102_REG_UCTRL_STS, v);
344 v &= ~(TS102_UCTRL_STS_RXO_STA|TS102_UCTRL_STS_TXE_STA);
345 if (sc->sc_cmdoff >= sc->sc_cmdlen) {
346 v &= ~TS102_UCTRL_STS_TXNF_STA;
347 if (tctrl_read(sc, TS102_REG_UCTRL_INT) &
348 TS102_UCTRL_INT_TXNF_REQ) {
349 tctrl_write(sc, TS102_REG_UCTRL_INT, 0);
350 progress = 1;
353 if ((v == 0) && ((sc->sc_flags & TCTRL_SEND_REQUEST) == 0 ||
354 sc->sc_state != TCTRL_IDLE)) {
355 wakeup(sc);
356 return progress;
359 progress = 1;
360 if (v & TS102_UCTRL_STS_RXNE_STA) {
361 d = tctrl_read_data(sc);
362 switch (sc->sc_state) {
363 case TCTRL_IDLE:
364 if (d == 0xfa) {
366 * external event,
367 * set a flag and wakeup the event thread
369 sc->sc_ext_pending = 1;
370 } else {
371 printf("%s: (op=0x%02x): unexpected data (0x%02x)\n",
372 sc->sc_dev.dv_xname, sc->sc_op, d);
374 goto again;
375 case TCTRL_ACK:
376 if (d != 0xfe) {
377 printf("%s: (op=0x%02x): unexpected ack value (0x%02x)\n",
378 sc->sc_dev.dv_xname, sc->sc_op, d);
380 #ifdef TCTRLDEBUG
381 printf(" ack=0x%02x", d);
382 #endif
383 sc->sc_rsplen--;
384 sc->sc_rspoff = 0;
385 sc->sc_state = sc->sc_rsplen ? TCTRL_DATA : TCTRL_IDLE;
386 sc->sc_wantdata = sc->sc_rsplen ? 1 : 0;
387 #ifdef TCTRLDEBUG
388 if (sc->sc_rsplen > 0) {
389 printf(" [data(%u)]", sc->sc_rsplen);
390 } else {
391 printf(" [idle]\n");
393 #endif
394 goto again;
395 case TCTRL_DATA:
396 sc->sc_rspbuf[sc->sc_rspoff++] = d;
397 #ifdef TCTRLDEBUG
398 printf(" [%d]=0x%02x", sc->sc_rspoff-1, d);
399 #endif
400 if (sc->sc_rspoff == sc->sc_rsplen) {
401 #ifdef TCTRLDEBUG
402 printf(" [idle]\n");
403 #endif
404 sc->sc_state = TCTRL_IDLE;
405 sc->sc_wantdata = 0;
407 goto again;
408 default:
409 printf("%s: (op=0x%02x): unexpected data (0x%02x) in state %d\n",
410 sc->sc_dev.dv_xname, sc->sc_op, d, sc->sc_state);
411 goto again;
414 if ((sc->sc_state == TCTRL_IDLE && sc->sc_wantdata == 0) ||
415 sc->sc_flags & TCTRL_SEND_REQUEST) {
416 if (sc->sc_flags & TCTRL_SEND_REQUEST) {
417 sc->sc_flags &= ~TCTRL_SEND_REQUEST;
418 sc->sc_wantdata = 1;
420 if (sc->sc_cmdlen > 0) {
421 tctrl_write(sc, TS102_REG_UCTRL_INT,
422 tctrl_read(sc, TS102_REG_UCTRL_INT)
423 |TS102_UCTRL_INT_TXNF_MSK
424 |TS102_UCTRL_INT_TXNF_REQ);
425 v = tctrl_read(sc, TS102_REG_UCTRL_STS);
428 if ((sc->sc_cmdoff < sc->sc_cmdlen) && (v & TS102_UCTRL_STS_TXNF_STA)) {
429 tctrl_write_data(sc, sc->sc_cmdbuf[sc->sc_cmdoff++]);
430 #ifdef TCTRLDEBUG
431 if (sc->sc_cmdoff == 1) {
432 printf("%s: op=0x%02x(l=%u)", sc->sc_dev.dv_xname,
433 sc->sc_cmdbuf[0], sc->sc_rsplen);
434 } else {
435 printf(" [%d]=0x%02x", sc->sc_cmdoff-1,
436 sc->sc_cmdbuf[sc->sc_cmdoff-1]);
438 #endif
439 if (sc->sc_cmdoff == sc->sc_cmdlen) {
440 sc->sc_state = sc->sc_rsplen ? TCTRL_ACK : TCTRL_IDLE;
441 #ifdef TCTRLDEBUG
442 printf(" %s", sc->sc_rsplen ? "[ack]" : "[idle]\n");
443 #endif
444 if (sc->sc_cmdoff == 1) {
445 sc->sc_op = sc->sc_cmdbuf[0];
447 tctrl_write(sc, TS102_REG_UCTRL_INT,
448 tctrl_read(sc, TS102_REG_UCTRL_INT)
449 & (~TS102_UCTRL_INT_TXNF_MSK
450 |TS102_UCTRL_INT_TXNF_REQ));
451 } else if (sc->sc_state == TCTRL_IDLE) {
452 sc->sc_op = sc->sc_cmdbuf[0];
453 sc->sc_state = TCTRL_ARGS;
454 #ifdef TCTRLDEBUG
455 printf(" [args]");
456 #endif
459 goto again;
462 static void
463 tctrl_setup_bitport_nop(void)
465 struct tctrl_softc *sc;
466 struct tctrl_req req;
467 int s;
469 sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
470 req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
471 req.cmdbuf[1] = 0xff;
472 req.cmdbuf[2] = 0x00;
473 req.cmdlen = 3;
474 req.rsplen = 2;
475 tadpole_request(&req, 1, 0);
476 s = splts102();
477 sc->sc_bitport = (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
478 splx(s);
481 static void
482 tctrl_setup_bitport(void)
484 struct tctrl_softc *sc;
485 struct tctrl_req req;
486 int s;
488 sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
489 s = splts102();
490 req.cmdbuf[2] = 0;
491 if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN)
492 || (!sc->sc_tft_on)) {
493 req.cmdbuf[2] = TS102_BITPORT_TFTPWR;
495 req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
496 req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR;
497 req.cmdlen = 3;
498 req.rsplen = 2;
499 tadpole_request(&req, 1, 0);
500 s = splts102();
501 sc->sc_bitport = (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
502 splx(s);
506 * The tadpole microcontroller is not preprogrammed with icon
507 * representations. The machine boots with the DC-IN light as
508 * a blank (all 0x00) and the other lights, as 4 rows of horizontal
509 * bars. The below code initializes the icons in the system to
510 * sane values. Some of these icons could be used for any purpose
511 * desired, namely the pcmcia, LAN and WAN lights. For the disk spinner,
512 * only the backslash is unprogrammed. (sigh)
514 * programming the icons is simple. It is a 5x8 matrix, which each row a
515 * bitfield in the order 0x10 0x08 0x04 0x02 0x01.
518 static void
519 tctrl_init_lcd(void)
521 struct tctrl_req req;
523 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
524 req.cmdlen = 11;
525 req.rsplen = 1;
526 req.cmdbuf[1] = 0x08; /*len*/
527 req.cmdbuf[2] = TS102_BLK_OFF_DEF_DC_GOOD;
528 req.cmdbuf[3] = 0x00; /* ..... */
529 req.cmdbuf[4] = 0x00; /* ..... */
530 req.cmdbuf[5] = 0x1f; /* XXXXX */
531 req.cmdbuf[6] = 0x00; /* ..... */
532 req.cmdbuf[7] = 0x15; /* X.X.X */
533 req.cmdbuf[8] = 0x00; /* ..... */
534 req.cmdbuf[9] = 0x00; /* ..... */
535 req.cmdbuf[10] = 0x00; /* ..... */
536 tadpole_request(&req, 1, 0);
538 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
539 req.cmdlen = 11;
540 req.rsplen = 1;
541 req.cmdbuf[1] = 0x08; /*len*/
542 req.cmdbuf[2] = TS102_BLK_OFF_DEF_BACKSLASH;
543 req.cmdbuf[3] = 0x00; /* ..... */
544 req.cmdbuf[4] = 0x10; /* X.... */
545 req.cmdbuf[5] = 0x08; /* .X... */
546 req.cmdbuf[6] = 0x04; /* ..X.. */
547 req.cmdbuf[7] = 0x02; /* ...X. */
548 req.cmdbuf[8] = 0x01; /* ....X */
549 req.cmdbuf[9] = 0x00; /* ..... */
550 req.cmdbuf[10] = 0x00; /* ..... */
551 tadpole_request(&req, 1, 0);
553 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
554 req.cmdlen = 11;
555 req.rsplen = 1;
556 req.cmdbuf[1] = 0x08; /*len*/
557 req.cmdbuf[2] = TS102_BLK_OFF_DEF_WAN1;
558 req.cmdbuf[3] = 0x0c; /* .XXX. */
559 req.cmdbuf[4] = 0x16; /* X.XX. */
560 req.cmdbuf[5] = 0x10; /* X.... */
561 req.cmdbuf[6] = 0x15; /* X.X.X */
562 req.cmdbuf[7] = 0x10; /* X.... */
563 req.cmdbuf[8] = 0x16; /* X.XX. */
564 req.cmdbuf[9] = 0x0c; /* .XXX. */
565 req.cmdbuf[10] = 0x00; /* ..... */
566 tadpole_request(&req, 1, 0);
568 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
569 req.cmdlen = 11;
570 req.rsplen = 1;
571 req.cmdbuf[1] = 0x08; /*len*/
572 req.cmdbuf[2] = TS102_BLK_OFF_DEF_WAN2;
573 req.cmdbuf[3] = 0x0c; /* .XXX. */
574 req.cmdbuf[4] = 0x0d; /* .XX.X */
575 req.cmdbuf[5] = 0x01; /* ....X */
576 req.cmdbuf[6] = 0x15; /* X.X.X */
577 req.cmdbuf[7] = 0x01; /* ....X */
578 req.cmdbuf[8] = 0x0d; /* .XX.X */
579 req.cmdbuf[9] = 0x0c; /* .XXX. */
580 req.cmdbuf[10] = 0x00; /* ..... */
581 tadpole_request(&req, 1, 0);
583 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
584 req.cmdlen = 11;
585 req.rsplen = 1;
586 req.cmdbuf[1] = 0x08; /*len*/
587 req.cmdbuf[2] = TS102_BLK_OFF_DEF_LAN1;
588 req.cmdbuf[3] = 0x00; /* ..... */
589 req.cmdbuf[4] = 0x04; /* ..X.. */
590 req.cmdbuf[5] = 0x08; /* .X... */
591 req.cmdbuf[6] = 0x13; /* X..XX */
592 req.cmdbuf[7] = 0x08; /* .X... */
593 req.cmdbuf[8] = 0x04; /* ..X.. */
594 req.cmdbuf[9] = 0x00; /* ..... */
595 req.cmdbuf[10] = 0x00; /* ..... */
596 tadpole_request(&req, 1, 0);
598 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
599 req.cmdlen = 11;
600 req.rsplen = 1;
601 req.cmdbuf[1] = 0x08; /*len*/
602 req.cmdbuf[2] = TS102_BLK_OFF_DEF_LAN2;
603 req.cmdbuf[3] = 0x00; /* ..... */
604 req.cmdbuf[4] = 0x04; /* ..X.. */
605 req.cmdbuf[5] = 0x02; /* ...X. */
606 req.cmdbuf[6] = 0x19; /* XX..X */
607 req.cmdbuf[7] = 0x02; /* ...X. */
608 req.cmdbuf[8] = 0x04; /* ..X.. */
609 req.cmdbuf[9] = 0x00; /* ..... */
610 req.cmdbuf[10] = 0x00; /* ..... */
611 tadpole_request(&req, 1, 0);
613 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
614 req.cmdlen = 11;
615 req.rsplen = 1;
616 req.cmdbuf[1] = 0x08; /*len*/
617 req.cmdbuf[2] = TS102_BLK_OFF_DEF_PCMCIA;
618 req.cmdbuf[3] = 0x00; /* ..... */
619 req.cmdbuf[4] = 0x0c; /* .XXX. */
620 req.cmdbuf[5] = 0x1f; /* XXXXX */
621 req.cmdbuf[6] = 0x1f; /* XXXXX */
622 req.cmdbuf[7] = 0x1f; /* XXXXX */
623 req.cmdbuf[8] = 0x1f; /* XXXXX */
624 req.cmdbuf[9] = 0x00; /* ..... */
625 req.cmdbuf[10] = 0x00; /* ..... */
626 tadpole_request(&req, 1, 0);
629 /* sc_lcdwanted -> lcd_state */
630 void
631 tctrl_update_lcd(struct tctrl_softc *sc)
633 struct tctrl_req req;
634 int s;
636 s = splhigh();
637 if (sc->sc_lcdwanted == sc->sc_lcdstate) {
638 splx(s);
639 return;
641 sc->sc_lcdstate = sc->sc_lcdwanted;
642 splx(s);
645 * the mask setup on this particular command is *very* bizzare
646 * and totally undocumented.
648 req.cmdbuf[0] = TS102_OP_CTL_LCD;
650 /* leave caps-lock alone */
651 req.cmdbuf[2] = (u_int8_t)(sc->sc_lcdstate & 0xfe);
652 req.cmdbuf[3] = (u_int8_t)((sc->sc_lcdstate & 0x100)>>8);
654 req.cmdbuf[1] = 1;
655 req.cmdbuf[4] = 0;
658 /* XXX this thing is weird.... */
659 req.cmdlen = 3;
660 req.rsplen = 2;
662 /* below are the values one would expect but which won't work */
663 #if 0
664 req.cmdlen = 5;
665 req.rsplen = 4;
666 #endif
667 tadpole_request(&req, 1, 0);
672 * set the blinken-lights on the lcd. what:
673 * what = 0 off, what = 1 on, what = 2 toggle
676 void
677 tadpole_set_lcd(int what, unsigned short which)
679 struct tctrl_softc *sc;
680 int s;
682 sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
684 s = splhigh();
685 switch (what) {
686 case 0:
687 sc->sc_lcdwanted &= ~which;
688 break;
689 case 1:
690 sc->sc_lcdwanted |= which;
691 break;
692 case 2:
693 sc->sc_lcdwanted ^= which;
694 break;
696 splx(s);
699 static void
700 tctrl_read_ext_status(void)
702 struct tctrl_softc *sc;
703 struct tctrl_req req;
704 int s;
706 sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
707 req.cmdbuf[0] = TS102_OP_RD_EXT_STATUS;
708 req.cmdlen = 1;
709 req.rsplen = 3;
710 #ifdef TCTRLDEBUG
711 printf("pre read: sc->sc_ext_status = 0x%x\n", sc->sc_ext_status);
712 #endif
713 tadpole_request(&req, 1, 0);
714 s = splts102();
715 sc->sc_ext_status = (req.rspbuf[0] << 8) + req.rspbuf[1];
716 splx(s);
717 #ifdef TCTRLDEBUG
718 printf("post read: sc->sc_ext_status = 0x%x\n", sc->sc_ext_status);
719 #endif
723 * return 0 if the user will notice and handle the event,
724 * return 1 if the kernel driver should do so.
726 static int
727 tctrl_apm_record_event(struct tctrl_softc *sc, u_int event_type)
729 struct apm_event_info *evp;
731 if ((sc->sc_flags & TCTRL_APM_CTLOPEN) &&
732 (sc->sc_event_count < APM_NEVENTS)) {
733 evp = &sc->sc_event_list[sc->sc_event_ptr];
734 sc->sc_event_count++;
735 sc->sc_event_ptr++;
736 sc->sc_event_ptr %= APM_NEVENTS;
737 evp->type = event_type;
738 evp->index = ++tctrl_apm_evindex;
739 selnotify(&sc->sc_rsel, 0, 0);
740 return(sc->sc_flags & TCTRL_APM_CTLOPEN) ? 0 : 1;
742 return(1);
745 static void
746 tctrl_read_event_status(struct tctrl_softc *sc)
748 struct tctrl_req req;
749 int s, lid;
750 uint32_t v;
752 req.cmdbuf[0] = TS102_OP_RD_EVENT_STATUS;
753 req.cmdlen = 1;
754 req.rsplen = 3;
755 tadpole_request(&req, 1, 0);
756 s = splts102();
757 v = req.rspbuf[0] * 256 + req.rspbuf[1];
758 #ifdef TCTRLDEBUG
759 printf("event: %x\n",v);
760 #endif
761 if (v & TS102_EVENT_STATUS_POWERON_BTN_PRESSED) {
762 printf("%s: Power button pressed\n",sc->sc_dev.dv_xname);
763 tctrl_powerfail(sc);
765 if (v & TS102_EVENT_STATUS_SHUTDOWN_REQUEST) {
766 printf("%s: SHUTDOWN REQUEST!\n", sc->sc_dev.dv_xname);
767 tctrl_powerfail(sc);
769 if (v & TS102_EVENT_STATUS_VERY_LOW_POWER_WARNING) {
770 /*printf("%s: VERY LOW POWER WARNING!\n", sc->sc_dev.dv_xname);*/
771 /* according to a tadpole header, and observation */
772 #ifdef TCTRLDEBUG
773 printf("%s: Battery charge level change\n",
774 sc->sc_dev.dv_xname);
775 #endif
777 if (v & TS102_EVENT_STATUS_LOW_POWER_WARNING) {
778 if (tctrl_apm_record_event(sc, APM_BATTERY_LOW))
779 printf("%s: LOW POWER WARNING!\n", sc->sc_dev.dv_xname);
781 if (v & TS102_EVENT_STATUS_DC_STATUS_CHANGE) {
782 splx(s);
783 tctrl_read_ext_status();
784 tctrl_ac_state(sc);
785 s = splts102();
786 if (tctrl_apm_record_event(sc, APM_POWER_CHANGE))
787 printf("%s: main power %s\n", sc->sc_dev.dv_xname,
788 (sc->sc_ext_status &
789 TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ?
790 "restored" : "removed");
792 if (v & TS102_EVENT_STATUS_LID_STATUS_CHANGE) {
793 splx(s);
794 tctrl_read_ext_status();
795 tctrl_lid_state(sc);
796 tctrl_setup_bitport();
797 #ifdef TCTRLDEBUG
798 printf("%s: lid %s\n", sc->sc_dev.dv_xname,
799 (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN)
800 ? "closed" : "opened");
801 #endif
802 lid = (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) == 0;
804 if (v & TS102_EVENT_STATUS_EXTERNAL_VGA_STATUS_CHANGE) {
805 int vga;
806 splx(s);
807 tctrl_read_ext_status();
808 vga = (sc->sc_ext_status &
809 TS102_EXT_STATUS_EXTERNAL_VGA_ATTACHED) != 0;
810 if (vga != sc->sc_extvga) {
811 sc->sc_extvga = vga;
812 if (sc->sc_video_callback != NULL) {
813 sc->sc_video_callback(
814 sc->sc_video_callback_cookie,
815 sc->sc_extvga);
819 #ifdef DIAGNOSTIC
820 if (v & TS102_EVENT_STATUS_EXT_MOUSE_STATUS_CHANGE) {
821 splx(s);
822 tctrl_read_ext_status();
823 if (sc->sc_ext_status &
824 TS102_EXT_STATUS_EXTERNAL_MOUSE_ATTACHED) {
825 printf("tctrl: external mouse detected\n");
828 #endif
829 sc->sc_ext_pending = 0;
830 splx(s);
833 static void
834 tctrl_lock(struct tctrl_softc *sc)
837 mutex_enter(&sc->sc_requestlock);
840 static void
841 tctrl_unlock(struct tctrl_softc *sc)
844 mutex_exit(&sc->sc_requestlock);
848 tadpole_request(struct tctrl_req *req, int spin, int sleep)
850 struct tctrl_softc *sc;
851 int i, s;
853 sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
854 if (!sc)
855 return ENODEV;
857 tctrl_lock(sc);
859 if (spin)
860 s = splhigh();
861 else
862 s = splts102();
863 sc->sc_flags |= TCTRL_SEND_REQUEST;
864 memcpy(sc->sc_cmdbuf, req->cmdbuf, req->cmdlen);
865 #ifdef DIAGNOSTIC
866 if (sc->sc_wantdata != 0) {
867 splx(s);
868 printf("tctrl: we lost the race\n");
869 tctrl_unlock(sc);
870 return EAGAIN;
872 #endif
873 sc->sc_wantdata = 1;
874 sc->sc_rsplen = req->rsplen;
875 sc->sc_cmdlen = req->cmdlen;
876 sc->sc_cmdoff = sc->sc_rspoff = 0;
878 /* we spin for certain commands, like poweroffs */
879 if (spin) {
880 /* for (i = 0; i < 30000; i++) {*/
881 i = 0;
882 while ((sc->sc_wantdata == 1) && (i < 30000)) {
883 tctrl_intr(sc);
884 DELAY(1);
885 i++;
887 #ifdef DIAGNOSTIC
888 if (i >= 30000) {
889 printf("tctrl: timeout busy waiting for micro controller request!\n");
890 sc->sc_wantdata = 0;
891 splx(s);
892 tctrl_unlock(sc);
893 return EAGAIN;
895 #endif
896 } else {
897 int timeout = 5 * (sc->sc_rsplen + sc->sc_cmdlen);
898 tctrl_intr(sc);
899 i = 0;
900 while (((sc->sc_rspoff != sc->sc_rsplen) ||
901 (sc->sc_cmdoff != sc->sc_cmdlen)) &&
902 (i < timeout))
903 if (sleep) {
904 tsleep(sc, PWAIT, "tctrl_data", 15);
905 i++;
906 } else
907 DELAY(1);
908 #ifdef DIAGNOSTIC
909 if (i >= timeout) {
910 printf("tctrl: timeout waiting for microcontroller request\n");
911 sc->sc_wantdata = 0;
912 splx(s);
913 tctrl_unlock(sc);
914 return EAGAIN;
916 #endif
919 * we give the user a reasonable amount of time for a command
920 * to complete. If it doesn't complete in time, we hand them
921 * garbage. This is here to stop things like setting the
922 * rsplen too long, and sleeping forever in a CMD_REQ ioctl.
924 sc->sc_wantdata = 0;
925 memcpy(req->rspbuf, sc->sc_rspbuf, req->rsplen);
926 splx(s);
928 tctrl_unlock(sc);
929 return 0;
932 void
933 tadpole_powerdown(void)
935 struct tctrl_req req;
937 req.cmdbuf[0] = TS102_OP_ADMIN_POWER_OFF;
938 req.cmdlen = 1;
939 req.rsplen = 1;
940 tadpole_request(&req, 1, 0);
943 void
944 tadpole_set_video(int enabled)
946 struct tctrl_softc *sc;
947 struct tctrl_req req;
948 int s;
950 sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
951 while (sc->sc_wantdata != 0)
952 DELAY(1);
953 s = splts102();
954 if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN && !enabled)
955 || (sc->sc_tft_on)) {
956 req.cmdbuf[2] = TS102_BITPORT_TFTPWR;
957 } else {
958 req.cmdbuf[2] = 0;
960 req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
961 req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR;
962 req.cmdlen = 3;
963 req.rsplen = 2;
965 if ((sc->sc_tft_on && !enabled) || (!sc->sc_tft_on && enabled)) {
966 sc->sc_tft_on = enabled;
967 if (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) {
968 splx(s);
969 return;
971 tadpole_request(&req, 1, 0);
972 sc->sc_bitport =
973 (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
975 splx(s);
978 static void
979 tctrl_write_data(struct tctrl_softc *sc, uint8_t v)
981 unsigned int i;
983 for (i = 0; i < 100; i++) {
984 if (TS102_UCTRL_STS_TXNF_STA &
985 tctrl_read(sc, TS102_REG_UCTRL_STS))
986 break;
988 tctrl_write(sc, TS102_REG_UCTRL_DATA, v);
991 static uint8_t
992 tctrl_read_data(struct tctrl_softc *sc)
994 unsigned int i, v;
996 for (i = 0; i < 100000; i++) {
997 if (TS102_UCTRL_STS_RXNE_STA &
998 tctrl_read(sc, TS102_REG_UCTRL_STS))
999 break;
1000 DELAY(1);
1003 v = tctrl_read(sc, TS102_REG_UCTRL_DATA);
1004 tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA);
1005 return v;
1008 static uint8_t
1009 tctrl_read(struct tctrl_softc *sc, bus_size_t off)
1012 sc->sc_junk = bus_space_read_1(sc->sc_memt, sc->sc_memh, off);
1013 return sc->sc_junk;
1016 static void
1017 tctrl_write(struct tctrl_softc *sc, bus_size_t off, uint8_t v)
1020 sc->sc_junk = v;
1021 bus_space_write_1(sc->sc_memt, sc->sc_memh, off, v);
1025 tctrlopen(dev_t dev, int flags, int mode, struct lwp *l)
1027 int unit = (minor(dev)&0xf0);
1028 int ctl = (minor(dev)&0x0f);
1029 struct tctrl_softc *sc;
1031 if (unit >= tctrl_cd.cd_ndevs)
1032 return(ENXIO);
1033 sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
1034 if (!sc)
1035 return(ENXIO);
1037 switch (ctl) {
1038 case TCTRL_STD_DEV:
1039 break;
1040 case TCTRL_APMCTL_DEV:
1041 if (!(flags & FWRITE))
1042 return(EINVAL);
1043 if (sc->sc_flags & TCTRL_APM_CTLOPEN)
1044 return(EBUSY);
1045 sc->sc_flags |= TCTRL_APM_CTLOPEN;
1046 break;
1047 default:
1048 return(ENXIO);
1049 break;
1052 return(0);
1056 tctrlclose(dev_t dev, int flags, int mode, struct lwp *l)
1058 int ctl = (minor(dev)&0x0f);
1059 struct tctrl_softc *sc;
1061 sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
1062 if (!sc)
1063 return(ENXIO);
1065 switch (ctl) {
1066 case TCTRL_STD_DEV:
1067 break;
1068 case TCTRL_APMCTL_DEV:
1069 sc->sc_flags &= ~TCTRL_APM_CTLOPEN;
1070 break;
1072 return(0);
1076 tctrlioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
1078 struct tctrl_req req, *reqn;
1079 struct tctrl_pwr *pwrreq;
1080 struct apm_power_info *powerp;
1081 struct apm_event_info *evp;
1082 struct tctrl_softc *sc;
1083 int i;
1084 uint8_t c;
1086 sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
1087 if (!sc)
1088 return ENXIO;
1090 switch (cmd) {
1092 case APM_IOC_STANDBY:
1093 /* turn off backlight and so on ? */
1095 return 0; /* for now */
1097 case APM_IOC_SUSPEND:
1098 /* not sure what to do here - we can't really suspend */
1100 return 0; /* for now */
1102 case OAPM_IOC_GETPOWER:
1103 case APM_IOC_GETPOWER:
1104 powerp = (struct apm_power_info *)data;
1105 req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_RATE;
1106 req.cmdlen = 1;
1107 req.rsplen = 2;
1108 tadpole_request(&req, 0, l->l_proc ? 1 : 0);
1109 if (req.rspbuf[0] > 0x00)
1110 powerp->battery_state = APM_BATT_CHARGING;
1111 req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_LEVEL;
1112 req.cmdlen = 1;
1113 req.rsplen = 3;
1114 tadpole_request(&req, 0, l->l_proc ? 1 : 0);
1115 c = req.rspbuf[0];
1116 powerp->battery_life = c;
1117 if (c > 0x70) /* the tadpole sometimes dips below zero, and */
1118 c = 0; /* into the 255 range. */
1119 powerp->minutes_left = (45 * c) / 100; /* XXX based on 45 min */
1120 if (powerp->battery_state != APM_BATT_CHARGING) {
1121 if (c < 0x20)
1122 powerp->battery_state = APM_BATT_CRITICAL;
1123 else if (c < 0x40)
1124 powerp->battery_state = APM_BATT_LOW;
1125 else if (c < 0x66)
1126 powerp->battery_state = APM_BATT_HIGH;
1127 else
1128 powerp->battery_state = APM_BATT_UNKNOWN;
1131 if (sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE)
1132 powerp->ac_state = APM_AC_ON;
1133 else
1134 powerp->ac_state = APM_AC_OFF;
1135 break;
1137 case APM_IOC_NEXTEVENT:
1138 if (!sc->sc_event_count)
1139 return EAGAIN;
1141 evp = (struct apm_event_info *)data;
1142 i = sc->sc_event_ptr + APM_NEVENTS - sc->sc_event_count;
1143 i %= APM_NEVENTS;
1144 *evp = sc->sc_event_list[i];
1145 sc->sc_event_count--;
1146 return(0);
1148 /* this ioctl assumes the caller knows exactly what he is doing */
1149 case TCTRL_CMD_REQ:
1150 reqn = (struct tctrl_req *)data;
1151 if ((i = kauth_authorize_generic(l->l_cred,
1152 KAUTH_GENERIC_ISSUSER, NULL)) != 0 &&
1153 (reqn->cmdbuf[0] == TS102_OP_CTL_BITPORT ||
1154 (reqn->cmdbuf[0] >= TS102_OP_CTL_WATCHDOG &&
1155 reqn->cmdbuf[0] <= TS102_OP_CTL_SECURITY_KEY) ||
1156 reqn->cmdbuf[0] == TS102_OP_CTL_TIMEZONE ||
1157 reqn->cmdbuf[0] == TS102_OP_CTL_DIAGNOSTIC_MODE ||
1158 reqn->cmdbuf[0] == TS102_OP_CMD_SOFTWARE_RESET ||
1159 (reqn->cmdbuf[0] >= TS102_OP_CMD_SET_RTC &&
1160 reqn->cmdbuf[0] < TS102_OP_RD_INT_CHARGE_LEVEL) ||
1161 reqn->cmdbuf[0] > TS102_OP_RD_EXT_CHARGE_LEVEL))
1162 return(i);
1163 tadpole_request(reqn, 0, l->l_proc ? 1 : 0);
1164 break;
1165 /* serial power mode (via auxiotwo) */
1166 case TCTRL_SERIAL_PWR:
1167 pwrreq = (struct tctrl_pwr *)data;
1168 if (pwrreq->rw)
1169 pwrreq->state = auxiotwoserialgetapm();
1170 else
1171 auxiotwoserialsetapm(pwrreq->state);
1172 break;
1174 /* modem power mode (via auxio) */
1175 case TCTRL_MODEM_PWR:
1176 return(EOPNOTSUPP); /* for now */
1177 break;
1180 default:
1181 return (ENOTTY);
1183 return (0);
1187 tctrlpoll(dev_t dev, int events, struct lwp *l)
1189 struct tctrl_softc *sc = device_lookup_private(&tctrl_cd,
1190 TCTRL_STD_DEV);
1191 int revents = 0;
1193 if (events & (POLLIN | POLLRDNORM)) {
1194 if (sc->sc_event_count)
1195 revents |= events & (POLLIN | POLLRDNORM);
1196 else
1197 selrecord(l, &sc->sc_rsel);
1200 return (revents);
1203 static void
1204 filt_tctrlrdetach(struct knote *kn)
1206 struct tctrl_softc *sc = kn->kn_hook;
1207 int s;
1209 s = splts102();
1210 SLIST_REMOVE(&sc->sc_rsel.sel_klist, kn, knote, kn_selnext);
1211 splx(s);
1214 static int
1215 filt_tctrlread(struct knote *kn, long hint)
1217 struct tctrl_softc *sc = kn->kn_hook;
1219 kn->kn_data = sc->sc_event_count;
1220 return (kn->kn_data > 0);
1223 static const struct filterops tctrlread_filtops =
1224 { 1, NULL, filt_tctrlrdetach, filt_tctrlread };
1227 tctrlkqfilter(dev_t dev, struct knote *kn)
1229 struct tctrl_softc *sc = device_lookup_private(&tctrl_cd,
1230 TCTRL_STD_DEV);
1231 struct klist *klist;
1232 int s;
1234 switch (kn->kn_filter) {
1235 case EVFILT_READ:
1236 klist = &sc->sc_rsel.sel_klist;
1237 kn->kn_fop = &tctrlread_filtops;
1238 break;
1240 default:
1241 return (1);
1244 kn->kn_hook = sc;
1246 s = splts102();
1247 SLIST_INSERT_HEAD(klist, kn, kn_selnext);
1248 splx(s);
1250 return (0);
1253 static void
1254 tctrl_sensor_setup(struct tctrl_softc *sc)
1256 int i, error;
1258 sc->sc_sme = sysmon_envsys_create();
1260 /* case temperature */
1261 (void)strlcpy(sc->sc_sensor[0].desc, "Case temperature",
1262 sizeof(sc->sc_sensor[0].desc));
1263 sc->sc_sensor[0].units = ENVSYS_STEMP;
1265 /* battery voltage */
1266 (void)strlcpy(sc->sc_sensor[1].desc, "Internal battery voltage",
1267 sizeof(sc->sc_sensor[1].desc));
1268 sc->sc_sensor[1].units = ENVSYS_SVOLTS_DC;
1270 /* DC voltage */
1271 (void)strlcpy(sc->sc_sensor[2].desc, "DC-In voltage",
1272 sizeof(sc->sc_sensor[2].desc));
1273 sc->sc_sensor[2].units = ENVSYS_SVOLTS_DC;
1275 for (i = 0; i < ENVSYS_NUMSENSORS; i++) {
1276 if (sysmon_envsys_sensor_attach(sc->sc_sme,
1277 &sc->sc_sensor[i])) {
1278 sysmon_envsys_destroy(sc->sc_sme);
1279 return;
1283 sc->sc_sme->sme_name = sc->sc_dev.dv_xname;
1284 sc->sc_sme->sme_cookie = sc;
1285 sc->sc_sme->sme_refresh = tctrl_refresh;
1287 if ((error = sysmon_envsys_register(sc->sc_sme)) != 0) {
1288 printf("%s: couldn't register sensors (%d)\n",
1289 sc->sc_dev.dv_xname, error);
1290 sysmon_envsys_destroy(sc->sc_sme);
1291 return;
1294 /* now register the power button */
1296 sysmon_task_queue_init();
1298 sc->sc_powerpressed = 0;
1299 memset(&sc->sc_sm_pbutton, 0, sizeof(struct sysmon_pswitch));
1300 sc->sc_sm_pbutton.smpsw_name = sc->sc_dev.dv_xname;
1301 sc->sc_sm_pbutton.smpsw_type = PSWITCH_TYPE_POWER;
1302 if (sysmon_pswitch_register(&sc->sc_sm_pbutton) != 0)
1303 printf("%s: unable to register power button with sysmon\n",
1304 sc->sc_dev.dv_xname);
1306 memset(&sc->sc_sm_lid, 0, sizeof(struct sysmon_pswitch));
1307 sc->sc_sm_lid.smpsw_name = sc->sc_dev.dv_xname;
1308 sc->sc_sm_lid.smpsw_type = PSWITCH_TYPE_LID;
1309 if (sysmon_pswitch_register(&sc->sc_sm_lid) != 0)
1310 printf("%s: unable to register lid switch with sysmon\n",
1311 sc->sc_dev.dv_xname);
1313 memset(&sc->sc_sm_ac, 0, sizeof(struct sysmon_pswitch));
1314 sc->sc_sm_ac.smpsw_name = sc->sc_dev.dv_xname;
1315 sc->sc_sm_ac.smpsw_type = PSWITCH_TYPE_ACADAPTER;
1316 if (sysmon_pswitch_register(&sc->sc_sm_ac) != 0)
1317 printf("%s: unable to register AC adaptor with sysmon\n",
1318 sc->sc_dev.dv_xname);
1321 static void
1322 tctrl_power_button_pressed(void *arg)
1324 struct tctrl_softc *sc = arg;
1326 sysmon_pswitch_event(&sc->sc_sm_pbutton, PSWITCH_EVENT_PRESSED);
1327 sc->sc_powerpressed = 0;
1330 static void
1331 tctrl_lid_state(struct tctrl_softc *sc)
1333 int state;
1335 state = (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) ?
1336 PSWITCH_EVENT_PRESSED : PSWITCH_EVENT_RELEASED;
1337 sysmon_pswitch_event(&sc->sc_sm_lid, state);
1340 static void
1341 tctrl_ac_state(struct tctrl_softc *sc)
1343 int state;
1345 state = (sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ?
1346 PSWITCH_EVENT_PRESSED : PSWITCH_EVENT_RELEASED;
1347 sysmon_pswitch_event(&sc->sc_sm_ac, state);
1350 static int
1351 tctrl_powerfail(void *arg)
1353 struct tctrl_softc *sc = (struct tctrl_softc *)arg;
1356 * We lost power. Queue a callback with thread context to
1357 * handle all the real work.
1359 if (sc->sc_powerpressed == 0) {
1360 sc->sc_powerpressed = 1;
1361 sysmon_task_queue_sched(0, tctrl_power_button_pressed, sc);
1363 return (1);
1366 static void
1367 tctrl_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
1369 /*struct tctrl_softc *sc = sme->sme_cookie;*/
1370 struct tctrl_req req;
1371 int sleepable;
1372 int i;
1374 i = edata->sensor;
1375 sleepable = curlwp ? 1 : 0;
1377 switch (i)
1379 case 0: /* case temperature */
1380 req.cmdbuf[0] = TS102_OP_RD_CURRENT_TEMP;
1381 req.cmdlen = 1;
1382 req.rsplen = 2;
1383 tadpole_request(&req, 0, sleepable);
1384 edata->value_cur = /* 273160? */
1385 (uint32_t)((int)((int)req.rspbuf[0] - 32) * 5000000
1386 / 9 + 273150000);
1387 req.cmdbuf[0] = TS102_OP_RD_MAX_TEMP;
1388 req.cmdlen = 1;
1389 req.rsplen = 2;
1390 tadpole_request(&req, 0, sleepable);
1391 edata->value_max =
1392 (uint32_t)((int)((int)req.rspbuf[0] - 32) * 5000000
1393 / 9 + 273150000);
1394 edata->flags |= ENVSYS_FVALID_MAX;
1395 req.cmdbuf[0] = TS102_OP_RD_MIN_TEMP;
1396 req.cmdlen = 1;
1397 req.rsplen = 2;
1398 tadpole_request(&req, 0, sleepable);
1399 edata->value_min =
1400 (uint32_t)((int)((int)req.rspbuf[0] - 32) * 5000000
1401 / 9 + 273150000);
1402 edata->flags |= ENVSYS_FVALID_MIN;
1403 edata->units = ENVSYS_STEMP;
1404 break;
1406 case 1: /* battery voltage */
1408 edata->units = ENVSYS_SVOLTS_DC;
1409 req.cmdbuf[0] = TS102_OP_RD_INT_BATT_VLT;
1410 req.cmdlen = 1;
1411 req.rsplen = 2;
1412 tadpole_request(&req, 0, sleepable);
1413 edata->value_cur = (int32_t)req.rspbuf[0] *
1414 1000000 / 11;
1416 break;
1417 case 2: /* DC voltage */
1419 edata->units = ENVSYS_SVOLTS_DC;
1420 req.cmdbuf[0] = TS102_OP_RD_DC_IN_VLT;
1421 req.cmdlen = 1;
1422 req.rsplen = 2;
1423 tadpole_request(&req, 0, sleepable);
1424 edata->value_cur = (int32_t)req.rspbuf[0] *
1425 1000000 / 11;
1427 break;
1429 edata->state = ENVSYS_SVALID;
1432 static void
1433 tctrl_event_thread(void *v)
1435 struct tctrl_softc *sc = v;
1436 struct device *dv;
1437 struct sd_softc *sd = NULL;
1438 struct lance_softc *le = NULL;
1439 int ticks = hz/2;
1440 int rcount, wcount;
1441 int s;
1443 while (sd == NULL) {
1444 dv = device_find_by_xname("sd0");
1445 if (dv != NULL)
1446 sd = device_private(dv);
1447 else
1448 tsleep(&sc->sc_events, PWAIT, "probe_disk", hz);
1450 dv = device_find_by_xname("le0");
1451 if (dv != NULL)
1452 le = device_private(dv);
1453 printf("found %s\n", device_xname(sd->sc_dev));
1454 rcount = sd->sc_dk.dk_stats->io_rxfer;
1455 wcount = sd->sc_dk.dk_stats->io_wxfer;
1457 tctrl_read_event_status(sc);
1459 while (1) {
1460 tsleep(&sc->sc_events, PWAIT, "tctrl_event", ticks);
1461 s = splhigh();
1462 if ((rcount != sd->sc_dk.dk_stats->io_rxfer) ||
1463 (wcount != sd->sc_dk.dk_stats->io_wxfer)) {
1464 rcount = sd->sc_dk.dk_stats->io_rxfer;
1465 wcount = sd->sc_dk.dk_stats->io_wxfer;
1466 sc->sc_lcdwanted |= TS102_LCD_DISK_ACTIVE;
1467 } else
1468 sc->sc_lcdwanted &= ~TS102_LCD_DISK_ACTIVE;
1469 if (le != NULL) {
1470 if (le->sc_havecarrier != 0) {
1471 sc->sc_lcdwanted |= TS102_LCD_LAN_ACTIVE;
1472 } else
1473 sc->sc_lcdwanted &= ~TS102_LCD_LAN_ACTIVE;
1475 splx(s);
1476 tctrl_update_lcd(sc);
1477 if (sc->sc_ext_pending)
1478 tctrl_read_event_status(sc);
1482 void
1483 tadpole_register_callback(void (*callback)(void *, int), void *cookie)
1485 struct tctrl_softc *sc;
1487 sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
1488 sc->sc_video_callback = callback;
1489 sc->sc_video_callback_cookie = cookie;
1490 if (sc->sc_video_callback != NULL) {
1491 sc->sc_video_callback(sc->sc_video_callback_cookie,
1492 sc->sc_extvga);