xref: /netbsd-src/sys/arch/sparc/dev/tctrl.c (revision 28c37e673e4d9b6cbdc7483062b915cc61d1ccf5)
1 /*	$NetBSD: tctrl.c,v 1.18 2002/10/02 16:02:16 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