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