xref: /original-bsd/sys/pmax/dev/dtop.c (revision eb9b57b3)
1 /*-
2  * Copyright (c) 1992 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Ralph Campbell and Rick Macklem.
7  *
8  * %sccs.include.redist.c%
9  *
10  *	@(#)dtop.c	7.2 (Berkeley) 12/20/92
11  */
12 
13 /*
14  * Mach Operating System
15  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
16  * All Rights Reserved.
17  *
18  * Permission to use, copy, modify and distribute this software and its
19  * documentation is hereby granted, provided that both the copyright
20  * notice and this permission notice appear in all copies of the
21  * software, derivative works or modified versions, and any portions
22  * thereof, and that both notices appear in supporting documentation.
23  *
24  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
25  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
26  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
27  *
28  * Carnegie Mellon requests users of this software to return to
29  *
30  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
31  *  School of Computer Science
32  *  Carnegie Mellon University
33  *  Pittsburgh PA 15213-3890
34  *
35  * any improvements or extensions that they make and grant Carnegie the
36  * rights to redistribute these changes.
37  */
38 /*
39  * 	Author: Alessandro Forin, Carnegie Mellon University
40  *
41  *	Hardware-level operations for the Desktop serial line
42  *	bus (i2c aka ACCESS).
43  */
44 /************************************************************
45 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
46 and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
47 
48                         All Rights Reserved
49 
50 Permission to use, copy, modify, and distribute this software and its
51 documentation for any purpose and without fee is hereby granted,
52 provided that the above copyright notice appear in all copies and that
53 both that copyright notice and this permission notice appear in
54 supporting documentation, and that the names of Digital or MIT not be
55 used in advertising or publicity pertaining to distribution of the
56 software without specific, written prior permission.
57 
58 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
59 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
60 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
61 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
62 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
63 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
64 SOFTWARE.
65 
66 ********************************************************/
67 
68 #include <dtop.h>
69 #if NDTOP > 0
70 #include <sys/param.h>
71 #include <sys/systm.h>
72 #include <sys/ioctl.h>
73 #include <sys/tty.h>
74 #include <sys/proc.h>
75 #include <sys/map.h>
76 #include <sys/buf.h>
77 #include <sys/conf.h>
78 #include <sys/file.h>
79 #include <sys/uio.h>
80 #include <sys/kernel.h>
81 #include <sys/syslog.h>
82 
83 #include <machine/pmioctl.h>
84 #include <machine/machConst.h>
85 #include <machine/dc7085cons.h>
86 
87 #include <pmax/pmax/pmaxtype.h>
88 #include <pmax/pmax/maxine.h>
89 #include <pmax/pmax/asic.h>
90 
91 #include <pmax/dev/device.h>
92 #include <pmax/dev/dtopreg.h>
93 #include <pmax/dev/fbreg.h>
94 
95 extern int pmax_boardtype;
96 
97 extern int ttrstrt	__P((void *));
98 void dtop_keyboard_autorepeat	__P((void *));
99 int dtop_null_device_handler	__P((dtop_device_t, dtop_message_t, int, int));
100 int dtop_locator_handler	__P((dtop_device_t, dtop_message_t, int, int));
101 int dtop_keyboard_handler	__P((dtop_device_t, dtop_message_t, int, int));
102 int dtopparam		__P((struct tty *, struct termios *));
103 int dtopstop		__P((struct tty *, int));
104 void dtopstart		__P((struct tty *));
105 void dtopKBDPutc	__P((dev_t, int));
106 static void dtop_keyboard_repeat __P((dtop_device_t));
107 
108 struct	tty dtop_tty[NDTOP];
109 void	(*dtopDivertXInput)();	/* X windows keyboard input routine */
110 void	(*dtopMouseEvent)();	/* X windows mouse motion event routine */
111 void	(*dtopMouseButtons)();	/* X windows mouse buttons event routine */
112 
113 #define	DTOP_MAX_POLL	0x7fff		/* about half a sec */
114 
115 typedef volatile unsigned int	*data_reg_t;	/* uC  */
116 #define	DTOP_GET_BYTE(data)	(((*(data)) >> 8) & 0xff)
117 #define	DTOP_PUT_BYTE(data,c)	{ *(data) = (c) << 8; }
118 
119 typedef volatile unsigned int	*poll_reg_t;	/* SIR */
120 #define	DTOP_RX_AVAIL(poll)	(*(poll) & 1)
121 #define	DTOP_TX_AVAIL(poll)	(*(poll) & 2)
122 
123 #define	GET_SHORT(b0,b1)	(((b0)<<8)|(b1))
124 
125 /*
126  * Driver status
127  */
128 struct dtop_softc {
129 	data_reg_t	data;
130 	poll_reg_t	poll;
131 	char		polling_mode;
132 	char		probed_once;
133 	short		bad_pkts;
134 
135 	struct dtop_ds {
136 		int		(*handler)();
137 		dtop_device	status;
138 	} device[(DTOP_ADDR_DEFAULT - DTOP_ADDR_FIRST) >> 1];
139 
140 #	define	DTOP_DEVICE_NO(address)	(((address)-DTOP_ADDR_FIRST)>>1)
141 
142 } dtop_softc[NDTOP];
143 
144 typedef struct dtop_softc *dtop_softc_t;
145 struct tty dtop_tty[NDTOP];
146 
147 /*
148  * lk201 keyboard divisions and up/down mode key bitmap.
149  */
150 #define NUMDIVS 14
151 static u_char divbeg[NUMDIVS] = {0xbf, 0x91, 0xbc, 0xbd, 0xb0, 0xad, 0xa6,
152 				 0xa9, 0x88, 0x56, 0x63, 0x6f, 0x7b, 0x7e};
153 static u_char divend[NUMDIVS] = {0xff, 0xa5, 0xbc, 0xbe, 0xb2, 0xaf, 0xa8,
154 				 0xac, 0x90, 0x62, 0x6e, 0x7a, 0x7d, 0x87};
155 /*
156  * Initial defaults, groups 5 and 6 are up/down
157  */
158 static u_long keymodes[8] = {0, 0, 0, 0, 0, 0x0003e000, 0, 0};
159 
160 /*
161  * Definition of the driver for the auto-configuration program.
162  */
163 int	dtopprobe();
164 void	dtopintr();
165 struct	driver dtopdriver =  {
166 	"dtop", dtopprobe, 0, 0, dtopintr,
167 };
168 
169 dtopprobe(cp)
170 	struct pmax_ctlr *cp;
171 {
172 	register struct tty *tp;
173 	register int cntr;
174 	int dtopunit = cp->pmax_unit, i, s;
175 	dtop_softc_t dtop;
176 
177 	if (dtopunit >= NDTOP)
178 		return (0);
179 	if (badaddr(cp->pmax_addr, 2))
180 		return (0);
181 	dtop = &dtop_softc[dtopunit];
182 
183 	dtop->poll = (poll_reg_t)MACH_PHYS_TO_UNCACHED(XINE_REG_INTR);
184 	dtop->data = (data_reg_t)cp->pmax_addr;
185 
186 	for (i = 0; i < DTOP_MAX_DEVICES; i++)
187 		dtop->device[i].handler = dtop_null_device_handler;
188 
189 	/* a lot more needed here, fornow: */
190 	dtop->device[DTOP_DEVICE_NO(0x6a)].handler = dtop_locator_handler;
191 	dtop->device[DTOP_DEVICE_NO(0x6c)].handler = dtop_keyboard_handler;
192 	dtop->device[DTOP_DEVICE_NO(0x6c)].status.keyboard.poll_frequency =
193 		(hz * 5) / 100; /* x0.01 secs */
194 	dtop->device[DTOP_DEVICE_NO(0x6c)].status.keyboard.k_ar_state =
195 		K_AR_IDLE;
196 
197 	/*
198 	 * Sometimes a first interrupt gets lost, so just in case
199 	 * poke it now.
200 	 */
201 	dtopintr(dtopunit);
202 	dtop->probed_once = 1;
203 	printf("dtop%d at nexus0 csr 0x%x priority %d\n",
204 		cp->pmax_unit, cp->pmax_addr, cp->pmax_pri);
205 	return (1);
206 }
207 
208 dtopopen(dev, flag, mode, p)
209 	dev_t dev;
210 	int flag, mode;
211 	struct proc *p;
212 {
213 	register struct tty *tp;
214 	register int unit;
215 	int s, error = 0;
216 
217 	unit = minor(dev);
218 	if (unit >= NDTOP)
219 		return (ENXIO);
220 	tp = &dtop_tty[unit];
221 	tp->t_oproc = dtopstart;
222 	tp->t_param = dtopparam;
223 	tp->t_dev = dev;
224 	if ((tp->t_state & TS_ISOPEN) == 0) {
225 		tp->t_state |= TS_WOPEN;
226 		ttychars(tp);
227 		if (tp->t_ispeed == 0) {
228 			tp->t_iflag = TTYDEF_IFLAG;
229 			tp->t_oflag = TTYDEF_OFLAG;
230 			tp->t_cflag = TTYDEF_CFLAG;
231 			tp->t_lflag = TTYDEF_LFLAG;
232 			tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
233 		}
234 		(void) dtopparam(tp, &tp->t_termios);
235 		ttsetwater(tp);
236 	} else if ((tp->t_state & TS_XCLUDE) && curproc->p_ucred->cr_uid != 0)
237 		return (EBUSY);
238 	s = spltty();
239 	while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL) &&
240 	       !(tp->t_state & TS_CARR_ON)) {
241 		tp->t_state |= TS_WOPEN;
242 		if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
243 		    ttopen, 0))
244 			break;
245 	}
246 	splx(s);
247 	if (error)
248 		return (error);
249 	error = (*linesw[tp->t_line].l_open)(dev, tp);
250 	return (error);
251 }
252 
253 /*ARGSUSED*/
254 dtopclose(dev, flag, mode, p)
255 	dev_t dev;
256 	int flag, mode;
257 	struct proc *p;
258 {
259 	register struct tty *tp;
260 	register int unit;
261 
262 	unit = minor(dev);
263 	tp = &dtop_tty[unit];
264 	(*linesw[tp->t_line].l_close)(tp, flag);
265 	return (ttyclose(tp));
266 }
267 
268 dtopread(dev, uio, flag)
269 	dev_t dev;
270 	struct uio *uio;
271 {
272 	register struct tty *tp;
273 
274 	tp = &dtop_tty[minor(dev)];
275 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
276 }
277 
278 dtopwrite(dev, uio, flag)
279 	dev_t dev;
280 	struct uio *uio;
281 {
282 	register struct tty *tp;
283 
284 	tp = &dtop_tty[minor(dev)];
285 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
286 }
287 
288 /*ARGSUSED*/
289 dtopioctl(dev, cmd, data, flag, p)
290 	dev_t dev;
291 	int cmd;
292 	caddr_t data;
293 	int flag;
294 	struct proc *p;
295 {
296 	register struct tty *tp;
297 	register int unit = minor(dev);
298 	int error;
299 
300 	tp = &dtop_tty[unit];
301 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
302 	if (error >= 0)
303 		return (error);
304 	error = ttioctl(tp, cmd, data, flag);
305 	if (error >= 0)
306 		return (error);
307 
308 	switch (cmd) {
309 
310 	case TIOCSBRK:
311 		ttyoutput(0, tp);
312 		break;
313 
314 	case TIOCCBRK:
315 		ttyoutput(0, tp);
316 		break;
317 
318 	case TIOCMGET:
319 		*(int *)data = DML_DTR | DML_DSR | DML_CAR;
320 		break;
321 
322 	default:
323 		return (ENOTTY);
324 	}
325 	return (0);
326 }
327 
328 /*
329  * Interrupt routine
330  */
331 void
332 dtopintr(unit)
333 	int unit;
334 {
335 	dtop_message msg;
336 	int devno;
337 	dtop_softc_t dtop;
338 
339 	dtop = &dtop_softc[unit];
340 	if (dtop_get_packet(dtop, &msg) < 0) {
341 		if (dtop->probed_once)
342 			printf("%s", "dtop: overrun (or stray)\n");
343 		return;
344 	}
345 
346 	devno = DTOP_DEVICE_NO(msg.src_address);
347 	if (devno < 0 || devno > 15)
348 		return;
349 
350 	(void) (*dtop->device[devno].handler)
351 			(&dtop->device[devno].status, &msg,
352 			 DTOP_EVENT_RECEIVE_PACKET, 0);
353 }
354 
355 void
356 dtopstart(tp)
357 	register struct tty *tp;
358 {
359 	register int cc;
360 	int s;
361 
362 	s = spltty();
363 	if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
364 		goto out;
365 	if (tp->t_outq.c_cc <= tp->t_lowat) {
366 		if (tp->t_state & TS_ASLEEP) {
367 			tp->t_state &= ~TS_ASLEEP;
368 			wakeup((caddr_t)&tp->t_outq);
369 		}
370 		selwakeup(&tp->t_wsel);
371 	}
372 	if (tp->t_outq.c_cc == 0)
373 		goto out;
374 	/* handle console specially */
375 	if (tp == dtop_tty) {
376 		while (tp->t_outq.c_cc > 0) {
377 			cc = getc(&tp->t_outq) & 0x7f;
378 			cnputc(cc);
379 		}
380 		/*
381 		 * After we flush the output queue we may need to wake
382 		 * up the process that made the output.
383 		 */
384 		if (tp->t_outq.c_cc <= tp->t_lowat) {
385 			if (tp->t_state & TS_ASLEEP) {
386 				tp->t_state &= ~TS_ASLEEP;
387 				wakeup((caddr_t)&tp->t_outq);
388 			}
389 			selwakeup(&tp->t_wsel);
390 		}
391 	}
392 out:
393 	splx(s);
394 }
395 
396 void
397 dtopKBDPutc(dev, c)
398 	dev_t dev;
399 	int c;
400 {
401 	register int i;
402 	static int param = 0, cmd, mod, typ;
403 	static u_char parms[2];
404 
405 	/*
406 	 * Emulate the lk201 command codes.
407 	 */
408 	if (param == 0) {
409 		typ = (c & 0x1);
410 		cmd = ((c >> 3) & 0xf);
411 		mod = ((c >> 1) & 0x3);
412 	} else
413 		parms[param - 1] = (c & 0x7f);
414 	if (c & 0x80) {
415 		if (typ) {
416 			/*
417 			 * A peripheral command code. Someday this driver
418 			 * should know how to send commands to the lk501,
419 			 * but until then this is all essentially a no-op.
420 			 */
421 			;
422 		} else {
423 			/*
424 			 * Set modes. These have to be emulated in software.
425 			 */
426 			if (cmd > 0 && cmd < 15) {
427 				cmd--;
428 				if (mod & 0x2)
429 				   for (i = divbeg[cmd]; i <= divend[cmd]; i++)
430 					keymodes[i >> 5] |=
431 						(1 << (i & 0x1f));
432 				else
433 				   for (i = divbeg[cmd]; i <= divend[cmd]; i++)
434 					keymodes[i >> 5] &=
435 						~(1 << (i & 0x1f));
436 			}
437 		}
438 		param = 0;
439 	} else if (++param > 2)
440 		param = 2;
441 }
442 
443 /*
444  * Take a packet off dtop interface
445  * A packet MUST be there, this is not checked for.
446  */
447 #define	DTOP_ESC_CHAR		0xf8
448 dtop_escape(c)
449 {
450 	/* I donno much about this stuff.. */
451 	switch (c) {
452 	case 0xe8:	return (0xf8);
453 	case 0xe9:	return (0xf9);
454 	case 0xea:	return (0xfa);
455 	case 0xeb:	return (0xfb);
456 	default:	/* printf("{esc %x}", c); */
457 			return (c);
458 	}
459 }
460 
461 dtop_get_packet(dtop, pkt)
462 	dtop_softc_t	dtop;
463 	dtop_message_t	pkt;
464 {
465 	register poll_reg_t	poll;
466 	register data_reg_t	data;
467 	register int		max, i, len;
468 	register unsigned char	c;
469 
470 	poll = dtop->poll;
471 	data = dtop->data;
472 
473 	/*
474 	 * The interface does not handle us the first byte,
475 	 * which is our address and cannot ever be anything
476 	 * else but 0x50.  This is a good thing, it makes
477 	 * the average packet exactly one word long, too.
478 	 */
479 	for (max = 0; (max < DTOP_MAX_POLL) && !DTOP_RX_AVAIL(poll); max++)
480 		DELAY(1);
481 	if (max == DTOP_MAX_POLL)
482 		goto bad;
483 	pkt->src_address = DTOP_GET_BYTE(data);
484 
485 	for (max = 0; (max < DTOP_MAX_POLL) && !DTOP_RX_AVAIL(poll); max++)
486 		DELAY(1);
487 	if (max == DTOP_MAX_POLL)
488 		goto bad;
489 	pkt->code.bits = DTOP_GET_BYTE(data);
490 
491 	/*
492 	 * Now get data and checksum
493 	 */
494 	len = pkt->code.val.len + 1;
495 	c = 0;
496 	for (i = 0; i < len; i++) {
497 again:
498 		for (max = 0; (max < DTOP_MAX_POLL) && !DTOP_RX_AVAIL(poll); max++)
499 			DELAY(1);
500 		if (max == DTOP_MAX_POLL)
501 			goto bad;
502 		if (c == DTOP_ESC_CHAR) {
503 			c = dtop_escape(DTOP_GET_BYTE(data) & 0xff);
504 		} else {
505 			c = DTOP_GET_BYTE(data);
506 			if (c == DTOP_ESC_CHAR)
507 				goto again;
508 		}
509 		pkt->body[i] = c;
510 	}
511 	return (len);
512 bad:
513 	dtop->bad_pkts++;
514 	return (-1);
515 }
516 
517 /*
518  * Get a keyboard char for the console
519  */
520 dtopKBDGetc()
521 {
522 	register int c;
523 	dtop_softc_t dtop;
524 
525 	dtop = &dtop_softc[0];
526 again:
527 	c = -1;
528 
529 	/*
530 	 * Now check keyboard
531 	 */
532 	if (DTOP_RX_AVAIL(dtop->poll)) {
533 
534 		dtop_message	msg;
535 		struct dtop_ds	*ds;
536 
537 		if (dtop_get_packet(dtop, &msg) >= 0) {
538 
539 		    ds = &dtop->device[DTOP_DEVICE_NO(msg.src_address)];
540 		    if (ds->handler == dtop_keyboard_handler) {
541 
542 			c = dtop_keyboard_handler(
543 					&ds->status, &msg,
544 					DTOP_EVENT_RECEIVE_PACKET, -1);
545 
546 			if (c > 0) return c;
547 
548 			c = -1;
549 		    }
550 		}
551 	}
552 
553 	if (c == -1) {
554 		DELAY(100);
555 		goto again;
556 	}
557 
558 	return c;
559 }
560 
561 int
562 dtopparam(tp, t)
563 	struct tty *tp;
564 	struct termios *t;
565 {
566 	if (tp->t_ispeed == 0)
567 		ttymodem(tp, 0);
568 	else
569 		/* called too early to invoke ttymodem, sigh */
570 		tp->t_state |= TS_CARR_ON;
571 	return (0);
572 }
573 
574 /*
575  * Stop output on a line.
576  */
577 /*ARGSUSED*/
578 dtopstop(tp, flag)
579 	register struct tty *tp;
580 	int flag;
581 {
582 	int s;
583 
584 	s = spltty();
585 	if (tp->t_state & TS_BUSY) {
586 		if (!(tp->t_state & TS_TTSTOP))
587 			tp->t_state |= TS_FLUSH;
588 	}
589 	splx(s);
590 }
591 
592 /*
593  * Default handler function
594  */
595 int
596 dtop_null_device_handler(dev, msg, event, outc)
597 	 dtop_device_t	dev;
598 	 dtop_message_t	msg;
599 	 int		event;
600 	 int		outc;
601 {
602 	/* See if the message was to the default address (powerup) */
603 
604 	/* Uhmm, donno how to handle this. Drop it */
605 	if (event == DTOP_EVENT_RECEIVE_PACKET)
606 		dev->unknown_report = *msg;
607 	return 0;
608 }
609 
610 /*
611  * Handler for locator devices (mice)
612  */
613 int
614 dtop_locator_handler(dev, msg, event, outc)
615 	 dtop_device_t	dev;
616 	 dtop_message_t	msg;
617 	 int		event;
618 	 int		outc;
619 {
620 	register unsigned short	buttons;
621 	register short coord;
622 	register int moved = 0;
623 	static MouseReport currentRep;
624 	register MouseReport *mrp = &currentRep;
625 
626 	if (dtopMouseButtons) {
627 		mrp->state = 0;
628 		/*
629 		 * Do the position first
630 		 */
631 		coord = GET_SHORT(msg->body[2], msg->body[3]);
632 		if (coord < 0) {
633 			coord = -coord;
634 			moved = 1;
635 		} else if (coord > 0) {
636 			mrp->state |= MOUSE_X_SIGN;
637 			moved = 1;
638 		}
639 		mrp->dx = (coord & 0x1f);
640 		coord = GET_SHORT(msg->body[4], msg->body[5]);
641 		if (coord < 0) {
642 			coord = -coord;
643 			moved = 1;
644 		} else if (coord > 0) {
645 			mrp->state |= MOUSE_Y_SIGN;
646 			moved = 1;
647 		}
648 		mrp->dy = (coord & 0x1f);
649 
650 		/*
651 		 * Time for the buttons now
652 		 */
653 		buttons = GET_SHORT(msg->body[0], msg->body[1]);
654 		mrp->state |= (buttons & 0x7);
655 		if (moved)
656 			(*dtopMouseEvent)(mrp);
657 		(*dtopMouseButtons)(mrp);
658 	}
659 	return (0);
660 }
661 
662 /*
663  * Handler for keyboard devices
664  * Special case: outc set for recv packet means
665  * we are inside the kernel debugger
666  */
667 int
668 dtop_keyboard_handler(dev, msg, event, outc)
669 	dtop_device_t dev;
670 	dtop_message_t msg;
671 	int event;
672 	int outc;
673 {
674 	register u_char *ls, *le, *ns, *ne;
675 	u_char save[11], retc;
676 	int msg_len, c;
677 	struct tty *tp = &dtop_tty[0];
678 
679 	/*
680 	 * Fiddle about emulating an lk201 keyboard. The lk501
681 	 * designers carefully ensured that keyboard handlers could be
682 	 * stateless, then we turn around and use lots of state to
683 	 * emulate the stateful lk201, since the X11R5 X servers
684 	 * only know about the lk201... (oh well)
685 	 */
686 	msg_len = msg->code.val.len;
687 
688 	/* Check for errors */
689 	c = msg->body[0];
690 	if ((c < DTOP_KBD_KEY_MIN) && (c != DTOP_KBD_EMPTY)) {
691 		printf("Keyboard error: %x %x %x..\n", msg_len, c, msg->body[1]);
692 		if (c != DTOP_KBD_OUT_ERR) return -1;
693 		/* spec sez if scan list overflow still there is data */
694 		msg->body[0] = 0;
695 	}
696 
697 	dev->keyboard.last_msec = TO_MS(time);
698 
699 	switch (dev->keyboard.k_ar_state) {
700 	case K_AR_IDLE:
701 		if (outc != 0xff) /* from debugger, might be too early */
702 			dtop_keyboard_autorepeat(dev);
703 		/* fall through */
704 	case K_AR_TRIGGER:
705 		dev->keyboard.k_ar_state = K_AR_ACTIVE;
706 		break;
707 	case K_AR_ACTIVE:
708 		break;
709 	case K_AR_OFF:
710 		printf("dtop keyb off?\n");
711 		dev->keyboard.k_ar_state = K_AR_IDLE;
712 	}
713 
714 	/*
715 	 * To make things readable, do a first pass cancelling out
716 	 * all keys that are still pressed, and a second one generating
717 	 * events.  While generating events, do the upstrokes first
718 	 * from oldest to youngest, then the downstrokes from oldest
719 	 * to youngest.  This copes with lost packets and provides
720 	 * a reasonable model even if scans are too slow.
721 	 */
722 
723 	/* make a copy of new state first */
724 	if (msg_len == 1)
725 		save[0] = msg->body[0];
726 	else if (msg_len > 0)
727 		bcopy(msg->body, save, msg_len);
728 
729 	/*
730 	 * Cancel out any keys in both the last and current message as
731 	 * they are unchanged.
732 	 */
733 	if (msg_len > 0 && dev->keyboard.last_codes_count > 0) {
734 		ls = dev->keyboard.last_codes;
735 		le = &dev->keyboard.last_codes[dev->keyboard.last_codes_count];
736 		ne = &msg->body[msg_len];
737 		for (; ls < le; ls++) {
738 			for (ns = msg->body; ns < ne; ns++)
739 				if (*ls == *ns) {
740 					*ls = *ns = 0;
741 					break;
742 				}
743 		}
744 	}
745 
746 	/*
747 	 * Now generate all upstrokes
748 	 */
749 	le = dev->keyboard.last_codes;
750 	ls = &dev->keyboard.last_codes[dev->keyboard.last_codes_count - 1];
751 	for ( ; ls >= le; ls--)
752 	    if (c = *ls) {
753 		(void) kbdMapChar(c);
754 
755 		if (outc == 0 && dtopDivertXInput &&
756 		    (keymodes[(c >> 5) & 0x7] & (1 << (c & 0x1f))))
757 			(*dtopDivertXInput)(c);
758 	    }
759 	/*
760 	 * And finally the downstrokes
761 	 */
762 	ne = (char*)msg->body;
763 	ns = (char*)&msg->body[msg_len - 1];
764 	retc = 0;
765 	for ( ; ns >= ne; ns--)
766 	    if (*ns) {
767 		c = kbdMapChar(*ns);
768 		if (outc == 0) {
769 		    if (dtopDivertXInput) {
770 			(*dtopDivertXInput)(*ns);
771 			c = -1; /* consumed by X */
772 		    } else if (c >= 0)
773 			(*linesw[tp->t_line].l_rint)(c, tp);
774 		}
775 		/* return the related keycode anyways */
776 		if ((c >= 0) && (retc == 0))
777 		    retc = c;
778 	    }
779 	outc = retc;
780 	/* install new scan state */
781 	if (msg_len == 1)
782 		dev->keyboard.last_codes[0] = save[0];
783 	else if (msg_len > 0)
784 		bcopy(save, dev->keyboard.last_codes, msg_len);
785 	dev->keyboard.last_codes_count = msg_len;
786 	return (outc);
787 }
788 
789 /*
790  * Timeout routine to do autorepeat.
791  */
792 void
793 dtop_keyboard_autorepeat(arg)
794 	void *arg;
795 {
796 	dtop_device_t dev = (dtop_device_t)arg;
797 	int s;
798 
799 	s = spltty();
800 	if (dev->keyboard.k_ar_state != K_AR_IDLE)
801 		dtop_keyboard_repeat(dev);
802 
803 	if (dev->keyboard.k_ar_state == K_AR_OFF)
804 		dev->keyboard.k_ar_state = K_AR_IDLE;
805 	else
806 		timeout(dtop_keyboard_autorepeat, dev, dev->keyboard.poll_frequency);
807 
808 	splx(s);
809 }
810 
811 /*
812  * See if an autorepeat is required.
813  */
814 static void
815 dtop_keyboard_repeat(dev)
816 	dtop_device_t dev;
817 {
818 	register int i, c;
819 	register u_int t, t0;
820 	struct tty *tp = dtop_tty;
821 
822 	for (i = 0; i < dev->keyboard.last_codes_count; i++) {
823 		c = (int)dev->keyboard.last_codes[i];
824 		if (c != DTOP_KBD_EMPTY &&
825 		    (keymodes[(c >> 5) & 0x7] & (1 << (c & 0x1f))) == 0) {
826 			/*
827 			 * Got a char. See if enough time from stroke,
828 			 * or from last repeat.
829 			 */
830 			t0 = (dev->keyboard.k_ar_state == K_AR_TRIGGER) ? 30 : 500;
831 			t = TO_MS(time);
832 			if ((t - dev->keyboard.last_msec) < t0)
833 				return;
834 
835 			dev->keyboard.k_ar_state = K_AR_TRIGGER;
836 
837 			if (dtopDivertXInput) {
838 				(*dtopDivertXInput)(KEY_REPEAT);
839 				return;
840 			}
841 
842 			if ((c = kbdMapChar(KEY_REPEAT)) >= 0)
843 				(*linesw[tp->t_line].l_rint)(c, tp);
844 			return;
845 		}
846 	}
847 	dev->keyboard.k_ar_state = K_AR_OFF;
848 }
849 #endif
850