tctrl.c revision 1.27
1/*	$NetBSD: tctrl.c,v 1.27 2005/07/06 11:31:16 macallan Exp $	*/
2
3/*-
4 * Copyright (c) 1998 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.27 2005/07/06 11:31:16 macallan Exp $");
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/callout.h>
45#include <sys/ioctl.h>
46#include <sys/select.h>
47#include <sys/tty.h>
48#include <sys/proc.h>
49#include <sys/user.h>
50#include <sys/conf.h>
51#include <sys/file.h>
52#include <sys/uio.h>
53#include <sys/kernel.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#include "sysmon_envsys.h"
74
75extern struct cfdriver tctrl_cd;
76
77dev_type_open(tctrlopen);
78dev_type_close(tctrlclose);
79dev_type_ioctl(tctrlioctl);
80dev_type_poll(tctrlpoll);
81dev_type_kqfilter(tctrlkqfilter);
82
83const struct cdevsw tctrl_cdevsw = {
84	tctrlopen, tctrlclose, noread, nowrite, tctrlioctl,
85	nostop, notty, tctrlpoll, nommap, tctrlkqfilter,
86};
87
88static const char *tctrl_ext_statuses[16] = {
89	"main power available",
90	"internal battery attached",
91	"external battery attached",
92	"external VGA attached",
93	"external keyboard attached",
94	"external mouse attached",
95	"lid down",
96	"internal battery charging",
97	"external battery charging",
98	"internal battery discharging",
99	"external battery discharging",
100};
101
102struct tctrl_softc {
103	struct	device sc_dev;
104	bus_space_tag_t	sc_memt;
105	bus_space_handle_t	sc_memh;
106	unsigned int	sc_junk;
107	unsigned int	sc_ext_status;
108	unsigned int	sc_flags;
109#define TCTRL_SEND_REQUEST		0x0001
110#define TCTRL_APM_CTLOPEN		0x0002
111	unsigned int	sc_wantdata;
112	volatile unsigned short	sc_lcdstate;
113	enum { TCTRL_IDLE, TCTRL_ARGS,
114		TCTRL_ACK, TCTRL_DATA } sc_state;
115	u_int8_t	sc_cmdbuf[16];
116	u_int8_t	sc_rspbuf[16];
117	u_int8_t	sc_bitport;
118	u_int8_t	sc_tft_on;
119	u_int8_t	sc_op;
120	u_int8_t	sc_cmdoff;
121	u_int8_t	sc_cmdlen;
122	u_int8_t	sc_rspoff;
123	u_int8_t	sc_rsplen;
124	/* APM stuff */
125#define APM_NEVENTS 16
126	struct	apm_event_info sc_event_list[APM_NEVENTS];
127	int	sc_event_count;
128	int	sc_event_ptr;
129	struct	selinfo sc_rsel;
130
131	/* ENVSYS stuff */
132#define ENVSYS_NUMSENSORS 3
133	struct	evcnt sc_intrcnt;	/* interrupt counting */
134	struct	sysmon_envsys sc_sme;
135	struct	envsys_tre_data sc_tre[ENVSYS_NUMSENSORS];
136	struct	envsys_basic_info sc_binfo[ENVSYS_NUMSENSORS];
137	struct	envsys_range sc_range[ENVSYS_NUMSENSORS];
138
139	struct	sysmon_pswitch sc_smcontext;
140	int	sc_powerpressed;
141};
142
143#define TCTRL_STD_DEV		0
144#define TCTRL_APMCTL_DEV	8
145
146static struct callout tctrl_event_ch = CALLOUT_INITIALIZER;
147
148static int tctrl_match __P((struct device *parent, struct cfdata *cf,
149	void *aux));
150static void tctrl_attach __P((struct device *parent, struct device *self,
151	void *aux));
152static void tctrl_write __P((struct tctrl_softc *sc, bus_size_t off,
153	u_int8_t v));
154static u_int8_t tctrl_read __P((struct tctrl_softc *sc, bus_size_t off));
155static void tctrl_write_data __P((struct tctrl_softc *sc, u_int8_t v));
156static u_int8_t tctrl_read_data __P((struct tctrl_softc *sc));
157static int tctrl_intr __P((void *arg));
158static void tctrl_setup_bitport __P((void));
159static void tctrl_setup_bitport_nop __P((void));
160static void tctrl_read_ext_status __P((void));
161static void tctrl_read_event_status __P((void *arg));
162static int tctrl_apm_record_event __P((struct tctrl_softc *sc,
163	u_int event_type));
164static void tctrl_init_lcd __P((void));
165
166static void tctrl_sensor_setup(struct tctrl_softc *);
167static int tctrl_gtredata(struct sysmon_envsys *, struct envsys_tre_data *);
168static int tctrl_streinfo(struct sysmon_envsys *, struct envsys_basic_info *);
169
170static void tctrl_power_button_pressed(void *);
171static int tctrl_powerfail(void *);
172
173CFATTACH_DECL(tctrl, sizeof(struct tctrl_softc),
174    tctrl_match, tctrl_attach, NULL, NULL);
175
176extern struct cfdriver tctrl_cd;
177/* XXX wtf is this? see i386/apm.c */
178int tctrl_apm_evindex;
179
180static int
181tctrl_match(parent, cf, aux)
182	struct device *parent;
183	struct cfdata *cf;
184	void *aux;
185{
186	union obio_attach_args *uoba = aux;
187	struct sbus_attach_args *sa = &uoba->uoba_sbus;
188
189	if (uoba->uoba_isobio4 != 0) {
190		return (0);
191	}
192
193	/* Tadpole 3GX/3GS uses "uctrl" for the Tadpole Microcontroller
194	 * (who's interface is off the TS102 PCMCIA controller but there
195	 * exists a OpenProm for microcontroller interface).
196	 */
197	return strcmp("uctrl", sa->sa_name) == 0;
198}
199
200static void
201tctrl_attach(parent, self, aux)
202	struct device *parent;
203	struct device *self;
204	void *aux;
205{
206	struct tctrl_softc *sc = (void *)self;
207	union obio_attach_args *uoba = aux;
208	struct sbus_attach_args *sa = &uoba->uoba_sbus;
209	unsigned int i, v;
210
211	/* We're living on a sbus slot that looks like an obio that
212	 * looks like an sbus slot.
213	 */
214	sc->sc_memt = sa->sa_bustag;
215	if (sbus_bus_map(sc->sc_memt,
216			 sa->sa_slot,
217			 sa->sa_offset - TS102_REG_UCTRL_INT,
218			 sa->sa_size,
219			 BUS_SPACE_MAP_LINEAR, &sc->sc_memh) != 0) {
220		printf(": can't map registers\n");
221		return;
222	}
223
224	printf("\n");
225
226	sc->sc_tft_on = 1;
227
228	/* clear any pending data.
229	 */
230	for (i = 0; i < 10000; i++) {
231		if ((TS102_UCTRL_STS_RXNE_STA &
232		    tctrl_read(sc, TS102_REG_UCTRL_STS)) == 0) {
233			break;
234		}
235		v = tctrl_read(sc, TS102_REG_UCTRL_DATA);
236		tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA);
237	}
238
239	if (sa->sa_nintr != 0) {
240		(void)bus_intr_establish(sc->sc_memt, sa->sa_pri, IPL_NONE,
241					 tctrl_intr, sc);
242		evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, NULL,
243				     sc->sc_dev.dv_xname, "intr");
244	}
245
246	/* See what the external status is */
247
248	tctrl_read_ext_status();
249	if (sc->sc_ext_status != 0) {
250		const char *sep;
251
252		printf("%s: ", sc->sc_dev.dv_xname);
253		v = sc->sc_ext_status;
254		for (i = 0, sep = ""; v != 0; i++, v >>= 1) {
255			if (v & 1) {
256				printf("%s%s", sep, tctrl_ext_statuses[i]);
257				sep = ", ";
258			}
259		}
260		printf("\n");
261	}
262
263	/* Get a current of the control bitport */
264	tctrl_setup_bitport_nop();
265	tctrl_write(sc, TS102_REG_UCTRL_INT,
266		    TS102_UCTRL_INT_RXNE_REQ|TS102_UCTRL_INT_RXNE_MSK);
267
268	sc->sc_wantdata = 0;
269	sc->sc_event_count = 0;
270
271	/* setup sensors and register the power button */
272	tctrl_sensor_setup(sc);
273
274	/* initialize the LCD */
275	tctrl_init_lcd();
276
277	/* initialize sc_lcdstate */
278	sc->sc_lcdstate = 0;
279	tctrl_set_lcd(2, 0);
280}
281
282static int
283tctrl_intr(arg)
284	void *arg;
285{
286	struct tctrl_softc *sc = arg;
287	unsigned int v, d;
288	int progress = 0;
289
290    again:
291	/* find out the cause(s) of the interrupt */
292	v = tctrl_read(sc, TS102_REG_UCTRL_STS) & TS102_UCTRL_STS_MASK;
293
294	/* clear the cause(s) of the interrupt */
295	tctrl_write(sc, TS102_REG_UCTRL_STS, v);
296
297	v &= ~(TS102_UCTRL_STS_RXO_STA|TS102_UCTRL_STS_TXE_STA);
298	if (sc->sc_cmdoff >= sc->sc_cmdlen) {
299		v &= ~TS102_UCTRL_STS_TXNF_STA;
300		if (tctrl_read(sc, TS102_REG_UCTRL_INT) &
301		    TS102_UCTRL_INT_TXNF_REQ) {
302			tctrl_write(sc, TS102_REG_UCTRL_INT, 0);
303			progress = 1;
304		}
305	}
306	if ((v == 0) && ((sc->sc_flags & TCTRL_SEND_REQUEST) == 0 ||
307	    sc->sc_state != TCTRL_IDLE)) {
308		wakeup(sc);
309		return progress;
310	}
311
312	progress = 1;
313	if (v & TS102_UCTRL_STS_RXNE_STA) {
314		d = tctrl_read_data(sc);
315		switch (sc->sc_state) {
316		case TCTRL_IDLE:
317			if (d == 0xfa) {
318				/* external event */
319				callout_reset(&tctrl_event_ch, 1,
320				    tctrl_read_event_status, NULL);
321			} else {
322				printf("%s: (op=0x%02x): unexpected data (0x%02x)\n",
323					sc->sc_dev.dv_xname, sc->sc_op, d);
324			}
325			goto again;
326		case TCTRL_ACK:
327			if (d != 0xfe) {
328				printf("%s: (op=0x%02x): unexpected ack value (0x%02x)\n",
329					sc->sc_dev.dv_xname, sc->sc_op, d);
330			}
331#ifdef TCTRLDEBUG
332			printf(" ack=0x%02x", d);
333#endif
334			sc->sc_rsplen--;
335			sc->sc_rspoff = 0;
336			sc->sc_state = sc->sc_rsplen ? TCTRL_DATA : TCTRL_IDLE;
337			sc->sc_wantdata = sc->sc_rsplen ? 1 : 0;
338#ifdef TCTRLDEBUG
339			if (sc->sc_rsplen > 0) {
340				printf(" [data(%u)]", sc->sc_rsplen);
341			} else {
342				printf(" [idle]\n");
343			}
344#endif
345			goto again;
346		case TCTRL_DATA:
347			sc->sc_rspbuf[sc->sc_rspoff++] = d;
348#ifdef TCTRLDEBUG
349			printf(" [%d]=0x%02x", sc->sc_rspoff-1, d);
350#endif
351			if (sc->sc_rspoff == sc->sc_rsplen) {
352#ifdef TCTRLDEBUG
353				printf(" [idle]\n");
354#endif
355				sc->sc_state = TCTRL_IDLE;
356				sc->sc_wantdata = 0;
357			}
358			goto again;
359		default:
360			printf("%s: (op=0x%02x): unexpected data (0x%02x) in state %d\n",
361			       sc->sc_dev.dv_xname, sc->sc_op, d, sc->sc_state);
362			goto again;
363		}
364	}
365	if ((sc->sc_state == TCTRL_IDLE && sc->sc_wantdata == 0) ||
366	    sc->sc_flags & TCTRL_SEND_REQUEST) {
367		if (sc->sc_flags & TCTRL_SEND_REQUEST) {
368			sc->sc_flags &= ~TCTRL_SEND_REQUEST;
369			sc->sc_wantdata = 1;
370		}
371		if (sc->sc_cmdlen > 0) {
372			tctrl_write(sc, TS102_REG_UCTRL_INT,
373				tctrl_read(sc, TS102_REG_UCTRL_INT)
374				|TS102_UCTRL_INT_TXNF_MSK
375				|TS102_UCTRL_INT_TXNF_REQ);
376			v = tctrl_read(sc, TS102_REG_UCTRL_STS);
377		}
378	}
379	if ((sc->sc_cmdoff < sc->sc_cmdlen) && (v & TS102_UCTRL_STS_TXNF_STA)) {
380		tctrl_write_data(sc, sc->sc_cmdbuf[sc->sc_cmdoff++]);
381#ifdef TCTRLDEBUG
382		if (sc->sc_cmdoff == 1) {
383			printf("%s: op=0x%02x(l=%u)", sc->sc_dev.dv_xname,
384				sc->sc_cmdbuf[0], sc->sc_rsplen);
385		} else {
386			printf(" [%d]=0x%02x", sc->sc_cmdoff-1,
387				sc->sc_cmdbuf[sc->sc_cmdoff-1]);
388		}
389#endif
390		if (sc->sc_cmdoff == sc->sc_cmdlen) {
391			sc->sc_state = sc->sc_rsplen ? TCTRL_ACK : TCTRL_IDLE;
392#ifdef TCTRLDEBUG
393			printf(" %s", sc->sc_rsplen ? "[ack]" : "[idle]\n");
394#endif
395			if (sc->sc_cmdoff == 1) {
396				sc->sc_op = sc->sc_cmdbuf[0];
397			}
398			tctrl_write(sc, TS102_REG_UCTRL_INT,
399				tctrl_read(sc, TS102_REG_UCTRL_INT)
400				& (~TS102_UCTRL_INT_TXNF_MSK
401				   |TS102_UCTRL_INT_TXNF_REQ));
402		} else if (sc->sc_state == TCTRL_IDLE) {
403			sc->sc_op = sc->sc_cmdbuf[0];
404			sc->sc_state = TCTRL_ARGS;
405#ifdef TCTRLDEBUG
406			printf(" [args]");
407#endif
408		}
409	}
410	goto again;
411}
412
413static void
414tctrl_setup_bitport_nop(void)
415{
416	struct tctrl_softc *sc;
417	struct tctrl_req req;
418	int s;
419
420	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
421	req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
422	req.cmdbuf[1] = 0xff;
423	req.cmdbuf[2] = 0;
424	req.cmdlen = 3;
425	req.rsplen = 2;
426	req.p = NULL;
427	tadpole_request(&req, 1);
428	s = splts102();
429	sc->sc_bitport = (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
430	splx(s);
431}
432
433static void
434tctrl_setup_bitport(void)
435{
436	struct tctrl_softc *sc;
437	struct tctrl_req req;
438	int s;
439
440	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
441	s = splts102();
442	if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN)
443	    || (!sc->sc_tft_on)) {
444		req.cmdbuf[2] = TS102_BITPORT_TFTPWR;
445	} else {
446		req.cmdbuf[2] = 0;
447	}
448	req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
449	req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR;
450	req.cmdlen = 3;
451	req.rsplen = 2;
452	req.p = NULL;
453	tadpole_request(&req, 1);
454	s = splts102();
455	sc->sc_bitport = (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
456	splx(s);
457}
458
459/*
460 * The tadpole microcontroller is not preprogrammed with icon
461 * representations.  The machine boots with the DC-IN light as
462 * a blank (all 0x00) and the other lights, as 4 rows of horizontal
463 * bars.  The below code initializes the icons in the system to
464 * sane values.  Some of these icons could be used for any purpose
465 * desired, namely the pcmcia, LAN and WAN lights.  For the disk spinner,
466 * only the backslash is unprogrammed.  (sigh)
467 *
468 * programming the icons is simple.  It is a 5x8 matrix, which each row a
469 * bitfield in the order 0x10 0x08 0x04 0x02 0x01.
470 */
471
472static void
473tctrl_init_lcd(void)
474{
475	struct tctrl_req req;
476
477	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
478	req.cmdlen = 11;
479	req.rsplen = 1;
480	req.cmdbuf[1] = 0x08;	/*len*/
481	req.cmdbuf[2] = TS102_BLK_OFF_DEF_DC_GOOD;
482	req.cmdbuf[3] =  0x00;	/* ..... */
483	req.cmdbuf[4] =  0x00;	/* ..... */
484	req.cmdbuf[5] =  0x1f;	/* XXXXX */
485	req.cmdbuf[6] =  0x00;	/* ..... */
486	req.cmdbuf[7] =  0x15;	/* X.X.X */
487	req.cmdbuf[8] =  0x00;	/* ..... */
488	req.cmdbuf[9] =  0x00;	/* ..... */
489	req.cmdbuf[10] = 0x00;	/* ..... */
490	req.p = NULL;
491	tadpole_request(&req, 1);
492
493	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
494	req.cmdlen = 11;
495	req.rsplen = 1;
496	req.cmdbuf[1] = 0x08;	/*len*/
497	req.cmdbuf[2] = TS102_BLK_OFF_DEF_BACKSLASH;
498	req.cmdbuf[3] =  0x00;	/* ..... */
499	req.cmdbuf[4] =  0x10;	/* X.... */
500	req.cmdbuf[5] =  0x08;	/* .X... */
501	req.cmdbuf[6] =  0x04;	/* ..X.. */
502	req.cmdbuf[7] =  0x02;	/* ...X. */
503	req.cmdbuf[8] =  0x01;	/* ....X */
504	req.cmdbuf[9] =  0x00;	/* ..... */
505	req.cmdbuf[10] = 0x00;	/* ..... */
506	req.p = NULL;
507	tadpole_request(&req, 1);
508
509	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
510	req.cmdlen = 11;
511	req.rsplen = 1;
512	req.cmdbuf[1] = 0x08;	/*len*/
513	req.cmdbuf[2] = TS102_BLK_OFF_DEF_WAN1;
514	req.cmdbuf[3] =  0x0c;	/* .XXX. */
515	req.cmdbuf[4] =  0x16;	/* X.XX. */
516	req.cmdbuf[5] =  0x10;	/* X.... */
517	req.cmdbuf[6] =  0x15;	/* X.X.X */
518	req.cmdbuf[7] =  0x10;	/* X.... */
519	req.cmdbuf[8] =  0x16;	/* X.XX. */
520	req.cmdbuf[9] =  0x0c;	/* .XXX. */
521	req.cmdbuf[10] = 0x00;	/* ..... */
522	req.p = NULL;
523	tadpole_request(&req, 1);
524
525	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
526	req.cmdlen = 11;
527	req.rsplen = 1;
528	req.cmdbuf[1] = 0x08;	/*len*/
529	req.cmdbuf[2] = TS102_BLK_OFF_DEF_WAN2;
530	req.cmdbuf[3] =  0x0c;	/* .XXX. */
531	req.cmdbuf[4] =  0x0d;	/* .XX.X */
532	req.cmdbuf[5] =  0x01;	/* ....X */
533	req.cmdbuf[6] =  0x15;	/* X.X.X */
534	req.cmdbuf[7] =  0x01;	/* ....X */
535	req.cmdbuf[8] =  0x0d;	/* .XX.X */
536	req.cmdbuf[9] =  0x0c;	/* .XXX. */
537	req.cmdbuf[10] = 0x00;	/* ..... */
538	req.p = NULL;
539	tadpole_request(&req, 1);
540
541	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
542	req.cmdlen = 11;
543	req.rsplen = 1;
544	req.cmdbuf[1] = 0x08;	/*len*/
545	req.cmdbuf[2] = TS102_BLK_OFF_DEF_LAN1;
546	req.cmdbuf[3] =  0x00;	/* ..... */
547	req.cmdbuf[4] =  0x04;	/* ..X.. */
548	req.cmdbuf[5] =  0x08;	/* .X... */
549	req.cmdbuf[6] =  0x13;	/* X..XX */
550	req.cmdbuf[7] =  0x08;	/* .X... */
551	req.cmdbuf[8] =  0x04;	/* ..X.. */
552	req.cmdbuf[9] =  0x00;	/* ..... */
553	req.cmdbuf[10] = 0x00;	/* ..... */
554	req.p = NULL;
555	tadpole_request(&req, 1);
556
557	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
558	req.cmdlen = 11;
559	req.rsplen = 1;
560	req.cmdbuf[1] = 0x08;	/*len*/
561	req.cmdbuf[2] = TS102_BLK_OFF_DEF_LAN2;
562	req.cmdbuf[3] =  0x00;	/* ..... */
563	req.cmdbuf[4] =  0x04;	/* ..X.. */
564	req.cmdbuf[5] =  0x02;	/* ...X. */
565	req.cmdbuf[6] =  0x19;	/* XX..X */
566	req.cmdbuf[7] =  0x02;	/* ...X. */
567	req.cmdbuf[8] =  0x04;	/* ..X.. */
568	req.cmdbuf[9] =  0x00;	/* ..... */
569	req.cmdbuf[10] = 0x00;	/* ..... */
570	req.p = NULL;
571	tadpole_request(&req, 1);
572
573	req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
574	req.cmdlen = 11;
575	req.rsplen = 1;
576	req.cmdbuf[1] = 0x08;	/*len*/
577	req.cmdbuf[2] = TS102_BLK_OFF_DEF_PCMCIA;
578	req.cmdbuf[3] =  0x00;	/* ..... */
579	req.cmdbuf[4] =  0x0c;	/* .XXX. */
580	req.cmdbuf[5] =  0x1f;	/* XXXXX */
581	req.cmdbuf[6] =  0x1f;	/* XXXXX */
582	req.cmdbuf[7] =  0x1f;	/* XXXXX */
583	req.cmdbuf[8] =  0x1f;	/* XXXXX */
584	req.cmdbuf[9] =  0x00;	/* ..... */
585	req.cmdbuf[10] = 0x00;	/* ..... */
586	req.p = NULL;
587	tadpole_request(&req, 1);
588}
589
590
591
592/*
593 * set the blinken-lights on the lcd.  what:
594 * what = 0 off,  what = 1 on,  what = 2 toggle
595 */
596
597void
598tctrl_set_lcd(what, which)
599	int what;
600	unsigned short which;
601{
602	struct tctrl_softc *sc;
603	struct tctrl_req req;
604	int s;
605
606	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
607	s = splts102();
608
609	/* provide a quick exit to save CPU time */
610	if ((what == 1 && sc->sc_lcdstate & which) ||
611	    (what == 0 && !(sc->sc_lcdstate & which))) {
612		splx(s);
613		return;
614	}
615	/*
616	 * the mask setup on this particular command is *very* bizzare
617	 * and totally undocumented.
618	 */
619	if ((what == 1) || (what == 2 && !(sc->sc_lcdstate & which))) {
620		req.cmdbuf[2] = (u_int8_t)(which&0xff);
621		req.cmdbuf[3] = (u_int8_t)((which&0x100)>>8);
622		sc->sc_lcdstate|=which;
623	} else {
624		req.cmdbuf[2] = 0;
625		req.cmdbuf[3] = 0;
626		sc->sc_lcdstate&=(~which);
627	}
628	req.cmdbuf[0] = TS102_OP_CTL_LCD;
629	req.cmdbuf[1] = (u_int8_t)((~which)&0xff);
630	req.cmdbuf[4] = (u_int8_t)((~which>>8)&1);
631
632
633	/* XXX this thing is weird.... */
634	req.cmdlen = 3;
635	req.rsplen = 2;
636
637	/* below are the values one would expect but which won't work */
638#if 0
639	req.cmdlen = 5;
640	req.rsplen = 4;
641#endif
642	req.p = NULL;
643	tadpole_request(&req, 1);
644
645	splx(s);
646}
647
648static void
649tctrl_read_ext_status(void)
650{
651	struct tctrl_softc *sc;
652	struct tctrl_req req;
653	int s;
654
655	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
656	req.cmdbuf[0] = TS102_OP_RD_EXT_STATUS;
657	req.cmdlen = 1;
658	req.rsplen = 3;
659	req.p = NULL;
660#ifdef TCTRLDEBUG
661	printf("pre read: sc->sc_ext_status = 0x%x\n", sc->sc_ext_status);
662#endif
663	tadpole_request(&req, 1);
664	s = splts102();
665	sc->sc_ext_status = req.rspbuf[0] * 256 + req.rspbuf[1];
666	splx(s);
667#ifdef TCTRLDEBUG
668	printf("post read: sc->sc_ext_status = 0x%x\n", sc->sc_ext_status);
669#endif
670}
671
672/*
673 * return 0 if the user will notice and handle the event,
674 * return 1 if the kernel driver should do so.
675 */
676static int
677tctrl_apm_record_event(sc, event_type)
678	struct tctrl_softc *sc;
679	u_int event_type;
680{
681	struct apm_event_info *evp;
682
683	if ((sc->sc_flags & TCTRL_APM_CTLOPEN) &&
684	    (sc->sc_event_count < APM_NEVENTS)) {
685		evp = &sc->sc_event_list[sc->sc_event_ptr];
686		sc->sc_event_count++;
687		sc->sc_event_ptr++;
688		sc->sc_event_ptr %= APM_NEVENTS;
689		evp->type = event_type;
690		evp->index = ++tctrl_apm_evindex;
691		selnotify(&sc->sc_rsel, 0);
692		return(sc->sc_flags & TCTRL_APM_CTLOPEN) ? 0 : 1;
693	}
694	return(1);
695}
696
697static void
698tctrl_read_event_status(arg)
699	void *arg;
700{
701	struct tctrl_softc *sc;
702	struct tctrl_req req;
703	int s;
704	unsigned int v;
705
706	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
707	req.cmdbuf[0] = TS102_OP_RD_EVENT_STATUS;
708	req.cmdlen = 1;
709	req.rsplen = 3;
710	req.p = NULL;
711	tadpole_request(&req, 1);
712	s = splts102();
713	v = req.rspbuf[0] * 256 + req.rspbuf[1];
714#ifdef TCTRLDEBUG
715	printf("event: %x\n",v);
716#endif
717	if (v & TS102_EVENT_STATUS_POWERON_BTN_PRESSED) {
718		printf("%s: Power button pressed\n",sc->sc_dev.dv_xname);
719		tctrl_powerfail(sc);
720	}
721	if (v & TS102_EVENT_STATUS_SHUTDOWN_REQUEST) {
722		printf("%s: SHUTDOWN REQUEST!\n", sc->sc_dev.dv_xname);
723	}
724	if (v & TS102_EVENT_STATUS_VERY_LOW_POWER_WARNING) {
725/*printf("%s: VERY LOW POWER WARNING!\n", sc->sc_dev.dv_xname);*/
726/* according to a tadpole header, and observation */
727#ifdef TCTRLDEBUG
728		printf("%s: Battery charge level change\n",
729		    sc->sc_dev.dv_xname);
730#endif
731	}
732	if (v & TS102_EVENT_STATUS_LOW_POWER_WARNING) {
733		if (tctrl_apm_record_event(sc, APM_BATTERY_LOW))
734			printf("%s: LOW POWER WARNING!\n", sc->sc_dev.dv_xname);
735	}
736	if (v & TS102_EVENT_STATUS_DC_STATUS_CHANGE) {
737		splx(s);
738		tctrl_read_ext_status();
739		s = splts102();
740		if (tctrl_apm_record_event(sc, APM_POWER_CHANGE))
741			printf("%s: main power %s\n", sc->sc_dev.dv_xname,
742			    (sc->sc_ext_status &
743			    TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ?
744			    "restored" : "removed");
745	}
746	if (v & TS102_EVENT_STATUS_LID_STATUS_CHANGE) {
747		splx(s);
748		tctrl_read_ext_status();
749		tctrl_setup_bitport();
750#ifdef TCTRLDEBUG
751		printf("%s: lid %s\n", sc->sc_dev.dv_xname,
752		    (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN)
753		    ? "closed" : "opened");
754#endif
755	}
756	splx(s);
757}
758
759void
760tadpole_request(req, spin)
761	struct tctrl_req *req;
762	int spin;
763{
764	struct tctrl_softc *sc;
765	int i, s;
766
767	if (tctrl_cd.cd_devs == NULL
768	    || tctrl_cd.cd_ndevs == 0
769	    || tctrl_cd.cd_devs[TCTRL_STD_DEV] == NULL) {
770		return;
771	}
772
773	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
774	while (sc->sc_wantdata != 0) {
775		if (req->p != NULL)
776			tsleep(&sc->sc_wantdata, PLOCK, "tctrl_lock", 10);
777		else
778			DELAY(1);
779	}
780	if (spin)
781		s = splhigh();
782	else
783		s = splts102();
784	sc->sc_flags |= TCTRL_SEND_REQUEST;
785	memcpy(sc->sc_cmdbuf, req->cmdbuf, req->cmdlen);
786	sc->sc_wantdata = 1;
787	sc->sc_rsplen = req->rsplen;
788	sc->sc_cmdlen = req->cmdlen;
789	sc->sc_cmdoff = sc->sc_rspoff = 0;
790
791	/* we spin for certain commands, like poweroffs */
792	if (spin) {
793/*		for (i = 0; i < 30000; i++) {*/
794		while (sc->sc_wantdata == 1) {
795			tctrl_intr(sc);
796			DELAY(1);
797		}
798	} else {
799		tctrl_intr(sc);
800		i = 0;
801		while (((sc->sc_rspoff != sc->sc_rsplen) ||
802		    (sc->sc_cmdoff != sc->sc_cmdlen)) &&
803		    (i < (5 * sc->sc_rsplen + sc->sc_cmdlen)))
804			if (req->p != NULL) {
805				tsleep(sc, PWAIT, "tctrl_data", 15);
806				i++;
807			}
808			else
809				DELAY(1);
810	}
811	/*
812	 * we give the user a reasonable amount of time for a command
813	 * to complete.  If it doesn't complete in time, we hand them
814	 * garbage.  This is here to stop things like setting the
815	 * rsplen too long, and sleeping forever in a CMD_REQ ioctl.
816	 */
817	sc->sc_wantdata = 0;
818	memcpy(req->rspbuf, sc->sc_rspbuf, req->rsplen);
819	splx(s);
820}
821
822void
823tadpole_powerdown(void)
824{
825	struct tctrl_req req;
826
827	req.cmdbuf[0] = TS102_OP_ADMIN_POWER_OFF;
828	req.cmdlen = 1;
829	req.rsplen = 1;
830	req.p = NULL;
831	tadpole_request(&req, 1);
832}
833
834void
835tadpole_set_video(enabled)
836	int enabled;
837{
838	struct tctrl_softc *sc;
839	struct tctrl_req req;
840	int s;
841
842	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
843	while (sc->sc_wantdata != 0)
844		DELAY(1);
845	s = splts102();
846	req.p = NULL;
847	if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN && !enabled)
848	    || (sc->sc_tft_on)) {
849		req.cmdbuf[2] = TS102_BITPORT_TFTPWR;
850	} else {
851		req.cmdbuf[2] = 0;
852	}
853	req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
854	req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR;
855	req.cmdlen = 3;
856	req.rsplen = 2;
857
858	if ((sc->sc_tft_on && !enabled) || (!sc->sc_tft_on && enabled)) {
859		sc->sc_tft_on = enabled;
860		if (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) {
861			splx(s);
862			return;
863		}
864		tadpole_request(&req, 1);
865		sc->sc_bitport =
866		    (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
867	}
868	splx(s);
869}
870
871static void
872tctrl_write_data(sc, v)
873	struct tctrl_softc *sc;
874	u_int8_t v;
875{
876	unsigned int i;
877
878	for (i = 0; i < 100; i++)  {
879		if (TS102_UCTRL_STS_TXNF_STA &
880		    tctrl_read(sc, TS102_REG_UCTRL_STS))
881			break;
882	}
883	tctrl_write(sc, TS102_REG_UCTRL_DATA, v);
884}
885
886static u_int8_t
887tctrl_read_data(sc)
888	struct tctrl_softc *sc;
889{
890	unsigned int i, v;
891
892	for (i = 0; i < 100000; i++) {
893		if (TS102_UCTRL_STS_RXNE_STA &
894		    tctrl_read(sc, TS102_REG_UCTRL_STS))
895			break;
896		DELAY(1);
897	}
898
899	v = tctrl_read(sc, TS102_REG_UCTRL_DATA);
900	tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA);
901	return v;
902}
903
904static u_int8_t
905tctrl_read(sc, off)
906	struct tctrl_softc *sc;
907	bus_size_t off;
908{
909
910	sc->sc_junk = bus_space_read_1(sc->sc_memt, sc->sc_memh, off);
911	return sc->sc_junk;
912}
913
914static void
915tctrl_write(sc, off, v)
916	struct tctrl_softc *sc;
917	bus_size_t off;
918	u_int8_t v;
919{
920
921	sc->sc_junk = v;
922	bus_space_write_1(sc->sc_memt, sc->sc_memh, off, v);
923}
924
925int
926tctrlopen(dev, flags, mode, p)
927	dev_t dev;
928	int flags, mode;
929	struct proc *p;
930{
931	int unit = (minor(dev)&0xf0);
932	int ctl = (minor(dev)&0x0f);
933	struct tctrl_softc *sc;
934
935	if (unit >= tctrl_cd.cd_ndevs)
936		return(ENXIO);
937	sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
938	if (!sc)
939		return(ENXIO);
940
941	switch (ctl) {
942	case TCTRL_STD_DEV:
943		break;
944	case TCTRL_APMCTL_DEV:
945		if (!(flags & FWRITE))
946			return(EINVAL);
947		if (sc->sc_flags & TCTRL_APM_CTLOPEN)
948			return(EBUSY);
949		sc->sc_flags |= TCTRL_APM_CTLOPEN;
950		break;
951	default:
952		return(ENXIO);
953		break;
954	}
955
956	return(0);
957}
958
959int
960tctrlclose(dev, flags, mode, p)
961	dev_t dev;
962	int flags, mode;
963	struct proc *p;
964{
965	int ctl = (minor(dev)&0x0f);
966	struct tctrl_softc *sc;
967
968	sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
969	if (!sc)
970		return(ENXIO);
971
972	switch (ctl) {
973	case TCTRL_STD_DEV:
974		break;
975	case TCTRL_APMCTL_DEV:
976		sc->sc_flags &= ~TCTRL_APM_CTLOPEN;
977		break;
978	}
979	return(0);
980}
981
982int
983tctrlioctl(dev, cmd, data, flags, p)
984        dev_t dev;
985        u_long cmd;
986        caddr_t data;
987        int flags;
988        struct proc *p;
989{
990	struct tctrl_req req, *reqn;
991	struct tctrl_pwr *pwrreq;
992	struct apm_power_info *powerp;
993	struct apm_event_info *evp;
994	struct tctrl_softc *sc;
995	int i;
996	/*u_int j;*/
997	u_int16_t a;
998	u_int8_t c;
999
1000	if (tctrl_cd.cd_devs == NULL
1001	    || tctrl_cd.cd_ndevs == 0
1002	    || tctrl_cd.cd_devs[TCTRL_STD_DEV] == NULL) {
1003		return ENXIO;
1004	}
1005	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
1006        switch (cmd) {
1007
1008	case APM_IOC_STANDBY:
1009		return(EOPNOTSUPP); /* for now */
1010
1011	case APM_IOC_SUSPEND:
1012		return(EOPNOTSUPP); /* for now */
1013
1014	case OAPM_IOC_GETPOWER:
1015	case APM_IOC_GETPOWER:
1016		powerp = (struct apm_power_info *)data;
1017		req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_RATE;
1018		req.cmdlen = 1;
1019		req.rsplen = 2;
1020		req.p = p;
1021		tadpole_request(&req, 0);
1022		if (req.rspbuf[0] > 0x00)
1023			powerp->battery_state = APM_BATT_CHARGING;
1024		req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_LEVEL;
1025		req.cmdlen = 1;
1026		req.rsplen = 3;
1027		req.p = p;
1028		tadpole_request(&req, 0);
1029		c = req.rspbuf[0];
1030		powerp->battery_life = c;
1031		if (c > 0x70)	/* the tadpole sometimes dips below zero, and */
1032			c = 0;	/* into the 255 range. */
1033		powerp->minutes_left = (45 * c) / 100; /* XXX based on 45 min */
1034		if (powerp->battery_state != APM_BATT_CHARGING) {
1035			if (c < 0x20)
1036				powerp->battery_state = APM_BATT_CRITICAL;
1037			else if (c < 0x40)
1038				powerp->battery_state = APM_BATT_LOW;
1039			else if (c < 0x66)
1040				powerp->battery_state = APM_BATT_HIGH;
1041			else
1042				powerp->battery_state = APM_BATT_UNKNOWN;
1043		}
1044		req.cmdbuf[0] = TS102_OP_RD_EXT_STATUS;
1045		req.cmdlen = 1;
1046		req.rsplen = 3;
1047		req.p = p;
1048		tadpole_request(&req, 0);
1049		a = req.rspbuf[0] * 256 + req.rspbuf[1];
1050		if (a & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE)
1051			powerp->ac_state = APM_AC_ON;
1052		else
1053			powerp->ac_state = APM_AC_OFF;
1054		break;
1055
1056	case APM_IOC_NEXTEVENT:
1057		if (!sc->sc_event_count)
1058			return EAGAIN;
1059
1060		evp = (struct apm_event_info *)data;
1061		i = sc->sc_event_ptr + APM_NEVENTS - sc->sc_event_count;
1062		i %= APM_NEVENTS;
1063		*evp = sc->sc_event_list[i];
1064		sc->sc_event_count--;
1065		return(0);
1066
1067	/* this ioctl assumes the caller knows exactly what he is doing */
1068	case TCTRL_CMD_REQ:
1069		reqn = (struct tctrl_req *)data;
1070		if ((i = suser(p->p_ucred, &p->p_acflag)) != 0 &&
1071		    (reqn->cmdbuf[0] == TS102_OP_CTL_BITPORT ||
1072		    (reqn->cmdbuf[0] >= TS102_OP_CTL_WATCHDOG &&
1073		    reqn->cmdbuf[0] <= TS102_OP_CTL_SECURITY_KEY) ||
1074		    reqn->cmdbuf[0] == TS102_OP_CTL_TIMEZONE ||
1075		    reqn->cmdbuf[0] == TS102_OP_CTL_DIAGNOSTIC_MODE ||
1076		    reqn->cmdbuf[0] == TS102_OP_CMD_SOFTWARE_RESET ||
1077		    (reqn->cmdbuf[0] >= TS102_OP_CMD_SET_RTC &&
1078		    reqn->cmdbuf[0] < TS102_OP_RD_INT_CHARGE_LEVEL) ||
1079		    reqn->cmdbuf[0] > TS102_OP_RD_EXT_CHARGE_LEVEL))
1080			return(i);
1081		reqn->p = p;
1082		tadpole_request(reqn, 0);
1083		break;
1084	/* serial power mode (via auxiotwo) */
1085	case TCTRL_SERIAL_PWR:
1086		pwrreq = (struct tctrl_pwr *)data;
1087		if (pwrreq->rw)
1088			pwrreq->state = auxiotwoserialgetapm();
1089		else
1090			auxiotwoserialsetapm(pwrreq->state);
1091		break;
1092
1093	/* modem power mode (via auxio) */
1094	case TCTRL_MODEM_PWR:
1095		return(EOPNOTSUPP); /* for now */
1096		break;
1097
1098
1099        default:
1100                return (ENOTTY);
1101        }
1102        return (0);
1103}
1104
1105int
1106tctrlpoll(dev, events, p)
1107	dev_t dev;
1108	int events;
1109	struct proc *p;
1110{
1111	struct tctrl_softc *sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
1112	int revents = 0;
1113
1114	if (events & (POLLIN | POLLRDNORM)) {
1115		if (sc->sc_event_count)
1116			revents |= events & (POLLIN | POLLRDNORM);
1117		else
1118			selrecord(p, &sc->sc_rsel);
1119	}
1120
1121	return (revents);
1122}
1123
1124static void
1125filt_tctrlrdetach(struct knote *kn)
1126{
1127	struct tctrl_softc *sc = kn->kn_hook;
1128	int s;
1129
1130	s = splts102();
1131	SLIST_REMOVE(&sc->sc_rsel.sel_klist, kn, knote, kn_selnext);
1132	splx(s);
1133}
1134
1135static int
1136filt_tctrlread(struct knote *kn, long hint)
1137{
1138	struct tctrl_softc *sc = kn->kn_hook;
1139
1140	kn->kn_data = sc->sc_event_count;
1141	return (kn->kn_data > 0);
1142}
1143
1144static const struct filterops tctrlread_filtops =
1145	{ 1, NULL, filt_tctrlrdetach, filt_tctrlread };
1146
1147int
1148tctrlkqfilter(dev_t dev, struct knote *kn)
1149{
1150	struct tctrl_softc *sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
1151	struct klist *klist;
1152	int s;
1153
1154	switch (kn->kn_filter) {
1155	case EVFILT_READ:
1156		klist = &sc->sc_rsel.sel_klist;
1157		kn->kn_fop = &tctrlread_filtops;
1158		break;
1159
1160	default:
1161		return (1);
1162	}
1163
1164	kn->kn_hook = sc;
1165
1166	s = splts102();
1167	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
1168	splx(s);
1169
1170	return (0);
1171}
1172
1173/* DO NOT SET THIS OPTION */
1174#ifdef TADPOLE_BLINK
1175void
1176cpu_disk_unbusy(busy)
1177        int busy;
1178{
1179	static struct timeval tctrl_ds_timestamp;
1180        struct timeval dv_time, diff_time;
1181	struct tctrl_softc *sc;
1182
1183	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
1184
1185	/* quickly bail */
1186	if (!(sc->sc_lcdstate & TS102_LCD_DISK_ACTIVE) || busy > 0)
1187		return;
1188
1189        /* we aren't terribly concerned with precision here */
1190        dv_time = mono_time;
1191        timersub(&dv_time, &tctrl_ds_timestamp, &diff_time);
1192
1193	if (diff_time.tv_sec > 0) {
1194                tctrl_set_lcd(0, TS102_LCD_DISK_ACTIVE);
1195		tctrl_ds_timestamp = mono_time;
1196	}
1197}
1198#endif
1199
1200static void
1201tctrl_sensor_setup(struct tctrl_softc *sc)
1202{
1203	int error;
1204
1205	/* case temperature */
1206	strcpy(sc->sc_binfo[0].desc, "Case temperature");
1207	sc->sc_binfo[0].sensor = 0;
1208	sc->sc_binfo[0].units = ENVSYS_STEMP;
1209	sc->sc_binfo[0].validflags = ENVSYS_FVALID | ENVSYS_FCURVALID;
1210	sc->sc_range[0].low = 0;
1211	sc->sc_range[0].high = 0;
1212	sc->sc_range[0].units = ENVSYS_STEMP;
1213	sc->sc_tre[0].sensor = 0;
1214	sc->sc_tre[0].warnflags = ENVSYS_WARN_OK;
1215	sc->sc_tre[0].validflags = ENVSYS_FVALID | ENVSYS_FCURVALID;
1216	sc->sc_tre[0].units = ENVSYS_STEMP;
1217
1218	/* battery voltage */
1219	strcpy(sc->sc_binfo[1].desc, "Internal battery voltage");
1220	sc->sc_binfo[1].sensor = 1;
1221	sc->sc_binfo[1].units = ENVSYS_SVOLTS_DC;
1222	sc->sc_binfo[1].validflags = ENVSYS_FVALID | ENVSYS_FCURVALID;
1223	sc->sc_range[1].low = 0;
1224	sc->sc_range[1].high = 0;
1225	sc->sc_range[1].units = ENVSYS_SVOLTS_DC;
1226	sc->sc_tre[1].sensor = 0;
1227	sc->sc_tre[1].warnflags = ENVSYS_WARN_OK;
1228	sc->sc_tre[1].validflags = ENVSYS_FVALID | ENVSYS_FCURVALID;
1229	sc->sc_tre[1].units = ENVSYS_SVOLTS_DC;
1230
1231	/* DC voltage */
1232	strcpy(sc->sc_binfo[2].desc, "DC-In voltage");
1233	sc->sc_binfo[2].sensor = 2;
1234	sc->sc_binfo[2].units = ENVSYS_SVOLTS_DC;
1235	sc->sc_binfo[2].validflags = ENVSYS_FVALID | ENVSYS_FCURVALID;
1236	sc->sc_range[2].low = 0;
1237	sc->sc_range[2].high = 0;
1238	sc->sc_range[2].units = ENVSYS_SVOLTS_DC;
1239	sc->sc_tre[2].sensor = 0;
1240	sc->sc_tre[2].warnflags = ENVSYS_WARN_OK;
1241	sc->sc_tre[2].validflags = ENVSYS_FVALID | ENVSYS_FCURVALID;
1242	sc->sc_tre[2].units = ENVSYS_SVOLTS_DC;
1243
1244	sc->sc_sme.sme_nsensors = ENVSYS_NUMSENSORS;
1245	sc->sc_sme.sme_envsys_version = 1000;
1246	sc->sc_sme.sme_ranges = sc->sc_range;
1247	sc->sc_sme.sme_sensor_info = sc->sc_binfo;
1248	sc->sc_sme.sme_sensor_data = sc->sc_tre;
1249	sc->sc_sme.sme_cookie = sc;
1250	sc->sc_sme.sme_gtredata = tctrl_gtredata;
1251	sc->sc_sme.sme_streinfo = tctrl_streinfo;
1252	sc->sc_sme.sme_flags = 0;
1253
1254	if ((error = sysmon_envsys_register(&sc->sc_sme)) != 0) {
1255		printf("%s: couldn't register sensors (%d)\n",
1256		    sc->sc_dev.dv_xname, error);
1257	}
1258
1259	/* now register the power button */
1260
1261	sysmon_task_queue_init();
1262
1263	sc->sc_powerpressed = 0;
1264	memset(&sc->sc_smcontext, 0, sizeof(struct sysmon_pswitch));
1265	sc->sc_smcontext.smpsw_name = sc->sc_dev.dv_xname;
1266	sc->sc_smcontext.smpsw_type = PSWITCH_TYPE_POWER;
1267	if (sysmon_pswitch_register(&sc->sc_smcontext) != 0)
1268		printf("%s: unable to register power button with sysmon\n",
1269		    sc->sc_dev.dv_xname);
1270}
1271
1272static void
1273tctrl_power_button_pressed(void *arg)
1274{
1275	struct tctrl_softc *sc = arg;
1276
1277	sysmon_pswitch_event(&sc->sc_smcontext, PSWITCH_EVENT_PRESSED);
1278	sc->sc_powerpressed = 0;
1279}
1280
1281static int
1282tctrl_powerfail(void *arg)
1283{
1284	struct tctrl_softc *sc = (struct tctrl_softc *)arg;
1285
1286	/*
1287	 * We lost power. Queue a callback with thread context to
1288	 * handle all the real work.
1289	 */
1290	if (sc->sc_powerpressed == 0) {
1291		sc->sc_powerpressed = 1;
1292		sysmon_task_queue_sched(0, tctrl_power_button_pressed, sc);
1293	}
1294	return (1);
1295}
1296
1297static int
1298tctrl_gtredata(struct sysmon_envsys *sme, struct envsys_tre_data *tred)
1299{
1300	/*struct tctrl_softc *sc = sme->sme_cookie;*/
1301	struct envsys_tre_data *cur_tre;
1302	struct envsys_basic_info *cur_i;
1303	struct tctrl_req req;
1304	struct proc *p;
1305	int i;
1306
1307	i = tred->sensor;
1308	cur_tre = &sme->sme_sensor_data[i];
1309	cur_i = &sme->sme_sensor_info[i];
1310	p = __curproc();
1311
1312	switch (i)
1313	{
1314		case 0:	/* case temperature */
1315			req.cmdbuf[0] = TS102_OP_RD_CURRENT_TEMP;
1316			req.cmdlen = 1;
1317			req.rsplen = 2;
1318			req.p = p;
1319			tadpole_request(&req, 0);
1320			cur_tre->cur.data_us =             /* 273160? */
1321			    (u_int32_t)((int)((int)req.rspbuf[0] - 32) * 5000000
1322			    / 9 + 273150000);
1323			cur_tre->validflags |= ENVSYS_FCURVALID;
1324			req.cmdbuf[0] = TS102_OP_RD_MAX_TEMP;
1325			req.cmdlen = 1;
1326			req.rsplen = 2;
1327			req.p = p;
1328			tadpole_request(&req, 0);
1329			cur_tre->max.data_us =
1330			    (u_int32_t)((int)((int)req.rspbuf[0] - 32) * 5000000
1331			    / 9 + 273150000);
1332			cur_tre->validflags |= ENVSYS_FMAXVALID;
1333			req.cmdbuf[0] = TS102_OP_RD_MIN_TEMP;
1334			req.cmdlen = 1;
1335			req.rsplen = 2;
1336			req.p = p;
1337			tadpole_request(&req, 0);
1338			cur_tre->min.data_us =
1339			    (u_int32_t)((int)((int)req.rspbuf[0] - 32) * 5000000
1340			    / 9 + 273150000);
1341			cur_tre->validflags |= ENVSYS_FMINVALID;
1342			cur_tre->units = ENVSYS_STEMP;
1343			break;
1344
1345		case 1: /* battery voltage */
1346			{
1347				cur_tre->validflags =
1348				    ENVSYS_FVALID|ENVSYS_FCURVALID;
1349				cur_tre->units = ENVSYS_SVOLTS_DC;
1350				req.cmdbuf[0] = TS102_OP_RD_INT_BATT_VLT;
1351				req.cmdlen = 1;
1352				req.rsplen = 2;
1353				req.p = p;
1354				tadpole_request(&req, 0);
1355				cur_tre->cur.data_s = (int32_t)req.rspbuf[0] *
1356				    1000000 / 11;
1357			}
1358			break;
1359		case 2: /* DC voltage */
1360			{
1361				cur_tre->validflags =
1362				    ENVSYS_FVALID|ENVSYS_FCURVALID;
1363				cur_tre->units = ENVSYS_SVOLTS_DC;
1364				req.cmdbuf[0] = TS102_OP_RD_DC_IN_VLT;
1365				req.cmdlen = 1;
1366				req.rsplen = 2;
1367				req.p = p;
1368				tadpole_request(&req, 0);
1369				cur_tre->cur.data_s = (int32_t)req.rspbuf[0] *
1370				    1000000 / 11;
1371			}
1372			break;
1373	}
1374	cur_tre->validflags |= ENVSYS_FVALID;
1375	*tred = sme->sme_sensor_data[i];
1376	return 0;
1377}
1378
1379
1380static int
1381tctrl_streinfo(struct sysmon_envsys *sme, struct envsys_basic_info *binfo)
1382{
1383	/* There is nothing to set here. */
1384	return (EINVAL);
1385}
1386
1387