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