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