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