1/*	$OpenBSD: hil.c,v 1.29 2022/01/09 05:42:37 jsg Exp $	*/
2/*
3 * Copyright (c) 2003, 2004, Miodrag Vallat.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 *
27 */
28
29/*
30 * Copyright (c) 1988 University of Utah.
31 * Copyright (c) 1990, 1993
32 *	The Regents of the University of California.  All rights reserved.
33 *
34 * This code is derived from software contributed to Berkeley by
35 * the Systems Programming Group of the University of Utah Computer
36 * Science Department.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 * 1. Redistributions of source code must retain the above copyright
42 *    notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 *    notice, this list of conditions and the following disclaimer in the
45 *    documentation and/or other materials provided with the distribution.
46 * 3. Neither the name of the University nor the names of its contributors
47 *    may be used to endorse or promote products derived from this software
48 *    without specific prior written permission.
49 *
50 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 * SUCH DAMAGE.
61 *
62 * from: Utah $Hdr: hil.c 1.38 92/01/21$
63 *
64 *	@(#)hil.c	8.2 (Berkeley) 1/12/94
65 */
66
67#include <sys/param.h>
68#include <sys/systm.h>
69#include <sys/conf.h>
70#include <sys/device.h>
71#include <sys/ioctl.h>
72#include <sys/kernel.h>
73#include <sys/proc.h>
74#include <sys/kthread.h>
75
76#include <machine/autoconf.h>
77#include <machine/bus.h>
78#include <machine/cpu.h>
79
80#include <dev/hil/hilreg.h>
81#include <dev/hil/hilvar.h>
82#include <dev/hil/hildevs.h>
83#include <dev/hil/hildevs_data.h>
84
85#include "hilkbd.h"
86
87/*
88 * splhigh is extremely conservative but insures atomic operation,
89 * splvm (clock only interrupts) seems to be good enough in practice.
90 */
91#define	splhil	splvm
92
93struct cfdriver hil_cd = {
94	NULL, "hil", DV_DULL
95};
96
97void	hilconfig(struct hil_softc *, u_int);
98void	hilempty(struct hil_softc *);
99int	hilsubmatch(struct device *, void *, void *);
100void	hil_process_int(struct hil_softc *, u_int8_t, u_int8_t);
101int	hil_process_poll(struct hil_softc *, u_int8_t, u_int8_t);
102void	hil_thread(void *);
103int	send_device_cmd(struct hil_softc *sc, u_int device, u_int cmd);
104void	polloff(struct hil_softc *);
105void	pollon(struct hil_softc *);
106
107static int hilwait(struct hil_softc *);
108static int hildatawait(struct hil_softc *);
109
110#define	hil_process_pending(sc)	wakeup(&(sc)->sc_pending)
111
112static __inline int
113hilwait(struct hil_softc *sc)
114{
115	int cnt;
116
117	for (cnt = 50000; cnt != 0; cnt--) {
118		DELAY(1);
119		if ((bus_space_read_1(sc->sc_bst, sc->sc_bsh, HILP_STAT) &
120		    HIL_BUSY) == 0)
121			break;
122	}
123
124	return (cnt);
125}
126
127static __inline int
128hildatawait(struct hil_softc *sc)
129{
130	int cnt;
131
132	for (cnt = 50000; cnt != 0; cnt--) {
133		DELAY(1);
134		if ((bus_space_read_1(sc->sc_bst, sc->sc_bsh, HILP_STAT) &
135		    HIL_DATA_RDY) != 0)
136			break;
137	}
138
139	return (cnt);
140}
141
142/*
143 * Common HIL bus attachment
144 */
145
146void
147hil_attach(struct hil_softc *sc, int *hil_is_console)
148{
149	printf("\n");
150
151	/*
152	 * Initialize loop information
153	 */
154	sc->sc_cmdending = 0;
155	sc->sc_actdev = sc->sc_cmddev = 0;
156	sc->sc_cmddone = 0;
157	sc->sc_cmdbp = sc->sc_cmdbuf;
158	sc->sc_pollbp = sc->sc_pollbuf;
159	sc->sc_console = hil_is_console;
160}
161
162/*
163 * HIL subdevice attachment
164 */
165
166int
167hildevprint(void *aux, const char *pnp)
168{
169	struct hil_attach_args *ha = aux;
170
171	if (pnp != NULL) {
172		printf("\"%s\" at %s id %x",
173		    ha->ha_descr, pnp, ha->ha_id);
174	}
175	printf(" code %d", ha->ha_code);
176	if (pnp == NULL) {
177		printf(": %s", ha->ha_descr);
178	}
179
180	return (UNCONF);
181}
182
183int
184hilsubmatch(struct device *parent, void *vcf, void *aux)
185{
186	struct hil_attach_args *ha = aux;
187	struct cfdata *cf = vcf;
188
189	if (cf->cf_loc[0] != -1 &&
190	    cf->cf_loc[0] != ha->ha_code)
191		return (0);
192
193	return ((*cf->cf_attach->ca_match)(parent, vcf, aux));
194}
195
196void
197hil_attach_deferred(void *v)
198{
199	struct hil_softc *sc = v;
200	int tries;
201	u_int8_t db;
202
203	sc->sc_status = HIL_STATUS_BUSY;
204
205	/*
206	 * Initialize the loop: reconfigure, don't report errors,
207	 * put keyboard in cooked mode, and enable autopolling.
208	 */
209	db = LPC_RECONF | LPC_KBDCOOK | LPC_NOERROR | LPC_AUTOPOLL;
210	send_hil_cmd(sc, HIL_WRITELPCTRL, &db, 1, NULL);
211
212	/*
213	 * Delay one second for reconfiguration and then read the
214	 * data to clear the interrupt (if the loop reconfigured).
215	 */
216	DELAY(1000000);
217	if (bus_space_read_1(sc->sc_bst, sc->sc_bsh, HILP_STAT) &
218	    HIL_DATA_RDY) {
219		db = bus_space_read_1(sc->sc_bst, sc->sc_bsh, HILP_DATA);
220		DELAY(1);
221	}
222
223	/*
224	 * The HIL loop may have reconfigured.  If so we proceed on,
225	 * if not we loop a few times until a successful reconfiguration
226	 * is reported back to us. If the HIL loop is still lost after a
227	 * few seconds, give up.
228	 */
229	for (tries = 10; tries != 0; tries--) {
230		if (send_hil_cmd(sc, HIL_READLPSTAT, NULL, 0, &db) == 0) {
231			if (db & (LPS_CONFFAIL | LPS_CONFGOOD))
232				break;
233		}
234
235#ifdef HILDEBUG
236		printf("%s: loop not ready, retrying...\n",
237		    sc->sc_dev.dv_xname);
238#endif
239
240		DELAY(1000000);
241        }
242
243	if (tries == 0 || (db & LPS_CONFFAIL)) {
244		printf("%s: no devices\n", sc->sc_dev.dv_xname);
245		sc->sc_pending = 0;
246		if (tries == 0)
247			return;
248	}
249
250	/*
251	 * Create asynchronous loop event handler thread.
252	 */
253	if (kthread_create(hil_thread, sc, &sc->sc_thread,
254	    sc->sc_dev.dv_xname) != 0) {
255		printf("%s: unable to create event thread\n",
256		    sc->sc_dev.dv_xname);
257		return;
258	}
259
260	/*
261	 * Enable loop interrupts.
262	 */
263	send_hil_cmd(sc, HIL_INTON, NULL, 0, NULL);
264
265	/*
266	 * Reconfigure if necessary
267	 */
268	sc->sc_status = HIL_STATUS_READY;
269	hil_process_pending(sc);
270}
271
272/*
273 * Asynchronous event processing
274 */
275
276int
277hil_intr(void *v)
278{
279	struct hil_softc *sc = v;
280	u_int8_t c, stat;
281
282	if (cold)
283		return (0);
284
285	stat = bus_space_read_1(sc->sc_bst, sc->sc_bsh, HILP_STAT);
286
287	/*
288	 * This should never happen if the interrupt comes from the
289	 * loop.
290	 */
291	if ((stat & HIL_DATA_RDY) == 0)
292		return (0);	/* not for us */
293
294	c = bus_space_read_1(sc->sc_bst, sc->sc_bsh,
295	    HILP_DATA);	/* clears interrupt */
296	DELAY(1);
297
298	hil_process_int(sc, stat, c);
299
300	if (sc->sc_status != HIL_STATUS_BUSY)
301		hil_process_pending(sc);
302
303	return (1);
304}
305
306void
307hil_process_int(struct hil_softc *sc, u_int8_t stat, u_int8_t c)
308{
309	struct hildev_softc *dev;
310
311	switch ((stat >> HIL_SSHIFT) & HIL_SMASK) {
312	case HIL_STATUS:
313		if (c & HIL_ERROR) {
314		  	sc->sc_cmddone = 1;
315			switch (c) {
316			case HIL_RECONFIG:
317				sc->sc_pending = HIL_PENDING_RECONFIG;
318				break;
319			case HIL_UNPLUGGED:
320				sc->sc_pending = HIL_PENDING_UNPLUGGED;
321				break;
322			}
323			break;
324		}
325		if (c & HIL_COMMAND) {
326		  	if (c & HIL_POLLDATA) {	/* End of data */
327				dev = sc->sc_devices[sc->sc_actdev];
328				if (dev != NULL && dev->sc_fn != NULL)
329					dev->sc_fn(dev,
330					    sc->sc_pollbp - sc->sc_pollbuf,
331					    sc->sc_pollbuf);
332			} else {		/* End of command */
333			  	sc->sc_cmdending = 1;
334			}
335			sc->sc_actdev = 0;
336		} else {
337		  	if (c & HIL_POLLDATA) {	/* Start of polled data */
338				sc->sc_actdev = (c & HIL_DEVMASK);
339				sc->sc_pollbp = sc->sc_pollbuf;
340			} else {		/* Start of command */
341				if (sc->sc_cmddev == (c & HIL_DEVMASK)) {
342					sc->sc_cmdbp = sc->sc_cmdbuf;
343					sc->sc_actdev = 0;
344				}
345			}
346		}
347	        break;
348	case HIL_DATA:
349		if (sc->sc_actdev != 0)	/* Collecting poll data */
350			*sc->sc_pollbp++ = c;
351		else {
352			if (sc->sc_cmddev != 0) {  /* Collecting cmd data */
353				if (sc->sc_cmdending) {
354					sc->sc_cmddone = 1;
355					sc->sc_cmdending = 0;
356				} else
357					*sc->sc_cmdbp++ = c;
358		        }
359		}
360		break;
361	}
362}
363
364/*
365 * Same as above, but in polled mode: return data as it gets seen, instead
366 * of buffering it.
367 */
368int
369hil_process_poll(struct hil_softc *sc, u_int8_t stat, u_int8_t c)
370{
371	u_int8_t db;
372
373	switch ((stat >> HIL_SSHIFT) & HIL_SMASK) {
374	case HIL_STATUS:
375		if (c & HIL_ERROR) {
376		  	sc->sc_cmddone = 1;
377			switch (c) {
378			case HIL_RECONFIG:
379				/*
380				 * Remember that a configuration event
381				 * occurred; it will be processed upon
382				 * leaving polled mode...
383				 */
384				sc->sc_pending = HIL_PENDING_RECONFIG;
385				/*
386				 * However, the keyboard will come back as
387				 * cooked, and we rely on it being in raw
388				 * mode. So, put it back in raw mode right
389				 * now.
390				 */
391				db = 0;
392				send_hil_cmd(sc, HIL_WRITEKBDSADR, &db,
393				    1, NULL);
394				break;
395			case HIL_UNPLUGGED:
396				/*
397				 * Remember that an unplugged event
398				 * occurred; it will be processed upon
399				 * leaving polled mode...
400				 */
401				sc->sc_pending = HIL_PENDING_UNPLUGGED;
402				break;
403			}
404			break;
405		}
406		if (c & HIL_COMMAND) {
407		  	if (!(c & HIL_POLLDATA)) {
408				/* End of command */
409			  	sc->sc_cmdending = 1;
410			}
411			sc->sc_actdev = 0;
412		} else {
413		  	if (c & HIL_POLLDATA) {
414				/* Start of polled data */
415				sc->sc_actdev = (c & HIL_DEVMASK);
416				sc->sc_pollbp = sc->sc_pollbuf;
417			} else {
418				/* Start of command - should not happen */
419				if (sc->sc_cmddev == (c & HIL_DEVMASK)) {
420					sc->sc_cmdbp = sc->sc_cmdbuf;
421					sc->sc_actdev = 0;
422				}
423			}
424		}
425	        break;
426	case HIL_DATA:
427		if (sc->sc_actdev != 0)	/* Collecting poll data */
428			return 1;
429		else {
430			if (sc->sc_cmddev != 0) {  /* Discarding cmd data */
431				if (sc->sc_cmdending) {
432					sc->sc_cmddone = 1;
433					sc->sc_cmdending = 0;
434				}
435		        }
436		}
437		break;
438	}
439
440	return 0;
441}
442
443void
444hil_thread(void *arg)
445{
446	struct hil_softc *sc = arg;
447	int s;
448
449	for (;;) {
450		s = splhil();
451		if (sc->sc_pending == 0) {
452			splx(s);
453			tsleep_nsec(&sc->sc_pending, PWAIT, "hil_event",
454			    INFSLP);
455			continue;
456		}
457
458		switch (sc->sc_pending) {
459		case HIL_PENDING_RECONFIG:
460			sc->sc_pending = 0;
461			hilconfig(sc, sc->sc_maxdev);
462			break;
463		case HIL_PENDING_UNPLUGGED:
464			sc->sc_pending = 0;
465			hilempty(sc);
466			break;
467		}
468		splx(s);
469	}
470}
471
472/*
473 * Called after the loop has reconfigured.  Here we need to:
474 *	- determine how many devices are on the loop
475 *	  (some may have been added or removed)
476 *	- make sure all keyboards are in raw mode
477 *
478 * Note that our device state is now potentially invalid as
479 * devices may no longer be where they were.  What we should
480 * do here is either track where the devices went and move
481 * state around accordingly...
482 *
483 * Note that it is necessary that we operate the loop with the keyboards
484 * in raw mode: they won't cause the loop to generate an NMI if the
485 * ``reset'' key combination is pressed, and we do not handle the hil
486 * NMI interrupt...
487 */
488void
489hilconfig(struct hil_softc *sc, u_int knowndevs)
490{
491	struct hil_attach_args ha;
492	u_int8_t db;
493	int id, s;
494
495	s = splhil();
496
497	/*
498	 * Determine how many devices are on the loop.
499	 */
500	db = 0;
501	send_hil_cmd(sc, HIL_READLPSTAT, NULL, 0, &db);
502	sc->sc_maxdev = db & LPS_DEVMASK;
503#ifdef HILDEBUG
504	printf("%s: %d device(s)\n", sc->sc_dev.dv_xname, sc->sc_maxdev);
505#endif
506
507	/*
508	 * Put all keyboards in raw mode now.
509	 */
510	db = 0;
511	send_hil_cmd(sc, HIL_WRITEKBDSADR, &db, 1, NULL);
512
513	/*
514	 * If the loop grew, attach new devices.
515	 */
516	for (id = knowndevs + 1; id <= sc->sc_maxdev; id++) {
517		int len;
518		const struct hildevice *hd;
519
520		if (send_device_cmd(sc, id, HIL_IDENTIFY) != 0) {
521			printf("%s: no answer from device %d\n",
522			    sc->sc_dev.dv_xname, id);
523			continue;
524		}
525
526		len = sc->sc_cmdbp - sc->sc_cmdbuf;
527		if (len == 0) {
528#ifdef HILDEBUG
529			printf("%s: no device at code %d\n",
530			    sc->sc_dev.dv_xname, id);
531#endif
532			continue;
533		}
534
535		/* Identify and attach device */
536		for (hd = hildevs; hd->minid >= 0; hd++)
537			if (sc->sc_cmdbuf[0] >= hd->minid &&
538			    sc->sc_cmdbuf[0] <= hd->maxid) {
539
540			ha.ha_console = *sc->sc_console;
541			ha.ha_code = id;
542			ha.ha_type = hd->type;
543			ha.ha_descr = hd->descr;
544			ha.ha_infolen = len;
545			bcopy(sc->sc_cmdbuf, ha.ha_info, len);
546
547			sc->sc_devices[id] = (struct hildev_softc *)
548			    config_found_sm(&sc->sc_dev, &ha, hildevprint,
549			        hilsubmatch);
550
551#if NHILKBD > 0
552			/*
553			 * If we just attached a keyboard as console,
554			 * console choice is not indeterminate anymore.
555			 */
556			if (sc->sc_devices[id] != NULL &&
557			    ha.ha_type == HIL_DEVICE_KEYBOARD &&
558			    ha.ha_console != 0)
559				*sc->sc_console = 1;
560#endif
561		}
562	}
563
564	/*
565	 * Detach remaining devices, if the loop has shrunk.
566	 */
567	for (id = sc->sc_maxdev + 1; id < NHILD; id++) {
568		if (sc->sc_devices[id] != NULL)
569			config_detach((struct device *)sc->sc_devices[id],
570			    DETACH_FORCE);
571		sc->sc_devices[id] = NULL;
572	}
573
574	sc->sc_cmdbp = sc->sc_cmdbuf;
575
576	splx(s);
577}
578
579/*
580 * Called after the loop has been unplugged. We simply force detach of
581 * all our children.
582 */
583void
584hilempty(struct hil_softc *sc)
585{
586	u_int8_t db;
587	int id, s;
588	u_int oldmaxdev;
589
590	s = splhil();
591
592	/*
593	 * Wait for the loop to be stable.
594	 */
595	for (;;) {
596		if (send_hil_cmd(sc, HIL_READLPSTAT, NULL, 0, &db) == 0) {
597			if (db & (LPS_CONFFAIL | LPS_CONFGOOD))
598				break;
599		} else {
600			db = LPS_CONFFAIL;
601			break;
602		}
603	}
604
605	if (db & LPS_CONFFAIL) {
606		sc->sc_maxdev = 0;
607	} else {
608		db = 0;
609		send_hil_cmd(sc, HIL_READLPSTAT, NULL, 0, &db);
610		oldmaxdev = sc->sc_maxdev;
611		sc->sc_maxdev = db & LPS_DEVMASK;
612
613		if (sc->sc_maxdev != 0) {
614			/*
615			 * The loop was not unplugged after all, but its
616			 * configuration has changed.
617			 */
618			hilconfig(sc, oldmaxdev);
619			splx(s);
620			return;
621		}
622	}
623
624	/*
625	 * Now detach all hil devices.
626	 */
627	for (id = sc->sc_maxdev + 1; id < NHILD; id++) {
628		if (sc->sc_devices[id] != NULL)
629			config_detach((struct device *)sc->sc_devices[id],
630			    DETACH_FORCE);
631		sc->sc_devices[id] = NULL;
632	}
633
634	sc->sc_cmdbp = sc->sc_cmdbuf;
635
636	splx(s);
637}
638
639/*
640 * Low level routines which actually talk to the 8042 chip.
641 */
642
643/*
644 * Send a command to the 8042 with zero or more bytes of data.
645 * If rdata is non-null, wait for and return a byte of data.
646 */
647int
648send_hil_cmd(struct hil_softc *sc, u_int cmd, u_int8_t *data, u_int dlen,
649    u_int8_t *rdata)
650{
651	u_int8_t status;
652	int s;
653
654	s = splhil();
655
656	if (hilwait(sc) == 0) {
657#ifdef HILDEBUG
658		printf("%s: no answer from the loop\n", sc->sc_dev.dv_xname);
659#endif
660		splx(s);
661		return (EBUSY);
662	}
663
664	bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_CMD, cmd);
665	while (dlen--) {
666	  	hilwait(sc);
667		bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_DATA, *data++);
668		DELAY(1);
669	}
670	if (rdata) {
671		do {
672			if (hildatawait(sc) == 0) {
673#ifdef HILDEBUG
674				printf("%s: no answer from the loop\n",
675				    sc->sc_dev.dv_xname);
676#endif
677				break;
678			}
679			status = bus_space_read_1(sc->sc_bst, sc->sc_bsh,
680			    HILP_STAT);
681			*rdata = bus_space_read_1(sc->sc_bst, sc->sc_bsh,
682			    HILP_DATA);
683			DELAY(1);
684		} while (((status >> HIL_SSHIFT) & HIL_SMASK) != HIL_68K);
685	}
686	splx(s);
687	return (0);
688}
689
690/*
691 * Send a command to a device on the loop.
692 * Since only one command can be active on the loop at any time,
693 * we must ensure that we are not interrupted during this process.
694 * Hence we mask interrupts to prevent potential access from most
695 * interrupt routines and turn off auto-polling to disable the
696 * internally generated poll commands.
697 * Needs to be called at splhil().
698 */
699int
700send_device_cmd(struct hil_softc *sc, u_int device, u_int cmd)
701{
702	u_int8_t status, c;
703	int rc = 0;
704
705	polloff(sc);
706
707	sc->sc_cmdbp = sc->sc_cmdbuf;
708	sc->sc_cmddev = device;
709
710	if (hilwait(sc) == 0) {
711#ifdef HILDEBUG
712		printf("%s: no answer from device %d\n",
713		    sc->sc_dev.dv_xname, device);
714#endif
715		rc = EBUSY;
716		goto out;
717	}
718
719	/*
720	 * Transfer the command and device info to the chip
721	 */
722	bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_CMD, HIL_STARTCMD);
723  	hilwait(sc);
724	bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_DATA, 8 + device);
725  	hilwait(sc);
726	bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_DATA, cmd);
727  	hilwait(sc);
728	bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_DATA, HIL_TIMEOUT);
729
730	/*
731	 * Trigger the command and wait for completion
732	 */
733	hilwait(sc);
734	bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_CMD, HIL_TRIGGER);
735	sc->sc_cmddone = 0;
736	do {
737		if (hildatawait(sc) == 0) {
738#ifdef HILDEBUG
739			printf("%s: no answer from device %d\n",
740			    sc->sc_dev.dv_xname, device);
741#endif
742			rc = EBUSY;
743			break;
744		}
745		status = bus_space_read_1(sc->sc_bst, sc->sc_bsh, HILP_STAT);
746		c = bus_space_read_1(sc->sc_bst, sc->sc_bsh, HILP_DATA);
747		DELAY(1);
748		hil_process_int(sc, status, c);
749	} while (sc->sc_cmddone == 0);
750out:
751	sc->sc_cmddev = 0;
752
753	pollon(sc);
754	return (rc);
755}
756
757int
758send_hildev_cmd(struct hildev_softc *dev, u_int cmd,
759    u_int8_t *outbuf, u_int *outlen)
760{
761	struct hil_softc *sc = (struct hil_softc *)dev->sc_dev.dv_parent;
762	int s, rc;
763
764	s = splhil();
765
766	if ((rc = send_device_cmd(sc, dev->sc_code, cmd)) == 0) {
767		/*
768		 * Return the command response in the buffer if necessary
769	 	*/
770		if (outbuf != NULL && outlen != NULL) {
771			*outlen = min(*outlen, sc->sc_cmdbp - sc->sc_cmdbuf);
772			bcopy(sc->sc_cmdbuf, outbuf, *outlen);
773		}
774	}
775
776	splx(s);
777	return (rc);
778}
779
780/*
781 * Turn auto-polling off and on.
782 */
783void
784polloff(struct hil_softc *sc)
785{
786	u_int8_t db;
787
788	if (hilwait(sc) == 0)
789		return;
790
791	/*
792	 * Turn off auto repeat
793	 */
794	bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_CMD, HIL_SETARR);
795	hilwait(sc);
796	bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_DATA, 0);
797
798	/*
799	 * Turn off auto-polling
800	 */
801	hilwait(sc);
802	bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_CMD, HIL_READLPCTRL);
803	hildatawait(sc);
804	db = bus_space_read_1(sc->sc_bst, sc->sc_bsh, HILP_DATA);
805	db &= ~LPC_AUTOPOLL;
806	hilwait(sc);
807	bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_CMD, HIL_WRITELPCTRL);
808	hilwait(sc);
809	bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_DATA, db);
810
811	/*
812	 * Must wait until polling is really stopped
813	 */
814	do {
815		hilwait(sc);
816		bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_CMD, HIL_READBUSY);
817		hildatawait(sc);
818		db = bus_space_read_1(sc->sc_bst, sc->sc_bsh, HILP_DATA);
819	} while (db & BSY_LOOPBUSY);
820
821	sc->sc_cmddone = 0;
822	sc->sc_cmddev = 0;
823}
824
825void
826pollon(struct hil_softc *sc)
827{
828	u_int8_t db;
829
830	if (hilwait(sc) == 0)
831		return;
832
833	/*
834	 * Turn on auto polling
835	 */
836	bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_CMD, HIL_READLPCTRL);
837	hildatawait(sc);
838	db = bus_space_read_1(sc->sc_bst, sc->sc_bsh, HILP_DATA);
839	db |= LPC_AUTOPOLL;
840	hilwait(sc);
841	bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_CMD, HIL_WRITELPCTRL);
842	hilwait(sc);
843	bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_DATA, db);
844
845	/*
846	 * Turn off auto repeat - we emulate this through wscons
847	 */
848	hilwait(sc);
849	bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_CMD, HIL_SETARR);
850	hilwait(sc);
851	bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_DATA, 0);
852	DELAY(1);
853}
854
855void
856hil_set_poll(struct hil_softc *sc, int on)
857{
858	if (on) {
859		pollon(sc);
860	} else {
861		hil_process_pending(sc);
862		send_hil_cmd(sc, HIL_INTON, NULL, 0, NULL);
863	}
864}
865
866int
867hil_poll_data(struct hildev_softc *dev, u_int8_t *stat, u_int8_t *data)
868{
869	struct hil_softc *sc = (struct hil_softc *)dev->sc_dev.dv_parent;
870	u_int8_t s, c;
871
872	s = bus_space_read_1(sc->sc_bst, sc->sc_bsh, HILP_STAT);
873	if ((s & HIL_DATA_RDY) == 0)
874		return -1;
875
876	c = bus_space_read_1(sc->sc_bst, sc->sc_bsh, HILP_DATA);
877	DELAY(1);
878
879	if (hil_process_poll(sc, s, c)) {
880		/* Discard any data not for us */
881		if (sc->sc_actdev == dev->sc_code) {
882			*stat = s;
883			*data = c;
884			return 0;
885		}
886	}
887
888	return -1;
889}
890