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