1/*	$NetBSD: tctrl.c,v 1.52 2011/07/01 18:50:41 dyoung 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.52 2011/07/01 18:50:41 dyoung Exp $");
34
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/ioctl.h>
38#include <sys/select.h>
39#include <sys/tty.h>
40#include <sys/proc.h>
41#include <sys/conf.h>
42#include <sys/file.h>
43#include <sys/uio.h>
44#include <sys/kernel.h>
45#include <sys/kthread.h>
46#include <sys/syslog.h>
47#include <sys/types.h>
48#include <sys/device.h>
49#include <sys/envsys.h>
50#include <sys/poll.h>
51#include <sys/kauth.h>
52
53#include <machine/apmvar.h>
54#include <machine/autoconf.h>
55#include <sys/bus.h>
56#include <machine/intr.h>
57#include <machine/tctrl.h>
58
59#include <sparc/dev/ts102reg.h>
60#include <sparc/dev/tctrlvar.h>
61#include <sparc/sparc/auxiotwo.h>
62#include <sparc/sparc/auxreg.h>
63
64#include <dev/sysmon/sysmonvar.h>
65#include <dev/sysmon/sysmon_taskq.h>
66
67#include "sysmon_envsys.h"
68
69/*#define TCTRLDEBUG*/
70
71/* disk spinner */
72#include <sys/disk.h>
73#include <dev/scsipi/sdvar.h>
74
75/* ethernet carrier */
76#include <net/if.h>
77#include <net/if_dl.h>
78#include <net/if_ether.h>
79#include <net/if_media.h>
80#include <dev/ic/lancevar.h>
81
82extern struct cfdriver tctrl_cd;
83
84dev_type_open(tctrlopen);
85dev_type_close(tctrlclose);
86dev_type_ioctl(tctrlioctl);
87dev_type_poll(tctrlpoll);
88dev_type_kqfilter(tctrlkqfilter);
89
90const struct cdevsw tctrl_cdevsw = {
91	tctrlopen, tctrlclose, noread, nowrite, tctrlioctl,
92	nostop, notty, tctrlpoll, nommap, tctrlkqfilter,
93};
94
95static const char *tctrl_ext_statuses[16] = {
96	"main power available",
97	"internal battery attached",
98	"external battery attached",
99	"external VGA attached",
100	"external keyboard attached",
101	"external mouse attached",
102	"lid down",
103	"internal battery charging",
104	"external battery charging",
105	"internal battery discharging",
106	"external battery discharging",
107};
108
109struct tctrl_softc {
110	device_t	sc_dev;
111	bus_space_tag_t	sc_memt;
112	bus_space_handle_t	sc_memh;
113	unsigned int	sc_junk;
114	unsigned int	sc_ext_status;
115	unsigned int	sc_flags;
116#define TCTRL_SEND_REQUEST		0x0001
117#define TCTRL_APM_CTLOPEN		0x0002
118	uint32_t	sc_wantdata;
119	uint32_t	sc_ext_pending;
120	volatile uint16_t	sc_lcdstate;
121	uint16_t	sc_lcdwanted;
122
123	enum { TCTRL_IDLE, TCTRL_ARGS,
124		TCTRL_ACK, TCTRL_DATA } sc_state;
125	uint8_t		sc_cmdbuf[16];
126	uint8_t		sc_rspbuf[16];
127	uint8_t		sc_bitport;
128	uint8_t		sc_tft_on;
129	uint8_t		sc_op;
130	uint8_t		sc_cmdoff;
131	uint8_t		sc_cmdlen;
132	uint8_t		sc_rspoff;
133	uint8_t		sc_rsplen;
134	/* APM stuff */
135#define APM_NEVENTS 16
136	struct	apm_event_info sc_event_list[APM_NEVENTS];
137	int	sc_event_count;
138	int	sc_event_ptr;
139	struct	selinfo sc_rsel;
140
141	/* ENVSYS stuff */
142#define ENVSYS_NUMSENSORS 3
143	struct	evcnt sc_intrcnt;	/* interrupt counting */
144	struct	sysmon_envsys *sc_sme;
145	envsys_data_t sc_sensor[ENVSYS_NUMSENSORS];
146
147	struct	sysmon_pswitch sc_sm_pbutton;	/* power button */
148	struct	sysmon_pswitch sc_sm_lid;	/* lid state */
149	struct	sysmon_pswitch sc_sm_ac;	/* AC adaptor presence */
150	int	sc_powerpressed;
151
152	/* hardware status stuff */
153	int sc_lid;	/* 1 - open, 0 - closed */
154	int sc_power_state;
155	int sc_spl;
156
157	/*
158	 * we call this when we detect connection or removal of an external
159	 * monitor. 0 for no monitor, !=0 for monitor present
160	 */
161	void (*sc_video_callback)(void *, int);
162	void *sc_video_callback_cookie;
163	int sc_extvga;
164
165	uint32_t sc_events;
166	lwp_t *sc_thread;			/* event thread */
167	kmutex_t sc_requestlock;
168};
169
170#define TCTRL_STD_DEV		0
171#define TCTRL_APMCTL_DEV	8
172
173static int tctrl_match(device_t, cfdata_t, void *);
174static void tctrl_attach(device_t, device_t, void *);
175static void tctrl_write(struct tctrl_softc *, bus_size_t, uint8_t);
176static uint8_t tctrl_read(struct tctrl_softc *, bus_size_t);
177static void tctrl_write_data(struct tctrl_softc *, uint8_t);
178static uint8_t tctrl_read_data(struct tctrl_softc *);
179static int tctrl_intr(void *);
180static void tctrl_setup_bitport(void);
181static void tctrl_setup_bitport_nop(void);
182static void tctrl_read_ext_status(void);
183static void tctrl_read_event_status(struct tctrl_softc *);
184static int tctrl_apm_record_event(struct tctrl_softc *, u_int);
185static void tctrl_init_lcd(void);
186
187static void tctrl_sensor_setup(struct tctrl_softc *);
188static void tctrl_refresh(struct sysmon_envsys *, envsys_data_t *);
189
190static void tctrl_power_button_pressed(void *);
191static void tctrl_lid_state(struct tctrl_softc *);
192static void tctrl_ac_state(struct tctrl_softc *);
193
194static int tctrl_powerfail(void *);
195
196static void tctrl_event_thread(void *);
197void tctrl_update_lcd(struct tctrl_softc *);
198
199static void tctrl_lock(struct tctrl_softc *);
200static void tctrl_unlock(struct tctrl_softc *);
201
202CFATTACH_DECL_NEW(tctrl, sizeof(struct tctrl_softc),
203    tctrl_match, tctrl_attach, NULL, NULL);
204
205static int tadpole_request(struct tctrl_req *, int, int);
206
207/* XXX wtf is this? see i386/apm.c */
208int tctrl_apm_evindex;
209
210static int
211tctrl_match(device_t parent, cfdata_t cf, void *aux)
212{
213	union obio_attach_args *uoba = aux;
214	struct sbus_attach_args *sa = &uoba->uoba_sbus;
215
216	if (uoba->uoba_isobio4 != 0) {
217		return (0);
218	}
219
220	/* Tadpole 3GX/3GS uses "uctrl" for the Tadpole Microcontroller
221	 * (who's interface is off the TS102 PCMCIA controller but there
222	 * exists a OpenProm for microcontroller interface).
223	 */
224	return strcmp("uctrl", sa->sa_name) == 0;
225}
226
227static void
228tctrl_attach(device_t parent, device_t self, void *aux)
229{
230	struct tctrl_softc *sc = device_private(self);
231	union obio_attach_args *uoba = aux;
232	struct sbus_attach_args *sa = &uoba->uoba_sbus;
233	unsigned int i, v;
234
235	/* We're living on a sbus slot that looks like an obio that
236	 * looks like an sbus slot.
237	 */
238	sc->sc_dev = self;
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				     device_xname(sc->sc_dev), "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: ", device_xname(sc->sc_dev));
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", device_xname(sc->sc_dev)) != 0) {
326		printf("%s: unable to create event kthread",
327		    device_xname(sc->sc_dev));
328	}
329}
330
331static int
332tctrl_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					device_xname(sc->sc_dev), 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					device_xname(sc->sc_dev), 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			       device_xname(sc->sc_dev), 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)", device_xname(sc->sc_dev),
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
463static void
464tctrl_setup_bitport_nop(void)
465{
466	struct tctrl_softc *sc;
467	struct tctrl_req req;
468	int s;
469
470	sc = device_lookup_private(&tctrl_cd, 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
482static void
483tctrl_setup_bitport(void)
484{
485	struct tctrl_softc *sc;
486	struct tctrl_req req;
487	int s;
488
489	sc = device_lookup_private(&tctrl_cd, 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
519static void
520tctrl_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 */
631void
632tctrl_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
677void
678tadpole_set_lcd(int what, unsigned short which)
679{
680	struct tctrl_softc *sc;
681	int s;
682
683	sc = device_lookup_private(&tctrl_cd, 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
700static void
701tctrl_read_ext_status(void)
702{
703	struct tctrl_softc *sc;
704	struct tctrl_req req;
705	int s;
706
707	sc = device_lookup_private(&tctrl_cd, 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 */
727static int
728tctrl_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
746static void
747tctrl_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",device_xname(sc->sc_dev));
764		tctrl_powerfail(sc);
765	}
766	if (v & TS102_EVENT_STATUS_SHUTDOWN_REQUEST) {
767		printf("%s: SHUTDOWN REQUEST!\n", device_xname(sc->sc_dev));
768		tctrl_powerfail(sc);
769	}
770	if (v & TS102_EVENT_STATUS_VERY_LOW_POWER_WARNING) {
771/*printf("%s: VERY LOW POWER WARNING!\n", device_xname(sc->sc_dev));*/
772/* according to a tadpole header, and observation */
773#ifdef TCTRLDEBUG
774		printf("%s: Battery charge level change\n",
775		    device_xname(sc->sc_dev));
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", device_xname(sc->sc_dev));
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", device_xname(sc->sc_dev),
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", device_xname(sc->sc_dev),
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
834static void
835tctrl_lock(struct tctrl_softc *sc)
836{
837
838	mutex_enter(&sc->sc_requestlock);
839}
840
841static void
842tctrl_unlock(struct tctrl_softc *sc)
843{
844
845	mutex_exit(&sc->sc_requestlock);
846}
847
848int
849tadpole_request(struct tctrl_req *req, int spin, int sleep)
850{
851	struct tctrl_softc *sc;
852	int i, s;
853
854	sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
855	if (!sc)
856		return ENODEV;
857
858	tctrl_lock(sc);
859
860	if (spin)
861		s = splhigh();
862	else
863		s = splts102();
864	sc->sc_flags |= TCTRL_SEND_REQUEST;
865	memcpy(sc->sc_cmdbuf, req->cmdbuf, req->cmdlen);
866#ifdef DIAGNOSTIC
867	if (sc->sc_wantdata != 0) {
868		splx(s);
869		printf("tctrl: we lost the race\n");
870		tctrl_unlock(sc);
871		return EAGAIN;
872	}
873#endif
874	sc->sc_wantdata = 1;
875	sc->sc_rsplen = req->rsplen;
876	sc->sc_cmdlen = req->cmdlen;
877	sc->sc_cmdoff = sc->sc_rspoff = 0;
878
879	/* we spin for certain commands, like poweroffs */
880	if (spin) {
881/*		for (i = 0; i < 30000; i++) {*/
882		i = 0;
883		while ((sc->sc_wantdata == 1) && (i < 30000)) {
884			tctrl_intr(sc);
885			DELAY(1);
886			i++;
887		}
888#ifdef DIAGNOSTIC
889		if (i >= 30000) {
890			printf("tctrl: timeout busy waiting for micro controller request!\n");
891			sc->sc_wantdata = 0;
892			splx(s);
893			tctrl_unlock(sc);
894			return EAGAIN;
895		}
896#endif
897	} else {
898		int timeout = 5 * (sc->sc_rsplen + sc->sc_cmdlen);
899		tctrl_intr(sc);
900		i = 0;
901		while (((sc->sc_rspoff != sc->sc_rsplen) ||
902		    (sc->sc_cmdoff != sc->sc_cmdlen)) &&
903		    (i < timeout))
904			if (sleep) {
905				tsleep(sc, PWAIT, "tctrl_data", 15);
906				i++;
907			} else
908				DELAY(1);
909#ifdef DIAGNOSTIC
910		if (i >= timeout) {
911			printf("tctrl: timeout waiting for microcontroller request\n");
912			sc->sc_wantdata = 0;
913			splx(s);
914			tctrl_unlock(sc);
915			return EAGAIN;
916		}
917#endif
918	}
919	/*
920	 * we give the user a reasonable amount of time for a command
921	 * to complete.  If it doesn't complete in time, we hand them
922	 * garbage.  This is here to stop things like setting the
923	 * rsplen too long, and sleeping forever in a CMD_REQ ioctl.
924	 */
925	sc->sc_wantdata = 0;
926	memcpy(req->rspbuf, sc->sc_rspbuf, req->rsplen);
927	splx(s);
928
929	tctrl_unlock(sc);
930	return 0;
931}
932
933void
934tadpole_powerdown(void)
935{
936	struct tctrl_req req;
937
938	req.cmdbuf[0] = TS102_OP_ADMIN_POWER_OFF;
939	req.cmdlen = 1;
940	req.rsplen = 1;
941	tadpole_request(&req, 1, 0);
942}
943
944void
945tadpole_set_video(int enabled)
946{
947	struct tctrl_softc *sc;
948	struct tctrl_req req;
949	int s;
950
951	sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
952	while (sc->sc_wantdata != 0)
953		DELAY(1);
954	s = splts102();
955	if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN && !enabled)
956	    || (sc->sc_tft_on)) {
957		req.cmdbuf[2] = TS102_BITPORT_TFTPWR;
958	} else {
959		req.cmdbuf[2] = 0;
960	}
961	req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
962	req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR;
963	req.cmdlen = 3;
964	req.rsplen = 2;
965
966	if ((sc->sc_tft_on && !enabled) || (!sc->sc_tft_on && enabled)) {
967		sc->sc_tft_on = enabled;
968		if (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) {
969			splx(s);
970			return;
971		}
972		tadpole_request(&req, 1, 0);
973		sc->sc_bitport =
974		    (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
975	}
976	splx(s);
977}
978
979static void
980tctrl_write_data(struct tctrl_softc *sc, uint8_t v)
981{
982	unsigned int i;
983
984	for (i = 0; i < 100; i++)  {
985		if (TS102_UCTRL_STS_TXNF_STA &
986		    tctrl_read(sc, TS102_REG_UCTRL_STS))
987			break;
988	}
989	tctrl_write(sc, TS102_REG_UCTRL_DATA, v);
990}
991
992static uint8_t
993tctrl_read_data(struct tctrl_softc *sc)
994{
995	unsigned int i, v;
996
997	for (i = 0; i < 100000; i++) {
998		if (TS102_UCTRL_STS_RXNE_STA &
999		    tctrl_read(sc, TS102_REG_UCTRL_STS))
1000			break;
1001		DELAY(1);
1002	}
1003
1004	v = tctrl_read(sc, TS102_REG_UCTRL_DATA);
1005	tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA);
1006	return v;
1007}
1008
1009static uint8_t
1010tctrl_read(struct tctrl_softc *sc, bus_size_t off)
1011{
1012
1013	sc->sc_junk = bus_space_read_1(sc->sc_memt, sc->sc_memh, off);
1014	return sc->sc_junk;
1015}
1016
1017static void
1018tctrl_write(struct tctrl_softc *sc, bus_size_t off, uint8_t v)
1019{
1020
1021	sc->sc_junk = v;
1022	bus_space_write_1(sc->sc_memt, sc->sc_memh, off, v);
1023}
1024
1025int
1026tctrlopen(dev_t dev, int flags, int mode, struct lwp *l)
1027{
1028	int unit = (minor(dev)&0xf0);
1029	int ctl = (minor(dev)&0x0f);
1030	struct tctrl_softc *sc;
1031
1032	if (unit >= tctrl_cd.cd_ndevs)
1033		return(ENXIO);
1034	sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
1035	if (!sc)
1036		return(ENXIO);
1037
1038	switch (ctl) {
1039	case TCTRL_STD_DEV:
1040		break;
1041	case TCTRL_APMCTL_DEV:
1042		if (!(flags & FWRITE))
1043			return(EINVAL);
1044		if (sc->sc_flags & TCTRL_APM_CTLOPEN)
1045			return(EBUSY);
1046		sc->sc_flags |= TCTRL_APM_CTLOPEN;
1047		break;
1048	default:
1049		return(ENXIO);
1050		break;
1051	}
1052
1053	return(0);
1054}
1055
1056int
1057tctrlclose(dev_t dev, int flags, int mode, struct lwp *l)
1058{
1059	int ctl = (minor(dev)&0x0f);
1060	struct tctrl_softc *sc;
1061
1062	sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
1063	if (!sc)
1064		return(ENXIO);
1065
1066	switch (ctl) {
1067	case TCTRL_STD_DEV:
1068		break;
1069	case TCTRL_APMCTL_DEV:
1070		sc->sc_flags &= ~TCTRL_APM_CTLOPEN;
1071		break;
1072	}
1073	return(0);
1074}
1075
1076int
1077tctrlioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
1078{
1079	struct tctrl_req req, *reqn;
1080	struct tctrl_pwr *pwrreq;
1081	struct apm_power_info *powerp;
1082	struct apm_event_info *evp;
1083	struct tctrl_softc *sc;
1084	int i;
1085	uint8_t c;
1086
1087	sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
1088	if (!sc)
1089		return ENXIO;
1090
1091        switch (cmd) {
1092
1093	case APM_IOC_STANDBY:
1094		/* turn off backlight and so on ? */
1095
1096		return 0; /* for now */
1097
1098	case APM_IOC_SUSPEND:
1099		/* not sure what to do here - we can't really suspend */
1100
1101		return 0; /* for now */
1102
1103	case OAPM_IOC_GETPOWER:
1104	case APM_IOC_GETPOWER:
1105		powerp = (struct apm_power_info *)data;
1106		req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_RATE;
1107		req.cmdlen = 1;
1108		req.rsplen = 2;
1109		tadpole_request(&req, 0, l->l_proc ? 1 : 0);
1110		if (req.rspbuf[0] > 0x00)
1111			powerp->battery_state = APM_BATT_CHARGING;
1112		req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_LEVEL;
1113		req.cmdlen = 1;
1114		req.rsplen = 3;
1115		tadpole_request(&req, 0, l->l_proc ? 1 : 0);
1116		c = req.rspbuf[0];
1117		powerp->battery_life = c;
1118		if (c > 0x70)	/* the tadpole sometimes dips below zero, and */
1119			c = 0;	/* into the 255 range. */
1120		powerp->minutes_left = (45 * c) / 100; /* XXX based on 45 min */
1121		if (powerp->battery_state != APM_BATT_CHARGING) {
1122			if (c < 0x20)
1123				powerp->battery_state = APM_BATT_CRITICAL;
1124			else if (c < 0x40)
1125				powerp->battery_state = APM_BATT_LOW;
1126			else if (c < 0x66)
1127				powerp->battery_state = APM_BATT_HIGH;
1128			else
1129				powerp->battery_state = APM_BATT_UNKNOWN;
1130		}
1131
1132		if (sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE)
1133			powerp->ac_state = APM_AC_ON;
1134		else
1135			powerp->ac_state = APM_AC_OFF;
1136		break;
1137
1138	case APM_IOC_NEXTEVENT:
1139		if (!sc->sc_event_count)
1140			return EAGAIN;
1141
1142		evp = (struct apm_event_info *)data;
1143		i = sc->sc_event_ptr + APM_NEVENTS - sc->sc_event_count;
1144		i %= APM_NEVENTS;
1145		*evp = sc->sc_event_list[i];
1146		sc->sc_event_count--;
1147		return(0);
1148
1149	/* this ioctl assumes the caller knows exactly what he is doing */
1150	case TCTRL_CMD_REQ:
1151		reqn = (struct tctrl_req *)data;
1152		if ((i = kauth_authorize_generic(l->l_cred,
1153		    KAUTH_GENERIC_ISSUSER, NULL)) != 0 &&
1154		    (reqn->cmdbuf[0] == TS102_OP_CTL_BITPORT ||
1155		    (reqn->cmdbuf[0] >= TS102_OP_CTL_WATCHDOG &&
1156		    reqn->cmdbuf[0] <= TS102_OP_CTL_SECURITY_KEY) ||
1157		    reqn->cmdbuf[0] == TS102_OP_CTL_TIMEZONE ||
1158		    reqn->cmdbuf[0] == TS102_OP_CTL_DIAGNOSTIC_MODE ||
1159		    reqn->cmdbuf[0] == TS102_OP_CMD_SOFTWARE_RESET ||
1160		    (reqn->cmdbuf[0] >= TS102_OP_CMD_SET_RTC &&
1161		    reqn->cmdbuf[0] < TS102_OP_RD_INT_CHARGE_LEVEL) ||
1162		    reqn->cmdbuf[0] > TS102_OP_RD_EXT_CHARGE_LEVEL))
1163			return(i);
1164		tadpole_request(reqn, 0, l->l_proc ? 1 : 0);
1165		break;
1166	/* serial power mode (via auxiotwo) */
1167	case TCTRL_SERIAL_PWR:
1168		pwrreq = (struct tctrl_pwr *)data;
1169		if (pwrreq->rw)
1170			pwrreq->state = auxiotwoserialgetapm();
1171		else
1172			auxiotwoserialsetapm(pwrreq->state);
1173		break;
1174
1175	/* modem power mode (via auxio) */
1176	case TCTRL_MODEM_PWR:
1177		return(EOPNOTSUPP); /* for now */
1178		break;
1179
1180
1181        default:
1182                return (ENOTTY);
1183        }
1184        return (0);
1185}
1186
1187int
1188tctrlpoll(dev_t dev, int events, struct lwp *l)
1189{
1190	struct tctrl_softc *sc = device_lookup_private(&tctrl_cd,
1191						       TCTRL_STD_DEV);
1192	int revents = 0;
1193
1194	if (events & (POLLIN | POLLRDNORM)) {
1195		if (sc->sc_event_count)
1196			revents |= events & (POLLIN | POLLRDNORM);
1197		else
1198			selrecord(l, &sc->sc_rsel);
1199	}
1200
1201	return (revents);
1202}
1203
1204static void
1205filt_tctrlrdetach(struct knote *kn)
1206{
1207	struct tctrl_softc *sc = kn->kn_hook;
1208	int s;
1209
1210	s = splts102();
1211	SLIST_REMOVE(&sc->sc_rsel.sel_klist, kn, knote, kn_selnext);
1212	splx(s);
1213}
1214
1215static int
1216filt_tctrlread(struct knote *kn, long hint)
1217{
1218	struct tctrl_softc *sc = kn->kn_hook;
1219
1220	kn->kn_data = sc->sc_event_count;
1221	return (kn->kn_data > 0);
1222}
1223
1224static const struct filterops tctrlread_filtops =
1225	{ 1, NULL, filt_tctrlrdetach, filt_tctrlread };
1226
1227int
1228tctrlkqfilter(dev_t dev, struct knote *kn)
1229{
1230	struct tctrl_softc *sc = device_lookup_private(&tctrl_cd,
1231						       TCTRL_STD_DEV);
1232	struct klist *klist;
1233	int s;
1234
1235	switch (kn->kn_filter) {
1236	case EVFILT_READ:
1237		klist = &sc->sc_rsel.sel_klist;
1238		kn->kn_fop = &tctrlread_filtops;
1239		break;
1240
1241	default:
1242		return (1);
1243	}
1244
1245	kn->kn_hook = sc;
1246
1247	s = splts102();
1248	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
1249	splx(s);
1250
1251	return (0);
1252}
1253
1254static void
1255tctrl_sensor_setup(struct tctrl_softc *sc)
1256{
1257	int i, error;
1258
1259	sc->sc_sme = sysmon_envsys_create();
1260
1261	/* case temperature */
1262	(void)strlcpy(sc->sc_sensor[0].desc, "Case temperature",
1263	    sizeof(sc->sc_sensor[0].desc));
1264	sc->sc_sensor[0].units = ENVSYS_STEMP;
1265	sc->sc_sensor[0].state = ENVSYS_SINVALID;
1266
1267	/* battery voltage */
1268	(void)strlcpy(sc->sc_sensor[1].desc, "Internal battery voltage",
1269	    sizeof(sc->sc_sensor[1].desc));
1270	sc->sc_sensor[1].units = ENVSYS_SVOLTS_DC;
1271	sc->sc_sensor[1].state = ENVSYS_SINVALID;
1272
1273	/* DC voltage */
1274	(void)strlcpy(sc->sc_sensor[2].desc, "DC-In voltage",
1275	    sizeof(sc->sc_sensor[2].desc));
1276	sc->sc_sensor[2].units = ENVSYS_SVOLTS_DC;
1277	sc->sc_sensor[2].state = ENVSYS_SINVALID;
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 = device_xname(sc->sc_dev);
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		    device_xname(sc->sc_dev), 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 = device_xname(sc->sc_dev);
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		    device_xname(sc->sc_dev));
1309
1310	memset(&sc->sc_sm_lid, 0, sizeof(struct sysmon_pswitch));
1311	sc->sc_sm_lid.smpsw_name = device_xname(sc->sc_dev);
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		    device_xname(sc->sc_dev));
1316
1317	memset(&sc->sc_sm_ac, 0, sizeof(struct sysmon_pswitch));
1318	sc->sc_sm_ac.smpsw_name = device_xname(sc->sc_dev);
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		    device_xname(sc->sc_dev));
1323}
1324
1325static void
1326tctrl_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
1334static void
1335tctrl_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
1344static void
1345tctrl_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
1354static int
1355tctrl_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
1370static void
1371tctrl_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
1436static void
1437tctrl_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", device_xname(sd->sc_dev));
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
1486void
1487tadpole_register_callback(void (*callback)(void *, int), void *cookie)
1488{
1489	struct tctrl_softc *sc;
1490
1491	sc = device_lookup_private(&tctrl_cd, 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