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