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