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