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