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