tctrl.c revision 1.33 1 /* $NetBSD: tctrl.c,v 1.33 2006/04/20 12:13:51 blymn 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.33 2006/04/20 12:13:51 blymn 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 = suser(l->l_proc->p_ucred, &l->l_proc->p_acflag)) != 0 &&
1177 (reqn->cmdbuf[0] == TS102_OP_CTL_BITPORT ||
1178 (reqn->cmdbuf[0] >= TS102_OP_CTL_WATCHDOG &&
1179 reqn->cmdbuf[0] <= TS102_OP_CTL_SECURITY_KEY) ||
1180 reqn->cmdbuf[0] == TS102_OP_CTL_TIMEZONE ||
1181 reqn->cmdbuf[0] == TS102_OP_CTL_DIAGNOSTIC_MODE ||
1182 reqn->cmdbuf[0] == TS102_OP_CMD_SOFTWARE_RESET ||
1183 (reqn->cmdbuf[0] >= TS102_OP_CMD_SET_RTC &&
1184 reqn->cmdbuf[0] < TS102_OP_RD_INT_CHARGE_LEVEL) ||
1185 reqn->cmdbuf[0] > TS102_OP_RD_EXT_CHARGE_LEVEL))
1186 return(i);
1187 reqn->p = l->l_proc;
1188 tadpole_request(reqn, 0);
1189 break;
1190 /* serial power mode (via auxiotwo) */
1191 case TCTRL_SERIAL_PWR:
1192 pwrreq = (struct tctrl_pwr *)data;
1193 if (pwrreq->rw)
1194 pwrreq->state = auxiotwoserialgetapm();
1195 else
1196 auxiotwoserialsetapm(pwrreq->state);
1197 break;
1198
1199 /* modem power mode (via auxio) */
1200 case TCTRL_MODEM_PWR:
1201 return(EOPNOTSUPP); /* for now */
1202 break;
1203
1204
1205 default:
1206 return (ENOTTY);
1207 }
1208 return (0);
1209 }
1210
1211 int
1212 tctrlpoll(dev_t dev, int events, struct lwp *l)
1213 {
1214 struct tctrl_softc *sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
1215 int revents = 0;
1216
1217 if (events & (POLLIN | POLLRDNORM)) {
1218 if (sc->sc_event_count)
1219 revents |= events & (POLLIN | POLLRDNORM);
1220 else
1221 selrecord(l, &sc->sc_rsel);
1222 }
1223
1224 return (revents);
1225 }
1226
1227 static void
1228 filt_tctrlrdetach(struct knote *kn)
1229 {
1230 struct tctrl_softc *sc = kn->kn_hook;
1231 int s;
1232
1233 s = splts102();
1234 SLIST_REMOVE(&sc->sc_rsel.sel_klist, kn, knote, kn_selnext);
1235 splx(s);
1236 }
1237
1238 static int
1239 filt_tctrlread(struct knote *kn, long hint)
1240 {
1241 struct tctrl_softc *sc = kn->kn_hook;
1242
1243 kn->kn_data = sc->sc_event_count;
1244 return (kn->kn_data > 0);
1245 }
1246
1247 static const struct filterops tctrlread_filtops =
1248 { 1, NULL, filt_tctrlrdetach, filt_tctrlread };
1249
1250 int
1251 tctrlkqfilter(dev_t dev, struct knote *kn)
1252 {
1253 struct tctrl_softc *sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
1254 struct klist *klist;
1255 int s;
1256
1257 switch (kn->kn_filter) {
1258 case EVFILT_READ:
1259 klist = &sc->sc_rsel.sel_klist;
1260 kn->kn_fop = &tctrlread_filtops;
1261 break;
1262
1263 default:
1264 return (1);
1265 }
1266
1267 kn->kn_hook = sc;
1268
1269 s = splts102();
1270 SLIST_INSERT_HEAD(klist, kn, kn_selnext);
1271 splx(s);
1272
1273 return (0);
1274 }
1275
1276 static void
1277 tctrl_sensor_setup(struct tctrl_softc *sc)
1278 {
1279 int error;
1280
1281 /* case temperature */
1282 strcpy(sc->sc_binfo[0].desc, "Case temperature");
1283 sc->sc_binfo[0].sensor = 0;
1284 sc->sc_binfo[0].units = ENVSYS_STEMP;
1285 sc->sc_binfo[0].validflags = ENVSYS_FVALID | ENVSYS_FCURVALID;
1286 sc->sc_range[0].low = 0;
1287 sc->sc_range[0].high = 0;
1288 sc->sc_range[0].units = ENVSYS_STEMP;
1289 sc->sc_tre[0].sensor = 0;
1290 sc->sc_tre[0].warnflags = ENVSYS_WARN_OK;
1291 sc->sc_tre[0].validflags = ENVSYS_FVALID | ENVSYS_FCURVALID;
1292 sc->sc_tre[0].units = ENVSYS_STEMP;
1293
1294 /* battery voltage */
1295 strcpy(sc->sc_binfo[1].desc, "Internal battery voltage");
1296 sc->sc_binfo[1].sensor = 1;
1297 sc->sc_binfo[1].units = ENVSYS_SVOLTS_DC;
1298 sc->sc_binfo[1].validflags = ENVSYS_FVALID | ENVSYS_FCURVALID;
1299 sc->sc_range[1].low = 0;
1300 sc->sc_range[1].high = 0;
1301 sc->sc_range[1].units = ENVSYS_SVOLTS_DC;
1302 sc->sc_tre[1].sensor = 0;
1303 sc->sc_tre[1].warnflags = ENVSYS_WARN_OK;
1304 sc->sc_tre[1].validflags = ENVSYS_FVALID | ENVSYS_FCURVALID;
1305 sc->sc_tre[1].units = ENVSYS_SVOLTS_DC;
1306
1307 /* DC voltage */
1308 strcpy(sc->sc_binfo[2].desc, "DC-In voltage");
1309 sc->sc_binfo[2].sensor = 2;
1310 sc->sc_binfo[2].units = ENVSYS_SVOLTS_DC;
1311 sc->sc_binfo[2].validflags = ENVSYS_FVALID | ENVSYS_FCURVALID;
1312 sc->sc_range[2].low = 0;
1313 sc->sc_range[2].high = 0;
1314 sc->sc_range[2].units = ENVSYS_SVOLTS_DC;
1315 sc->sc_tre[2].sensor = 0;
1316 sc->sc_tre[2].warnflags = ENVSYS_WARN_OK;
1317 sc->sc_tre[2].validflags = ENVSYS_FVALID | ENVSYS_FCURVALID;
1318 sc->sc_tre[2].units = ENVSYS_SVOLTS_DC;
1319
1320 sc->sc_sme.sme_nsensors = ENVSYS_NUMSENSORS;
1321 sc->sc_sme.sme_envsys_version = 1000;
1322 sc->sc_sme.sme_ranges = sc->sc_range;
1323 sc->sc_sme.sme_sensor_info = sc->sc_binfo;
1324 sc->sc_sme.sme_sensor_data = sc->sc_tre;
1325 sc->sc_sme.sme_cookie = sc;
1326 sc->sc_sme.sme_gtredata = tctrl_gtredata;
1327 sc->sc_sme.sme_streinfo = tctrl_streinfo;
1328 sc->sc_sme.sme_flags = 0;
1329
1330 if ((error = sysmon_envsys_register(&sc->sc_sme)) != 0) {
1331 printf("%s: couldn't register sensors (%d)\n",
1332 sc->sc_dev.dv_xname, error);
1333 }
1334
1335 /* now register the power button */
1336
1337 sysmon_task_queue_init();
1338
1339 sc->sc_powerpressed = 0;
1340 memset(&sc->sc_sm_pbutton, 0, sizeof(struct sysmon_pswitch));
1341 sc->sc_sm_pbutton.smpsw_name = sc->sc_dev.dv_xname;
1342 sc->sc_sm_pbutton.smpsw_type = PSWITCH_TYPE_POWER;
1343 if (sysmon_pswitch_register(&sc->sc_sm_pbutton) != 0)
1344 printf("%s: unable to register power button with sysmon\n",
1345 sc->sc_dev.dv_xname);
1346
1347 memset(&sc->sc_sm_lid, 0, sizeof(struct sysmon_pswitch));
1348 sc->sc_sm_lid.smpsw_name = sc->sc_dev.dv_xname;
1349 sc->sc_sm_lid.smpsw_type = PSWITCH_TYPE_LID;
1350 if (sysmon_pswitch_register(&sc->sc_sm_lid) != 0)
1351 printf("%s: unable to register lid switch with sysmon\n",
1352 sc->sc_dev.dv_xname);
1353
1354 memset(&sc->sc_sm_ac, 0, sizeof(struct sysmon_pswitch));
1355 sc->sc_sm_ac.smpsw_name = sc->sc_dev.dv_xname;
1356 sc->sc_sm_ac.smpsw_type = PSWITCH_TYPE_ACADAPTER;
1357 if (sysmon_pswitch_register(&sc->sc_sm_ac) != 0)
1358 printf("%s: unable to register AC adaptor with sysmon\n",
1359 sc->sc_dev.dv_xname);
1360 }
1361
1362 static void
1363 tctrl_power_button_pressed(void *arg)
1364 {
1365 struct tctrl_softc *sc = arg;
1366
1367 sysmon_pswitch_event(&sc->sc_sm_pbutton, PSWITCH_EVENT_PRESSED);
1368 sc->sc_powerpressed = 0;
1369 }
1370
1371 static void
1372 tctrl_lid_state(struct tctrl_softc *sc)
1373 {
1374 int state;
1375
1376 state = (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) ?
1377 PSWITCH_STATE_PRESSED : PSWITCH_STATE_RELEASED;
1378 sysmon_pswitch_event(&sc->sc_sm_lid, state);
1379 }
1380
1381 static void
1382 tctrl_ac_state(struct tctrl_softc *sc)
1383 {
1384 int state;
1385
1386 state = (sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ?
1387 PSWITCH_STATE_PRESSED : PSWITCH_STATE_RELEASED;
1388 sysmon_pswitch_event(&sc->sc_sm_ac, state);
1389 }
1390
1391 static int
1392 tctrl_powerfail(void *arg)
1393 {
1394 struct tctrl_softc *sc = (struct tctrl_softc *)arg;
1395
1396 /*
1397 * We lost power. Queue a callback with thread context to
1398 * handle all the real work.
1399 */
1400 if (sc->sc_powerpressed == 0) {
1401 sc->sc_powerpressed = 1;
1402 sysmon_task_queue_sched(0, tctrl_power_button_pressed, sc);
1403 }
1404 return (1);
1405 }
1406
1407 static int
1408 tctrl_gtredata(struct sysmon_envsys *sme, struct envsys_tre_data *tred)
1409 {
1410 /*struct tctrl_softc *sc = sme->sme_cookie;*/
1411 struct envsys_tre_data *cur_tre;
1412 struct envsys_basic_info *cur_i;
1413 struct tctrl_req req;
1414 struct proc *p;
1415 int i;
1416
1417 i = tred->sensor;
1418 cur_tre = &sme->sme_sensor_data[i];
1419 cur_i = &sme->sme_sensor_info[i];
1420 p = __curproc();
1421
1422 switch (i)
1423 {
1424 case 0: /* case temperature */
1425 req.cmdbuf[0] = TS102_OP_RD_CURRENT_TEMP;
1426 req.cmdlen = 1;
1427 req.rsplen = 2;
1428 req.p = p;
1429 tadpole_request(&req, 0);
1430 cur_tre->cur.data_us = /* 273160? */
1431 (uint32_t)((int)((int)req.rspbuf[0] - 32) * 5000000
1432 / 9 + 273150000);
1433 cur_tre->validflags |= ENVSYS_FCURVALID;
1434 req.cmdbuf[0] = TS102_OP_RD_MAX_TEMP;
1435 req.cmdlen = 1;
1436 req.rsplen = 2;
1437 req.p = p;
1438 tadpole_request(&req, 0);
1439 cur_tre->max.data_us =
1440 (uint32_t)((int)((int)req.rspbuf[0] - 32) * 5000000
1441 / 9 + 273150000);
1442 cur_tre->validflags |= ENVSYS_FMAXVALID;
1443 req.cmdbuf[0] = TS102_OP_RD_MIN_TEMP;
1444 req.cmdlen = 1;
1445 req.rsplen = 2;
1446 req.p = p;
1447 tadpole_request(&req, 0);
1448 cur_tre->min.data_us =
1449 (uint32_t)((int)((int)req.rspbuf[0] - 32) * 5000000
1450 / 9 + 273150000);
1451 cur_tre->validflags |= ENVSYS_FMINVALID;
1452 cur_tre->units = ENVSYS_STEMP;
1453 break;
1454
1455 case 1: /* battery voltage */
1456 {
1457 cur_tre->validflags =
1458 ENVSYS_FVALID|ENVSYS_FCURVALID;
1459 cur_tre->units = ENVSYS_SVOLTS_DC;
1460 req.cmdbuf[0] = TS102_OP_RD_INT_BATT_VLT;
1461 req.cmdlen = 1;
1462 req.rsplen = 2;
1463 req.p = p;
1464 tadpole_request(&req, 0);
1465 cur_tre->cur.data_s = (int32_t)req.rspbuf[0] *
1466 1000000 / 11;
1467 }
1468 break;
1469 case 2: /* DC voltage */
1470 {
1471 cur_tre->validflags =
1472 ENVSYS_FVALID|ENVSYS_FCURVALID;
1473 cur_tre->units = ENVSYS_SVOLTS_DC;
1474 req.cmdbuf[0] = TS102_OP_RD_DC_IN_VLT;
1475 req.cmdlen = 1;
1476 req.rsplen = 2;
1477 req.p = p;
1478 tadpole_request(&req, 0);
1479 cur_tre->cur.data_s = (int32_t)req.rspbuf[0] *
1480 1000000 / 11;
1481 }
1482 break;
1483 }
1484 cur_tre->validflags |= ENVSYS_FVALID;
1485 *tred = sme->sme_sensor_data[i];
1486 return 0;
1487 }
1488
1489
1490 static int
1491 tctrl_streinfo(struct sysmon_envsys *sme, struct envsys_basic_info *binfo)
1492 {
1493
1494 /* There is nothing to set here. */
1495 return (EINVAL);
1496 }
1497
1498 static void
1499 tctrl_create_event_thread(void *v)
1500 {
1501 struct tctrl_softc *sc = v;
1502 const char *name = sc->sc_dev.dv_xname;
1503
1504 if (kthread_create1(tctrl_event_thread, sc, &sc->sc_thread, "%s",
1505 name) != 0) {
1506 printf("%s: unable to create event kthread", name);
1507 }
1508 }
1509
1510 static void
1511 tctrl_event_thread(void *v)
1512 {
1513 struct tctrl_softc *sc = v;
1514 struct device *dv;
1515 struct sd_softc *sd = NULL;
1516 struct lance_softc *le = NULL;
1517 int ticks = hz/2;
1518 int rcount, wcount;
1519 int s;
1520
1521 while (sd == NULL) {
1522 for (dv = alldevs.tqh_first; dv; dv = dv->dv_list.tqe_next) {
1523 if (strcmp(dv->dv_xname, "sd0") == 0) {
1524 sd = (struct sd_softc *)dv;
1525 }
1526 if (le == NULL) {
1527 if (strcmp(dv->dv_xname, "le0") == 0)
1528 le = (struct lance_softc *)dv;
1529 }
1530 }
1531 if (sd == NULL)
1532 tsleep(&sc->sc_events, PWAIT, "probe_disk", hz);
1533 }
1534 printf("found %s\n", sd->sc_dev.dv_xname);
1535 rcount = sd->sc_dk.dk_stats->io_rxfer;
1536 wcount = sd->sc_dk.dk_stats->io_wxfer;
1537
1538 tctrl_read_event_status(sc);
1539
1540 while (1) {
1541 tsleep(&sc->sc_events, PWAIT, "tctrl_event", ticks);
1542 s = splhigh();
1543 if ((rcount != sd->sc_dk.dk_stats->io_rxfer) ||
1544 (wcount != sd->sc_dk.dk_stats->io_wxfer)) {
1545 rcount = sd->sc_dk.dk_stats->io_rxfer;
1546 wcount = sd->sc_dk.dk_stats->io_wxfer;
1547 sc->sc_lcdwanted |= TS102_LCD_DISK_ACTIVE;
1548 } else
1549 sc->sc_lcdwanted &= ~TS102_LCD_DISK_ACTIVE;
1550 if (le != NULL) {
1551 if (le->sc_havecarrier != 0) {
1552 sc->sc_lcdwanted |= TS102_LCD_LAN_ACTIVE;
1553 } else
1554 sc->sc_lcdwanted &= ~TS102_LCD_LAN_ACTIVE;
1555 }
1556 splx(s);
1557 tctrl_update_lcd(sc);
1558 if (sc->sc_ext_pending)
1559 tctrl_read_event_status(sc);
1560 }
1561 }
1562
1563 void
1564 tadpole_register_callback(void (*callback)(void *, int), void *cookie)
1565 {
1566 struct tctrl_softc *sc;
1567
1568 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
1569 sc->sc_video_callback = callback;
1570 sc->sc_video_callback_cookie = cookie;
1571 if (sc->sc_video_callback != NULL) {
1572 sc->sc_video_callback(sc->sc_video_callback_cookie,
1573 sc->sc_extvga);
1574 }
1575 }
1576