tctrl.c revision 1.17 1 /* $NetBSD: tctrl.c,v 1.17 2002/10/01 18:57:53 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Matt Thomas.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/callout.h>
42 #include <sys/ioctl.h>
43 #include <sys/select.h>
44 #include <sys/tty.h>
45 #include <sys/proc.h>
46 #include <sys/user.h>
47 #include <sys/conf.h>
48 #include <sys/file.h>
49 #include <sys/uio.h>
50 #include <sys/kernel.h>
51 #include <sys/syslog.h>
52 #include <sys/types.h>
53 #include <sys/device.h>
54 #include <sys/envsys.h>
55 #include <sys/poll.h>
56
57 #include <machine/apmvar.h>
58 #include <machine/autoconf.h>
59 #include <machine/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 APM_IOC_GETPOWER:
991 powerp = (struct apm_power_info *)data;
992 req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_RATE;
993 req.cmdlen = 1;
994 req.rsplen = 2;
995 req.p = p;
996 tadpole_request(&req, 0);
997 if (req.rspbuf[0] > 0x00)
998 powerp->battery_state = APM_BATT_CHARGING;
999 req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_LEVEL;
1000 req.cmdlen = 1;
1001 req.rsplen = 3;
1002 req.p = p;
1003 tadpole_request(&req, 0);
1004 c = req.rspbuf[0];
1005 powerp->battery_life = c;
1006 if (c > 0x70) /* the tadpole sometimes dips below zero, and */
1007 c = 0; /* into the 255 range. */
1008 powerp->minutes_left = (45 * c) / 100; /* XXX based on 45 min */
1009 if (powerp->battery_state != APM_BATT_CHARGING) {
1010 if (c < 0x20)
1011 powerp->battery_state = APM_BATT_CRITICAL;
1012 else if (c < 0x40)
1013 powerp->battery_state = APM_BATT_LOW;
1014 else if (c < 0x66)
1015 powerp->battery_state = APM_BATT_HIGH;
1016 else
1017 powerp->battery_state = APM_BATT_UNKNOWN;
1018 }
1019 req.cmdbuf[0] = TS102_OP_RD_EXT_STATUS;
1020 req.cmdlen = 1;
1021 req.rsplen = 3;
1022 req.p = p;
1023 tadpole_request(&req, 0);
1024 a = req.rspbuf[0] * 256 + req.rspbuf[1];
1025 if (a & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE)
1026 powerp->ac_state = APM_AC_ON;
1027 else
1028 powerp->ac_state = APM_AC_OFF;
1029 break;
1030
1031 case APM_IOC_NEXTEVENT:
1032 if (!sc->sc_event_count)
1033 return EAGAIN;
1034
1035 evp = (struct apm_event_info *)data;
1036 i = sc->sc_event_ptr + APM_NEVENTS - sc->sc_event_count;
1037 i %= APM_NEVENTS;
1038 *evp = sc->sc_event_list[i];
1039 sc->sc_event_count--;
1040 return(0);
1041
1042 /* this ioctl assumes the caller knows exactly what he is doing */
1043 case TCTRL_CMD_REQ:
1044 reqn = (struct tctrl_req *)data;
1045 if ((i = suser(p->p_ucred, &p->p_acflag)) != 0 &&
1046 (reqn->cmdbuf[0] == TS102_OP_CTL_BITPORT ||
1047 (reqn->cmdbuf[0] >= TS102_OP_CTL_WATCHDOG &&
1048 reqn->cmdbuf[0] <= TS102_OP_CTL_SECURITY_KEY) ||
1049 reqn->cmdbuf[0] == TS102_OP_CTL_TIMEZONE ||
1050 reqn->cmdbuf[0] == TS102_OP_CTL_DIAGNOSTIC_MODE ||
1051 reqn->cmdbuf[0] == TS102_OP_CMD_SOFTWARE_RESET ||
1052 (reqn->cmdbuf[0] >= TS102_OP_CMD_SET_RTC &&
1053 reqn->cmdbuf[0] < TS102_OP_RD_INT_CHARGE_LEVEL) ||
1054 reqn->cmdbuf[0] > TS102_OP_RD_EXT_CHARGE_LEVEL))
1055 return(i);
1056 reqn->p = p;
1057 tadpole_request(reqn, 0);
1058 break;
1059
1060 case ENVSYS_VERSION:
1061 *(int32_t *)data = 1000;
1062 break;
1063
1064 case ENVSYS_GRANGE:
1065 envrange = (envsys_range_t *)data;
1066 i = 0;
1067 envrange->high = envrange->low = 0;
1068 for (j=0; j < ENVSYS_NUMSENSORS; j++) {
1069 if (!i && envrange->units == sc->sc_esensors[j].units) {
1070 envrange->low = j;
1071 i++;
1072 }
1073 if (i && envrange->units == sc->sc_esensors[j].units)
1074 envrange->high = j;
1075 }
1076 if (!i) {
1077 envrange->high = 0;
1078 envrange->low = 1;
1079 }
1080 break;
1081
1082 case ENVSYS_GTREDATA:
1083 envdata = (envsys_temp_data_t *)data;
1084 if (envdata->sensor >= ENVSYS_NUMSENSORS) {
1085 envdata->validflags = 0;
1086 break;
1087 }
1088 envdata->warnflags = ENVSYS_WARN_OK;
1089 if (envdata->sensor == 0) {
1090 envdata->validflags |= ENVSYS_FVALID;
1091 req.cmdbuf[0] = TS102_OP_RD_CURRENT_TEMP;
1092 req.cmdlen = 1;
1093 req.rsplen = 2;
1094 req.p = p;
1095 tadpole_request(&req, 0);
1096 envdata->cur.data_us = /* 273160? */
1097 (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000000/9+273150000);
1098 envdata->validflags |= ENVSYS_FCURVALID;
1099 req.cmdbuf[0] = TS102_OP_RD_MAX_TEMP;
1100 req.cmdlen = 1;
1101 req.rsplen = 2;
1102 req.p = p;
1103 tadpole_request(&req, 0);
1104 envdata->max.data_us =
1105 (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000000/9+273150000);
1106 envdata->validflags |= ENVSYS_FMAXVALID;
1107 req.cmdbuf[0] = TS102_OP_RD_MIN_TEMP;
1108 req.cmdlen = 1;
1109 req.rsplen = 2;
1110 req.p = p;
1111 tadpole_request(&req, 0);
1112 envdata->min.data_us =
1113 (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000000/9+273150000);
1114 envdata->validflags |= ENVSYS_FMINVALID;
1115 envdata->units = sc->sc_esensors[envdata->sensor].units;
1116 break;
1117 } else if (envdata->sensor == 1 || envdata->sensor == 2) {
1118 envdata->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID;
1119 envdata->units = sc->sc_esensors[envdata->sensor].units;
1120 if (envdata->sensor == 1)
1121 req.cmdbuf[0] = TS102_OP_RD_INT_BATT_VLT;
1122 else
1123 req.cmdbuf[0] = TS102_OP_RD_DC_IN_VLT;
1124 req.cmdlen = 1;
1125 req.rsplen = 2;
1126 req.p = p;
1127 tadpole_request(&req, 0);
1128 envdata->cur.data_s = (int32_t)req.rspbuf[0]*1000000/11;
1129 break;
1130 }
1131 break;
1132
1133 case ENVSYS_GTREINFO:
1134 envinfo = (envsys_temp_info_t *)data;
1135 if (envinfo->sensor >= ENVSYS_NUMSENSORS) {
1136 envinfo->validflags = 0;
1137 break;
1138 }
1139 envinfo->units = sc->sc_esensors[envinfo->sensor].units;
1140 memcpy(envinfo->desc, sc->sc_esensors[envinfo->sensor].desc,
1141 sizeof(sc->sc_esensors[envinfo->sensor].desc) >
1142 sizeof(envinfo->desc) ? sizeof(envinfo->desc) :
1143 sizeof(sc->sc_esensors[envinfo->sensor].desc));
1144 if (envinfo->units == ENVSYS_STEMP) {
1145 envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID|
1146 ENVSYS_FMINVALID|ENVSYS_FMAXVALID;
1147 } else if (envinfo->units == ENVSYS_SVOLTS_DC) {
1148 envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID;
1149 } else
1150 envinfo->validflags = 0;
1151 break;
1152
1153 case ENVSYS_STREINFO:
1154 envinfo = (envsys_temp_info_t *)data;
1155 if (envinfo->sensor >= ENVSYS_NUMSENSORS) {
1156 envinfo->validflags = 0;
1157 break;
1158 }
1159 if (envinfo->units == sc->sc_esensors[envinfo->sensor].units)
1160 memcpy(sc->sc_esensors[envinfo->sensor].desc,
1161 envinfo->desc,
1162 sizeof(envinfo->desc) > sizeof(char)*32 ?
1163 sizeof(char)*32 : sizeof(envinfo->desc) );
1164 if (envinfo->units == ENVSYS_STEMP) {
1165 envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID|
1166 ENVSYS_FMINVALID|ENVSYS_FMAXVALID;
1167 } else if (envinfo->units == ENVSYS_SVOLTS_DC) {
1168 envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID;
1169 } else
1170 envinfo->validflags = 0;
1171 break;
1172
1173 /* serial power mode (via auxiotwo) */
1174 case TCTRL_SERIAL_PWR:
1175 pwrreq = (struct tctrl_pwr *)data;
1176 if (pwrreq->rw)
1177 pwrreq->state = auxiotwoserialgetapm();
1178 else
1179 auxiotwoserialsetapm(pwrreq->state);
1180 break;
1181
1182 /* modem power mode (via auxio) */
1183 case TCTRL_MODEM_PWR:
1184 return(EOPNOTSUPP); /* for now */
1185 break;
1186
1187
1188 default:
1189 return (ENOTTY);
1190 }
1191 return (0);
1192 }
1193
1194 int
1195 tctrlpoll(dev, events, p)
1196 dev_t dev;
1197 int events;
1198 struct proc *p;
1199 {
1200 struct tctrl_softc *sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
1201 int revents = 0;
1202
1203 if (events & (POLLIN | POLLRDNORM)) {
1204 if (sc->sc_event_count)
1205 revents |= events & (POLLIN | POLLRDNORM);
1206 else
1207 selrecord(p, &sc->sc_rsel);
1208 }
1209
1210 return (revents);
1211 }
1212 /* DO NOT SET THIS OPTION */
1213 #ifdef TADPOLE_BLINK
1214 void
1215 cpu_disk_unbusy(busy)
1216 int busy;
1217 {
1218 static struct timeval tctrl_ds_timestamp;
1219 struct timeval dv_time, diff_time;
1220 struct tctrl_softc *sc;
1221
1222 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
1223
1224 /* quickly bail */
1225 if (!(sc->sc_lcdstate & TS102_LCD_DISK_ACTIVE) || busy > 0)
1226 return;
1227
1228 /* we aren't terribly concerned with precision here */
1229 dv_time = mono_time;
1230 timersub(&dv_time, &tctrl_ds_timestamp, &diff_time);
1231
1232 if (diff_time.tv_sec > 0) {
1233 tctrl_set_lcd(0, TS102_LCD_DISK_ACTIVE);
1234 tctrl_ds_timestamp = mono_time;
1235 }
1236 }
1237 #endif
1238