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