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