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