xref: /netbsd-src/sys/arch/sparc/dev/tctrl.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
1 /*	$NetBSD: tctrl.c,v 1.44 2007/11/16 08:00:12 xtraeme 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.44 2007/11/16 08:00:12 xtraeme 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 	envsys_data_t sc_sensor[ENVSYS_NUMSENSORS];
154 
155 	struct	sysmon_pswitch sc_sm_pbutton;	/* power button */
156 	struct	sysmon_pswitch sc_sm_lid;	/* lid state */
157 	struct	sysmon_pswitch sc_sm_ac;	/* AC adaptor presence */
158 	int	sc_powerpressed;
159 
160 	/* hardware status stuff */
161 	int sc_lid;	/* 1 - open, 0 - closed */
162 	int sc_power_state;
163 	int sc_spl;
164 
165 	/*
166 	 * we call this when we detect connection or removal of an external
167 	 * monitor. 0 for no monitor, !=0 for monitor present
168 	 */
169 	void (*sc_video_callback)(void *, int);
170 	void *sc_video_callback_cookie;
171 	int sc_extvga;
172 
173 	uint32_t sc_events;
174 	lwp_t *sc_thread;			/* event thread */
175 	kmutex_t sc_requestlock;
176 };
177 
178 #define TCTRL_STD_DEV		0
179 #define TCTRL_APMCTL_DEV	8
180 
181 static int tctrl_match(struct device *, struct cfdata *, void *);
182 static void tctrl_attach(struct device *, struct device *, void *);
183 static void tctrl_write(struct tctrl_softc *, bus_size_t, uint8_t);
184 static uint8_t tctrl_read(struct tctrl_softc *, bus_size_t);
185 static void tctrl_write_data(struct tctrl_softc *, uint8_t);
186 static uint8_t tctrl_read_data(struct tctrl_softc *);
187 static int tctrl_intr(void *);
188 static void tctrl_setup_bitport(void);
189 static void tctrl_setup_bitport_nop(void);
190 static void tctrl_read_ext_status(void);
191 static void tctrl_read_event_status(struct tctrl_softc *);
192 static int tctrl_apm_record_event(struct tctrl_softc *, u_int);
193 static void tctrl_init_lcd(void);
194 
195 static void tctrl_sensor_setup(struct tctrl_softc *);
196 static void tctrl_refresh(struct sysmon_envsys *, envsys_data_t *);
197 
198 static void tctrl_power_button_pressed(void *);
199 static void tctrl_lid_state(struct tctrl_softc *);
200 static void tctrl_ac_state(struct tctrl_softc *);
201 
202 static int tctrl_powerfail(void *);
203 
204 static void tctrl_event_thread(void *);
205 void tctrl_update_lcd(struct tctrl_softc *);
206 
207 static void tctrl_lock(struct tctrl_softc *);
208 static void tctrl_unlock(struct tctrl_softc *);
209 
210 CFATTACH_DECL(tctrl, sizeof(struct tctrl_softc),
211     tctrl_match, tctrl_attach, NULL, NULL);
212 
213 static int tadpole_request(struct tctrl_req *, int, int);
214 
215 /* XXX wtf is this? see i386/apm.c */
216 int tctrl_apm_evindex;
217 
218 static int
219 tctrl_match(struct device *parent, struct cfdata *cf, void *aux)
220 {
221 	union obio_attach_args *uoba = aux;
222 	struct sbus_attach_args *sa = &uoba->uoba_sbus;
223 
224 	if (uoba->uoba_isobio4 != 0) {
225 		return (0);
226 	}
227 
228 	/* Tadpole 3GX/3GS uses "uctrl" for the Tadpole Microcontroller
229 	 * (who's interface is off the TS102 PCMCIA controller but there
230 	 * exists a OpenProm for microcontroller interface).
231 	 */
232 	return strcmp("uctrl", sa->sa_name) == 0;
233 }
234 
235 static void
236 tctrl_attach(struct device *parent, struct device *self, void *aux)
237 {
238 	struct tctrl_softc *sc = (void *)self;
239 	union obio_attach_args *uoba = aux;
240 	struct sbus_attach_args *sa = &uoba->uoba_sbus;
241 	unsigned int i, v;
242 
243 	/* We're living on a sbus slot that looks like an obio that
244 	 * looks like an sbus slot.
245 	 */
246 	sc->sc_memt = sa->sa_bustag;
247 	if (sbus_bus_map(sc->sc_memt,
248 			 sa->sa_slot,
249 			 sa->sa_offset - TS102_REG_UCTRL_INT,
250 			 sa->sa_size,
251 			 BUS_SPACE_MAP_LINEAR, &sc->sc_memh) != 0) {
252 		printf(": can't map registers\n");
253 		return;
254 	}
255 
256 	printf("\n");
257 
258 	sc->sc_tft_on = 1;
259 
260 	/* clear any pending data.
261 	 */
262 	for (i = 0; i < 10000; i++) {
263 		if ((TS102_UCTRL_STS_RXNE_STA &
264 		    tctrl_read(sc, TS102_REG_UCTRL_STS)) == 0) {
265 			break;
266 		}
267 		v = tctrl_read(sc, TS102_REG_UCTRL_DATA);
268 		tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA);
269 	}
270 
271 	if (sa->sa_nintr != 0) {
272 		(void)bus_intr_establish(sc->sc_memt, sa->sa_pri, IPL_NONE,
273 					 tctrl_intr, sc);
274 		evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, NULL,
275 				     sc->sc_dev.dv_xname, "intr");
276 	}
277 
278 	/* See what the external status is */
279 	sc->sc_ext_status = 0;
280 	tctrl_read_ext_status();
281 	if (sc->sc_ext_status != 0) {
282 		const char *sep;
283 
284 		printf("%s: ", sc->sc_dev.dv_xname);
285 		v = sc->sc_ext_status;
286 		for (i = 0, sep = ""; v != 0; i++, v >>= 1) {
287 			if (v & 1) {
288 				printf("%s%s", sep, tctrl_ext_statuses[i]);
289 				sep = ", ";
290 			}
291 		}
292 		printf("\n");
293 	}
294 
295 	/* Get a current of the control bitport */
296 	tctrl_setup_bitport_nop();
297 	tctrl_write(sc, TS102_REG_UCTRL_INT,
298 		    TS102_UCTRL_INT_RXNE_REQ|TS102_UCTRL_INT_RXNE_MSK);
299 	sc->sc_lid = (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) == 0;
300 	sc->sc_power_state = PWR_RESUME;
301 
302 	sc->sc_extvga = (sc->sc_ext_status &
303 	    TS102_EXT_STATUS_EXTERNAL_VGA_ATTACHED) != 0;
304 	sc->sc_video_callback = NULL;
305 
306 
307 	sc->sc_wantdata = 0;
308 	sc->sc_event_count = 0;
309 	sc->sc_ext_pending = 0;
310 		sc->sc_ext_pending = 0;
311 
312 	mutex_init(&sc->sc_requestlock, MUTEX_DEFAULT, IPL_NONE);
313 
314 	/* setup sensors and register the power button */
315 	tctrl_sensor_setup(sc);
316 	tctrl_lid_state(sc);
317 	tctrl_ac_state(sc);
318 
319 	/* initialize the LCD */
320 	tctrl_init_lcd();
321 
322 	/* initialize sc_lcdstate */
323 	sc->sc_lcdstate = 0;
324 	sc->sc_lcdwanted = 0;
325 	tadpole_set_lcd(2, 0);
326 
327 	/* fire up the LCD event thread */
328 	sc->sc_events = 0;
329 
330 	if (kthread_create(PRI_NONE, 0, NULL, tctrl_event_thread, sc,
331 	    &sc->sc_thread, "%s", sc->sc_dev.dv_xname) != 0) {
332 		printf("%s: unable to create event kthread",
333 		    sc->sc_dev.dv_xname);
334 	}
335 }
336 
337 static int
338 tctrl_intr(void *arg)
339 {
340 	struct tctrl_softc *sc = arg;
341 	unsigned int v, d;
342 	int progress = 0;
343 
344     again:
345 	/* find out the cause(s) of the interrupt */
346 	v = tctrl_read(sc, TS102_REG_UCTRL_STS) & TS102_UCTRL_STS_MASK;
347 
348 	/* clear the cause(s) of the interrupt */
349 	tctrl_write(sc, TS102_REG_UCTRL_STS, v);
350 
351 	v &= ~(TS102_UCTRL_STS_RXO_STA|TS102_UCTRL_STS_TXE_STA);
352 	if (sc->sc_cmdoff >= sc->sc_cmdlen) {
353 		v &= ~TS102_UCTRL_STS_TXNF_STA;
354 		if (tctrl_read(sc, TS102_REG_UCTRL_INT) &
355 		    TS102_UCTRL_INT_TXNF_REQ) {
356 			tctrl_write(sc, TS102_REG_UCTRL_INT, 0);
357 			progress = 1;
358 		}
359 	}
360 	if ((v == 0) && ((sc->sc_flags & TCTRL_SEND_REQUEST) == 0 ||
361 	    sc->sc_state != TCTRL_IDLE)) {
362 		wakeup(sc);
363 		return progress;
364 	}
365 
366 	progress = 1;
367 	if (v & TS102_UCTRL_STS_RXNE_STA) {
368 		d = tctrl_read_data(sc);
369 		switch (sc->sc_state) {
370 		case TCTRL_IDLE:
371 			if (d == 0xfa) {
372 				/*
373 				 * external event,
374 				 * set a flag and wakeup the event thread
375 				 */
376 				sc->sc_ext_pending = 1;
377 			} else {
378 				printf("%s: (op=0x%02x): unexpected data (0x%02x)\n",
379 					sc->sc_dev.dv_xname, sc->sc_op, d);
380 			}
381 			goto again;
382 		case TCTRL_ACK:
383 			if (d != 0xfe) {
384 				printf("%s: (op=0x%02x): unexpected ack value (0x%02x)\n",
385 					sc->sc_dev.dv_xname, sc->sc_op, d);
386 			}
387 #ifdef TCTRLDEBUG
388 			printf(" ack=0x%02x", d);
389 #endif
390 			sc->sc_rsplen--;
391 			sc->sc_rspoff = 0;
392 			sc->sc_state = sc->sc_rsplen ? TCTRL_DATA : TCTRL_IDLE;
393 			sc->sc_wantdata = sc->sc_rsplen ? 1 : 0;
394 #ifdef TCTRLDEBUG
395 			if (sc->sc_rsplen > 0) {
396 				printf(" [data(%u)]", sc->sc_rsplen);
397 			} else {
398 				printf(" [idle]\n");
399 			}
400 #endif
401 			goto again;
402 		case TCTRL_DATA:
403 			sc->sc_rspbuf[sc->sc_rspoff++] = d;
404 #ifdef TCTRLDEBUG
405 			printf(" [%d]=0x%02x", sc->sc_rspoff-1, d);
406 #endif
407 			if (sc->sc_rspoff == sc->sc_rsplen) {
408 #ifdef TCTRLDEBUG
409 				printf(" [idle]\n");
410 #endif
411 				sc->sc_state = TCTRL_IDLE;
412 				sc->sc_wantdata = 0;
413 			}
414 			goto again;
415 		default:
416 			printf("%s: (op=0x%02x): unexpected data (0x%02x) in state %d\n",
417 			       sc->sc_dev.dv_xname, sc->sc_op, d, sc->sc_state);
418 			goto again;
419 		}
420 	}
421 	if ((sc->sc_state == TCTRL_IDLE && sc->sc_wantdata == 0) ||
422 	    sc->sc_flags & TCTRL_SEND_REQUEST) {
423 		if (sc->sc_flags & TCTRL_SEND_REQUEST) {
424 			sc->sc_flags &= ~TCTRL_SEND_REQUEST;
425 			sc->sc_wantdata = 1;
426 		}
427 		if (sc->sc_cmdlen > 0) {
428 			tctrl_write(sc, TS102_REG_UCTRL_INT,
429 				tctrl_read(sc, TS102_REG_UCTRL_INT)
430 				|TS102_UCTRL_INT_TXNF_MSK
431 				|TS102_UCTRL_INT_TXNF_REQ);
432 			v = tctrl_read(sc, TS102_REG_UCTRL_STS);
433 		}
434 	}
435 	if ((sc->sc_cmdoff < sc->sc_cmdlen) && (v & TS102_UCTRL_STS_TXNF_STA)) {
436 		tctrl_write_data(sc, sc->sc_cmdbuf[sc->sc_cmdoff++]);
437 #ifdef TCTRLDEBUG
438 		if (sc->sc_cmdoff == 1) {
439 			printf("%s: op=0x%02x(l=%u)", sc->sc_dev.dv_xname,
440 				sc->sc_cmdbuf[0], sc->sc_rsplen);
441 		} else {
442 			printf(" [%d]=0x%02x", sc->sc_cmdoff-1,
443 				sc->sc_cmdbuf[sc->sc_cmdoff-1]);
444 		}
445 #endif
446 		if (sc->sc_cmdoff == sc->sc_cmdlen) {
447 			sc->sc_state = sc->sc_rsplen ? TCTRL_ACK : TCTRL_IDLE;
448 #ifdef TCTRLDEBUG
449 			printf(" %s", sc->sc_rsplen ? "[ack]" : "[idle]\n");
450 #endif
451 			if (sc->sc_cmdoff == 1) {
452 				sc->sc_op = sc->sc_cmdbuf[0];
453 			}
454 			tctrl_write(sc, TS102_REG_UCTRL_INT,
455 				tctrl_read(sc, TS102_REG_UCTRL_INT)
456 				& (~TS102_UCTRL_INT_TXNF_MSK
457 				   |TS102_UCTRL_INT_TXNF_REQ));
458 		} else if (sc->sc_state == TCTRL_IDLE) {
459 			sc->sc_op = sc->sc_cmdbuf[0];
460 			sc->sc_state = TCTRL_ARGS;
461 #ifdef TCTRLDEBUG
462 			printf(" [args]");
463 #endif
464 		}
465 	}
466 	goto again;
467 }
468 
469 static void
470 tctrl_setup_bitport_nop(void)
471 {
472 	struct tctrl_softc *sc;
473 	struct tctrl_req req;
474 	int s;
475 
476 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
477 	req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
478 	req.cmdbuf[1] = 0xff;
479 	req.cmdbuf[2] = 0x00;
480 	req.cmdlen = 3;
481 	req.rsplen = 2;
482 	tadpole_request(&req, 1, 0);
483 	s = splts102();
484 	sc->sc_bitport = (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
485 	splx(s);
486 }
487 
488 static void
489 tctrl_setup_bitport(void)
490 {
491 	struct tctrl_softc *sc;
492 	struct tctrl_req req;
493 	int s;
494 
495 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
496 	s = splts102();
497 	req.cmdbuf[2] = 0;
498 	if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN)
499 	    || (!sc->sc_tft_on)) {
500 		req.cmdbuf[2] = TS102_BITPORT_TFTPWR;
501 	}
502 	req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
503 	req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR;
504 	req.cmdlen = 3;
505 	req.rsplen = 2;
506 	tadpole_request(&req, 1, 0);
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 	tadpole_request(&req, 1, 0);
544 
545 	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
546 	req.cmdlen = 11;
547 	req.rsplen = 1;
548 	req.cmdbuf[1] = 0x08;	/*len*/
549 	req.cmdbuf[2] = TS102_BLK_OFF_DEF_BACKSLASH;
550 	req.cmdbuf[3] =  0x00;	/* ..... */
551 	req.cmdbuf[4] =  0x10;	/* X.... */
552 	req.cmdbuf[5] =  0x08;	/* .X... */
553 	req.cmdbuf[6] =  0x04;	/* ..X.. */
554 	req.cmdbuf[7] =  0x02;	/* ...X. */
555 	req.cmdbuf[8] =  0x01;	/* ....X */
556 	req.cmdbuf[9] =  0x00;	/* ..... */
557 	req.cmdbuf[10] = 0x00;	/* ..... */
558 	tadpole_request(&req, 1, 0);
559 
560 	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
561 	req.cmdlen = 11;
562 	req.rsplen = 1;
563 	req.cmdbuf[1] = 0x08;	/*len*/
564 	req.cmdbuf[2] = TS102_BLK_OFF_DEF_WAN1;
565 	req.cmdbuf[3] =  0x0c;	/* .XXX. */
566 	req.cmdbuf[4] =  0x16;	/* X.XX. */
567 	req.cmdbuf[5] =  0x10;	/* X.... */
568 	req.cmdbuf[6] =  0x15;	/* X.X.X */
569 	req.cmdbuf[7] =  0x10;	/* X.... */
570 	req.cmdbuf[8] =  0x16;	/* X.XX. */
571 	req.cmdbuf[9] =  0x0c;	/* .XXX. */
572 	req.cmdbuf[10] = 0x00;	/* ..... */
573 	tadpole_request(&req, 1, 0);
574 
575 	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
576 	req.cmdlen = 11;
577 	req.rsplen = 1;
578 	req.cmdbuf[1] = 0x08;	/*len*/
579 	req.cmdbuf[2] = TS102_BLK_OFF_DEF_WAN2;
580 	req.cmdbuf[3] =  0x0c;	/* .XXX. */
581 	req.cmdbuf[4] =  0x0d;	/* .XX.X */
582 	req.cmdbuf[5] =  0x01;	/* ....X */
583 	req.cmdbuf[6] =  0x15;	/* X.X.X */
584 	req.cmdbuf[7] =  0x01;	/* ....X */
585 	req.cmdbuf[8] =  0x0d;	/* .XX.X */
586 	req.cmdbuf[9] =  0x0c;	/* .XXX. */
587 	req.cmdbuf[10] = 0x00;	/* ..... */
588 	tadpole_request(&req, 1, 0);
589 
590 	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
591 	req.cmdlen = 11;
592 	req.rsplen = 1;
593 	req.cmdbuf[1] = 0x08;	/*len*/
594 	req.cmdbuf[2] = TS102_BLK_OFF_DEF_LAN1;
595 	req.cmdbuf[3] =  0x00;	/* ..... */
596 	req.cmdbuf[4] =  0x04;	/* ..X.. */
597 	req.cmdbuf[5] =  0x08;	/* .X... */
598 	req.cmdbuf[6] =  0x13;	/* X..XX */
599 	req.cmdbuf[7] =  0x08;	/* .X... */
600 	req.cmdbuf[8] =  0x04;	/* ..X.. */
601 	req.cmdbuf[9] =  0x00;	/* ..... */
602 	req.cmdbuf[10] = 0x00;	/* ..... */
603 	tadpole_request(&req, 1, 0);
604 
605 	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
606 	req.cmdlen = 11;
607 	req.rsplen = 1;
608 	req.cmdbuf[1] = 0x08;	/*len*/
609 	req.cmdbuf[2] = TS102_BLK_OFF_DEF_LAN2;
610 	req.cmdbuf[3] =  0x00;	/* ..... */
611 	req.cmdbuf[4] =  0x04;	/* ..X.. */
612 	req.cmdbuf[5] =  0x02;	/* ...X. */
613 	req.cmdbuf[6] =  0x19;	/* XX..X */
614 	req.cmdbuf[7] =  0x02;	/* ...X. */
615 	req.cmdbuf[8] =  0x04;	/* ..X.. */
616 	req.cmdbuf[9] =  0x00;	/* ..... */
617 	req.cmdbuf[10] = 0x00;	/* ..... */
618 	tadpole_request(&req, 1, 0);
619 
620 	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
621 	req.cmdlen = 11;
622 	req.rsplen = 1;
623 	req.cmdbuf[1] = 0x08;	/*len*/
624 	req.cmdbuf[2] = TS102_BLK_OFF_DEF_PCMCIA;
625 	req.cmdbuf[3] =  0x00;	/* ..... */
626 	req.cmdbuf[4] =  0x0c;	/* .XXX. */
627 	req.cmdbuf[5] =  0x1f;	/* XXXXX */
628 	req.cmdbuf[6] =  0x1f;	/* XXXXX */
629 	req.cmdbuf[7] =  0x1f;	/* XXXXX */
630 	req.cmdbuf[8] =  0x1f;	/* XXXXX */
631 	req.cmdbuf[9] =  0x00;	/* ..... */
632 	req.cmdbuf[10] = 0x00;	/* ..... */
633 	tadpole_request(&req, 1, 0);
634 }
635 
636 /* sc_lcdwanted -> lcd_state */
637 void
638 tctrl_update_lcd(struct tctrl_softc *sc)
639 {
640 	struct tctrl_req req;
641 	int s;
642 
643 	s = splhigh();
644 	if (sc->sc_lcdwanted == sc->sc_lcdstate) {
645 		splx(s);
646 		return;
647 	}
648 	sc->sc_lcdstate = sc->sc_lcdwanted;
649 	splx(s);
650 
651 	/*
652 	 * the mask setup on this particular command is *very* bizzare
653 	 * and totally undocumented.
654 	 */
655 	req.cmdbuf[0] = TS102_OP_CTL_LCD;
656 
657 	/* leave caps-lock alone */
658 	req.cmdbuf[2] = (u_int8_t)(sc->sc_lcdstate & 0xfe);
659 	req.cmdbuf[3] = (u_int8_t)((sc->sc_lcdstate & 0x100)>>8);
660 
661 	req.cmdbuf[1] = 1;
662 	req.cmdbuf[4] = 0;
663 
664 
665 	/* XXX this thing is weird.... */
666 	req.cmdlen = 3;
667 	req.rsplen = 2;
668 
669 	/* below are the values one would expect but which won't work */
670 #if 0
671 	req.cmdlen = 5;
672 	req.rsplen = 4;
673 #endif
674 	tadpole_request(&req, 1, 0);
675 }
676 
677 
678 /*
679  * set the blinken-lights on the lcd.  what:
680  * what = 0 off,  what = 1 on,  what = 2 toggle
681  */
682 
683 void
684 tadpole_set_lcd(int what, unsigned short which)
685 {
686 	struct tctrl_softc *sc;
687 	int s;
688 
689 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
690 
691 	s = splhigh();
692 	switch (what) {
693 		case 0:
694 			sc->sc_lcdwanted &= ~which;
695 			break;
696 		case 1:
697 			sc->sc_lcdwanted |= which;
698 			break;
699 		case 2:
700 			sc->sc_lcdwanted ^= which;
701 			break;
702 	}
703 	splx(s);
704 }
705 
706 static void
707 tctrl_read_ext_status(void)
708 {
709 	struct tctrl_softc *sc;
710 	struct tctrl_req req;
711 	int s;
712 
713 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
714 	req.cmdbuf[0] = TS102_OP_RD_EXT_STATUS;
715 	req.cmdlen = 1;
716 	req.rsplen = 3;
717 #ifdef TCTRLDEBUG
718 	printf("pre read: sc->sc_ext_status = 0x%x\n", sc->sc_ext_status);
719 #endif
720 	tadpole_request(&req, 1, 0);
721 	s = splts102();
722 	sc->sc_ext_status = (req.rspbuf[0] << 8) + req.rspbuf[1];
723 	splx(s);
724 #ifdef TCTRLDEBUG
725 	printf("post read: sc->sc_ext_status = 0x%x\n", sc->sc_ext_status);
726 #endif
727 }
728 
729 /*
730  * return 0 if the user will notice and handle the event,
731  * return 1 if the kernel driver should do so.
732  */
733 static int
734 tctrl_apm_record_event(struct tctrl_softc *sc, u_int event_type)
735 {
736 	struct apm_event_info *evp;
737 
738 	if ((sc->sc_flags & TCTRL_APM_CTLOPEN) &&
739 	    (sc->sc_event_count < APM_NEVENTS)) {
740 		evp = &sc->sc_event_list[sc->sc_event_ptr];
741 		sc->sc_event_count++;
742 		sc->sc_event_ptr++;
743 		sc->sc_event_ptr %= APM_NEVENTS;
744 		evp->type = event_type;
745 		evp->index = ++tctrl_apm_evindex;
746 		selnotify(&sc->sc_rsel, 0);
747 		return(sc->sc_flags & TCTRL_APM_CTLOPEN) ? 0 : 1;
748 	}
749 	return(1);
750 }
751 
752 static void
753 tctrl_read_event_status(struct tctrl_softc *sc)
754 {
755 	struct tctrl_req req;
756 	int s, lid;
757 	uint32_t v;
758 
759 	req.cmdbuf[0] = TS102_OP_RD_EVENT_STATUS;
760 	req.cmdlen = 1;
761 	req.rsplen = 3;
762 	tadpole_request(&req, 1, 0);
763 	s = splts102();
764 	v = req.rspbuf[0] * 256 + req.rspbuf[1];
765 #ifdef TCTRLDEBUG
766 	printf("event: %x\n",v);
767 #endif
768 	if (v & TS102_EVENT_STATUS_POWERON_BTN_PRESSED) {
769 		printf("%s: Power button pressed\n",sc->sc_dev.dv_xname);
770 		tctrl_powerfail(sc);
771 	}
772 	if (v & TS102_EVENT_STATUS_SHUTDOWN_REQUEST) {
773 		printf("%s: SHUTDOWN REQUEST!\n", sc->sc_dev.dv_xname);
774 		tctrl_powerfail(sc);
775 	}
776 	if (v & TS102_EVENT_STATUS_VERY_LOW_POWER_WARNING) {
777 /*printf("%s: VERY LOW POWER WARNING!\n", sc->sc_dev.dv_xname);*/
778 /* according to a tadpole header, and observation */
779 #ifdef TCTRLDEBUG
780 		printf("%s: Battery charge level change\n",
781 		    sc->sc_dev.dv_xname);
782 #endif
783 	}
784 	if (v & TS102_EVENT_STATUS_LOW_POWER_WARNING) {
785 		if (tctrl_apm_record_event(sc, APM_BATTERY_LOW))
786 			printf("%s: LOW POWER WARNING!\n", sc->sc_dev.dv_xname);
787 	}
788 	if (v & TS102_EVENT_STATUS_DC_STATUS_CHANGE) {
789 		splx(s);
790 		tctrl_read_ext_status();
791 		tctrl_ac_state(sc);
792 		s = splts102();
793 		if (tctrl_apm_record_event(sc, APM_POWER_CHANGE))
794 			printf("%s: main power %s\n", sc->sc_dev.dv_xname,
795 			    (sc->sc_ext_status &
796 			    TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ?
797 			    "restored" : "removed");
798 	}
799 	if (v & TS102_EVENT_STATUS_LID_STATUS_CHANGE) {
800 		splx(s);
801 		tctrl_read_ext_status();
802 		tctrl_lid_state(sc);
803 		tctrl_setup_bitport();
804 #ifdef TCTRLDEBUG
805 		printf("%s: lid %s\n", sc->sc_dev.dv_xname,
806 		    (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN)
807 		    ? "closed" : "opened");
808 #endif
809 		lid = (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) == 0;
810 	}
811 	if (v & TS102_EVENT_STATUS_EXTERNAL_VGA_STATUS_CHANGE) {
812 		int vga;
813 		splx(s);
814 		tctrl_read_ext_status();
815 		vga = (sc->sc_ext_status &
816 		    TS102_EXT_STATUS_EXTERNAL_VGA_ATTACHED) != 0;
817 		if (vga != sc->sc_extvga) {
818 			sc->sc_extvga = vga;
819 			if (sc->sc_video_callback != NULL) {
820 				sc->sc_video_callback(
821 				    sc->sc_video_callback_cookie,
822 				    sc->sc_extvga);
823 			}
824 		}
825 	}
826 #ifdef DIAGNOSTIC
827 	if (v & TS102_EVENT_STATUS_EXT_MOUSE_STATUS_CHANGE) {
828 		splx(s);
829 		tctrl_read_ext_status();
830 		if (sc->sc_ext_status &
831 		    TS102_EXT_STATUS_EXTERNAL_MOUSE_ATTACHED) {
832 			printf("tctrl: external mouse detected\n");
833 		}
834 	}
835 #endif
836 	sc->sc_ext_pending = 0;
837 	splx(s);
838 }
839 
840 static void
841 tctrl_lock(struct tctrl_softc *sc)
842 {
843 
844 	mutex_enter(&sc->sc_requestlock);
845 }
846 
847 static void
848 tctrl_unlock(struct tctrl_softc *sc)
849 {
850 
851 	mutex_exit(&sc->sc_requestlock);
852 }
853 
854 int
855 tadpole_request(struct tctrl_req *req, int spin, int sleep)
856 {
857 	struct tctrl_softc *sc;
858 	int i, s;
859 
860 	if (tctrl_cd.cd_devs == NULL
861 	    || tctrl_cd.cd_ndevs == 0
862 	    || tctrl_cd.cd_devs[TCTRL_STD_DEV] == NULL) {
863 		return ENODEV;
864 	}
865 
866 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
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 = (struct tctrl_softc *) tctrl_cd.cd_devs[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 = tctrl_cd.cd_devs[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 = tctrl_cd.cd_devs[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 	if (tctrl_cd.cd_devs == NULL
1097 	    || tctrl_cd.cd_ndevs == 0
1098 	    || tctrl_cd.cd_devs[TCTRL_STD_DEV] == NULL) {
1099 		return ENXIO;
1100 	}
1101 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
1102         switch (cmd) {
1103 
1104 	case APM_IOC_STANDBY:
1105 		/* turn off backlight and so on ? */
1106 
1107 		return 0; /* for now */
1108 
1109 	case APM_IOC_SUSPEND:
1110 		/* not sure what to do here - we can't really suspend */
1111 
1112 		return 0; /* for now */
1113 
1114 	case OAPM_IOC_GETPOWER:
1115 	case APM_IOC_GETPOWER:
1116 		powerp = (struct apm_power_info *)data;
1117 		req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_RATE;
1118 		req.cmdlen = 1;
1119 		req.rsplen = 2;
1120 		tadpole_request(&req, 0, l->l_proc ? 1 : 0);
1121 		if (req.rspbuf[0] > 0x00)
1122 			powerp->battery_state = APM_BATT_CHARGING;
1123 		req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_LEVEL;
1124 		req.cmdlen = 1;
1125 		req.rsplen = 3;
1126 		tadpole_request(&req, 0, l->l_proc ? 1 : 0);
1127 		c = req.rspbuf[0];
1128 		powerp->battery_life = c;
1129 		if (c > 0x70)	/* the tadpole sometimes dips below zero, and */
1130 			c = 0;	/* into the 255 range. */
1131 		powerp->minutes_left = (45 * c) / 100; /* XXX based on 45 min */
1132 		if (powerp->battery_state != APM_BATT_CHARGING) {
1133 			if (c < 0x20)
1134 				powerp->battery_state = APM_BATT_CRITICAL;
1135 			else if (c < 0x40)
1136 				powerp->battery_state = APM_BATT_LOW;
1137 			else if (c < 0x66)
1138 				powerp->battery_state = APM_BATT_HIGH;
1139 			else
1140 				powerp->battery_state = APM_BATT_UNKNOWN;
1141 		}
1142 
1143 		if (sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE)
1144 			powerp->ac_state = APM_AC_ON;
1145 		else
1146 			powerp->ac_state = APM_AC_OFF;
1147 		break;
1148 
1149 	case APM_IOC_NEXTEVENT:
1150 		if (!sc->sc_event_count)
1151 			return EAGAIN;
1152 
1153 		evp = (struct apm_event_info *)data;
1154 		i = sc->sc_event_ptr + APM_NEVENTS - sc->sc_event_count;
1155 		i %= APM_NEVENTS;
1156 		*evp = sc->sc_event_list[i];
1157 		sc->sc_event_count--;
1158 		return(0);
1159 
1160 	/* this ioctl assumes the caller knows exactly what he is doing */
1161 	case TCTRL_CMD_REQ:
1162 		reqn = (struct tctrl_req *)data;
1163 		if ((i = kauth_authorize_generic(l->l_cred,
1164 		    KAUTH_GENERIC_ISSUSER, NULL)) != 0 &&
1165 		    (reqn->cmdbuf[0] == TS102_OP_CTL_BITPORT ||
1166 		    (reqn->cmdbuf[0] >= TS102_OP_CTL_WATCHDOG &&
1167 		    reqn->cmdbuf[0] <= TS102_OP_CTL_SECURITY_KEY) ||
1168 		    reqn->cmdbuf[0] == TS102_OP_CTL_TIMEZONE ||
1169 		    reqn->cmdbuf[0] == TS102_OP_CTL_DIAGNOSTIC_MODE ||
1170 		    reqn->cmdbuf[0] == TS102_OP_CMD_SOFTWARE_RESET ||
1171 		    (reqn->cmdbuf[0] >= TS102_OP_CMD_SET_RTC &&
1172 		    reqn->cmdbuf[0] < TS102_OP_RD_INT_CHARGE_LEVEL) ||
1173 		    reqn->cmdbuf[0] > TS102_OP_RD_EXT_CHARGE_LEVEL))
1174 			return(i);
1175 		tadpole_request(reqn, 0, l->l_proc ? 1 : 0);
1176 		break;
1177 	/* serial power mode (via auxiotwo) */
1178 	case TCTRL_SERIAL_PWR:
1179 		pwrreq = (struct tctrl_pwr *)data;
1180 		if (pwrreq->rw)
1181 			pwrreq->state = auxiotwoserialgetapm();
1182 		else
1183 			auxiotwoserialsetapm(pwrreq->state);
1184 		break;
1185 
1186 	/* modem power mode (via auxio) */
1187 	case TCTRL_MODEM_PWR:
1188 		return(EOPNOTSUPP); /* for now */
1189 		break;
1190 
1191 
1192         default:
1193                 return (ENOTTY);
1194         }
1195         return (0);
1196 }
1197 
1198 int
1199 tctrlpoll(dev_t dev, int events, struct lwp *l)
1200 {
1201 	struct tctrl_softc *sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
1202 	int revents = 0;
1203 
1204 	if (events & (POLLIN | POLLRDNORM)) {
1205 		if (sc->sc_event_count)
1206 			revents |= events & (POLLIN | POLLRDNORM);
1207 		else
1208 			selrecord(l, &sc->sc_rsel);
1209 	}
1210 
1211 	return (revents);
1212 }
1213 
1214 static void
1215 filt_tctrlrdetach(struct knote *kn)
1216 {
1217 	struct tctrl_softc *sc = kn->kn_hook;
1218 	int s;
1219 
1220 	s = splts102();
1221 	SLIST_REMOVE(&sc->sc_rsel.sel_klist, kn, knote, kn_selnext);
1222 	splx(s);
1223 }
1224 
1225 static int
1226 filt_tctrlread(struct knote *kn, long hint)
1227 {
1228 	struct tctrl_softc *sc = kn->kn_hook;
1229 
1230 	kn->kn_data = sc->sc_event_count;
1231 	return (kn->kn_data > 0);
1232 }
1233 
1234 static const struct filterops tctrlread_filtops =
1235 	{ 1, NULL, filt_tctrlrdetach, filt_tctrlread };
1236 
1237 int
1238 tctrlkqfilter(dev_t dev, struct knote *kn)
1239 {
1240 	struct tctrl_softc *sc = tctrl_cd.cd_devs[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 
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 
1280 	/* DC voltage */
1281 	(void)strlcpy(sc->sc_sensor[2].desc, "DC-In voltage",
1282 	    sizeof(sc->sc_sensor[2].desc));
1283 	sc->sc_sensor[2].units = ENVSYS_SVOLTS_DC;
1284 
1285 	for (i = 0; i < ENVSYS_NUMSENSORS; i++) {
1286 		if (sysmon_envsys_sensor_attach(sc->sc_sme,
1287 						&sc->sc_sensor[i])) {
1288 			sysmon_envsys_destroy(sc->sc_sme);
1289 			return;
1290 		}
1291 	}
1292 
1293 	sc->sc_sme->sme_name = sc->sc_dev.dv_xname;
1294 	sc->sc_sme->sme_cookie = sc;
1295 	sc->sc_sme->sme_refresh = tctrl_refresh;
1296 
1297 	if ((error = sysmon_envsys_register(sc->sc_sme)) != 0) {
1298 		printf("%s: couldn't register sensors (%d)\n",
1299 		    sc->sc_dev.dv_xname, error);
1300 		sysmon_envsys_destroy(sc->sc_sme);
1301 		return;
1302 	}
1303 
1304 	/* now register the power button */
1305 
1306 	sysmon_task_queue_init();
1307 
1308 	sc->sc_powerpressed = 0;
1309 	memset(&sc->sc_sm_pbutton, 0, sizeof(struct sysmon_pswitch));
1310 	sc->sc_sm_pbutton.smpsw_name = sc->sc_dev.dv_xname;
1311 	sc->sc_sm_pbutton.smpsw_type = PSWITCH_TYPE_POWER;
1312 	if (sysmon_pswitch_register(&sc->sc_sm_pbutton) != 0)
1313 		printf("%s: unable to register power button with sysmon\n",
1314 		    sc->sc_dev.dv_xname);
1315 
1316 	memset(&sc->sc_sm_lid, 0, sizeof(struct sysmon_pswitch));
1317 	sc->sc_sm_lid.smpsw_name = sc->sc_dev.dv_xname;
1318 	sc->sc_sm_lid.smpsw_type = PSWITCH_TYPE_LID;
1319 	if (sysmon_pswitch_register(&sc->sc_sm_lid) != 0)
1320 		printf("%s: unable to register lid switch with sysmon\n",
1321 		    sc->sc_dev.dv_xname);
1322 
1323 	memset(&sc->sc_sm_ac, 0, sizeof(struct sysmon_pswitch));
1324 	sc->sc_sm_ac.smpsw_name = sc->sc_dev.dv_xname;
1325 	sc->sc_sm_ac.smpsw_type = PSWITCH_TYPE_ACADAPTER;
1326 	if (sysmon_pswitch_register(&sc->sc_sm_ac) != 0)
1327 		printf("%s: unable to register AC adaptor with sysmon\n",
1328 		    sc->sc_dev.dv_xname);
1329 }
1330 
1331 static void
1332 tctrl_power_button_pressed(void *arg)
1333 {
1334 	struct tctrl_softc *sc = arg;
1335 
1336 	sysmon_pswitch_event(&sc->sc_sm_pbutton, PSWITCH_EVENT_PRESSED);
1337 	sc->sc_powerpressed = 0;
1338 }
1339 
1340 static void
1341 tctrl_lid_state(struct tctrl_softc *sc)
1342 {
1343 	int state;
1344 
1345 	state = (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) ?
1346 	    PSWITCH_EVENT_PRESSED : PSWITCH_EVENT_RELEASED;
1347 	sysmon_pswitch_event(&sc->sc_sm_lid, state);
1348 }
1349 
1350 static void
1351 tctrl_ac_state(struct tctrl_softc *sc)
1352 {
1353 	int state;
1354 
1355 	state = (sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ?
1356 	    PSWITCH_EVENT_PRESSED : PSWITCH_EVENT_RELEASED;
1357 	sysmon_pswitch_event(&sc->sc_sm_ac, state);
1358 }
1359 
1360 static int
1361 tctrl_powerfail(void *arg)
1362 {
1363 	struct tctrl_softc *sc = (struct tctrl_softc *)arg;
1364 
1365 	/*
1366 	 * We lost power. Queue a callback with thread context to
1367 	 * handle all the real work.
1368 	 */
1369 	if (sc->sc_powerpressed == 0) {
1370 		sc->sc_powerpressed = 1;
1371 		sysmon_task_queue_sched(0, tctrl_power_button_pressed, sc);
1372 	}
1373 	return (1);
1374 }
1375 
1376 static void
1377 tctrl_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
1378 {
1379 	/*struct tctrl_softc *sc = sme->sme_cookie;*/
1380 	struct tctrl_req req;
1381 	int sleepable;
1382 	int i;
1383 
1384 	i = edata->sensor;
1385 	sleepable = curlwp ? 1 : 0;
1386 
1387 	switch (i)
1388 	{
1389 		case 0:	/* case temperature */
1390 			req.cmdbuf[0] = TS102_OP_RD_CURRENT_TEMP;
1391 			req.cmdlen = 1;
1392 			req.rsplen = 2;
1393 			tadpole_request(&req, 0, sleepable);
1394 			edata->value_cur =             /* 273160? */
1395 			    (uint32_t)((int)((int)req.rspbuf[0] - 32) * 5000000
1396 			    / 9 + 273150000);
1397 			req.cmdbuf[0] = TS102_OP_RD_MAX_TEMP;
1398 			req.cmdlen = 1;
1399 			req.rsplen = 2;
1400 			tadpole_request(&req, 0, sleepable);
1401 			edata->value_max =
1402 			    (uint32_t)((int)((int)req.rspbuf[0] - 32) * 5000000
1403 			    / 9 + 273150000);
1404 			edata->flags |= ENVSYS_FVALID_MAX;
1405 			req.cmdbuf[0] = TS102_OP_RD_MIN_TEMP;
1406 			req.cmdlen = 1;
1407 			req.rsplen = 2;
1408 			tadpole_request(&req, 0, sleepable);
1409 			edata->value_min =
1410 			    (uint32_t)((int)((int)req.rspbuf[0] - 32) * 5000000
1411 			    / 9 + 273150000);
1412 			edata->flags |= ENVSYS_FVALID_MIN;
1413 			edata->units = ENVSYS_STEMP;
1414 			break;
1415 
1416 		case 1: /* battery voltage */
1417 			{
1418 				edata->units = ENVSYS_SVOLTS_DC;
1419 				req.cmdbuf[0] = TS102_OP_RD_INT_BATT_VLT;
1420 				req.cmdlen = 1;
1421 				req.rsplen = 2;
1422 				tadpole_request(&req, 0, sleepable);
1423 				edata->value_cur = (int32_t)req.rspbuf[0] *
1424 				    1000000 / 11;
1425 			}
1426 			break;
1427 		case 2: /* DC voltage */
1428 			{
1429 				edata->units = ENVSYS_SVOLTS_DC;
1430 				req.cmdbuf[0] = TS102_OP_RD_DC_IN_VLT;
1431 				req.cmdlen = 1;
1432 				req.rsplen = 2;
1433 				tadpole_request(&req, 0, sleepable);
1434 				edata->value_cur = (int32_t)req.rspbuf[0] *
1435 				    1000000 / 11;
1436 			}
1437 			break;
1438 	}
1439 	edata->state = ENVSYS_SVALID;
1440 }
1441 
1442 static void
1443 tctrl_event_thread(void *v)
1444 {
1445 	struct tctrl_softc *sc = v;
1446 	struct device *dv;
1447 	struct sd_softc *sd = NULL;
1448 	struct lance_softc *le = NULL;
1449 	int ticks = hz/2;
1450 	int rcount, wcount;
1451 	int s;
1452 
1453 	while (sd == NULL) {
1454 		for (dv = alldevs.tqh_first; dv; dv = dv->dv_list.tqe_next) {
1455 			if (strcmp(dv->dv_xname, "sd0") == 0) {
1456 			    	sd = (struct sd_softc *)dv;
1457 			}
1458 			if (le == NULL) {
1459 				if (strcmp(dv->dv_xname, "le0") == 0)
1460 					le = (struct lance_softc *)dv;
1461 			}
1462 		}
1463 		if (sd == NULL)
1464 			tsleep(&sc->sc_events, PWAIT, "probe_disk", hz);
1465 	}
1466 	printf("found %s\n", sd->sc_dev.dv_xname);
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 = (struct tctrl_softc *) tctrl_cd.cd_devs[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