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