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