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