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