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