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