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