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