tctrl.c revision 1.13.2.1 1 /* $NetBSD: tctrl.c,v 1.13.2.1 2001/10/10 11:56:33 fvdl 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 #include <sys/vnode.h>
57
58 #include <machine/apmvar.h>
59 #include <machine/autoconf.h>
60 #include <machine/bus.h>
61 #include <machine/intr.h>
62 #include <machine/tctrl.h>
63
64 #include <sparc/dev/ts102reg.h>
65 #include <sparc/dev/tctrlvar.h>
66 #include <sparc/sparc/auxiotwo.h>
67
68 cdev_decl(tctrl);
69
70 extern struct cfdriver tctrl_cd;
71
72 static const char *tctrl_ext_statuses[16] = {
73 "main power available",
74 "internal battery attached",
75 "external battery attached",
76 "external VGA attached",
77 "external keyboard attached",
78 "external mouse attached",
79 "lid down",
80 "internal battery charging",
81 "external battery charging",
82 "internal battery discharging",
83 "external battery discharging",
84 };
85
86 struct tctrl_softc {
87 struct device sc_dev;
88 bus_space_tag_t sc_memt;
89 bus_space_handle_t sc_memh;
90 unsigned int sc_junk;
91 unsigned int sc_ext_status;
92 unsigned int sc_flags;
93 #define TCTRL_SEND_REQUEST 0x0001
94 #define TCTRL_APM_CTLOPEN 0x0002
95 unsigned int sc_wantdata;
96 volatile unsigned short sc_lcdstate;
97 enum { TCTRL_IDLE, TCTRL_ARGS,
98 TCTRL_ACK, TCTRL_DATA } sc_state;
99 u_int8_t sc_cmdbuf[16];
100 u_int8_t sc_rspbuf[16];
101 u_int8_t sc_bitport;
102 u_int8_t sc_tft_on;
103 u_int8_t sc_op;
104 u_int8_t sc_cmdoff;
105 u_int8_t sc_cmdlen;
106 u_int8_t sc_rspoff;
107 u_int8_t sc_rsplen;
108 /* APM stuff */
109 #define APM_NEVENTS 16
110 struct apm_event_info sc_event_list[APM_NEVENTS];
111 int sc_event_count;
112 int sc_event_ptr;
113 struct selinfo sc_rsel;
114 /* ENVSYS stuff */
115 #define ENVSYS_NUMSENSORS 3
116 struct envsys_sensor sc_esensors[ENVSYS_NUMSENSORS];
117
118 struct evcnt sc_intrcnt; /* interrupt counting */
119 };
120
121 #define TCTRL_STD_DEV 0
122 #define TCTRL_APMCTL_DEV 8
123
124 static struct callout tctrl_event_ch = CALLOUT_INITIALIZER;
125
126 static int tctrl_match __P((struct device *parent, struct cfdata *cf,
127 void *aux));
128 static void tctrl_attach __P((struct device *parent, struct device *self,
129 void *aux));
130 static void tctrl_write __P((struct tctrl_softc *sc, bus_size_t off,
131 u_int8_t v));
132 static u_int8_t tctrl_read __P((struct tctrl_softc *sc, bus_size_t off));
133 static void tctrl_write_data __P((struct tctrl_softc *sc, u_int8_t v));
134 static u_int8_t tctrl_read_data __P((struct tctrl_softc *sc));
135 static int tctrl_intr __P((void *arg));
136 static void tctrl_setup_bitport __P((void));
137 static void tctrl_setup_bitport_nop __P((void));
138 static void tctrl_read_ext_status __P((void));
139 static void tctrl_read_event_status __P((void *arg));
140 static int tctrl_apm_record_event __P((struct tctrl_softc *sc,
141 u_int event_type));
142 static void tctrl_init_lcd __P((void));
143
144 struct cfattach tctrl_ca = {
145 sizeof(struct tctrl_softc), tctrl_match, tctrl_attach
146 };
147
148 extern struct cfdriver tctrl_cd;
149 /* XXX wtf is this? see i386/apm.c */
150 int tctrl_apm_evindex;
151
152 static int
153 tctrl_match(parent, cf, aux)
154 struct device *parent;
155 struct cfdata *cf;
156 void *aux;
157 {
158 union obio_attach_args *uoba = aux;
159 struct sbus_attach_args *sa = &uoba->uoba_sbus;
160
161 if (uoba->uoba_isobio4 != 0) {
162 return (0);
163 }
164
165 /* Tadpole 3GX/3GS uses "uctrl" for the Tadpole Microcontroller
166 * (who's interface is off the TS102 PCMCIA controller but there
167 * exists a OpenProm for microcontroller interface).
168 */
169 return strcmp("uctrl", sa->sa_name) == 0;
170 }
171
172 static void
173 tctrl_attach(parent, self, aux)
174 struct device *parent;
175 struct device *self;
176 void *aux;
177 {
178 struct tctrl_softc *sc = (void *)self;
179 union obio_attach_args *uoba = aux;
180 struct sbus_attach_args *sa = &uoba->uoba_sbus;
181 unsigned int i, v;
182 #if 0
183 unsigned int ack, msb, lsb;
184 #endif
185
186 /* We're living on a sbus slot that looks like an obio that
187 * looks like an sbus slot.
188 */
189 sc->sc_memt = sa->sa_bustag;
190 if (sbus_bus_map(sc->sc_memt, sa->sa_slot,
191 sa->sa_offset - TS102_REG_UCTRL_INT, sa->sa_size,
192 BUS_SPACE_MAP_LINEAR, 0,
193 &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(devvp, flags, mode, p)
893 struct vnode *devvp;
894 int flags, mode;
895 struct proc *p;
896 {
897 dev_t dev = vdev_rdev(devvp);
898 int unit = (minor(dev)&0xf0);
899 int ctl = (minor(dev)&0x0f);
900 struct tctrl_softc *sc;
901
902 if (unit >= tctrl_cd.cd_ndevs)
903 return(ENXIO);
904 sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
905 if (!sc)
906 return(ENXIO);
907
908 switch (ctl) {
909 case TCTRL_STD_DEV:
910 break;
911 case TCTRL_APMCTL_DEV:
912 if (!(flags & FWRITE))
913 return(EINVAL);
914 if (sc->sc_flags & TCTRL_APM_CTLOPEN)
915 return(EBUSY);
916 sc->sc_flags |= TCTRL_APM_CTLOPEN;
917 break;
918 default:
919 return(ENXIO);
920 break;
921 }
922
923 vdev_setprivdata(devvp, sc);
924
925 return(0);
926 }
927
928 int
929 tctrlclose(devvp, flags, mode, p)
930 struct vnode *devvp;
931 int flags, mode;
932 struct proc *p;
933 {
934 int ctl = (minor(vdev_rdev(devvp))&0x0f);
935 struct tctrl_softc *sc;
936
937 sc = vdev_privdata(devvp);
938 if (!sc)
939 return(ENXIO);
940
941 switch (ctl) {
942 case TCTRL_STD_DEV:
943 break;
944 case TCTRL_APMCTL_DEV:
945 sc->sc_flags &= ~TCTRL_APM_CTLOPEN;
946 break;
947 }
948 return(0);
949 }
950
951 int
952 tctrlioctl(devvp, cmd, data, flags, p)
953 struct vnode *devvp;
954 u_long cmd;
955 caddr_t data;
956 int flags;
957 struct proc *p;
958 {
959 struct tctrl_req req, *reqn;
960 struct tctrl_pwr *pwrreq;
961 envsys_range_t *envrange;
962 envsys_temp_data_t *envdata;
963 envsys_temp_info_t *envinfo;
964 struct apm_power_info *powerp;
965 struct apm_event_info *evp;
966 struct tctrl_softc *sc;
967 int i;
968 u_int j;
969 u_int16_t a;
970 u_int8_t c;
971
972 if (tctrl_cd.cd_devs == NULL
973 || tctrl_cd.cd_ndevs == 0
974 || tctrl_cd.cd_devs[TCTRL_STD_DEV] == NULL) {
975 return ENXIO;
976 }
977 sc = vdev_privdata(devvp);
978 switch (cmd) {
979
980 case APM_IOC_STANDBY:
981 return(EOPNOTSUPP); /* for now */
982
983 case APM_IOC_SUSPEND:
984 return(EOPNOTSUPP); /* for now */
985
986 case APM_IOC_GETPOWER:
987 powerp = (struct apm_power_info *)data;
988 req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_RATE;
989 req.cmdlen = 1;
990 req.rsplen = 2;
991 req.p = p;
992 tadpole_request(&req, 0);
993 if (req.rspbuf[0] > 0x00)
994 powerp->battery_state = APM_BATT_CHARGING;
995 req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_LEVEL;
996 req.cmdlen = 1;
997 req.rsplen = 3;
998 req.p = p;
999 tadpole_request(&req, 0);
1000 c = req.rspbuf[0];
1001 powerp->battery_life = c;
1002 if (c > 0x70) /* the tadpole sometimes dips below zero, and */
1003 c = 0; /* into the 255 range. */
1004 powerp->minutes_left = (45 * c) / 100; /* XXX based on 45 min */
1005 if (powerp->battery_state != APM_BATT_CHARGING) {
1006 if (c < 0x20)
1007 powerp->battery_state = APM_BATT_CRITICAL;
1008 else if (c < 0x40)
1009 powerp->battery_state = APM_BATT_LOW;
1010 else if (c < 0x66)
1011 powerp->battery_state = APM_BATT_HIGH;
1012 else
1013 powerp->battery_state = APM_BATT_UNKNOWN;
1014 }
1015 req.cmdbuf[0] = TS102_OP_RD_EXT_STATUS;
1016 req.cmdlen = 1;
1017 req.rsplen = 3;
1018 req.p = p;
1019 tadpole_request(&req, 0);
1020 a = req.rspbuf[0] * 256 + req.rspbuf[1];
1021 if (a & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE)
1022 powerp->ac_state = APM_AC_ON;
1023 else
1024 powerp->ac_state = APM_AC_OFF;
1025 break;
1026
1027 case APM_IOC_NEXTEVENT:
1028 if (!sc->sc_event_count)
1029 return EAGAIN;
1030
1031 evp = (struct apm_event_info *)data;
1032 i = sc->sc_event_ptr + APM_NEVENTS - sc->sc_event_count;
1033 i %= APM_NEVENTS;
1034 *evp = sc->sc_event_list[i];
1035 sc->sc_event_count--;
1036 return(0);
1037
1038 /* this ioctl assumes the caller knows exactly what he is doing */
1039 case TCTRL_CMD_REQ:
1040 reqn = (struct tctrl_req *)data;
1041 if ((i = suser(p->p_ucred, &p->p_acflag)) != 0 &&
1042 (reqn->cmdbuf[0] == TS102_OP_CTL_BITPORT ||
1043 (reqn->cmdbuf[0] >= TS102_OP_CTL_WATCHDOG &&
1044 reqn->cmdbuf[0] <= TS102_OP_CTL_SECURITY_KEY) ||
1045 reqn->cmdbuf[0] == TS102_OP_CTL_TIMEZONE ||
1046 reqn->cmdbuf[0] == TS102_OP_CTL_DIAGNOSTIC_MODE ||
1047 reqn->cmdbuf[0] == TS102_OP_CMD_SOFTWARE_RESET ||
1048 (reqn->cmdbuf[0] >= TS102_OP_CMD_SET_RTC &&
1049 reqn->cmdbuf[0] < TS102_OP_RD_INT_CHARGE_LEVEL) ||
1050 reqn->cmdbuf[0] > TS102_OP_RD_EXT_CHARGE_LEVEL))
1051 return(i);
1052 reqn->p = p;
1053 tadpole_request(reqn, 0);
1054 break;
1055
1056 case ENVSYS_VERSION:
1057 *(int32_t *)data = 1000;
1058 break;
1059
1060 case ENVSYS_GRANGE:
1061 envrange = (envsys_range_t *)data;
1062 i = 0;
1063 envrange->high = envrange->low = 0;
1064 for (j=0; j < ENVSYS_NUMSENSORS; j++) {
1065 if (!i && envrange->units == sc->sc_esensors[j].units) {
1066 envrange->low = j;
1067 i++;
1068 }
1069 if (i && envrange->units == sc->sc_esensors[j].units)
1070 envrange->high = j;
1071 }
1072 if (!i) {
1073 envrange->high = 0;
1074 envrange->low = 1;
1075 }
1076 break;
1077
1078 case ENVSYS_GTREDATA:
1079 envdata = (envsys_temp_data_t *)data;
1080 if (envdata->sensor >= ENVSYS_NUMSENSORS) {
1081 envdata->validflags = 0;
1082 break;
1083 }
1084 envdata->warnflags = ENVSYS_WARN_OK;
1085 if (envdata->sensor == 0) {
1086 envdata->validflags |= ENVSYS_FVALID;
1087 req.cmdbuf[0] = TS102_OP_RD_CURRENT_TEMP;
1088 req.cmdlen = 1;
1089 req.rsplen = 2;
1090 req.p = p;
1091 tadpole_request(&req, 0);
1092 envdata->cur.data_us = /* 273160? */
1093 (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000000/9+273150000);
1094 envdata->validflags |= ENVSYS_FCURVALID;
1095 req.cmdbuf[0] = TS102_OP_RD_MAX_TEMP;
1096 req.cmdlen = 1;
1097 req.rsplen = 2;
1098 req.p = p;
1099 tadpole_request(&req, 0);
1100 envdata->max.data_us =
1101 (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000000/9+273150000);
1102 envdata->validflags |= ENVSYS_FMAXVALID;
1103 req.cmdbuf[0] = TS102_OP_RD_MIN_TEMP;
1104 req.cmdlen = 1;
1105 req.rsplen = 2;
1106 req.p = p;
1107 tadpole_request(&req, 0);
1108 envdata->min.data_us =
1109 (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000000/9+273150000);
1110 envdata->validflags |= ENVSYS_FMINVALID;
1111 envdata->units = sc->sc_esensors[envdata->sensor].units;
1112 break;
1113 } else if (envdata->sensor == 1 || envdata->sensor == 2) {
1114 envdata->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID;
1115 envdata->units = sc->sc_esensors[envdata->sensor].units;
1116 if (envdata->sensor == 1)
1117 req.cmdbuf[0] = TS102_OP_RD_INT_BATT_VLT;
1118 else
1119 req.cmdbuf[0] = TS102_OP_RD_DC_IN_VLT;
1120 req.cmdlen = 1;
1121 req.rsplen = 2;
1122 req.p = p;
1123 tadpole_request(&req, 0);
1124 envdata->cur.data_s = (int32_t)req.rspbuf[0]*1000000/11;
1125 break;
1126 }
1127 break;
1128
1129 case ENVSYS_GTREINFO:
1130 envinfo = (envsys_temp_info_t *)data;
1131 if (envinfo->sensor >= ENVSYS_NUMSENSORS) {
1132 envinfo->validflags = 0;
1133 break;
1134 }
1135 envinfo->units = sc->sc_esensors[envinfo->sensor].units;
1136 memcpy(envinfo->desc, sc->sc_esensors[envinfo->sensor].desc,
1137 sizeof(sc->sc_esensors[envinfo->sensor].desc) >
1138 sizeof(envinfo->desc) ? sizeof(envinfo->desc) :
1139 sizeof(sc->sc_esensors[envinfo->sensor].desc));
1140 if (envinfo->units == ENVSYS_STEMP) {
1141 envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID|
1142 ENVSYS_FMINVALID|ENVSYS_FMAXVALID;
1143 } else if (envinfo->units == ENVSYS_SVOLTS_DC) {
1144 envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID;
1145 } else
1146 envinfo->validflags = 0;
1147 break;
1148
1149 case ENVSYS_STREINFO:
1150 envinfo = (envsys_temp_info_t *)data;
1151 if (envinfo->sensor >= ENVSYS_NUMSENSORS) {
1152 envinfo->validflags = 0;
1153 break;
1154 }
1155 if (envinfo->units == sc->sc_esensors[envinfo->sensor].units)
1156 memcpy(sc->sc_esensors[envinfo->sensor].desc,
1157 envinfo->desc,
1158 sizeof(envinfo->desc) > sizeof(char)*32 ?
1159 sizeof(char)*32 : sizeof(envinfo->desc) );
1160 if (envinfo->units == ENVSYS_STEMP) {
1161 envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID|
1162 ENVSYS_FMINVALID|ENVSYS_FMAXVALID;
1163 } else if (envinfo->units == ENVSYS_SVOLTS_DC) {
1164 envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID;
1165 } else
1166 envinfo->validflags = 0;
1167 break;
1168
1169 /* serial power mode (via auxiotwo) */
1170 case TCTRL_SERIAL_PWR:
1171 pwrreq = (struct tctrl_pwr *)data;
1172 if (pwrreq->rw)
1173 pwrreq->state = auxiotwoserialgetapm();
1174 else
1175 auxiotwoserialsetapm(pwrreq->state);
1176 break;
1177
1178 /* modem power mode (via auxio) */
1179 case TCTRL_MODEM_PWR:
1180 return(EOPNOTSUPP); /* for now */
1181 break;
1182
1183
1184 default:
1185 return (ENOTTY);
1186 }
1187 return (0);
1188 }
1189
1190 int
1191 tctrlpoll(devvp, events, p)
1192 struct vnode *devvp;
1193 int events;
1194 struct proc *p;
1195 {
1196 struct tctrl_softc *sc = vdev_privdata(devvp);
1197 int revents = 0;
1198
1199 if (events & (POLLIN | POLLRDNORM)) {
1200 if (sc->sc_event_count)
1201 revents |= events & (POLLIN | POLLRDNORM);
1202 else
1203 selrecord(p, &sc->sc_rsel);
1204 }
1205
1206 return (revents);
1207 }
1208 /* DO NOT SET THIS OPTION */
1209 #ifdef TADPOLE_BLINK
1210 void
1211 cpu_disk_unbusy(busy)
1212 int busy;
1213 {
1214 static struct timeval tctrl_ds_timestamp;
1215 struct timeval dv_time, diff_time;
1216 struct tctrl_softc *sc;
1217
1218 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
1219
1220 /* quickly bail */
1221 if (!(sc->sc_lcdstate & TS102_LCD_DISK_ACTIVE) || busy > 0)
1222 return;
1223
1224 /* we aren't terribly concerned with precision here */
1225 dv_time = mono_time;
1226 timersub(&dv_time, &tctrl_ds_timestamp, &diff_time);
1227
1228 if (diff_time.tv_sec > 0) {
1229 tctrl_set_lcd(0, TS102_LCD_DISK_ACTIVE);
1230 tctrl_ds_timestamp = mono_time;
1231 }
1232 }
1233 #endif
1234