xref: /netbsd/sys/arch/hp300/dev/dnkbd.c (revision c8d03042)
1 /*	$NetBSD: dnkbd.c,v 1.5 2011/02/18 19:15:43 tsutsui Exp $	*/
2 /*	$OpenBSD: dnkbd.c,v 1.17 2009/07/23 21:05:56 blambert Exp $	*/
3 
4 /*
5  * Copyright (c) 2005, Miodrag Vallat
6  * Copyright (c) 1997 Michael Smith.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 /*
31  * Driver for the Apollo Domain keyboard and mouse.
32  */
33 
34 #include "opt_wsdisplay_compat.h"
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/device.h>
39 #include <sys/ioctl.h>
40 #include <sys/kernel.h>
41 #include <sys/callout.h>
42 #include <sys/conf.h>
43 #include <sys/bus.h>
44 #include <sys/cpu.h>
45 
46 #include <machine/autoconf.h>
47 
48 #include <dev/cons.h>
49 
50 #include <dev/wscons/wsconsio.h>
51 #include <dev/wscons/wskbdvar.h>
52 #include <dev/wscons/wsksymdef.h>
53 #include <dev/wscons/wsksymvar.h>
54 #include "wsmouse.h"
55 #if NWSMOUSE > 0
56 #include <dev/wscons/wsmousevar.h>
57 #endif
58 
59 #include <dev/ic/ns16550reg.h>
60 #include <dev/ic/comreg.h>
61 
62 #include <hp300/dev/dnkbdmap.h>
63 #include <hp300/dev/frodoreg.h>
64 #include <hp300/dev/frodovar.h>
65 
66 #include "hilkbd.h"
67 #include "ioconf.h"
68 
69 /*
70  * Keyboard key codes
71  */
72 
73 #define	DNKEY_CAPSLOCK	0x7e
74 #define	DNKEY_REPEAT	0x7f
75 #define	DNKEY_RELEASE	0x80
76 #define	DNKEY_CHANNEL	0xff
77 
78 /*
79  * Channels
80  */
81 
82 #define	DNCHANNEL_RESET	0x00
83 #define	DNCHANNEL_KBD	0x01
84 #define	DNCHANNEL_MOUSE	0x02
85 
86 /*
87  * Keyboard modes
88  */
89 
90 #define	DNMODE_COOKED	0x00
91 #define	DNMODE_RAW	0x01
92 
93 /*
94  * Keyboard commands
95  */
96 
97 #define	DNCMD_PREFIX	0xff
98 #define	DNCMD_COOKED	DNMODE_COOKED
99 #define	DNCMD_RAW	DNMODE_RAW
100 #define	DNCMD_IDENT_1	0x12
101 #define	DNCMD_IDENT_2	0x21
102 
103 /*
104  * Bell commands
105  */
106 
107 #define	DNCMD_BELL	0x21
108 #define	DNCMD_BELL_ON	0x81
109 #define	DNCMD_BELL_OFF	0x82
110 
111 /*
112  * Mouse status
113  */
114 
115 #define	DNBUTTON_L	0x10
116 #define	DNBUTTON_R	0x20
117 #define	DNBUTTON_M	0x40
118 
119 struct dnkbd_softc {
120 	device_t	sc_dev;
121 	bus_space_tag_t sc_bst;
122 	bus_space_handle_t sc_bsh;
123 
124 	int		sc_flags;
125 #define	SF_ENABLED	0x01		/* keyboard enabled */
126 #define	SF_CONSOLE	0x02		/* keyboard is console */
127 #define	SF_POLLING	0x04		/* polling mode */
128 #define	SF_PLUGGED	0x08		/* keyboard has been seen plugged */
129 #define	SF_ATTACHED	0x10		/* subdevices have been attached */
130 #define	SF_MOUSE	0x20		/* mouse enabled */
131 #define	SF_BELL		0x40		/* bell is active */
132 #define	SF_BELL_TMO	0x80		/* bell stop timeout is scheduled */
133 
134 	u_int		sc_identlen;
135 #define	MAX_IDENTLEN	32
136 	char		sc_ident[MAX_IDENTLEN];
137 	kbd_t		sc_layout;
138 
139 	enum { STATE_KEYBOARD, STATE_MOUSE, STATE_CHANNEL, STATE_ECHO }
140 			sc_state, sc_prevstate;
141 	u_int		sc_echolen;
142 
143 	uint8_t		sc_mousepkt[3];	/* mouse packet being constructed */
144 	u_int		sc_mousepos;	/* index in above */
145 
146 	struct callout	sc_bellstop_tmo;
147 
148 	device_t	sc_wskbddev;
149 #if NWSMOUSE > 0
150 	device_t	sc_wsmousedev;
151 #endif
152 
153 #ifdef WSDISPLAY_COMPAT_RAWKBD
154 	int		sc_rawkbd;
155 	int		sc_nrep;
156 	char		sc_rep[2];	/* at most, one key */
157 	struct callout	sc_rawrepeat_ch;
158 #define	REP_DELAY1	400
159 #define	REP_DELAYN	100
160 #endif
161 };
162 
163 static int	dnkbd_match(device_t, cfdata_t, void *);
164 static void	dnkbd_attach(device_t, device_t, void *);
165 
166 CFATTACH_DECL_NEW(dnkbd, sizeof(struct dnkbd_softc),
167     dnkbd_match, dnkbd_attach, NULL, NULL);
168 
169 static void	dnkbd_init(struct dnkbd_softc *, uint16_t, uint16_t);
170 static int	dnkbd_enable(void *, int);
171 static void	dnkbd_set_leds(void *, int);
172 static int	dnkbd_ioctl(void *, u_long, void *, int, struct lwp *);
173 
174 static const struct wskbd_accessops dnkbd_accessops = {
175 	dnkbd_enable,
176 	dnkbd_set_leds,
177 	dnkbd_ioctl
178 };
179 
180 #if NWSMOUSE > 0
181 static int	dnmouse_enable(void *);
182 static int	dnmouse_ioctl(void *, u_long, void *, int, struct lwp *);
183 static void	dnmouse_disable(void *);
184 
185 static const struct wsmouse_accessops dnmouse_accessops = {
186 	dnmouse_enable,
187 	dnmouse_ioctl,
188 	dnmouse_disable
189 };
190 #endif
191 
192 static void	dnkbd_bell(void *, u_int, u_int, u_int);
193 static void	dnkbd_cngetc(void *, u_int *, int *);
194 static void	dnkbd_cnpollc(void *, int);
195 
196 static const struct wskbd_consops dnkbd_consops = {
197 	dnkbd_cngetc,
198 	dnkbd_cnpollc,
199 	dnkbd_bell
200 };
201 
202 static struct wskbd_mapdata dnkbd_keymapdata = {
203 	dnkbd_keydesctab,
204 #ifdef DNKBD_LAYOUT
205 	DNKBD_LAYOUT
206 #else
207 	KB_US
208 #endif
209 };
210 
211 typedef enum { EVENT_NONE, EVENT_KEYBOARD, EVENT_MOUSE } dnevent;
212 
213 static void	dnevent_kbd(struct dnkbd_softc *, int);
214 static void	dnevent_kbd_internal(struct dnkbd_softc *, int);
215 static void	dnevent_mouse(struct dnkbd_softc *, uint8_t *);
216 static void	dnkbd_attach_subdevices(struct dnkbd_softc *);
217 static void	dnkbd_bellstop(void *);
218 static void	dnkbd_decode(int, u_int *, int *);
219 static dnevent	dnkbd_input(struct dnkbd_softc *, int);
220 static int	dnkbd_intr(void *);
221 static int	dnkbd_pollin(struct dnkbd_softc *, u_int);
222 static int	dnkbd_pollout(struct dnkbd_softc *, int);
223 static int	dnkbd_probe(struct dnkbd_softc *);
224 #ifdef WSDISPLAY_COMPAT_RAWKBD
225 static void	dnkbd_rawrepeat(void *);
226 #endif
227 static int	dnkbd_send(struct dnkbd_softc *, const uint8_t *, size_t);
228 static int	dnsubmatch_kbd(device_t, cfdata_t, const int *, void *);
229 static int	dnsubmatch_mouse(device_t, cfdata_t, const int *, void *);
230 
231 int
232 dnkbd_match(device_t parent, cfdata_t cf, void *aux)
233 {
234 	struct frodo_attach_args *fa = aux;
235 
236 	if (strcmp(fa->fa_name, dnkbd_cd.cd_name) != 0)
237 		return 0;
238 
239 	if (machineid == HP_382) {
240 		/* 382 has frodo but no Domain keyboard connector. */
241 		return 0;
242 	}
243 
244 	/* only attach to the first frodo port */
245 	return fa->fa_offset == FRODO_APCI_OFFSET(0);
246 }
247 
248 void
249 dnkbd_attach(device_t parent, device_t self, void *aux)
250 {
251 	struct dnkbd_softc *sc = device_private(self);
252 	struct frodo_attach_args *fa = aux;
253 
254 	aprint_normal(": ");
255 
256 	sc->sc_dev = self;
257 	sc->sc_bst = fa->fa_bst;
258 	if (bus_space_map(sc->sc_bst, fa->fa_base + fa->fa_offset,
259 	    FRODO_APCISPACE, 0, &sc->sc_bsh) != 0) {
260 		aprint_error(": can't map i/o space\n");
261 		return;
262 	}
263 
264 	callout_init(&sc->sc_bellstop_tmo, 0);
265 	callout_setfunc(&sc->sc_bellstop_tmo, dnkbd_bellstop, sc);
266 #ifdef WSDISPLAY_COMPAT_RAWKBD
267 	callout_init(&sc->sc_rawrepeat_ch, 0);
268 	callout_setfunc(&sc->sc_rawrepeat_ch, dnkbd_rawrepeat, sc);
269 #endif
270 
271 	/* reset the port */
272 	dnkbd_init(sc, 1200, LCR_8BITS | LCR_PEVEN | LCR_PENAB);
273 
274 	frodo_intr_establish(parent, dnkbd_intr, sc, fa->fa_line, IPL_VM);
275 
276 	/* probe for keyboard */
277 	if (dnkbd_probe(sc) != 0) {
278 		aprint_normal("no keyboard\n");
279 		return;
280 	}
281 
282 	dnkbd_attach_subdevices(sc);
283 }
284 
285 void
286 dnkbd_init(struct dnkbd_softc *sc, uint16_t rate, uint16_t lctl)
287 {
288 	bus_space_tag_t bst;
289 	bus_space_handle_t bsh;
290 
291 	bst = sc->sc_bst;
292 	bsh = sc->sc_bsh;
293 
294 	bus_space_write_1(bst, bsh, com_lctl, LCR_DLAB);
295 	bus_space_write_1(bst, bsh, com_dlbl, rate & 0xff);
296 	bus_space_write_1(bst, bsh, com_dlbh, (rate >> 8) & 0xff);
297 	bus_space_write_1(bst, bsh, com_lctl, lctl);
298 	bus_space_write_1(bst, bsh, com_ier, IER_ERXRDY | IER_ETXRDY);
299 	bus_space_write_1(bst, bsh, com_fifo,
300 	    FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_1);
301 	bus_space_write_1(bst, bsh, com_mcr, MCR_DTR | MCR_RTS);
302 
303 	delay(100);
304 }
305 
306 void
307 dnkbd_attach_subdevices(struct dnkbd_softc *sc)
308 {
309 	struct wskbddev_attach_args ka;
310 #if NWSMOUSE > 0
311 	struct wsmousedev_attach_args ma;
312 #endif
313 #if NHILKBD > 0
314 	extern int hil_is_console;
315 #endif
316 
317 	/*
318 	 * If both hilkbd and dnkbd are configured, prefer the Domain
319 	 * keyboard as console (if we are here, we know the keyboard is
320 	 * plugged), unless the console keyboard has been claimed already
321 	 * (i.e. late hotplug with hil keyboard plugged first).
322 	 */
323 	if (major(cn_tab->cn_dev) == devsw_name2chr("wsdisplay", NULL, 0)) {
324 #if NHILKBD > 0
325 		if (hil_is_console == -1) {
326 			ka.console = 1;
327 			hil_is_console = 0;
328 		} else
329 			ka.console = 0;
330 #else
331 		ka.console = 1;
332 #endif
333 	} else
334 		ka.console = 0;
335 
336 	ka.keymap = &dnkbd_keymapdata;
337 	ka.accessops = &dnkbd_accessops;
338 	ka.accesscookie = sc;
339 #ifndef DKKBD_LAYOUT
340 	dnkbd_keymapdata.layout = sc->sc_layout;
341 #endif
342 
343 	if (ka.console) {
344 		sc->sc_flags = SF_PLUGGED | SF_CONSOLE | SF_ENABLED;
345 		wskbd_cnattach(&dnkbd_consops, sc, &dnkbd_keymapdata);
346 	} else {
347 		sc->sc_flags = SF_PLUGGED;
348 	}
349 
350 	sc->sc_wskbddev = config_found_sm_loc(sc->sc_dev, "dnkbd", NULL, &ka,
351 	    wskbddevprint, dnsubmatch_kbd);
352 
353 #if NWSMOUSE > 0
354 	ma.accessops = &dnmouse_accessops;
355 	ma.accesscookie = sc;
356 
357 	sc->sc_wsmousedev = config_found_sm_loc(sc->sc_dev, "dnkbd", NULL, &ma,
358 	    wsmousedevprint, dnsubmatch_mouse);
359 #endif
360 
361 	SET(sc->sc_flags, SF_ATTACHED);
362 }
363 
364 int
365 dnsubmatch_kbd(device_t parent, cfdata_t cf, const int *locs, void *aux)
366 {
367 
368 	if (strcmp(cf->cf_name, wskbd_cd.cd_name) != 0)
369 		return 0;
370 
371 	return config_match(parent, cf, aux);
372 }
373 
374 #if NWSMOUSE > 0
375 int
376 dnsubmatch_mouse(device_t parent, cfdata_t cf, const int *locs, void *aux)
377 {
378 
379 	if (strcmp(cf->cf_name, wsmouse_cd.cd_name) != 0)
380 		return 0;
381 
382 	return config_match(parent, cf, aux);
383 }
384 #endif
385 
386 int
387 dnkbd_probe(struct dnkbd_softc *sc)
388 {
389 	int dat, rc, flags;
390 	uint8_t cmdbuf[2];
391 	char rspbuf[MAX_IDENTLEN], *word, *end;
392 	u_int i;
393 	int s;
394 
395 	s = spltty();
396 	flags = sc->sc_flags;
397 	SET(sc->sc_flags, SF_POLLING);
398 	sc->sc_state = STATE_CHANNEL;
399 	splx(s);
400 
401 	/*
402 	 * Switch keyboard to raw mode.
403 	 */
404 	cmdbuf[0] = DNCMD_RAW;
405 	rc = dnkbd_send(sc, cmdbuf, 1);
406 	if (rc != 0)
407 		goto out;
408 
409 	/*
410 	 * Send the identify command.
411 	 */
412 	cmdbuf[0] = DNCMD_IDENT_1;
413 	cmdbuf[1] = DNCMD_IDENT_2;
414 	rc = dnkbd_send(sc, cmdbuf, 2);
415 	if (rc != 0)
416 		goto out;
417 
418 	for (i = 0; ; i++) {
419 		dat = dnkbd_pollin(sc, 10000);
420 		if (dat == -1)
421 			break;
422 
423 		if (i < sizeof(rspbuf))
424 			rspbuf[i] = dat;
425 	}
426 
427 	if (i > sizeof(rspbuf) || i == 0) {
428 		aprint_error_dev(sc->sc_dev,
429 		    "unexpected identify string length %d\n", i);
430 		rc = ENXIO;
431 		goto out;
432 	}
433 
434 	/*
435 	 * Make sure the identification string is NULL terminated
436 	 * (overwriting the keyboard mode byte if necessary).
437 	 */
438 	i--;
439 	if (rspbuf[i] != 0)
440 		rspbuf[i] = 0;
441 
442 	/*
443 	 * Now display the identification strings, if they changed.
444 	 */
445 	if (i != sc->sc_identlen || memcmp(rspbuf, sc->sc_ident, i) != 0) {
446 		sc->sc_layout = KB_US;
447 		sc->sc_identlen = i;
448 		memcpy(sc->sc_ident, rspbuf, i);
449 
450 		if (cold == 0)
451 			aprint_normal_dev(sc->sc_dev, "");
452 		aprint_normal("model ");
453 		word = rspbuf;
454 		for (i = 0; i < 3; i++) {
455 			end = strchr(word, '\r');
456 			if (end == NULL)
457 				break;
458 			*end++ = '\0';
459 			aprint_normal("<%s> ", word);
460 			/*
461 			 * Parse the layout code if applicable
462 			 */
463 			if (i == 1 && *word++ == '3') {
464 				if (*word == '-')
465 					word++;
466 				switch (*word) {
467 #if 0
468 				default:
469 				case ' ':
470 					sc->sc_layout = KB_US;
471 					break;
472 #endif
473 				case 'a':
474 					sc->sc_layout = KB_DE;
475 					break;
476 				case 'b':
477 					sc->sc_layout = KB_FR;
478 					break;
479 				case 'c':
480 					sc->sc_layout = KB_DK;
481 					break;
482 				case 'd':
483 					sc->sc_layout = KB_SV;
484 					break;
485 				case 'e':
486 					sc->sc_layout = KB_UK;
487 					break;
488 				case 'f':
489 					sc->sc_layout = KB_JP;
490 					break;
491 				case 'g':
492 					sc->sc_layout = KB_SG;
493 					break;
494 				}
495 			}
496 			word = end;
497 		}
498 		aprint_normal("\n");
499 	}
500 
501 	/*
502 	 * Ready to work, the default channel is the keyboard.
503 	 */
504 	sc->sc_state = STATE_KEYBOARD;
505 
506 out:
507 	s = spltty();
508 	sc->sc_flags = flags;
509 	splx(s);
510 
511 	return rc;
512 }
513 
514 /*
515  * State machine.
516  *
517  * In raw mode, the keyboard may feed us the following sequences:
518  * - on the keyboard channel:
519  *   + a raw key code, in the range 0x01-0x7e, or'ed with 0x80 if key release.
520  *   + the key repeat sequence 0x7f.
521  * - on the mouse channel:
522  *   + a 3 byte mouse sequence (buttons state, dx move, dy move).
523  * - at any time:
524  *   + a 2 byte channel sequence (0xff followed by the channel number) telling
525  *     us which device the following input will come from.
526  *   + if we get 0xff but an invalid channel number, this is a command echo.
527  *     Currently we only handle this for bell commands, which size are known.
528  *     Other commands are issued through dnkbd_send() which ``eats'' the echo.
529  *
530  * Older keyboards reset the channel to the keyboard (by sending ff 01) after
531  * every mouse packet.
532  */
533 
534 dnevent
535 dnkbd_input(struct dnkbd_softc *sc, int dat)
536 {
537 	dnevent event = EVENT_NONE;
538 
539 	switch (sc->sc_state) {
540 	case STATE_KEYBOARD:
541 		switch (dat) {
542 		case DNKEY_REPEAT:
543 			/*
544 			 * We ignore event repeats, as wskbd does its own
545 			 * soft repeat processing.
546 			 */
547 			break;
548 		case DNKEY_CHANNEL:
549 			sc->sc_prevstate = sc->sc_state;
550 			sc->sc_state = STATE_CHANNEL;
551 			break;
552 		default:
553 			event = EVENT_KEYBOARD;
554 			break;
555 		}
556 		break;
557 
558 	case STATE_MOUSE:
559 		if (dat == DNKEY_CHANNEL && sc->sc_mousepos == 0) {
560 			sc->sc_prevstate = sc->sc_state;
561 			sc->sc_state = STATE_CHANNEL;
562 		} else {
563 			sc->sc_mousepkt[sc->sc_mousepos++] = dat;
564 			if (sc->sc_mousepos == sizeof(sc->sc_mousepkt)) {
565 				sc->sc_mousepos = 0;
566 				event = EVENT_MOUSE;
567 			}
568 		}
569 		break;
570 
571 	case STATE_CHANNEL:
572 		switch (dat) {
573 		case DNKEY_CHANNEL:
574 			/*
575 			 * During hotplug, we might get spurious 0xff bytes.
576 			 * Ignore them.
577 			 */
578 			break;
579 		case DNCHANNEL_RESET:
580 			/*
581 			 * Identify the keyboard again. This will switch it to
582 			 * raw mode again. If this fails, we'll consider the
583 			 * keyboard as unplugged (to ignore further events until
584 			 * a successful reset).
585 			 */
586 			if (dnkbd_probe(sc) == 0) {
587 				/*
588 				 * We need to attach wskbd and wsmouse children
589 				 * if this is a live first plug.
590 				 */
591 				if (!ISSET(sc->sc_flags, SF_ATTACHED))
592 					dnkbd_attach_subdevices(sc);
593 				SET(sc->sc_flags, SF_PLUGGED);
594 			} else {
595 				CLR(sc->sc_flags, SF_PLUGGED);
596 			}
597 
598 			sc->sc_state = STATE_KEYBOARD;
599 			break;
600 		case DNCHANNEL_KBD:
601 			sc->sc_state = STATE_KEYBOARD;
602 			break;
603 		case DNCHANNEL_MOUSE:
604 			sc->sc_state = STATE_MOUSE;
605 			sc->sc_mousepos = 0;	/* just in case */
606 			break;
607 		case DNCMD_BELL:
608 			/*
609 			 * We are getting a bell command echoed to us.
610 			 * Ignore it.
611 			 */
612 			sc->sc_state = STATE_ECHO;
613 			sc->sc_echolen = 1;	/* one byte to follow */
614 			break;
615 		default:
616 			printf("%s: unexpected channel byte %02x\n",
617 			    device_xname(sc->sc_dev), dat);
618 			break;
619 		}
620 		break;
621 
622 	case STATE_ECHO:
623 		if (--sc->sc_echolen == 0) {
624 			/* get back to the state we were in before the echo */
625 			sc->sc_state = sc->sc_prevstate;
626 		}
627 		break;
628 	}
629 
630 	return event;
631 }
632 
633 /*
634  * Event breakers.
635  */
636 
637 void
638 dnkbd_decode(int keycode, u_int *type, int *key)
639 {
640 	*type = (keycode & DNKEY_RELEASE) ?
641 	    WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN;
642 	*key = (keycode & ~DNKEY_RELEASE);
643 }
644 
645 void
646 dnevent_kbd(struct dnkbd_softc *sc, int dat)
647 {
648 	if (!ISSET(sc->sc_flags, SF_PLUGGED))
649 		return;
650 
651 	if (sc->sc_wskbddev == NULL)
652 		return;
653 
654 	if (!ISSET(sc->sc_flags, SF_ENABLED))
655 		return;
656 
657 	/*
658 	 * Even in raw mode, the caps lock key is treated specially:
659 	 * first key press causes event 0x7e, release causes no event;
660 	 * then a new key press causes nothing, and release causes
661 	 * event 0xfe. Moreover, while kept down, it does not produce
662 	 * repeat events.
663 	 *
664 	 * So the best we can do is fake the missed events, but this
665 	 * will not allow the capslock key to be remapped as a control
666 	 * key since it will not be possible to chord it with anything.
667 	 */
668 	dnevent_kbd_internal(sc, dat);
669 	if ((dat & ~DNKEY_RELEASE) == DNKEY_CAPSLOCK)
670 		dnevent_kbd_internal(sc, dat ^ DNKEY_RELEASE);
671 }
672 
673 void
674 dnevent_kbd_internal(struct dnkbd_softc *sc, int dat)
675 {
676 	u_int type;
677 	int key;
678 	int s;
679 
680 	dnkbd_decode(dat, &type, &key);
681 
682 #ifdef WSDISPLAY_COMPAT_RAWKBD
683 	if (sc->sc_rawkbd) {
684 		u_char cbuf[2];
685 		int c, j = 0;
686 
687 		c = dnkbd_raw[key];
688 		if (c != 0) {
689 			/* fake extended scancode if necessary */
690 			if (c & 0x80)
691 				cbuf[j++] = 0xe0;
692 			cbuf[j] = c & 0x7f;
693 			if (type == WSCONS_EVENT_KEY_UP)
694 				cbuf[j] |= 0x80;
695 			else {
696 				/* remember pressed key for autorepeat */
697 				memcpy(sc->sc_rep, cbuf, sizeof(sc->sc_rep));
698 			}
699 			j++;
700 		}
701 
702 		if (j != 0) {
703 			s = spltty();
704 			wskbd_rawinput(sc->sc_wskbddev, cbuf, j);
705 			splx(s);
706 			callout_stop(&sc->sc_rawrepeat_ch);
707 			sc->sc_nrep = j;
708 			callout_schedule(&sc->sc_rawrepeat_ch,
709 			    mstohz(REP_DELAY1));
710 		}
711 	} else
712 #endif
713 	{
714 		s = spltty();
715 		wskbd_input(sc->sc_wskbddev, type, key);
716 		splx(s);
717 	}
718 }
719 
720 #ifdef WSDISPLAY_COMPAT_RAWKBD
721 void
722 dnkbd_rawrepeat(void *v)
723 {
724 	struct dnkbd_softc *sc = v;
725 	int s;
726 
727 	s = spltty();
728 	wskbd_rawinput(sc->sc_wskbddev, sc->sc_rep, sc->sc_nrep);
729 	splx(s);
730 
731 	callout_schedule(&sc->sc_rawrepeat_ch, mstohz(REP_DELAYN));
732 }
733 #endif
734 
735 #if NWSMOUSE > 0
736 void
737 dnevent_mouse(struct dnkbd_softc *sc, uint8_t *dat)
738 {
739 	if (!ISSET(sc->sc_flags, SF_PLUGGED))
740 		return;
741 
742 	if (sc->sc_wsmousedev == NULL)
743 		return;
744 
745 	if (!ISSET(sc->sc_flags, SF_MOUSE))
746 		return;
747 
748 	/*
749 	 * First byte is button status. It has the 0x80 bit always set, and
750 	 * the next 3 bits are *cleared* when the mouse buttons are pressed.
751 	 */
752 #ifdef DEBUG
753 	if (!ISSET(*dat, 0x80)) {
754 		printf("%s: incorrect mouse packet %02x %02x %02x\n",
755 		    device_xname(sc->sc_dev), dat[0], dat[1], dat[2]);
756 		return;
757 	}
758 #endif
759 
760 	wsmouse_input(sc->sc_wsmousedev,
761 	    (~dat[0] & (DNBUTTON_L | DNBUTTON_M | DNBUTTON_R)) >> 4,
762 	    (int8_t)dat[1], (int8_t)dat[2], 0, 0, WSMOUSE_INPUT_DELTA);
763 }
764 #endif
765 
766 /*
767  * Low-level communication routines.
768  */
769 
770 int
771 dnkbd_pollin(struct dnkbd_softc *sc, u_int tries)
772 {
773 	bus_space_tag_t bst;
774 	bus_space_handle_t bsh;
775 	u_int cnt;
776 
777 	bst = sc->sc_bst;
778 	bsh = sc->sc_bsh;
779 
780 	for (cnt = tries; cnt != 0; cnt--) {
781 		if (bus_space_read_1(bst, bsh, com_lsr) & LSR_RXRDY)
782 			break;
783 		DELAY(10);
784 	}
785 
786 	if (cnt == 0)
787 		return -1;
788 	else
789 		return (int)bus_space_read_1(bst, bsh, com_data);
790 }
791 
792 int
793 dnkbd_pollout(struct dnkbd_softc *sc, int dat)
794 {
795 	bus_space_tag_t bst;
796 	bus_space_handle_t bsh;
797 	u_int cnt;
798 
799 	bst = sc->sc_bst;
800 	bsh = sc->sc_bsh;
801 
802 	for (cnt = 10000; cnt != 0; cnt--) {
803 		if (bus_space_read_1(bst, bsh, com_lsr) & LSR_TXRDY)
804 			break;
805 		DELAY(10);
806 	}
807 	if (cnt == 0)
808 		return EBUSY;
809 	else {
810 		bus_space_write_1(bst, bsh, com_data, dat);
811 		return 0;
812 	}
813 }
814 
815 int
816 dnkbd_send(struct dnkbd_softc *sc, const uint8_t *cmdbuf, size_t cmdlen)
817 {
818 	int cnt, rc, dat;
819 	u_int cmdpos;
820 
821 	/* drain rxfifo */
822 	for (cnt = 10; cnt != 0; cnt--) {
823 		if (dnkbd_pollin(sc, 10) == -1)
824 			break;
825 	}
826 	if (cnt == 0)
827 		return EBUSY;
828 
829 	/* send command escape */
830 	if ((rc = dnkbd_pollout(sc, DNCMD_PREFIX)) != 0)
831 		return rc;
832 
833 	/* send command buffer */
834 	for (cmdpos = 0; cmdpos < cmdlen; cmdpos++) {
835 		if ((rc = dnkbd_pollout(sc, cmdbuf[cmdpos])) != 0)
836 			return rc;
837 	}
838 
839 	/* wait for command echo */
840 	do {
841 		dat = dnkbd_pollin(sc, 10000);
842 		if (dat == -1)
843 			return EIO;
844 	} while (dat != DNCMD_PREFIX);
845 
846 	for (cmdpos = 0; cmdpos < cmdlen; cmdpos++) {
847 		dat = dnkbd_pollin(sc, 10000);
848 		if (dat != cmdbuf[cmdpos])
849 			return EIO;
850 	}
851 
852 	return 0;
853 }
854 
855 int
856 dnkbd_intr(void *v)
857 {
858 	struct dnkbd_softc *sc = v;
859 	bus_space_tag_t bst;
860 	bus_space_handle_t bsh;
861 	uint8_t iir, lsr, c;
862 	int claimed = 0;
863 
864 	bst = sc->sc_bst;
865 	bsh = sc->sc_bsh;
866 
867 	for (;;) {
868 		iir = bus_space_read_1(bst, bsh, com_iir);
869 
870 		switch (iir & IIR_IMASK) {
871 		case IIR_RLS:
872 			/*
873 			 * Line status change. This should never happen,
874 			 * so silently ack the interrupt.
875 			 */
876 			c = bus_space_read_1(bst, bsh, com_lsr);
877 			break;
878 
879 		case IIR_RXRDY:
880 		case IIR_RXTOUT:
881 			/*
882 			 * Data available. We process it byte by byte,
883 			 * unless we are doing polling work...
884 			 */
885 			if (ISSET(sc->sc_flags, SF_POLLING)) {
886 				return 1;
887 			}
888 
889 			for (;;) {
890 				c = bus_space_read_1(bst, bsh, com_data);
891 				switch (dnkbd_input(sc, c)) {
892 				case EVENT_KEYBOARD:
893 					dnevent_kbd(sc, c);
894 					break;
895 #if NWSMOUSE > 0
896 				case EVENT_MOUSE:
897 					dnevent_mouse(sc, sc->sc_mousepkt);
898 					break;
899 #endif
900 				default:	/* appease gcc */
901 					break;
902 				}
903 				lsr = bus_space_read_1(bst, bsh, com_lsr) &
904 				    LSR_RCV_MASK;
905 				if (lsr == 0)
906 					break;
907 				else if (lsr != LSR_RXRDY) {
908 					/* ignore error */
909 					break;
910 				}
911 			}
912 			break;
913 
914 		case IIR_TXRDY:
915 			/*
916 			 * Transmit available. Since we do all our commands
917 			 * in polling mode, we do not need to do anything here.
918 			 */
919 			break;
920 
921 		default:
922 			if (iir & IIR_NOPEND)
923 				return claimed;
924 			/* FALLTHROUGH */
925 
926 		case IIR_MLSC:
927 			/*
928 			 * Modem status change. This should never happen,
929 			 * so silently ack the interrupt.
930 			 */
931 			c = bus_space_read_1(bst, bsh, com_msr);
932 			break;
933 		}
934 
935 		claimed = 1;
936 	}
937 }
938 
939 /*
940  * Wskbd callbacks
941  */
942 
943 int
944 dnkbd_enable(void *v, int on)
945 {
946 	struct dnkbd_softc *sc = v;
947 
948 	if (on) {
949 		if (ISSET(sc->sc_flags, SF_ENABLED))
950 			return EBUSY;
951 		SET(sc->sc_flags, SF_ENABLED);
952 	} else {
953 		if (ISSET(sc->sc_flags, SF_CONSOLE))
954 			return EBUSY;
955 		CLR(sc->sc_flags, SF_ENABLED);
956 	}
957 
958 	return 0;
959 }
960 
961 void
962 dnkbd_set_leds(void *v, int leds)
963 {
964 	/*
965 	 * Not supported. There is only one LED on this keyboard, and
966 	 * is hardware tied to the caps lock key.
967 	 */
968 }
969 
970 int
971 dnkbd_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
972 {
973 #ifdef WSDISPLAY_COMPAT_RAWKBD
974 	struct dnkbd_softc *sc = v;
975 #endif
976 
977 #define WSKBD_TYPE_UNKNOWN	0
978 
979 	switch (cmd) {
980 	case WSKBDIO_GTYPE:
981 		*(int *)data = WSKBD_TYPE_UNKNOWN;	/* XXX */
982 		return 0;
983 	case WSKBDIO_SETLEDS:
984 		return ENXIO;
985 	case WSKBDIO_GETLEDS:
986 		*(int *)data = 0;
987 		return 0;
988 	case WSKBDIO_COMPLEXBELL:
989 #define	d	((struct wskbd_bell_data *)data)
990 		dnkbd_bell(v, d->period, d->pitch, d->volume);
991 #undef d
992 		return 0;
993 #ifdef WSDISPLAY_COMPAT_RAWKBD
994 	case WSKBDIO_SETMODE:
995 		sc->sc_rawkbd = *(int *)data == WSKBD_RAW;
996 		callout_stop(&sc->sc_rawrepeat_ch);
997 		return 0;
998 #endif
999 	}
1000 
1001 	return EPASSTHROUGH;
1002 }
1003 
1004 #if NWSMOUSE > 0
1005 /*
1006  * Wsmouse callbacks
1007  */
1008 
1009 int
1010 dnmouse_enable(void *v)
1011 {
1012 	struct dnkbd_softc *sc = v;
1013 
1014 	if (ISSET(sc->sc_flags, SF_MOUSE))
1015 		return EBUSY;
1016 	SET(sc->sc_flags, SF_MOUSE);
1017 
1018 	return 0;
1019 }
1020 
1021 int
1022 dnmouse_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
1023 {
1024 #if 0
1025 	struct dnkbd_softc *sc = v;
1026 #endif
1027 
1028 #define WSMOUSE_TYPE_UNKNOWN	0
1029 
1030 	switch (cmd) {
1031 	case WSMOUSEIO_GTYPE:
1032 		*(int *)data = WSMOUSE_TYPE_UNKNOWN;	/* XXX */
1033 		return 0;
1034 	}
1035 
1036 	return -1;
1037 }
1038 
1039 void
1040 dnmouse_disable(void *v)
1041 {
1042 	struct dnkbd_softc *sc = v;
1043 
1044 	CLR(sc->sc_flags, SF_MOUSE);
1045 }
1046 #endif
1047 
1048 /*
1049  * Console support
1050  */
1051 
1052 void
1053 dnkbd_cngetc(void *v, u_int *type, int *data)
1054 {
1055 	static int lastdat = 0;
1056 	struct dnkbd_softc *sc = v;
1057 	int s;
1058 	int dat;
1059 
1060 	/* Take care of caps lock */
1061 	if ((lastdat & ~DNKEY_RELEASE) == DNKEY_CAPSLOCK) {
1062 		dat = lastdat ^ DNKEY_RELEASE;
1063 		lastdat = 0;
1064 	} else {
1065 		for (;;) {
1066 			s = splhigh();
1067 			dat = dnkbd_pollin(sc, 10000);
1068 			if (dat != -1) {
1069 				if (dnkbd_input(sc, dat) == EVENT_KEYBOARD) {
1070 					splx(s);
1071 					break;
1072 				}
1073 			}
1074 			splx(s);
1075 		}
1076 		lastdat = dat;
1077 	}
1078 
1079 	dnkbd_decode(dat, type, data);
1080 }
1081 
1082 void
1083 dnkbd_cnpollc(void *v, int on)
1084 {
1085 	struct dnkbd_softc *sc = v;
1086 
1087 	if (on)
1088 		SET(sc->sc_flags, SF_POLLING);
1089 	else
1090 		CLR(sc->sc_flags, SF_POLLING);
1091 }
1092 
1093 /*
1094  * Bell routines.
1095  */
1096 void
1097 dnkbd_bell(void *v, u_int period, u_int pitch, u_int volume)
1098 {
1099 	struct dnkbd_softc *sc = v;
1100 	int s;
1101 
1102 	s = spltty();
1103 
1104 	if (pitch == 0 || period == 0 || volume == 0) {
1105 		if (ISSET(sc->sc_flags, SF_BELL_TMO)) {
1106 			callout_stop(&sc->sc_bellstop_tmo);
1107 			dnkbd_bellstop(v);
1108 		}
1109 	} else {
1110 
1111 		if (!ISSET(sc->sc_flags, SF_BELL)) {
1112 			dnkbd_pollout(sc, DNCMD_PREFIX);
1113 			dnkbd_pollout(sc, DNCMD_BELL);
1114 			dnkbd_pollout(sc, DNCMD_BELL_ON);
1115 			SET(sc->sc_flags, SF_BELL);
1116 		}
1117 
1118 		if (ISSET(sc->sc_flags, SF_BELL_TMO))
1119 			callout_stop(&sc->sc_bellstop_tmo);
1120 		callout_schedule(&sc->sc_bellstop_tmo, period);
1121 		SET(sc->sc_flags, SF_BELL_TMO);
1122 	}
1123 
1124 	splx(s);
1125 }
1126 
1127 void
1128 dnkbd_bellstop(void *v)
1129 {
1130 	struct dnkbd_softc *sc = v;
1131 	int s;
1132 
1133 	s = spltty();
1134 
1135 	dnkbd_pollout(sc, DNCMD_PREFIX);
1136 	dnkbd_pollout(sc, DNCMD_BELL);
1137 	dnkbd_pollout(sc, DNCMD_BELL_OFF);
1138 	CLR(sc->sc_flags, SF_BELL);
1139 	CLR(sc->sc_flags, SF_BELL_TMO);
1140 
1141 	splx(s);
1142 }
1143