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