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