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