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