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