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