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