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