xref: /original-bsd/sys/pmax/dev/dtop.c (revision a6d8c59f)
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.1 (Berkeley) 11/15/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 #include <dtop.h>
46 #if NDTOP > 0
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/ioctl.h>
50 #include <sys/tty.h>
51 #include <sys/proc.h>
52 #include <sys/map.h>
53 #include <sys/buf.h>
54 #include <sys/conf.h>
55 #include <sys/file.h>
56 #include <sys/uio.h>
57 #include <sys/kernel.h>
58 #include <sys/syslog.h>
59 
60 #include <machine/pmioctl.h>
61 #include <machine/machConst.h>
62 #include <machine/dc7085cons.h>
63 
64 #include <pmax/pmax/pmaxtype.h>
65 #include <pmax/pmax/maxine.h>
66 #include <pmax/pmax/asic.h>
67 
68 #include <pmax/dev/device.h>
69 #include <pmax/dev/dtopreg.h>
70 #include <pmax/dev/fbreg.h>
71 
72 extern int pmax_boardtype;
73 
74 extern int ttrstrt	__P((void *));
75 void dtop_keyboard_autorepeat	__P((void *));
76 int dtop_null_device_handler	__P((dtop_device_t, dtop_message_t, int, int));
77 int dtop_locator_handler	__P((dtop_device_t, dtop_message_t, int, int));
78 int dtop_keyboard_handler	__P((dtop_device_t, dtop_message_t, int, int));
79 int dtopparam		__P((struct tty *, struct termios *));
80 int dtopstop		__P((struct tty *, int));
81 void dtopstart		__P((struct tty *));
82 void dtopKBDPutc	__P((dev_t, int));
83 
84 struct	tty dtop_tty[NDTOP];
85 void	(*dtopDivertXInput)();	/* X windows keyboard input routine */
86 void	(*dtopMouseEvent)();	/* X windows mouse motion event routine */
87 void	(*dtopMouseButtons)();	/* X windows mouse buttons event routine */
88 
89 #define	DTOP_MAX_POLL	0x7fff		/* about half a sec */
90 
91 typedef volatile unsigned int	*data_reg_t;	/* uC  */
92 #define	DTOP_GET_BYTE(data)	(((*(data)) >> 8) & 0xff)
93 #define	DTOP_PUT_BYTE(data,c)	{ *(data) = (c) << 8; }
94 
95 typedef volatile unsigned int	*poll_reg_t;	/* SIR */
96 #define	DTOP_RX_AVAIL(poll)	(*(poll) & 1)
97 #define	DTOP_TX_AVAIL(poll)	(*(poll) & 2)
98 
99 #define	GET_SHORT(b0,b1)	(((b0)<<8)|(b1))
100 
101 /*
102  * Driver status
103  */
104 struct dtop_softc {
105 	data_reg_t	data;
106 	poll_reg_t	poll;
107 	char		polling_mode;
108 	char		probed_once;
109 	short		bad_pkts;
110 
111 	struct dtop_ds {
112 		int		(*handler)();
113 		dtop_device	status;
114 	} device[(DTOP_ADDR_DEFAULT - DTOP_ADDR_FIRST) >> 1];
115 
116 #	define	DTOP_DEVICE_NO(address)	(((address)-DTOP_ADDR_FIRST)>>1)
117 
118 } dtop_softc[NDTOP];
119 
120 typedef struct dtop_softc *dtop_softc_t;
121 struct tty dtop_tty[NDTOP];
122 static int dtopenabled = 0;
123 
124 /*
125  * Definition of the driver for the auto-configuration program.
126  */
127 int	dtopprobe();
128 void	dtopintr();
129 struct	driver dtopdriver =  {
130 	"dtop", dtopprobe, 0, 0, dtopintr,
131 };
132 
133 dtopprobe(cp)
134 	struct pmax_ctlr *cp;
135 {
136 	register struct tty *tp;
137 	register int cntr;
138 	int dtopunit = cp->pmax_unit, i, s;
139 	dtop_softc_t dtop;
140 
141 	if (dtopunit >= NDTOP)
142 		return (0);
143 	if (badaddr(cp->pmax_addr, 2))
144 		return (0);
145 	dtop = &dtop_softc[dtopunit];
146 
147 	dtop->poll = (poll_reg_t)MACH_PHYS_TO_UNCACHED(XINE_REG_INTR);
148 	dtop->data = (data_reg_t)cp->pmax_addr;
149 
150 	for (i = 0; i < DTOP_MAX_DEVICES; i++)
151 		dtop->device[i].handler = dtop_null_device_handler;
152 
153 	/* a lot more needed here, fornow: */
154 	dtop->device[DTOP_DEVICE_NO(0x6a)].handler = dtop_locator_handler;
155 	dtop->device[DTOP_DEVICE_NO(0x6c)].handler = dtop_keyboard_handler;
156 	dtop->device[DTOP_DEVICE_NO(0x6c)].status.keyboard.poll_frequency =
157 		(hz * 5) / 100; /* x0.01 secs */
158 	dtop->device[DTOP_DEVICE_NO(0x6c)].status.keyboard.k_ar_state =
159 		K_AR_IDLE;
160 
161 	/*
162 	 * Sometimes a first interrupt gets lost, so just in case
163 	 * poke it now.
164 	 */
165 	dtopintr(dtopunit);
166 	dtopenabled = 1;
167 	return (1);
168 }
169 
170 dtopopen(dev, flag, mode, p)
171 	dev_t dev;
172 	int flag, mode;
173 	struct proc *p;
174 {
175 	register struct tty *tp;
176 	register int unit;
177 	int s, error = 0;
178 
179 	unit = minor(dev);
180 	if (unit >= NDTOP)
181 		return (ENXIO);
182 	tp = &dtop_tty[unit];
183 	tp->t_oproc = dtopstart;
184 	tp->t_param = dtopparam;
185 	tp->t_dev = dev;
186 	if ((tp->t_state & TS_ISOPEN) == 0) {
187 		tp->t_state |= TS_WOPEN;
188 		ttychars(tp);
189 		if (tp->t_ispeed == 0) {
190 			tp->t_iflag = TTYDEF_IFLAG;
191 			tp->t_oflag = TTYDEF_OFLAG;
192 			tp->t_cflag = TTYDEF_CFLAG;
193 			tp->t_lflag = TTYDEF_LFLAG;
194 			tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
195 		}
196 		(void) dtopparam(tp, &tp->t_termios);
197 		ttsetwater(tp);
198 	} else if ((tp->t_state & TS_XCLUDE) && curproc->p_ucred->cr_uid != 0)
199 		return (EBUSY);
200 	s = spltty();
201 	while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL) &&
202 	       !(tp->t_state & TS_CARR_ON)) {
203 		tp->t_state |= TS_WOPEN;
204 		if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
205 		    ttopen, 0))
206 			break;
207 	}
208 	splx(s);
209 	if (error)
210 		return (error);
211 	error = (*linesw[tp->t_line].l_open)(dev, tp);
212 	return (error);
213 }
214 
215 /*ARGSUSED*/
216 dtopclose(dev, flag, mode, p)
217 	dev_t dev;
218 	int flag, mode;
219 	struct proc *p;
220 {
221 	register struct tty *tp;
222 	register int unit;
223 
224 	unit = minor(dev);
225 	tp = &dtop_tty[unit];
226 	(*linesw[tp->t_line].l_close)(tp, flag);
227 	return (ttyclose(tp));
228 }
229 
230 dtopread(dev, uio, flag)
231 	dev_t dev;
232 	struct uio *uio;
233 {
234 	register struct tty *tp;
235 
236 	tp = &dtop_tty[minor(dev)];
237 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
238 }
239 
240 dtopwrite(dev, uio, flag)
241 	dev_t dev;
242 	struct uio *uio;
243 {
244 	register struct tty *tp;
245 
246 	tp = &dtop_tty[minor(dev)];
247 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
248 }
249 
250 /*ARGSUSED*/
251 dtopioctl(dev, cmd, data, flag, p)
252 	dev_t dev;
253 	int cmd;
254 	caddr_t data;
255 	int flag;
256 	struct proc *p;
257 {
258 	register struct tty *tp;
259 	register int unit = minor(dev);
260 	int error;
261 
262 	tp = &dtop_tty[unit];
263 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
264 	if (error >= 0)
265 		return (error);
266 	error = ttioctl(tp, cmd, data, flag);
267 	if (error >= 0)
268 		return (error);
269 
270 	switch (cmd) {
271 
272 	case TIOCSBRK:
273 		ttyoutput(0, tp);
274 		break;
275 
276 	case TIOCCBRK:
277 		ttyoutput(0, tp);
278 		break;
279 
280 	case TIOCMGET:
281 		*(int *)data = DML_DTR | DML_DSR | DML_CAR;
282 		break;
283 
284 	default:
285 		return (ENOTTY);
286 	}
287 	return (0);
288 }
289 
290 /*
291  * Interrupt routine
292  */
293 void
294 dtopintr(unit)
295 	int unit;
296 {
297 	dtop_message msg;
298 	int devno;
299 	dtop_softc_t dtop;
300 
301 	dtop = &dtop_softc[unit];
302 	if (dtop_get_packet(dtop, &msg) < 0) {
303 		if (dtopenabled)
304 			printf("%s", "dtop: overrun (or stray)\n");
305 		return;
306 	}
307 
308 	devno = DTOP_DEVICE_NO(msg.src_address);
309 	if (devno < 0 || devno > 15)
310 		return;
311 
312 	(void) (*dtop->device[devno].handler)
313 			(&dtop->device[devno].status, &msg,
314 			 DTOP_EVENT_RECEIVE_PACKET, 0);
315 }
316 
317 void
318 dtopstart(tp)
319 	register struct tty *tp;
320 {
321 	register int cc;
322 	int s;
323 
324 	s = spltty();
325 	if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
326 		goto out;
327 	if (tp->t_outq.c_cc <= tp->t_lowat) {
328 		if (tp->t_state & TS_ASLEEP) {
329 			tp->t_state &= ~TS_ASLEEP;
330 			wakeup((caddr_t)&tp->t_outq);
331 		}
332 		selwakeup(&tp->t_wsel);
333 	}
334 	if (tp->t_outq.c_cc == 0)
335 		goto out;
336 	/* handle console specially */
337 	if (tp == dtop_tty) {
338 		while (tp->t_outq.c_cc > 0) {
339 			cc = getc(&tp->t_outq) & 0x7f;
340 			cnputc(cc);
341 		}
342 		/*
343 		 * After we flush the output queue we may need to wake
344 		 * up the process that made the output.
345 		 */
346 		if (tp->t_outq.c_cc <= tp->t_lowat) {
347 			if (tp->t_state & TS_ASLEEP) {
348 				tp->t_state &= ~TS_ASLEEP;
349 				wakeup((caddr_t)&tp->t_outq);
350 			}
351 			selwakeup(&tp->t_wsel);
352 		}
353 	}
354 out:
355 	splx(s);
356 }
357 
358 void
359 dtopKBDPutc(dev, c)
360 	dev_t dev;
361 	int c;
362 {
363 
364 	/*
365 	 * Not yet, someday we will know how to send commands to the
366 	 * LK501 over the Access bus.
367 	 */
368 }
369 
370 /*
371  * Take a packet off dtop interface
372  * A packet MUST be there, this is not checked for.
373  */
374 #define	DTOP_ESC_CHAR		0xf8
375 dtop_escape(c)
376 {
377 	/* I donno much about this stuff.. */
378 	switch (c) {
379 	case 0xe8:	return (0xf8);
380 	case 0xe9:	return (0xf9);
381 	case 0xea:	return (0xfa);
382 	case 0xeb:	return (0xfb);
383 	default:	/* printf("{esc %x}", c); */
384 			return (c);
385 	}
386 }
387 
388 dtop_get_packet(dtop, pkt)
389 	dtop_softc_t	dtop;
390 	dtop_message_t	pkt;
391 {
392 	register poll_reg_t	poll;
393 	register data_reg_t	data;
394 	register int		max, i, len;
395 	register unsigned char	c;
396 
397 	poll = dtop->poll;
398 	data = dtop->data;
399 
400 	/*
401 	 * The interface does not handle us the first byte,
402 	 * which is our address and cannot ever be anything
403 	 * else but 0x50.  This is a good thing, it makes
404 	 * the average packet exactly one word long, too.
405 	 */
406 	for (max = 0; (max < DTOP_MAX_POLL) && !DTOP_RX_AVAIL(poll); max++)
407 		DELAY(16);
408 	if (max == DTOP_MAX_POLL)
409 		goto bad;
410 	pkt->src_address = DTOP_GET_BYTE(data);
411 
412 	for (max = 0; (max < DTOP_MAX_POLL) && !DTOP_RX_AVAIL(poll); max++)
413 		DELAY(16);
414 	if (max == DTOP_MAX_POLL)
415 		goto bad;
416 	pkt->code.bits = DTOP_GET_BYTE(data);
417 
418 	/*
419 	 * Now get data and checksum
420 	 */
421 	len = pkt->code.val.len + 1;
422 	c = 0;
423 	for (i = 0; i < len; i++) {
424 again:
425 		for (max = 0; (max < DTOP_MAX_POLL) && !DTOP_RX_AVAIL(poll); max++)
426 			DELAY(16);
427 		if (max == DTOP_MAX_POLL)
428 			goto bad;
429 		if (c == DTOP_ESC_CHAR) {
430 			c = dtop_escape(DTOP_GET_BYTE(data) & 0xff);
431 		} else {
432 			c = DTOP_GET_BYTE(data);
433 			if (c == DTOP_ESC_CHAR)
434 				goto again;
435 		}
436 		pkt->body[i] = c;
437 	}
438 	return (len);
439 bad:
440 	dtop->bad_pkts++;
441 	return (-1);
442 }
443 
444 /*
445  * Get a keyboard char for the console
446  */
447 dtopKBDGetc()
448 {
449 	register int c;
450 	dtop_softc_t dtop;
451 
452 	dtop = &dtop_softc[0];
453 again:
454 	c = -1;
455 
456 	/*
457 	 * Now check keyboard
458 	 */
459 	if (DTOP_RX_AVAIL(dtop->poll)) {
460 
461 		dtop_message	msg;
462 		struct dtop_ds	*ds;
463 
464 		if (dtop_get_packet(dtop, &msg) >= 0) {
465 
466 		    ds = &dtop->device[DTOP_DEVICE_NO(msg.src_address)];
467 		    if (ds->handler == dtop_keyboard_handler) {
468 
469 			c = dtop_keyboard_handler(
470 					&ds->status, &msg,
471 					DTOP_EVENT_RECEIVE_PACKET, -1);
472 
473 			if (c > 0) return c;
474 
475 			c = -1;
476 		    }
477 		}
478 	}
479 
480 	if (c == -1) {
481 		DELAY(100);
482 		goto again;
483 	}
484 
485 	return c;
486 }
487 
488 int
489 dtopparam(tp, t)
490 	struct tty *tp;
491 	struct termios *t;
492 {
493 	if (tp->t_ispeed == 0)
494 		ttymodem(tp, 0);
495 	else
496 		/* called too early to invoke ttymodem, sigh */
497 		tp->t_state |= TS_CARR_ON;
498 	return (0);
499 }
500 
501 /*
502  * Stop output on a line.
503  */
504 /*ARGSUSED*/
505 dtopstop(tp, flag)
506 	register struct tty *tp;
507 	int flag;
508 {
509 	int s;
510 
511 	s = spltty();
512 	if (tp->t_state & TS_BUSY) {
513 		if (!(tp->t_state & TS_TTSTOP))
514 			tp->t_state |= TS_FLUSH;
515 	}
516 	splx(s);
517 }
518 
519 /*
520  * Default handler function
521  */
522 int
523 dtop_null_device_handler(dev, msg, event, outc)
524 	 dtop_device_t	dev;
525 	 dtop_message_t	msg;
526 	 int		event;
527 	 int		outc;
528 {
529 	/* See if the message was to the default address (powerup) */
530 
531 	/* Uhmm, donno how to handle this. Drop it */
532 	if (event == DTOP_EVENT_RECEIVE_PACKET)
533 		dev->unknown_report = *msg;
534 	return 0;
535 }
536 
537 /*
538  * Handler for locator devices (mice)
539  */
540 int
541 dtop_locator_handler(dev, msg, event, outc)
542 	 dtop_device_t	dev;
543 	 dtop_message_t	msg;
544 	 int		event;
545 	 int		outc;
546 {
547 	register unsigned short	buttons;
548 	register short coord;
549 	register int moved = 0;
550 	static MouseReport currentRep;
551 	register MouseReport *mrp = &currentRep;
552 
553 	if (dtopMouseButtons) {
554 		/*
555 		 * Do the position first
556 		 */
557 		coord = GET_SHORT(msg->body[2], msg->body[3]);
558 		mrp->dx = coord;
559 		if (coord != 0)
560 			moved = 1;
561 		coord = GET_SHORT(msg->body[4], msg->body[5]);
562 		coord = - coord;
563 		mrp->dy = coord;
564 		if (coord != 0)
565 			moved = 1;
566 
567 		/*
568 		 * Time for the buttons now
569 		 */
570 		buttons = GET_SHORT(msg->body[0], msg->body[1]);
571 		mrp->state = MOUSE_Y_SIGN | MOUSE_X_SIGN | (buttons & 0x7);
572 		if (moved)
573 			(*dtopMouseEvent)(mrp);
574 		(*dtopMouseButtons)(mrp);
575 	}
576 	return (0);
577 }
578 
579 /*
580  * Handler for keyboard devices
581  * Special case: outc set for recv packet means
582  * we are inside the kernel debugger
583  */
584 int
585 dtop_keyboard_handler(dev, msg, event, outc)
586 	dtop_device_t dev;
587 	dtop_message_t msg;
588 	int event;
589 	int outc;
590 {
591 	register u_char *ls, *le, *ns, *ne;
592 	u_char save[11], retc;
593 	int msg_len, c;
594 	struct tty *tp = &dtop_tty[0];
595 
596 	/*
597 	 * Fiddle about emulating an lk201 keyboard. The lk501
598 	 * designers carefully ensured that keyboard handlers could be
599 	 * stateless, then we turn around and use lots of state to
600 	 * emulate the stateful lk201, since the X11R5 X servers
601 	 * only know about the lk201... (oh well)
602 	 */
603 	if (event != DTOP_EVENT_RECEIVE_PACKET) {
604 		switch (event) {
605 		case DTOP_EVENT_POLL:
606 		    {
607 			register unsigned int	t, t0;
608 
609 			/*
610 			 * Note we will always have at least the
611 			 * end-of-list marker present (a zero)
612 			 * Here stop and trigger of autorepeat.
613 			 * Do not repeat shift keys, either.
614 			 */
615 			{
616 				register unsigned char	uc, i = 0;
617 
618 rpt_char:
619 				uc = dev->keyboard.last_codes[i];
620 
621 				if (uc == DTOP_KBD_EMPTY) {
622 					dev->keyboard.k_ar_state = K_AR_OFF;
623 					return 0;
624 				}
625 				if ((uc >= KEY_R_SHIFT) && (uc <= KEY_R_ALT)) {
626 					/* sometimes swapped. Grrr. */
627 					if (++i < dev->keyboard.last_codes_count)
628 						goto rpt_char;
629 					dev->keyboard.k_ar_state = K_AR_OFF;
630 					return 0;
631 				}
632 				c = uc;
633 			}
634 
635 			/*
636 			 * Got a char. See if enough time from stroke,
637 			 * or from last repeat.
638 			 */
639 			t0 = (dev->keyboard.k_ar_state == K_AR_TRIGGER) ? 30 : 500;
640 			t = TO_MS(time);
641 			if ((t - dev->keyboard.last_msec) < t0)
642 				return 0;
643 
644 			dev->keyboard.k_ar_state = K_AR_TRIGGER;
645 
646 			if (dtopDivertXInput) {
647 				(*dtopDivertXInput)(KEY_REPEAT);
648 				return (0);
649 			}
650 			if ((outc = kbdMapChar(KEY_REPEAT)) >= 0)
651 				(*linesw[tp->t_line].l_rint)(outc, tp);
652 			return 0;
653 		    }
654 		default:
655 			printf("Unknown dtop keyb\n");
656 		}
657 		return -1;
658 	}
659 
660 	msg_len = msg->code.val.len;
661 
662 	/* Check for errors */
663 	c = msg->body[0];
664 	if ((c < DTOP_KBD_KEY_MIN) && (c != DTOP_KBD_EMPTY)) {
665 		printf("Keyboard error: %x %x %x..\n", msg_len, c, msg->body[1]);
666 		if (c != DTOP_KBD_OUT_ERR) return -1;
667 		/* spec sez if scan list overflow still there is data */
668 		msg->body[0] = 0;
669 	}
670 
671 	dev->keyboard.last_msec = TO_MS(time);
672 
673 	switch (dev->keyboard.k_ar_state) {
674 	case K_AR_IDLE:
675 		if (outc != 0xff) /* from debugger, might be too early */
676 			dtop_keyboard_autorepeat(dev);
677 		/* fall through */
678 	case K_AR_TRIGGER:
679 		dev->keyboard.k_ar_state = K_AR_ACTIVE;
680 		break;
681 	case K_AR_ACTIVE:
682 		break;
683 	case K_AR_OFF:
684 		printf("dtop keyb off?\n");
685 		dev->keyboard.k_ar_state = K_AR_IDLE;
686 	}
687 
688 	/*
689 	 * To make things readable, do a first pass cancelling out
690 	 * all keys that are still pressed, and a second one generating
691 	 * events.  While generating events, do the upstrokes first
692 	 * from oldest to youngest, then the downstrokes from oldest
693 	 * to youngest.  This copes with lost packets and provides
694 	 * a reasonable model even if scans are too slow.
695 	 */
696 
697 	/* make a copy of new state first */
698 	if (msg_len == 1)
699 		save[0] = msg->body[0];
700 	else if (msg_len > 0)
701 		bcopy(msg->body, save, msg_len);
702 
703 	/*
704 	 * Cancel out any keys in both the last and current message as
705 	 * they are unchanged.
706 	 */
707 	if (msg_len > 0 && dev->keyboard.last_codes_count > 0) {
708 		ls = dev->keyboard.last_codes;
709 		le = &dev->keyboard.last_codes[dev->keyboard.last_codes_count];
710 		ne = &msg->body[msg_len];
711 		for (; ls < le; ls++) {
712 			for (ns = msg->body; ns < ne; ns++)
713 				if (*ls == *ns) {
714 					*ls = *ns = 0;
715 					break;
716 				}
717 		}
718 	}
719 
720 	/*
721 	 * Now generate all upstrokes
722 	 */
723 	le = dev->keyboard.last_codes;
724 	ls = &dev->keyboard.last_codes[dev->keyboard.last_codes_count - 1];
725 	for ( ; ls >= le; ls--)
726 	    if (c = *ls) {
727 		/*
728 		 * If there are no other down/up keys currently down, we
729 		 * should actually generate a KEY_UP, but that would require
730 		 * a lot more state.
731 		 */
732 		(void) kbdMapChar(c);
733 
734 		if (outc == 0 && dtopDivertXInput)
735 			(*dtopDivertXInput)(c);
736 	    }
737 	/*
738 	 * And finally the downstrokes
739 	 */
740 	ne = (char*)msg->body;
741 	ns = (char*)&msg->body[msg_len - 1];
742 	retc = 0;
743 	for ( ; ns >= ne; ns--)
744 	    if (*ns) {
745 		c = kbdMapChar(*ns);
746 		if (outc == 0) {
747 		    if (dtopDivertXInput) {
748 			(*dtopDivertXInput)(*ns);
749 			c = -1; /* consumed by X */
750 		    } else if (c >= 0)
751 			(*linesw[tp->t_line].l_rint)(c, tp);
752 		}
753 		/* return the related keycode anyways */
754 		if ((c >= 0) && (retc == 0))
755 		    retc = c;
756 	    }
757 	outc = retc;
758 	/* install new scan state */
759 	if (msg_len == 1)
760 		dev->keyboard.last_codes[0] = save[0];
761 	else if (msg_len > 0)
762 		bcopy(save, dev->keyboard.last_codes, msg_len);
763 	dev->keyboard.last_codes_count = msg_len;
764 	return (outc);
765 }
766 
767 /*
768  * Polled operations: we must do autorepeat by hand. Sigh.
769  */
770 void
771 dtop_keyboard_autorepeat(arg)
772 	void *arg;
773 {
774 	dtop_device_t dev = (dtop_device_t)arg;
775 	int s;
776 
777 	s = spltty();
778 	if (dev->keyboard.k_ar_state != K_AR_IDLE)
779 		(void)dtop_keyboard_handler(dev, 0, DTOP_EVENT_POLL, 0);
780 
781 	if (dev->keyboard.k_ar_state == K_AR_OFF)
782 		dev->keyboard.k_ar_state = K_AR_IDLE;
783 	else
784 		timeout(dtop_keyboard_autorepeat, dev, dev->keyboard.poll_frequency);
785 
786 	splx(s);
787 }
788 #endif
789