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