xref: /original-bsd/sys/pmax/dev/dtop.c (revision b3e8e369)
1f0cd4484Sralph /*-
2e05100ceSbostic  * Copyright (c) 1992, 1993
3e05100ceSbostic  *	The Regents of the University of California.  All rights reserved.
4f0cd4484Sralph  *
5f0cd4484Sralph  * This code is derived from software contributed to Berkeley by
6f0cd4484Sralph  * Ralph Campbell and Rick Macklem.
7f0cd4484Sralph  *
8f0cd4484Sralph  * %sccs.include.redist.c%
9f0cd4484Sralph  *
10*b3e8e369Sralph  *	@(#)dtop.c	8.3 (Berkeley) 06/02/95
11f0cd4484Sralph  */
12f0cd4484Sralph 
13f0cd4484Sralph /*
14f0cd4484Sralph  * Mach Operating System
15f0cd4484Sralph  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
16f0cd4484Sralph  * All Rights Reserved.
17f0cd4484Sralph  *
18f0cd4484Sralph  * Permission to use, copy, modify and distribute this software and its
19f0cd4484Sralph  * documentation is hereby granted, provided that both the copyright
20f0cd4484Sralph  * notice and this permission notice appear in all copies of the
21f0cd4484Sralph  * software, derivative works or modified versions, and any portions
22f0cd4484Sralph  * thereof, and that both notices appear in supporting documentation.
23f0cd4484Sralph  *
24f0cd4484Sralph  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
25f0cd4484Sralph  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
26f0cd4484Sralph  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
27f0cd4484Sralph  *
28f0cd4484Sralph  * Carnegie Mellon requests users of this software to return to
29f0cd4484Sralph  *
30f0cd4484Sralph  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
31f0cd4484Sralph  *  School of Computer Science
32f0cd4484Sralph  *  Carnegie Mellon University
33f0cd4484Sralph  *  Pittsburgh PA 15213-3890
34f0cd4484Sralph  *
35f0cd4484Sralph  * any improvements or extensions that they make and grant Carnegie the
36f0cd4484Sralph  * rights to redistribute these changes.
37f0cd4484Sralph  */
38f0cd4484Sralph /*
39f0cd4484Sralph  * 	Author: Alessandro Forin, Carnegie Mellon University
40f0cd4484Sralph  *
41f0cd4484Sralph  *	Hardware-level operations for the Desktop serial line
42f0cd4484Sralph  *	bus (i2c aka ACCESS).
43f0cd4484Sralph  */
446fe16165Sralph /************************************************************
456fe16165Sralph Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
466fe16165Sralph and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
476fe16165Sralph 
486fe16165Sralph                         All Rights Reserved
496fe16165Sralph 
506fe16165Sralph Permission to use, copy, modify, and distribute this software and its
516fe16165Sralph documentation for any purpose and without fee is hereby granted,
526fe16165Sralph provided that the above copyright notice appear in all copies and that
536fe16165Sralph both that copyright notice and this permission notice appear in
546fe16165Sralph supporting documentation, and that the names of Digital or MIT not be
556fe16165Sralph used in advertising or publicity pertaining to distribution of the
566fe16165Sralph software without specific, written prior permission.
576fe16165Sralph 
586fe16165Sralph DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
596fe16165Sralph ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
606fe16165Sralph DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
616fe16165Sralph ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
626fe16165Sralph WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
636fe16165Sralph ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
646fe16165Sralph SOFTWARE.
656fe16165Sralph 
666fe16165Sralph ********************************************************/
67f0cd4484Sralph 
68f0cd4484Sralph #include <dtop.h>
69f0cd4484Sralph #if NDTOP > 0
70f0cd4484Sralph #include <sys/param.h>
71f0cd4484Sralph #include <sys/systm.h>
72f0cd4484Sralph #include <sys/ioctl.h>
73f0cd4484Sralph #include <sys/tty.h>
74f0cd4484Sralph #include <sys/proc.h>
75f0cd4484Sralph #include <sys/map.h>
76f0cd4484Sralph #include <sys/buf.h>
77f0cd4484Sralph #include <sys/conf.h>
78f0cd4484Sralph #include <sys/file.h>
79f0cd4484Sralph #include <sys/uio.h>
80f0cd4484Sralph #include <sys/kernel.h>
81f0cd4484Sralph #include <sys/syslog.h>
82f0cd4484Sralph 
83f0cd4484Sralph #include <machine/pmioctl.h>
84f0cd4484Sralph #include <machine/machConst.h>
85f0cd4484Sralph #include <machine/dc7085cons.h>
86f0cd4484Sralph 
87f0cd4484Sralph #include <pmax/pmax/pmaxtype.h>
88f0cd4484Sralph #include <pmax/pmax/maxine.h>
89f0cd4484Sralph #include <pmax/pmax/asic.h>
90f0cd4484Sralph 
91f0cd4484Sralph #include <pmax/dev/device.h>
92f0cd4484Sralph #include <pmax/dev/dtopreg.h>
93f0cd4484Sralph #include <pmax/dev/fbreg.h>
94f0cd4484Sralph 
95f0cd4484Sralph extern int pmax_boardtype;
96f0cd4484Sralph 
9758e22cd5Sralph void dtop_keyboard_repeat	__P((void *));
98f0cd4484Sralph int dtop_null_device_handler	__P((dtop_device_t, dtop_message_t, int, int));
99f0cd4484Sralph int dtop_locator_handler	__P((dtop_device_t, dtop_message_t, int, int));
100f0cd4484Sralph int dtop_keyboard_handler	__P((dtop_device_t, dtop_message_t, int, int));
101f0cd4484Sralph int dtopparam		__P((struct tty *, struct termios *));
102f0cd4484Sralph int dtopstop		__P((struct tty *, int));
103f0cd4484Sralph void dtopstart		__P((struct tty *));
104f0cd4484Sralph void dtopKBDPutc	__P((dev_t, int));
105f0cd4484Sralph 
106f0cd4484Sralph struct	tty dtop_tty[NDTOP];
107f0cd4484Sralph void	(*dtopDivertXInput)();	/* X windows keyboard input routine */
108f0cd4484Sralph void	(*dtopMouseEvent)();	/* X windows mouse motion event routine */
109f0cd4484Sralph void	(*dtopMouseButtons)();	/* X windows mouse buttons event routine */
110f0cd4484Sralph 
111f0cd4484Sralph #define	DTOP_MAX_POLL	0x7fff		/* about half a sec */
112f0cd4484Sralph 
113f0cd4484Sralph typedef volatile unsigned int	*data_reg_t;	/* uC  */
114f0cd4484Sralph #define	DTOP_GET_BYTE(data)	(((*(data)) >> 8) & 0xff)
115f0cd4484Sralph #define	DTOP_PUT_BYTE(data,c)	{ *(data) = (c) << 8; }
116f0cd4484Sralph 
117f0cd4484Sralph typedef volatile unsigned int	*poll_reg_t;	/* SIR */
118f0cd4484Sralph #define	DTOP_RX_AVAIL(poll)	(*(poll) & 1)
119f0cd4484Sralph #define	DTOP_TX_AVAIL(poll)	(*(poll) & 2)
120f0cd4484Sralph 
121f0cd4484Sralph #define	GET_SHORT(b0,b1)	(((b0)<<8)|(b1))
122f0cd4484Sralph 
123f0cd4484Sralph /*
124f0cd4484Sralph  * Driver status
125f0cd4484Sralph  */
126f0cd4484Sralph struct dtop_softc {
127f0cd4484Sralph 	data_reg_t	data;
128f0cd4484Sralph 	poll_reg_t	poll;
129f0cd4484Sralph 	char		polling_mode;
130f0cd4484Sralph 	char		probed_once;
131f0cd4484Sralph 	short		bad_pkts;
132f0cd4484Sralph 
133f0cd4484Sralph 	struct dtop_ds {
134f0cd4484Sralph 		int		(*handler)();
135f0cd4484Sralph 		dtop_device	status;
136f0cd4484Sralph 	} device[(DTOP_ADDR_DEFAULT - DTOP_ADDR_FIRST) >> 1];
137f0cd4484Sralph 
138f0cd4484Sralph #	define	DTOP_DEVICE_NO(address)	(((address)-DTOP_ADDR_FIRST)>>1)
139f0cd4484Sralph 
140f0cd4484Sralph } dtop_softc[NDTOP];
141f0cd4484Sralph 
142f0cd4484Sralph typedef struct dtop_softc *dtop_softc_t;
143f0cd4484Sralph struct tty dtop_tty[NDTOP];
1446fe16165Sralph 
1456fe16165Sralph /*
1466fe16165Sralph  * lk201 keyboard divisions and up/down mode key bitmap.
1476fe16165Sralph  */
1486fe16165Sralph #define NUMDIVS 14
1496fe16165Sralph static u_char divbeg[NUMDIVS] = {0xbf, 0x91, 0xbc, 0xbd, 0xb0, 0xad, 0xa6,
1506fe16165Sralph 				 0xa9, 0x88, 0x56, 0x63, 0x6f, 0x7b, 0x7e};
1516fe16165Sralph static u_char divend[NUMDIVS] = {0xff, 0xa5, 0xbc, 0xbe, 0xb2, 0xaf, 0xa8,
1526fe16165Sralph 				 0xac, 0x90, 0x62, 0x6e, 0x7a, 0x7d, 0x87};
1536fe16165Sralph /*
1546fe16165Sralph  * Initial defaults, groups 5 and 6 are up/down
1556fe16165Sralph  */
1566fe16165Sralph static u_long keymodes[8] = {0, 0, 0, 0, 0, 0x0003e000, 0, 0};
157f0cd4484Sralph 
158f0cd4484Sralph /*
159f0cd4484Sralph  * Definition of the driver for the auto-configuration program.
160f0cd4484Sralph  */
161f0cd4484Sralph int	dtopprobe();
162f0cd4484Sralph void	dtopintr();
163f0cd4484Sralph struct	driver dtopdriver =  {
164f0cd4484Sralph 	"dtop", dtopprobe, 0, 0, dtopintr,
165f0cd4484Sralph };
166f0cd4484Sralph 
167f0cd4484Sralph dtopprobe(cp)
168f0cd4484Sralph 	struct pmax_ctlr *cp;
169f0cd4484Sralph {
170f0cd4484Sralph 	register struct tty *tp;
171f0cd4484Sralph 	register int cntr;
172f0cd4484Sralph 	int dtopunit = cp->pmax_unit, i, s;
173f0cd4484Sralph 	dtop_softc_t dtop;
174f0cd4484Sralph 
175f0cd4484Sralph 	if (dtopunit >= NDTOP)
176f0cd4484Sralph 		return (0);
177f0cd4484Sralph 	if (badaddr(cp->pmax_addr, 2))
178f0cd4484Sralph 		return (0);
179f0cd4484Sralph 	dtop = &dtop_softc[dtopunit];
180f0cd4484Sralph 
181f0cd4484Sralph 	dtop->poll = (poll_reg_t)MACH_PHYS_TO_UNCACHED(XINE_REG_INTR);
182f0cd4484Sralph 	dtop->data = (data_reg_t)cp->pmax_addr;
183f0cd4484Sralph 
184f0cd4484Sralph 	for (i = 0; i < DTOP_MAX_DEVICES; i++)
185f0cd4484Sralph 		dtop->device[i].handler = dtop_null_device_handler;
186f0cd4484Sralph 
187f0cd4484Sralph 	/* a lot more needed here, fornow: */
188f0cd4484Sralph 	dtop->device[DTOP_DEVICE_NO(0x6a)].handler = dtop_locator_handler;
189f0cd4484Sralph 	dtop->device[DTOP_DEVICE_NO(0x6c)].handler = dtop_keyboard_handler;
190f0cd4484Sralph 	dtop->device[DTOP_DEVICE_NO(0x6c)].status.keyboard.k_ar_state =
191f0cd4484Sralph 		K_AR_IDLE;
192f0cd4484Sralph 
1936fe16165Sralph 	dtop->probed_once = 1;
1946fe16165Sralph 	printf("dtop%d at nexus0 csr 0x%x priority %d\n",
1956fe16165Sralph 		cp->pmax_unit, cp->pmax_addr, cp->pmax_pri);
196f0cd4484Sralph 	return (1);
197f0cd4484Sralph }
198f0cd4484Sralph 
dtopopen(dev,flag,mode,p)199f0cd4484Sralph dtopopen(dev, flag, mode, p)
200f0cd4484Sralph 	dev_t dev;
201f0cd4484Sralph 	int flag, mode;
202f0cd4484Sralph 	struct proc *p;
203f0cd4484Sralph {
204f0cd4484Sralph 	register struct tty *tp;
205f0cd4484Sralph 	register int unit;
206f0cd4484Sralph 	int s, error = 0;
207f0cd4484Sralph 
208f0cd4484Sralph 	unit = minor(dev);
209f0cd4484Sralph 	if (unit >= NDTOP)
210f0cd4484Sralph 		return (ENXIO);
211f0cd4484Sralph 	tp = &dtop_tty[unit];
212f0cd4484Sralph 	tp->t_oproc = dtopstart;
213f0cd4484Sralph 	tp->t_param = dtopparam;
214f0cd4484Sralph 	tp->t_dev = dev;
215f0cd4484Sralph 	if ((tp->t_state & TS_ISOPEN) == 0) {
216f0cd4484Sralph 		tp->t_state |= TS_WOPEN;
217f0cd4484Sralph 		ttychars(tp);
218f0cd4484Sralph 		if (tp->t_ispeed == 0) {
219f0cd4484Sralph 			tp->t_iflag = TTYDEF_IFLAG;
220f0cd4484Sralph 			tp->t_oflag = TTYDEF_OFLAG;
221f0cd4484Sralph 			tp->t_cflag = TTYDEF_CFLAG;
222f0cd4484Sralph 			tp->t_lflag = TTYDEF_LFLAG;
223f0cd4484Sralph 			tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
224f0cd4484Sralph 		}
225f0cd4484Sralph 		(void) dtopparam(tp, &tp->t_termios);
226f0cd4484Sralph 		ttsetwater(tp);
227f0cd4484Sralph 	} else if ((tp->t_state & TS_XCLUDE) && curproc->p_ucred->cr_uid != 0)
228f0cd4484Sralph 		return (EBUSY);
229f0cd4484Sralph 	s = spltty();
230f0cd4484Sralph 	while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL) &&
231f0cd4484Sralph 	       !(tp->t_state & TS_CARR_ON)) {
232f0cd4484Sralph 		tp->t_state |= TS_WOPEN;
233f0cd4484Sralph 		if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
234f0cd4484Sralph 		    ttopen, 0))
235f0cd4484Sralph 			break;
236f0cd4484Sralph 	}
237f0cd4484Sralph 	splx(s);
238f0cd4484Sralph 	if (error)
239f0cd4484Sralph 		return (error);
240f0cd4484Sralph 	error = (*linesw[tp->t_line].l_open)(dev, tp);
241f0cd4484Sralph 	return (error);
242f0cd4484Sralph }
243f0cd4484Sralph 
244f0cd4484Sralph /*ARGSUSED*/
dtopclose(dev,flag,mode,p)245f0cd4484Sralph dtopclose(dev, flag, mode, p)
246f0cd4484Sralph 	dev_t dev;
247f0cd4484Sralph 	int flag, mode;
248f0cd4484Sralph 	struct proc *p;
249f0cd4484Sralph {
250f0cd4484Sralph 	register struct tty *tp;
251f0cd4484Sralph 	register int unit;
252f0cd4484Sralph 
253f0cd4484Sralph 	unit = minor(dev);
254f0cd4484Sralph 	tp = &dtop_tty[unit];
255f0cd4484Sralph 	(*linesw[tp->t_line].l_close)(tp, flag);
256f0cd4484Sralph 	return (ttyclose(tp));
257f0cd4484Sralph }
258f0cd4484Sralph 
dtopread(dev,uio,flag)259f0cd4484Sralph dtopread(dev, uio, flag)
260f0cd4484Sralph 	dev_t dev;
261f0cd4484Sralph 	struct uio *uio;
262f0cd4484Sralph {
263f0cd4484Sralph 	register struct tty *tp;
264f0cd4484Sralph 
265f0cd4484Sralph 	tp = &dtop_tty[minor(dev)];
266f0cd4484Sralph 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
267f0cd4484Sralph }
268f0cd4484Sralph 
dtopwrite(dev,uio,flag)269f0cd4484Sralph dtopwrite(dev, uio, flag)
270f0cd4484Sralph 	dev_t dev;
271f0cd4484Sralph 	struct uio *uio;
272f0cd4484Sralph {
273f0cd4484Sralph 	register struct tty *tp;
274f0cd4484Sralph 
275f0cd4484Sralph 	tp = &dtop_tty[minor(dev)];
276f0cd4484Sralph 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
277f0cd4484Sralph }
278f0cd4484Sralph 
279f0cd4484Sralph /*ARGSUSED*/
dtopioctl(dev,cmd,data,flag,p)280f0cd4484Sralph dtopioctl(dev, cmd, data, flag, p)
281f0cd4484Sralph 	dev_t dev;
282*b3e8e369Sralph 	u_long cmd;
283f0cd4484Sralph 	caddr_t data;
284f0cd4484Sralph 	int flag;
285f0cd4484Sralph 	struct proc *p;
286f0cd4484Sralph {
287f0cd4484Sralph 	register struct tty *tp;
288f0cd4484Sralph 	register int unit = minor(dev);
289f0cd4484Sralph 	int error;
290f0cd4484Sralph 
291f0cd4484Sralph 	tp = &dtop_tty[unit];
292f0cd4484Sralph 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
293f0cd4484Sralph 	if (error >= 0)
294f0cd4484Sralph 		return (error);
295f0cd4484Sralph 	error = ttioctl(tp, cmd, data, flag);
296f0cd4484Sralph 	if (error >= 0)
297f0cd4484Sralph 		return (error);
298f0cd4484Sralph 
299f0cd4484Sralph 	switch (cmd) {
300f0cd4484Sralph 
301f0cd4484Sralph 	case TIOCSBRK:
302f0cd4484Sralph 		ttyoutput(0, tp);
303f0cd4484Sralph 		break;
304f0cd4484Sralph 
305f0cd4484Sralph 	case TIOCCBRK:
306f0cd4484Sralph 		ttyoutput(0, tp);
307f0cd4484Sralph 		break;
308f0cd4484Sralph 
309f0cd4484Sralph 	case TIOCMGET:
310f0cd4484Sralph 		*(int *)data = DML_DTR | DML_DSR | DML_CAR;
311f0cd4484Sralph 		break;
312f0cd4484Sralph 
313f0cd4484Sralph 	default:
314f0cd4484Sralph 		return (ENOTTY);
315f0cd4484Sralph 	}
316f0cd4484Sralph 	return (0);
317f0cd4484Sralph }
318f0cd4484Sralph 
319f0cd4484Sralph /*
320f0cd4484Sralph  * Interrupt routine
321f0cd4484Sralph  */
322f0cd4484Sralph void
dtopintr(unit)323f0cd4484Sralph dtopintr(unit)
324f0cd4484Sralph 	int unit;
325f0cd4484Sralph {
326f0cd4484Sralph 	dtop_message msg;
327f0cd4484Sralph 	int devno;
328f0cd4484Sralph 	dtop_softc_t dtop;
329f0cd4484Sralph 
330f0cd4484Sralph 	dtop = &dtop_softc[unit];
331f0cd4484Sralph 	if (dtop_get_packet(dtop, &msg) < 0) {
33258e22cd5Sralph #ifdef DIAGNOSTIC
33358e22cd5Sralph 	    printf("dtop: overrun (or stray)\n");
33458e22cd5Sralph #endif
33558e22cd5Sralph 	    /*
33658e22cd5Sralph 	     * Ugh! The most common occurrence of a data overrun is upon a
33758e22cd5Sralph 	     * key press and the result is a software generated "stuck key".
33858e22cd5Sralph 	     * All I can think to do is fake an "all keys up" whenever a
33958e22cd5Sralph 	     * data overrun occurs.
34058e22cd5Sralph 	     */
34158e22cd5Sralph 	    msg.src_address = 0x6c;
34258e22cd5Sralph 	    msg.code.val.len = 1;
34358e22cd5Sralph 	    msg.body[0] = DTOP_KBD_EMPTY;
344f0cd4484Sralph 	}
345f0cd4484Sralph 
34658e22cd5Sralph 	/*
34758e22cd5Sralph 	 * If not probed yet, just throw the data away.
34858e22cd5Sralph 	 */
34958e22cd5Sralph 	if (!dtop->probed_once)
35058e22cd5Sralph 		return;
35158e22cd5Sralph 
352f0cd4484Sralph 	devno = DTOP_DEVICE_NO(msg.src_address);
353f0cd4484Sralph 	if (devno < 0 || devno > 15)
354f0cd4484Sralph 		return;
355f0cd4484Sralph 	(void) (*dtop->device[devno].handler)
356f0cd4484Sralph 			(&dtop->device[devno].status, &msg,
357f0cd4484Sralph 			 DTOP_EVENT_RECEIVE_PACKET, 0);
358f0cd4484Sralph }
359f0cd4484Sralph 
360f0cd4484Sralph void
dtopstart(tp)361f0cd4484Sralph dtopstart(tp)
362f0cd4484Sralph 	register struct tty *tp;
363f0cd4484Sralph {
364f0cd4484Sralph 	register int cc;
365f0cd4484Sralph 	int s;
366f0cd4484Sralph 
367f0cd4484Sralph 	s = spltty();
368f0cd4484Sralph 	if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
369f0cd4484Sralph 		goto out;
370f0cd4484Sralph 	if (tp->t_outq.c_cc <= tp->t_lowat) {
371f0cd4484Sralph 		if (tp->t_state & TS_ASLEEP) {
372f0cd4484Sralph 			tp->t_state &= ~TS_ASLEEP;
373f0cd4484Sralph 			wakeup((caddr_t)&tp->t_outq);
374f0cd4484Sralph 		}
375f0cd4484Sralph 		selwakeup(&tp->t_wsel);
376f0cd4484Sralph 	}
377f0cd4484Sralph 	if (tp->t_outq.c_cc == 0)
378f0cd4484Sralph 		goto out;
379f0cd4484Sralph 	/* handle console specially */
380f0cd4484Sralph 	if (tp == dtop_tty) {
381f0cd4484Sralph 		while (tp->t_outq.c_cc > 0) {
382f0cd4484Sralph 			cc = getc(&tp->t_outq) & 0x7f;
383f0cd4484Sralph 			cnputc(cc);
384f0cd4484Sralph 		}
385f0cd4484Sralph 		/*
386f0cd4484Sralph 		 * After we flush the output queue we may need to wake
387f0cd4484Sralph 		 * up the process that made the output.
388f0cd4484Sralph 		 */
389f0cd4484Sralph 		if (tp->t_outq.c_cc <= tp->t_lowat) {
390f0cd4484Sralph 			if (tp->t_state & TS_ASLEEP) {
391f0cd4484Sralph 				tp->t_state &= ~TS_ASLEEP;
392f0cd4484Sralph 				wakeup((caddr_t)&tp->t_outq);
393f0cd4484Sralph 			}
394f0cd4484Sralph 			selwakeup(&tp->t_wsel);
395f0cd4484Sralph 		}
396f0cd4484Sralph 	}
397f0cd4484Sralph out:
398f0cd4484Sralph 	splx(s);
399f0cd4484Sralph }
400f0cd4484Sralph 
401f0cd4484Sralph void
dtopKBDPutc(dev,c)402f0cd4484Sralph dtopKBDPutc(dev, c)
403f0cd4484Sralph 	dev_t dev;
404f0cd4484Sralph 	int c;
405f0cd4484Sralph {
4066fe16165Sralph 	register int i;
4076fe16165Sralph 	static int param = 0, cmd, mod, typ;
4086fe16165Sralph 	static u_char parms[2];
409f0cd4484Sralph 
410f0cd4484Sralph 	/*
4116fe16165Sralph 	 * Emulate the lk201 command codes.
412f0cd4484Sralph 	 */
4136fe16165Sralph 	if (param == 0) {
4146fe16165Sralph 		typ = (c & 0x1);
4156fe16165Sralph 		cmd = ((c >> 3) & 0xf);
4166fe16165Sralph 		mod = ((c >> 1) & 0x3);
4176fe16165Sralph 	} else
4186fe16165Sralph 		parms[param - 1] = (c & 0x7f);
4196fe16165Sralph 	if (c & 0x80) {
4206fe16165Sralph 		if (typ) {
4216fe16165Sralph 			/*
4226fe16165Sralph 			 * A peripheral command code. Someday this driver
4236fe16165Sralph 			 * should know how to send commands to the lk501,
4246fe16165Sralph 			 * but until then this is all essentially a no-op.
4256fe16165Sralph 			 */
4266fe16165Sralph 			;
4276fe16165Sralph 		} else {
4286fe16165Sralph 			/*
4296fe16165Sralph 			 * Set modes. These have to be emulated in software.
4306fe16165Sralph 			 */
4316fe16165Sralph 			if (cmd > 0 && cmd < 15) {
4326fe16165Sralph 				cmd--;
4336fe16165Sralph 				if (mod & 0x2)
4346fe16165Sralph 				   for (i = divbeg[cmd]; i <= divend[cmd]; i++)
4356fe16165Sralph 					keymodes[i >> 5] |=
4366fe16165Sralph 						(1 << (i & 0x1f));
4376fe16165Sralph 				else
4386fe16165Sralph 				   for (i = divbeg[cmd]; i <= divend[cmd]; i++)
4396fe16165Sralph 					keymodes[i >> 5] &=
4406fe16165Sralph 						~(1 << (i & 0x1f));
4416fe16165Sralph 			}
4426fe16165Sralph 		}
4436fe16165Sralph 		param = 0;
4446fe16165Sralph 	} else if (++param > 2)
4456fe16165Sralph 		param = 2;
446f0cd4484Sralph }
447f0cd4484Sralph 
448f0cd4484Sralph /*
449f0cd4484Sralph  * Take a packet off dtop interface
450f0cd4484Sralph  * A packet MUST be there, this is not checked for.
451f0cd4484Sralph  */
452f0cd4484Sralph #define	DTOP_ESC_CHAR		0xf8
dtop_escape(c)453f0cd4484Sralph dtop_escape(c)
454f0cd4484Sralph {
455f0cd4484Sralph 	/* I donno much about this stuff.. */
456f0cd4484Sralph 	switch (c) {
457f0cd4484Sralph 	case 0xe8:	return (0xf8);
458f0cd4484Sralph 	case 0xe9:	return (0xf9);
459f0cd4484Sralph 	case 0xea:	return (0xfa);
460f0cd4484Sralph 	case 0xeb:	return (0xfb);
461f0cd4484Sralph 	default:	/* printf("{esc %x}", c); */
462f0cd4484Sralph 			return (c);
463f0cd4484Sralph 	}
464f0cd4484Sralph }
465f0cd4484Sralph 
dtop_get_packet(dtop,pkt)466f0cd4484Sralph dtop_get_packet(dtop, pkt)
467f0cd4484Sralph 	dtop_softc_t	dtop;
468f0cd4484Sralph 	dtop_message_t	pkt;
469f0cd4484Sralph {
470f0cd4484Sralph 	register poll_reg_t	poll;
471f0cd4484Sralph 	register data_reg_t	data;
472f0cd4484Sralph 	register int		max, i, len;
473f0cd4484Sralph 	register unsigned char	c;
474f0cd4484Sralph 
475f0cd4484Sralph 	poll = dtop->poll;
476f0cd4484Sralph 	data = dtop->data;
477f0cd4484Sralph 
478f0cd4484Sralph 	/*
479f0cd4484Sralph 	 * The interface does not handle us the first byte,
480f0cd4484Sralph 	 * which is our address and cannot ever be anything
481f0cd4484Sralph 	 * else but 0x50.  This is a good thing, it makes
482f0cd4484Sralph 	 * the average packet exactly one word long, too.
483f0cd4484Sralph 	 */
484f0cd4484Sralph 	for (max = 0; (max < DTOP_MAX_POLL) && !DTOP_RX_AVAIL(poll); max++)
4856fe16165Sralph 		DELAY(1);
486f0cd4484Sralph 	if (max == DTOP_MAX_POLL)
487f0cd4484Sralph 		goto bad;
488f0cd4484Sralph 	pkt->src_address = DTOP_GET_BYTE(data);
489f0cd4484Sralph 
490f0cd4484Sralph 	for (max = 0; (max < DTOP_MAX_POLL) && !DTOP_RX_AVAIL(poll); max++)
4916fe16165Sralph 		DELAY(1);
492f0cd4484Sralph 	if (max == DTOP_MAX_POLL)
493f0cd4484Sralph 		goto bad;
494f0cd4484Sralph 	pkt->code.bits = DTOP_GET_BYTE(data);
495f0cd4484Sralph 
496f0cd4484Sralph 	/*
497f0cd4484Sralph 	 * Now get data and checksum
498f0cd4484Sralph 	 */
499f0cd4484Sralph 	len = pkt->code.val.len + 1;
500f0cd4484Sralph 	c = 0;
501f0cd4484Sralph 	for (i = 0; i < len; i++) {
502f0cd4484Sralph again:
503f0cd4484Sralph 		for (max = 0; (max < DTOP_MAX_POLL) && !DTOP_RX_AVAIL(poll); max++)
5046fe16165Sralph 			DELAY(1);
505f0cd4484Sralph 		if (max == DTOP_MAX_POLL)
506f0cd4484Sralph 			goto bad;
507f0cd4484Sralph 		if (c == DTOP_ESC_CHAR) {
508f0cd4484Sralph 			c = dtop_escape(DTOP_GET_BYTE(data) & 0xff);
509f0cd4484Sralph 		} else {
510f0cd4484Sralph 			c = DTOP_GET_BYTE(data);
511f0cd4484Sralph 			if (c == DTOP_ESC_CHAR)
512f0cd4484Sralph 				goto again;
513f0cd4484Sralph 		}
514f0cd4484Sralph 		pkt->body[i] = c;
515f0cd4484Sralph 	}
516f0cd4484Sralph 	return (len);
517f0cd4484Sralph bad:
518f0cd4484Sralph 	dtop->bad_pkts++;
519f0cd4484Sralph 	return (-1);
520f0cd4484Sralph }
521f0cd4484Sralph 
522f0cd4484Sralph /*
523f0cd4484Sralph  * Get a keyboard char for the console
524f0cd4484Sralph  */
dtopKBDGetc()525f0cd4484Sralph dtopKBDGetc()
526f0cd4484Sralph {
527f0cd4484Sralph 	register int c;
528f0cd4484Sralph 	dtop_softc_t dtop;
529f0cd4484Sralph 
530f0cd4484Sralph 	dtop = &dtop_softc[0];
531f0cd4484Sralph again:
532f0cd4484Sralph 	c = -1;
533f0cd4484Sralph 
534f0cd4484Sralph 	/*
535f0cd4484Sralph 	 * Now check keyboard
536f0cd4484Sralph 	 */
537f0cd4484Sralph 	if (DTOP_RX_AVAIL(dtop->poll)) {
538f0cd4484Sralph 
539f0cd4484Sralph 		dtop_message	msg;
540f0cd4484Sralph 		struct dtop_ds	*ds;
541f0cd4484Sralph 
542f0cd4484Sralph 		if (dtop_get_packet(dtop, &msg) >= 0) {
543f0cd4484Sralph 
544f0cd4484Sralph 		    ds = &dtop->device[DTOP_DEVICE_NO(msg.src_address)];
545f0cd4484Sralph 		    if (ds->handler == dtop_keyboard_handler) {
546f0cd4484Sralph 
547f0cd4484Sralph 			c = dtop_keyboard_handler(
548f0cd4484Sralph 					&ds->status, &msg,
549f0cd4484Sralph 					DTOP_EVENT_RECEIVE_PACKET, -1);
550f0cd4484Sralph 
551f0cd4484Sralph 			if (c > 0) return c;
552f0cd4484Sralph 
553f0cd4484Sralph 			c = -1;
554f0cd4484Sralph 		    }
555f0cd4484Sralph 		}
556f0cd4484Sralph 	}
557f0cd4484Sralph 
558f0cd4484Sralph 	if (c == -1) {
559f0cd4484Sralph 		DELAY(100);
560f0cd4484Sralph 		goto again;
561f0cd4484Sralph 	}
562f0cd4484Sralph 
563f0cd4484Sralph 	return c;
564f0cd4484Sralph }
565f0cd4484Sralph 
566f0cd4484Sralph int
dtopparam(tp,t)567f0cd4484Sralph dtopparam(tp, t)
568f0cd4484Sralph 	struct tty *tp;
569f0cd4484Sralph 	struct termios *t;
570f0cd4484Sralph {
571f0cd4484Sralph 	if (tp->t_ispeed == 0)
572f0cd4484Sralph 		ttymodem(tp, 0);
573f0cd4484Sralph 	else
574f0cd4484Sralph 		/* called too early to invoke ttymodem, sigh */
575f0cd4484Sralph 		tp->t_state |= TS_CARR_ON;
576f0cd4484Sralph 	return (0);
577f0cd4484Sralph }
578f0cd4484Sralph 
579f0cd4484Sralph /*
580f0cd4484Sralph  * Stop output on a line.
581f0cd4484Sralph  */
582f0cd4484Sralph /*ARGSUSED*/
dtopstop(tp,flag)583f0cd4484Sralph dtopstop(tp, flag)
584f0cd4484Sralph 	register struct tty *tp;
585f0cd4484Sralph 	int flag;
586f0cd4484Sralph {
587f0cd4484Sralph 	int s;
588f0cd4484Sralph 
589f0cd4484Sralph 	s = spltty();
590f0cd4484Sralph 	if (tp->t_state & TS_BUSY) {
591f0cd4484Sralph 		if (!(tp->t_state & TS_TTSTOP))
592f0cd4484Sralph 			tp->t_state |= TS_FLUSH;
593f0cd4484Sralph 	}
594f0cd4484Sralph 	splx(s);
595f0cd4484Sralph }
596f0cd4484Sralph 
597f0cd4484Sralph /*
598f0cd4484Sralph  * Default handler function
599f0cd4484Sralph  */
600f0cd4484Sralph int
dtop_null_device_handler(dev,msg,event,outc)601f0cd4484Sralph dtop_null_device_handler(dev, msg, event, outc)
602f0cd4484Sralph 	 dtop_device_t	dev;
603f0cd4484Sralph 	 dtop_message_t	msg;
604f0cd4484Sralph 	 int		event;
605f0cd4484Sralph 	 int		outc;
606f0cd4484Sralph {
607f0cd4484Sralph 	/* See if the message was to the default address (powerup) */
608f0cd4484Sralph 
609f0cd4484Sralph 	/* Uhmm, donno how to handle this. Drop it */
610f0cd4484Sralph 	if (event == DTOP_EVENT_RECEIVE_PACKET)
611f0cd4484Sralph 		dev->unknown_report = *msg;
612f0cd4484Sralph 	return 0;
613f0cd4484Sralph }
614f0cd4484Sralph 
615f0cd4484Sralph /*
616f0cd4484Sralph  * Handler for locator devices (mice)
617f0cd4484Sralph  */
618f0cd4484Sralph int
dtop_locator_handler(dev,msg,event,outc)619f0cd4484Sralph dtop_locator_handler(dev, msg, event, outc)
620f0cd4484Sralph 	 dtop_device_t	dev;
621f0cd4484Sralph 	 dtop_message_t	msg;
622f0cd4484Sralph 	 int		event;
623f0cd4484Sralph 	 int		outc;
624f0cd4484Sralph {
625f0cd4484Sralph 	register unsigned short	buttons;
626f0cd4484Sralph 	register short coord;
627f0cd4484Sralph 	register int moved = 0;
628f0cd4484Sralph 	static MouseReport currentRep;
629f0cd4484Sralph 	register MouseReport *mrp = &currentRep;
630f0cd4484Sralph 
631f0cd4484Sralph 	if (dtopMouseButtons) {
6326fe16165Sralph 		mrp->state = 0;
633f0cd4484Sralph 		/*
634f0cd4484Sralph 		 * Do the position first
635f0cd4484Sralph 		 */
636f0cd4484Sralph 		coord = GET_SHORT(msg->body[2], msg->body[3]);
6376fe16165Sralph 		if (coord < 0) {
638f0cd4484Sralph 			coord = -coord;
639f0cd4484Sralph 			moved = 1;
6406fe16165Sralph 		} else if (coord > 0) {
6416fe16165Sralph 			mrp->state |= MOUSE_X_SIGN;
6426fe16165Sralph 			moved = 1;
6436fe16165Sralph 		}
6446fe16165Sralph 		mrp->dx = (coord & 0x1f);
6456fe16165Sralph 		coord = GET_SHORT(msg->body[4], msg->body[5]);
6466fe16165Sralph 		if (coord < 0) {
6476fe16165Sralph 			coord = -coord;
6486fe16165Sralph 			moved = 1;
6496fe16165Sralph 		} else if (coord > 0) {
6506fe16165Sralph 			mrp->state |= MOUSE_Y_SIGN;
6516fe16165Sralph 			moved = 1;
6526fe16165Sralph 		}
6536fe16165Sralph 		mrp->dy = (coord & 0x1f);
654f0cd4484Sralph 
655f0cd4484Sralph 		/*
656f0cd4484Sralph 		 * Time for the buttons now
65758e22cd5Sralph 		 * Shuffle button bits around to serial mouse order.
658f0cd4484Sralph 		 */
659f0cd4484Sralph 		buttons = GET_SHORT(msg->body[0], msg->body[1]);
66058e22cd5Sralph 		mrp->state |= (((buttons >> 1) & 0x3) | ((buttons << 2) & 0x4));
661f0cd4484Sralph 		if (moved)
662f0cd4484Sralph 			(*dtopMouseEvent)(mrp);
663f0cd4484Sralph 		(*dtopMouseButtons)(mrp);
664f0cd4484Sralph 	}
665f0cd4484Sralph 	return (0);
666f0cd4484Sralph }
667f0cd4484Sralph 
668f0cd4484Sralph /*
669f0cd4484Sralph  * Handler for keyboard devices
670f0cd4484Sralph  * Special case: outc set for recv packet means
671f0cd4484Sralph  * we are inside the kernel debugger
672f0cd4484Sralph  */
673f0cd4484Sralph int
dtop_keyboard_handler(dev,msg,event,outc)674f0cd4484Sralph dtop_keyboard_handler(dev, msg, event, outc)
675f0cd4484Sralph 	dtop_device_t dev;
676f0cd4484Sralph 	dtop_message_t msg;
677f0cd4484Sralph 	int event;
678f0cd4484Sralph 	int outc;
679f0cd4484Sralph {
680f0cd4484Sralph 	register u_char *ls, *le, *ns, *ne;
681f0cd4484Sralph 	u_char save[11], retc;
68258e22cd5Sralph 	int msg_len, c, s;
683f0cd4484Sralph 	struct tty *tp = &dtop_tty[0];
684f0cd4484Sralph 
685f0cd4484Sralph 	/*
686f0cd4484Sralph 	 * Fiddle about emulating an lk201 keyboard. The lk501
687f0cd4484Sralph 	 * designers carefully ensured that keyboard handlers could be
688f0cd4484Sralph 	 * stateless, then we turn around and use lots of state to
689f0cd4484Sralph 	 * emulate the stateful lk201, since the X11R5 X servers
690f0cd4484Sralph 	 * only know about the lk201... (oh well)
691f0cd4484Sralph 	 */
69258e22cd5Sralph 	/*
69358e22cd5Sralph 	 * Turn off any autorepeat timeout.
69458e22cd5Sralph 	 */
69558e22cd5Sralph 	s = splhigh();
69658e22cd5Sralph 	if (dev->keyboard.k_ar_state != K_AR_IDLE) {
69758e22cd5Sralph 		dev->keyboard.k_ar_state = K_AR_IDLE;
69858e22cd5Sralph 		untimeout(dtop_keyboard_repeat, (void *)dev);
69958e22cd5Sralph 	}
70058e22cd5Sralph 	splx(s);
701f0cd4484Sralph 	msg_len = msg->code.val.len;
702f0cd4484Sralph 
703f0cd4484Sralph 	/* Check for errors */
704f0cd4484Sralph 	c = msg->body[0];
705f0cd4484Sralph 	if ((c < DTOP_KBD_KEY_MIN) && (c != DTOP_KBD_EMPTY)) {
706f0cd4484Sralph 		printf("Keyboard error: %x %x %x..\n", msg_len, c, msg->body[1]);
70758e22cd5Sralph #ifdef notdef
708f0cd4484Sralph 		if (c != DTOP_KBD_OUT_ERR) return -1;
70958e22cd5Sralph #endif
71058e22cd5Sralph 		/*
71158e22cd5Sralph 		 * Fake an "all ups" to avoid the stuck key syndrome.
71258e22cd5Sralph 		 */
71358e22cd5Sralph 		c = msg->body[0] = DTOP_KBD_EMPTY;
71458e22cd5Sralph 		msg_len = 1;
715f0cd4484Sralph 	}
716f0cd4484Sralph 
717f0cd4484Sralph 	dev->keyboard.last_msec = TO_MS(time);
718f0cd4484Sralph 	/*
719f0cd4484Sralph 	 * To make things readable, do a first pass cancelling out
720f0cd4484Sralph 	 * all keys that are still pressed, and a second one generating
721f0cd4484Sralph 	 * events.  While generating events, do the upstrokes first
722f0cd4484Sralph 	 * from oldest to youngest, then the downstrokes from oldest
723f0cd4484Sralph 	 * to youngest.  This copes with lost packets and provides
724f0cd4484Sralph 	 * a reasonable model even if scans are too slow.
725f0cd4484Sralph 	 */
726f0cd4484Sralph 
727f0cd4484Sralph 	/* make a copy of new state first */
728f0cd4484Sralph 	if (msg_len == 1)
729f0cd4484Sralph 		save[0] = msg->body[0];
730f0cd4484Sralph 	else if (msg_len > 0)
731f0cd4484Sralph 		bcopy(msg->body, save, msg_len);
732f0cd4484Sralph 
733f0cd4484Sralph 	/*
734f0cd4484Sralph 	 * Cancel out any keys in both the last and current message as
735f0cd4484Sralph 	 * they are unchanged.
736f0cd4484Sralph 	 */
737f0cd4484Sralph 	if (msg_len > 0 && dev->keyboard.last_codes_count > 0) {
738f0cd4484Sralph 		ls = dev->keyboard.last_codes;
739f0cd4484Sralph 		le = &dev->keyboard.last_codes[dev->keyboard.last_codes_count];
740f0cd4484Sralph 		ne = &msg->body[msg_len];
741f0cd4484Sralph 		for (; ls < le; ls++) {
742f0cd4484Sralph 			for (ns = msg->body; ns < ne; ns++)
743f0cd4484Sralph 				if (*ls == *ns) {
744f0cd4484Sralph 					*ls = *ns = 0;
745f0cd4484Sralph 					break;
746f0cd4484Sralph 				}
747f0cd4484Sralph 		}
748f0cd4484Sralph 	}
749f0cd4484Sralph 
750f0cd4484Sralph 	/*
751f0cd4484Sralph 	 * Now generate all upstrokes
752f0cd4484Sralph 	 */
753f0cd4484Sralph 	le = dev->keyboard.last_codes;
754f0cd4484Sralph 	ls = &dev->keyboard.last_codes[dev->keyboard.last_codes_count - 1];
755f0cd4484Sralph 	for ( ; ls >= le; ls--)
756f0cd4484Sralph 	    if (c = *ls) {
757f0cd4484Sralph 		(void) kbdMapChar(c);
758f0cd4484Sralph 
7596fe16165Sralph 		if (outc == 0 && dtopDivertXInput &&
7606fe16165Sralph 		    (keymodes[(c >> 5) & 0x7] & (1 << (c & 0x1f))))
761f0cd4484Sralph 			(*dtopDivertXInput)(c);
762f0cd4484Sralph 	    }
763f0cd4484Sralph 	/*
764f0cd4484Sralph 	 * And finally the downstrokes
765f0cd4484Sralph 	 */
766f0cd4484Sralph 	ne = (char*)msg->body;
767f0cd4484Sralph 	ns = (char*)&msg->body[msg_len - 1];
768f0cd4484Sralph 	retc = 0;
769f0cd4484Sralph 	for ( ; ns >= ne; ns--)
770f0cd4484Sralph 	    if (*ns) {
771f0cd4484Sralph 		c = kbdMapChar(*ns);
772f0cd4484Sralph 		if (outc == 0) {
773f0cd4484Sralph 		    if (dtopDivertXInput) {
774f0cd4484Sralph 			(*dtopDivertXInput)(*ns);
775f0cd4484Sralph 			c = -1; /* consumed by X */
776f0cd4484Sralph 		    } else if (c >= 0)
777f0cd4484Sralph 			(*linesw[tp->t_line].l_rint)(c, tp);
77858e22cd5Sralph 		    dev->keyboard.k_ar_state = K_AR_ACTIVE;
779f0cd4484Sralph 		}
780f0cd4484Sralph 		/* return the related keycode anyways */
781f0cd4484Sralph 		if ((c >= 0) && (retc == 0))
782f0cd4484Sralph 		    retc = c;
783f0cd4484Sralph 	    }
784f0cd4484Sralph 	outc = retc;
785f0cd4484Sralph 	/* install new scan state */
786f0cd4484Sralph 	if (msg_len == 1)
787f0cd4484Sralph 		dev->keyboard.last_codes[0] = save[0];
788f0cd4484Sralph 	else if (msg_len > 0)
789f0cd4484Sralph 		bcopy(save, dev->keyboard.last_codes, msg_len);
790f0cd4484Sralph 	dev->keyboard.last_codes_count = msg_len;
79158e22cd5Sralph 	if (dev->keyboard.k_ar_state == K_AR_ACTIVE)
79258e22cd5Sralph 		timeout(dtop_keyboard_repeat, (void *)dev, hz / 2);
793f0cd4484Sralph 	return (outc);
794f0cd4484Sralph }
795f0cd4484Sralph 
796f0cd4484Sralph /*
79758e22cd5Sralph  * Do an autorepeat as required.
798f0cd4484Sralph  */
799f0cd4484Sralph void
dtop_keyboard_repeat(arg)80058e22cd5Sralph dtop_keyboard_repeat(arg)
801f0cd4484Sralph 	void *arg;
802f0cd4484Sralph {
803f0cd4484Sralph 	dtop_device_t dev = (dtop_device_t)arg;
8046fe16165Sralph 	register int i, c;
8056fe16165Sralph 	struct tty *tp = dtop_tty;
80658e22cd5Sralph 	int s = spltty(), gotone = 0;
8076fe16165Sralph 
8086fe16165Sralph 	for (i = 0; i < dev->keyboard.last_codes_count; i++) {
8096fe16165Sralph 		c = (int)dev->keyboard.last_codes[i];
8106fe16165Sralph 		if (c != DTOP_KBD_EMPTY &&
8116fe16165Sralph 		    (keymodes[(c >> 5) & 0x7] & (1 << (c & 0x1f))) == 0) {
8126fe16165Sralph 			dev->keyboard.k_ar_state = K_AR_TRIGGER;
8136fe16165Sralph 			if (dtopDivertXInput) {
8146fe16165Sralph 				(*dtopDivertXInput)(KEY_REPEAT);
81558e22cd5Sralph 				gotone = 1;
81658e22cd5Sralph 				continue;
8176fe16165Sralph 			}
8186fe16165Sralph 
81958e22cd5Sralph 			if ((c = kbdMapChar(KEY_REPEAT)) >= 0) {
8206fe16165Sralph 				(*linesw[tp->t_line].l_rint)(c, tp);
82158e22cd5Sralph 				gotone = 1;
8226fe16165Sralph 			}
8236fe16165Sralph 		}
82458e22cd5Sralph 	}
82558e22cd5Sralph 	if (gotone)
82658e22cd5Sralph 		timeout(dtop_keyboard_repeat, arg, hz / 20);
82758e22cd5Sralph 	else
82858e22cd5Sralph 		dev->keyboard.k_ar_state = K_AR_IDLE;
82958e22cd5Sralph 	splx(s);
8306fe16165Sralph }
831f0cd4484Sralph #endif
832