sa1111_kbc.c revision 1.2
1/*      $NetBSD: sa1111_kbc.c,v 1.2 2003/07/15 00:24:50 lukem Exp $ */
2
3/*
4 * Copyright (c) 2002  Genetec Corporation.  All rights reserved.
5 * Written by Hiroyuki Bessho for Genetec Corporation.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. The name of Genetec Corporation may not be used to endorse or
16 *    promote products derived from this software without specific prior
17 *    written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GENETEC CORPORATION
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 * Driver for keyboard controller in SA-1111 companion chip.
32 *
33 * PC keyboard driver (sys/dev/pckbc/pckbd.c) works only with 8042
34 * keyboard controller driver (sys/dev/ic/pckbc.c).  This file
35 * provides same functions as those of 8042 driver.
36 *
37 * XXX: we need cleaner interface between the keyboard driver and
38 *      keyboard controller drivers.
39 */
40/*
41 * Copyright (c) 1998
42 *	Matthias Drochner.  All rights reserved.
43 *
44 * Redistribution and use in source and binary forms, with or without
45 * modification, are permitted provided that the following conditions
46 * are met:
47 * 1. Redistributions of source code must retain the above copyright
48 *    notice, this list of conditions and the following disclaimer.
49 * 2. Redistributions in binary form must reproduce the above copyright
50 *    notice, this list of conditions and the following disclaimer in the
51 *    documentation and/or other materials provided with the distribution.
52 * 3. All advertising materials mentioning features or use of this software
53 *    must display the following acknowledgement:
54 *	This product includes software developed for the NetBSD Project
55 *	by Matthias Drochner.
56 * 4. The name of the author may not be used to endorse or promote products
57 *    derived from this software without specific prior written permission.
58 *
59 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
60 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
61 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
62 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
63 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
64 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
65 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
66 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
67 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
68 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
69 */
70
71#include <sys/cdefs.h>
72__KERNEL_RCSID(0, "$NetBSD: sa1111_kbc.c,v 1.2 2003/07/15 00:24:50 lukem Exp $");
73
74#include <sys/param.h>
75#include <sys/systm.h>
76#include <sys/types.h>
77#include <sys/callout.h>
78#include <sys/kernel.h>
79#include <sys/proc.h>
80#include <sys/conf.h>
81#include <sys/device.h>
82#include <sys/malloc.h>
83#include <sys/errno.h>
84#include <sys/queue.h>
85#include <sys/lock.h>
86
87#include <machine/bus.h>
88#include <arm/sa11x0/sa1111_reg.h>
89#include <arm/sa11x0/sa1111_var.h>
90
91#include <dev/ic/pckbcvar.h>		/* for prototypes */
92
93#include "pckbd.h"
94#include "rnd.h"
95#include "locators.h"
96
97/* descriptor for one device command */
98struct pckbc_devcmd {
99	TAILQ_ENTRY(pckbc_devcmd) next;
100	int flags;
101#define KBC_CMDFLAG_SYNC 1 /* give descriptor back to caller */
102#define KBC_CMDFLAG_SLOW 2
103	u_char cmd[4];
104	int cmdlen, cmdidx, retries;
105	u_char response[4];
106	int status, responselen, responseidx;
107};
108
109struct sackbc_softc {
110	struct device dev;
111
112	bus_space_tag_t    iot;
113	bus_space_handle_t ioh;
114
115	void	*ih_rx;			/* receive interrupt */
116	int	intr;			/* interrupt number */
117
118	int	polling;	/* don't process data in interrupt handler */
119	int	poll_stat;	/* data read from inr handler if polling */
120	int	poll_data;	/* status read from intr handler if polling */
121
122	TAILQ_HEAD(, pckbc_devcmd) cmdqueue; /* active commands */
123	TAILQ_HEAD(, pckbc_devcmd) freequeue; /* free commands */
124#define NCMD  5
125	struct pckbc_devcmd cmd[NCMD];
126
127	struct callout t_cleanup;
128	pckbc_inputfcn inputhandler;
129	void *inputarg;
130	const char *subname;
131
132};
133
134#define CMD_IN_QUEUE(q) (TAILQ_FIRST(&(q)->cmdqueue) != NULL)
135
136#define N_KBC_SLOTS  2
137/*static struct sackbc_softc *sackbc_slot[N_KBC_SLOTS] = { NULL, NULL };*/
138
139static	int	sackbc_match(struct device *, struct cfdata *, void *);
140static	void	sackbc_attach(struct device *, struct device *, void *);
141static int	 sackbc_cmdresponse( struct sackbc_softc *, int );
142
143CFATTACH_DECL(sackbc, sizeof(struct sackbc_softc), sackbc_match,
144    sackbc_attach, NULL, NULL);
145
146/* XXX should not be here */
147#define KBC_DEVCMD_ACK 0xfa
148#define KBC_DEVCMD_RESEND 0xfe
149
150#define	KBD_DELAY	DELAY(8)
151
152/*#define SACKBCDEBUG*/
153
154#ifdef SACKBCDEBUG
155#define DPRINTF(arg)  printf arg
156#else
157#define DPRINTF(arg)
158#endif
159
160static void sackbc_poll_cmd1( struct sackbc_softc *, struct pckbc_devcmd * );
161
162
163
164static int
165sackbc_match(struct device *parent, struct cfdata *cf, void *aux)
166{
167	struct sa1111_attach_args *aa = (struct sa1111_attach_args *)aux;
168
169	switch( aa->sa_addr ){
170	case SACC_KBD0: case SACC_KBD1:
171		return 1;
172	}
173	return 0;
174}
175
176#if 0
177static int
178sackbc_txint( void *cookie )
179{
180	struct sackbc_softc *sc = cookie;
181
182	bus_space_read_4( sc->iot, sc->ioh, SACCKBD_STAT );
183
184	return 0;
185}
186#endif
187
188static int
189sackbc_rxint( void *cookie )
190{
191	struct sackbc_softc *sc = cookie;
192	int stat, code=-1;
193
194	stat = bus_space_read_4( sc->iot, sc->ioh, SACCKBD_STAT );
195	DPRINTF(( "sackbc_rxint stat=%x\n", stat ));
196	if( stat & KBDSTAT_RXF ){
197		code = bus_space_read_4( sc->iot, sc->ioh, SACCKBD_DATA );
198
199		if( sc->polling ){
200			sc->poll_data = code;
201			sc->poll_stat = stat;
202		}
203		else if (CMD_IN_QUEUE(sc) && sackbc_cmdresponse(sc, code))
204			;
205		else if( sc->inputhandler ){
206			(* sc->inputhandler)( sc->inputarg, code );
207		}
208		return 1;
209	}
210
211	return 0;
212}
213
214static int
215sackbcprint(void *aux, const char *pnp)
216{
217	return (QUIET);
218}
219
220static void
221sackbc_setup_intrhandler(struct sackbc_softc *sc)
222{
223	if( !(sc->polling) && sc->ih_rx==NULL ){
224		sc->ih_rx = sacc_intr_establish(
225			(sacc_chipset_tag_t *)(sc->dev.dv_parent),
226			sc->intr+1, IST_EDGE_RAISE, IPL_TTY, sackbc_rxint, sc );
227		if( sc->ih_rx == NULL ){
228			printf( "%s: can't establish interrupt\n",
229			    sc->dev.dv_xname );
230		}
231	}
232}
233
234static void
235sackbc_disable_intrhandler( struct sackbc_softc *sc )
236{
237	if( sc->polling && sc->ih_rx ){
238		sacc_intr_disestablish(
239			(sacc_chipset_tag_t *)(sc->dev.dv_parent),
240			sc->ih_rx );
241		sc->ih_rx = NULL;
242	}
243}
244
245static int
246sackbc_submatch(struct device *parent, struct cfdata *cf, void *aux)
247{
248	struct pckbc_attach_args *pa = aux;
249
250	DPRINTF(( "slot = %d ", cf->cf_loc[SACKBCCF_SLOT] ));
251
252	if( pa->pa_slot == PCKBCCF_SLOT_DEFAULT )
253		pa->pa_slot = cf->cf_loc[SACKBCCF_SLOT];
254
255	return config_match(parent, cf, aux);
256}
257
258static	void
259sackbc_attach(struct device *parent, struct device *self, void *aux)
260{
261	struct sackbc_softc *sc = (struct sackbc_softc *)self;
262	struct sacc_softc *psc = (struct sacc_softc *)parent;
263	struct sa1111_attach_args *aa = (struct sa1111_attach_args *)aux;
264	uint32_t tmp, clock_bit;
265	int i, found, intr;
266
267	switch( aa->sa_addr ){
268	case SACC_KBD0: clock_bit = (1<<6); intr = 21; break;
269	case SACC_KBD1: clock_bit = (1<<5); intr = 18; break;
270	default:
271		return;
272	}
273
274	if( aa->sa_size <= 0 )
275		aa->sa_size = SACCKBD_SIZE;
276	if( aa->sa_intr == SACCCF_INTR_DEFAULT )
277		aa->sa_intr = intr;
278
279	sc->iot = psc->sc_iot;
280	if( bus_space_subregion( psc->sc_iot, psc->sc_ioh,
281	    aa->sa_addr, aa->sa_size, &sc->ioh ) ){
282		printf( ": can't map subregion\n" );
283		return;
284	}
285
286	/* enable clock for PS/2 kbd or mouse */
287	tmp = bus_space_read_4( psc->sc_iot, psc->sc_ioh, SACCSC_SKPCR );
288	bus_space_write_4( psc->sc_iot, psc->sc_ioh, SACCSC_SKPCR,
289	    tmp | clock_bit );
290
291	sc->ih_rx = NULL;
292	sc->intr = aa->sa_intr;
293	sc->inputhandler = NULL;
294	sc->subname = sc->dev.dv_xname;
295
296	TAILQ_INIT(&sc->cmdqueue);
297	TAILQ_INIT(&sc->freequeue);
298
299	for (i = 0; i < NCMD; i++) {
300		TAILQ_INSERT_TAIL(&sc->freequeue, &(sc->cmd[i]), next);
301	}
302	sc->polling = 0;
303
304	tmp = bus_space_read_4( sc->iot, sc->ioh, SACCKBD_CR );
305	bus_space_write_4( sc->iot, sc->ioh, SACCKBD_CR, tmp | KBDCR_ENA );
306
307	/* XXX: this is necessary to get keyboard working. but I don't know why */
308	bus_space_write_4( sc->iot, sc->ioh, SACCKBD_CLKDIV, 2 );
309
310	tmp = bus_space_read_4( sc->iot, sc->ioh, SACCKBD_STAT );
311	if( (tmp & KBDSTAT_ENA) == 0 ){
312		printf("??? can't enable KBD controller\n");
313		return;
314	}
315
316	printf("\n");
317
318	{
319		struct pckbc_attach_args pa;
320
321		pa.pa_tag = sc;
322		pa.pa_slot = PCKBCCF_SLOT_DEFAULT; /* Bogus */
323
324		found = (config_found_sm(self, &pa,
325		    sackbcprint, sackbc_submatch) != NULL);
326
327#if 0 && NRND > 0			/* XXX: not yet */
328		if (found && (t->t_slotdata[slot] != NULL))
329			rnd_attach_source(&t->t_slotdata[slot]->rnd_source,
330			    sc->subname[slot], RND_TYPE_TTY, 0);
331#endif
332	}
333
334}
335
336
337static inline int
338sackbc_wait_output( struct sackbc_softc *sc )
339{
340	u_int i, stat;
341
342	for (i = 100000; i; i--){
343		stat = bus_space_read_4(sc->iot, sc->ioh, SACCKBD_STAT);
344		delay(100);
345		if( stat & KBDSTAT_TXE)
346			return 1;
347	}
348	return 0;
349}
350
351static int
352sackbc_poll_data1( struct sackbc_softc *sc )
353{
354	int i, s, stat, c = -1;
355
356	s = spltty();
357
358	if (sc->polling){
359		stat	= sc->poll_stat;
360		c	= sc->poll_data;
361		sc->poll_data = -1;
362		sc->poll_stat = -1;
363		if( stat >= 0 &&
364		    (stat & (KBDSTAT_RXF|KBDSTAT_STP)) == KBDSTAT_RXF ){
365			splx(s);
366			return c;
367		}
368	}
369
370	/* if 1 port read takes 1us (?), this polls for 100ms */
371	for (i = 100000; i; i--) {
372		stat = bus_space_read_4(sc->iot, sc->ioh, SACCKBD_STAT);
373		if( (stat & (KBDSTAT_RXF|KBDSTAT_STP)) == KBDSTAT_RXF ){
374			KBD_DELAY;
375			c = bus_space_read_4(sc->iot, sc->ioh, SACCKBD_DATA);
376			break;
377		}
378	}
379
380	splx(s);
381	return (c);
382}
383
384static int
385sackbc_send_cmd( struct sackbc_softc *sc, int val )
386{
387	if ( !sackbc_wait_output(sc) )
388		return (0);
389	bus_space_write_1( sc->iot, sc->ioh, SACCKBD_DATA, val );
390	return (1);
391}
392
393#define sackbc_send_devcmd	sackbc_send_cmd
394
395/*
396 * Clean up a command queue, throw away everything.
397 */
398static void
399sackbc_cleanqueue( struct sackbc_softc *sc )
400{
401	struct pckbc_devcmd *cmd;
402#ifdef SACKBCDEBUG
403	int i;
404#endif
405
406	while ((cmd = TAILQ_FIRST(&sc->cmdqueue))) {
407		TAILQ_REMOVE(&sc->cmdqueue, cmd, next);
408#ifdef SACKBCDEBUG
409		printf("sackbc_cleanqueue: removing");
410		for (i = 0; i < cmd->cmdlen; i++)
411			printf(" %02x", cmd->cmd[i]);
412		printf("\n");
413#endif
414		TAILQ_INSERT_TAIL(&sc->freequeue, cmd, next);
415	}
416}
417
418/*
419 * Timeout error handler: clean queues and data port.
420 * XXX could be less invasive.
421 */
422static void
423sackbc_cleanup(void *self)
424{
425	struct sackbc_softc *sc = self;
426	int s;
427
428	printf("sackbc: command timeout\n");
429
430	s = spltty();
431
432	sackbc_cleanqueue(sc);
433
434	while (bus_space_read_4(sc->iot, sc->ioh, SACCKBD_STAT) & KBDSTAT_RXF) {
435		KBD_DELAY;
436		(void) bus_space_read_4(sc->iot, sc->ioh, SACCKBD_DATA);
437	}
438
439	/* reset KBC? */
440
441	splx(s);
442}
443
444
445/*
446 * Pass command to device during normal operation.
447 * to be called at spltty()
448 */
449static void
450sackbc_start( struct sackbc_softc *sc )
451{
452	struct pckbc_devcmd *cmd = TAILQ_FIRST(&sc->cmdqueue);
453
454	if (sc->polling) {
455		while(cmd){
456			sackbc_poll_cmd1(sc, cmd);
457			if (cmd->status)
458				printf("sackbc_start: command error\n");
459
460			TAILQ_REMOVE(&sc->cmdqueue, cmd, next);
461			if (cmd->flags & KBC_CMDFLAG_SYNC)
462				wakeup(cmd);
463			else {
464				callout_stop(&sc->t_cleanup);
465				TAILQ_INSERT_TAIL(&sc->freequeue, cmd, next);
466			}
467			cmd = TAILQ_FIRST(&sc->cmdqueue);
468		}
469		return;
470	}
471
472	if (!sackbc_send_devcmd(sc, cmd->cmd[cmd->cmdidx])) {
473		printf("sackbc_start: send error\n");
474		/* XXX what now? */
475		return;
476	}
477}
478
479/*
480 * Handle command responses coming in asynchonously,
481 * return nonzero if valid response.
482 * to be called at spltty()
483 */
484static int
485sackbc_cmdresponse( struct sackbc_softc *sc, int data)
486{
487	struct pckbc_devcmd *cmd = TAILQ_FIRST(&sc->cmdqueue);
488#ifdef DIAGNOSTIC
489	if (!cmd)
490		panic("sackbc_cmdresponse: no active command");
491#endif
492	if (cmd->cmdidx < cmd->cmdlen) {
493		if (data != KBC_DEVCMD_ACK && data != KBC_DEVCMD_RESEND)
494			return (0);
495
496		if (data == KBC_DEVCMD_RESEND) {
497			if (cmd->retries++ < 5) {
498				/* try again last command */
499				goto restart;
500			} else {
501				printf("pckbc: cmd failed\n");
502				cmd->status = EIO;
503				/* dequeue */
504			}
505		} else {
506			if (++cmd->cmdidx < cmd->cmdlen)
507				goto restart;
508			if (cmd->responselen)
509				return (1);
510			/* else dequeue */
511		}
512	} else if (cmd->responseidx < cmd->responselen) {
513		cmd->response[cmd->responseidx++] = data;
514		if (cmd->responseidx < cmd->responselen)
515			return (1);
516		/* else dequeue */
517	} else
518		return (0);
519
520	/* dequeue: */
521	TAILQ_REMOVE(&sc->cmdqueue, cmd, next);
522	if (cmd->flags & KBC_CMDFLAG_SYNC)
523		wakeup(cmd);
524	else {
525		callout_stop(&sc->t_cleanup);
526		TAILQ_INSERT_TAIL(&sc->freequeue, cmd, next);
527	}
528	if (!CMD_IN_QUEUE(sc))
529		return (1);
530restart:
531	sackbc_start(sc);
532	return (1);
533}
534
535/*
536 * Pass command to device, poll for ACK and data.
537 * to be called at spltty()
538 */
539static void
540sackbc_poll_cmd1( struct sackbc_softc *sc, struct pckbc_devcmd *cmd )
541{
542	int i, c = 0;
543
544	while (cmd->cmdidx < cmd->cmdlen) {
545		DPRINTF((" tx: %x ", cmd->cmd[cmd->cmdidx]));
546		if (!sackbc_send_devcmd(sc, cmd->cmd[cmd->cmdidx])) {
547			printf("sackbc_cmd: send error\n");
548			cmd->status = EIO;
549			return;
550		}
551		delay(1000);
552		for (i = 10; i; i--) { /* 1s ??? */
553			c = sackbc_poll_data1(sc);
554			if (c != -1){
555				DPRINTF((" rx: %x", c ));
556				break;
557			}
558		}
559
560		if (c == KBC_DEVCMD_ACK) {
561			cmd->cmdidx++;
562			continue;
563		}
564		if (c == KBC_DEVCMD_RESEND) {
565			DPRINTF(("sackbc_cmd: RESEND\n"));
566
567			if (cmd->retries++ < 5)
568				continue;
569			else {
570				DPRINTF(("sackbc: cmd failed\n"));
571
572				cmd->status = EIO;
573				return;
574			}
575		}
576		if (c == -1) {
577			DPRINTF(("pckbc_cmd: timeout\n"));
578
579			cmd->status = EIO;
580			return;
581		}
582		DPRINTF(("pckbc_cmd: lost 0x%x\n", c));
583
584	}
585
586	while (cmd->responseidx < cmd->responselen) {
587		if (cmd->flags & KBC_CMDFLAG_SLOW)
588			i = 100; /* 10s ??? */
589		else
590			i = 10; /* 1s ??? */
591		while (i--) {
592			c = sackbc_poll_data1(sc);
593			if (c != -1){
594				DPRINTF((" resp: %x", c));
595				break;
596			}
597		}
598		if (c == -1) {
599			DPRINTF(("pckbc_cmd: no response"));
600
601			cmd->status = ETIMEDOUT;
602			return;
603		} else
604			cmd->response[cmd->responseidx++] = c;
605	}
606	DPRINTF(("\n"));
607}
608
609
610/*
611 * Glue functions for pckbd on sackbc.
612 * These functions emulate those in dev/ic/pckbc.c.
613 *
614 */
615
616void
617pckbc_set_inputhandler( pckbc_tag_t self, pckbc_slot_t slot,
618    pckbc_inputfcn func, void *arg, char *name)
619{
620	struct sackbc_softc *sc = (struct sackbc_softc *) self;
621
622	if( sc == NULL )
623		return;
624
625	DPRINTF(( "set_inputhandler %p %p\n", func, arg ));
626
627	sc->inputhandler = func;
628	sc->inputarg = arg;
629	sc->subname = name;
630
631	sackbc_setup_intrhandler(sc);
632}
633
634
635/* for use in autoconfiguration */
636int
637pckbc_poll_cmd(pckbc_tag_t self, pckbc_slot_t slot,
638    u_char *cmd, int len, int responselen, u_char *respbuf, int slow)
639{
640	struct pckbc_devcmd nc;
641struct sackbc_softc *sc = (struct sackbc_softc *) self;
642
643	if( sc == NULL )
644		return EINVAL;
645
646	if ((len > 4) || (responselen > 4))
647		return EINVAL;
648
649	memset(&nc, 0, sizeof(nc));
650	memcpy(nc.cmd, cmd, len);
651	nc.cmdlen = len;
652	nc.responselen = responselen;
653	nc.flags = (slow ? KBC_CMDFLAG_SLOW : 0);
654
655	sackbc_poll_cmd1(sc, &nc);
656
657	if (nc.status == 0 && respbuf)
658		memcpy(respbuf, nc.response, responselen);
659
660	return (nc.status);
661}
662
663
664/*
665 * switch scancode translation on / off
666 * return nonzero on success
667 */
668int
669pckbc_xt_translation(pckbc_tag_t self, pckbc_slot_t slot, int on)
670{
671	/* KBD/Mouse controller doesn't have scancode translation */
672	return !on;
673}
674
675void
676pckbc_slot_enable(pckbc_tag_t self, pckbc_slot_t slot, int on)
677{
678#if 0
679	struct sackbc_softc *sc = (struct sackbc_softc *) self;
680	int cmd;
681
682	cmd = on ? KBC_KBDENABLE : KBC_KBDDISABLE;
683	if ( !sackbc_send_cmd(sc, cmd ) )
684		printf("sackbc_slot_enable(%d) failed\n", on);
685#endif
686}
687
688
689void
690pckbc_flush(pckbc_tag_t self, pckbc_slot_t slot)
691{
692	struct sackbc_softc *sc  = (struct sackbc_softc *)self;
693
694	(void) sackbc_poll_data1(sc);
695}
696
697#if 0
698int
699sackbc_poll_data( struct sackbc_softc *sc )
700{
701	struct pckbc_internal *t = self;
702	struct pckbc_slotdata *q = t->t_slotdata[slot];
703	int c;
704
705	c = pckbc_poll_data1(t, slot, t->t_haveaux);
706	if (c != -1 && q && CMD_IN_QUEUE(q)) {
707		/* we jumped into a running command - try to
708		 deliver the response */
709		if (pckbc_cmdresponse(t, slot, c))
710			return (-1);
711	}
712	return (c);
713}
714#endif
715
716void
717pckbc_set_poll(pckbc_tag_t self, pckbc_slot_t slot, int on)
718{
719	struct sackbc_softc *sc = (struct sackbc_softc *)self;
720	int s;
721
722	s = spltty();
723
724	if( sc->polling != on ){
725
726		sc->polling = on;
727
728		if( on ){
729			sc->poll_data = sc->poll_stat = -1;
730			sackbc_disable_intrhandler(sc);
731		}
732		else {
733			/*
734			 * If disabling polling on a device that's
735			 * been configured, make sure there are no
736			 * bytes left in the FIFO, holding up the
737			 * interrupt line.  Otherwise we won't get any
738			 * further interrupts.
739			 */
740			sackbc_rxint(sc);
741			sackbc_setup_intrhandler(sc);
742		}
743	}
744	splx(s);
745}
746
747/*
748 * Put command into the device's command queue, return zero or errno.
749 */
750int
751pckbc_enqueue_cmd( pckbc_tag_t self, pckbc_slot_t slot, u_char *cmd,
752    int len, int responselen, int sync, u_char *respbuf)
753{
754	struct sackbc_softc *sc = (struct sackbc_softc *)self;
755	struct pckbc_devcmd *nc;
756	int s, isactive, res = 0;
757
758	if ( sc == NULL || (len > 4) || (responselen > 4) )
759		return (EINVAL);
760
761	s = spltty();
762	nc = TAILQ_FIRST(&sc->freequeue);
763	if (nc) {
764		TAILQ_REMOVE(&sc->freequeue, nc, next);
765	}
766	splx(s);
767	if (!nc)
768		return (ENOMEM);
769
770	memset(nc, 0, sizeof(*nc));
771	memcpy(nc->cmd, cmd, len);
772	nc->cmdlen = len;
773	nc->responselen = responselen;
774	nc->flags = (sync ? KBC_CMDFLAG_SYNC : 0);
775
776	s = spltty();
777
778	if (sc->polling && sync) {
779		/*
780		 * XXX We should poll until the queue is empty.
781		 * But we don't come here normally, so make
782		 * it simple and throw away everything.
783		 */
784		sackbc_cleanqueue(sc);
785	}
786
787	isactive = CMD_IN_QUEUE(sc);
788	TAILQ_INSERT_TAIL(&sc->cmdqueue, nc, next);
789	if (!isactive)
790		sackbc_start(sc);
791
792	if (sc->polling)
793		res = (sync ? nc->status : 0);
794	else if (sync) {
795		if ((res = tsleep(nc, 0, "kbccmd", 1*hz))) {
796			TAILQ_REMOVE(&sc->cmdqueue, nc, next);
797			sackbc_cleanup(sc);
798		} else
799			res = nc->status;
800	} else
801		callout_reset(&sc->t_cleanup, hz, sackbc_cleanup, sc);
802
803	if (sync) {
804		if (respbuf)
805			memcpy(respbuf, nc->response, responselen);
806		TAILQ_INSERT_TAIL(&sc->freequeue, nc, next);
807	}
808
809	splx(s);
810
811	return (res);
812}
813
814int
815pckbc_poll_data(pckbc_tag_t self, pckbc_slot_t slot)
816{
817	struct sackbc_softc *sc = (struct sackbc_softc *)self;
818	int c;
819
820	c = sackbc_poll_data1(sc);
821	if (c != -1 && CMD_IN_QUEUE(sc)) {
822		/* we jumped into a running command - try to
823		 deliver the response */
824		if (sackbc_cmdresponse(sc, c))
825			return -1;
826	}
827	return (c);
828}
829