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