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