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