xref: /netbsd/sys/arch/hp300/dev/dnkbd.c (revision 487c217e)
1 /*	$NetBSD: dnkbd.c,v 1.6 2014/04/24 11:58:04 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 #define APCIBRD(x)	(500000 / (x))
214 
215 static void	dnevent_kbd(struct dnkbd_softc *, int);
216 static void	dnevent_kbd_internal(struct dnkbd_softc *, int);
217 static void	dnevent_mouse(struct dnkbd_softc *, uint8_t *);
218 static void	dnkbd_attach_subdevices(struct dnkbd_softc *);
219 static void	dnkbd_bellstop(void *);
220 static void	dnkbd_decode(int, u_int *, int *);
221 static dnevent	dnkbd_input(struct dnkbd_softc *, int);
222 static int	dnkbd_intr(void *);
223 static int	dnkbd_pollin(struct dnkbd_softc *, u_int);
224 static int	dnkbd_pollout(struct dnkbd_softc *, int);
225 static int	dnkbd_probe(struct dnkbd_softc *);
226 #ifdef WSDISPLAY_COMPAT_RAWKBD
227 static void	dnkbd_rawrepeat(void *);
228 #endif
229 static int	dnkbd_send(struct dnkbd_softc *, const uint8_t *, size_t);
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 	u_int divisor;
291 
292 	bst = sc->sc_bst;
293 	bsh = sc->sc_bsh;
294 
295 	divisor = APCIBRD(rate);
296 	bus_space_write_1(bst, bsh, com_lctl, LCR_DLAB);
297 	bus_space_write_1(bst, bsh, com_dlbl, divisor & 0xff);
298 	bus_space_write_1(bst, bsh, com_dlbh, (divisor >> 8) & 0xff);
299 	bus_space_write_1(bst, bsh, com_lctl, lctl);
300 	bus_space_write_1(bst, bsh, com_ier, IER_ERXRDY | IER_ETXRDY);
301 	bus_space_write_1(bst, bsh, com_fifo,
302 	    FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_1);
303 	bus_space_write_1(bst, bsh, com_mcr, MCR_DTR | MCR_RTS);
304 
305 	delay(100);
306 	(void)bus_space_read_1(bst, bsh, com_iir);
307 }
308 
309 void
310 dnkbd_attach_subdevices(struct dnkbd_softc *sc)
311 {
312 	struct wskbddev_attach_args ka;
313 #if NWSMOUSE > 0
314 	struct wsmousedev_attach_args ma;
315 #endif
316 #if NHILKBD > 0
317 	extern int hil_is_console;
318 #endif
319 
320 	/*
321 	 * If both hilkbd and dnkbd are configured, prefer the Domain
322 	 * keyboard as console (if we are here, we know the keyboard is
323 	 * plugged), unless the console keyboard has been claimed already
324 	 * (i.e. late hotplug with hil keyboard plugged first).
325 	 */
326 	if (major(cn_tab->cn_dev) == devsw_name2chr("wsdisplay", NULL, 0)) {
327 #if NHILKBD > 0
328 		if (hil_is_console == -1) {
329 			ka.console = 1;
330 			hil_is_console = 0;
331 		} else
332 			ka.console = 0;
333 #else
334 		ka.console = 1;
335 #endif
336 	} else
337 		ka.console = 0;
338 
339 	ka.keymap = &dnkbd_keymapdata;
340 	ka.accessops = &dnkbd_accessops;
341 	ka.accesscookie = sc;
342 #ifndef DKKBD_LAYOUT
343 	dnkbd_keymapdata.layout = sc->sc_layout;
344 #endif
345 
346 	if (ka.console) {
347 		sc->sc_flags = SF_PLUGGED | SF_CONSOLE | SF_ENABLED;
348 		wskbd_cnattach(&dnkbd_consops, sc, &dnkbd_keymapdata);
349 	} else {
350 		sc->sc_flags = SF_PLUGGED;
351 	}
352 
353 	sc->sc_wskbddev =
354 	    config_found_ia(sc->sc_dev, "wskbddev", &ka, wskbddevprint);
355 
356 #if NWSMOUSE > 0
357 	ma.accessops = &dnmouse_accessops;
358 	ma.accesscookie = sc;
359 
360 	sc->sc_wsmousedev =
361 	    config_found_ia(sc->sc_dev, "wsmousedev", &ma, wsmousedevprint);
362 #endif
363 
364 	SET(sc->sc_flags, SF_ATTACHED);
365 }
366 
367 int
368 dnkbd_probe(struct dnkbd_softc *sc)
369 {
370 	int dat, rc, flags;
371 	uint8_t cmdbuf[2];
372 	char rspbuf[MAX_IDENTLEN], *word, *end;
373 	u_int i;
374 	int s;
375 
376 	s = spltty();
377 	flags = sc->sc_flags;
378 	SET(sc->sc_flags, SF_POLLING);
379 	sc->sc_state = STATE_CHANNEL;
380 	splx(s);
381 
382 	/*
383 	 * Switch keyboard to raw mode.
384 	 */
385 	cmdbuf[0] = DNCMD_RAW;
386 	rc = dnkbd_send(sc, cmdbuf, 1);
387 	if (rc != 0)
388 		goto out;
389 
390 	/*
391 	 * Send the identify command.
392 	 */
393 	cmdbuf[0] = DNCMD_IDENT_1;
394 	cmdbuf[1] = DNCMD_IDENT_2;
395 	rc = dnkbd_send(sc, cmdbuf, 2);
396 	if (rc != 0)
397 		goto out;
398 
399 	for (i = 0; ; i++) {
400 		dat = dnkbd_pollin(sc, 10000);
401 		if (dat == -1)
402 			break;
403 
404 		if (i < sizeof(rspbuf))
405 			rspbuf[i] = dat;
406 	}
407 
408 	if (i > sizeof(rspbuf) || i == 0) {
409 		aprint_error_dev(sc->sc_dev,
410 		    "unexpected identify string length %d\n", i);
411 		rc = ENXIO;
412 		goto out;
413 	}
414 
415 	/*
416 	 * Make sure the identification string is NULL terminated
417 	 * (overwriting the keyboard mode byte if necessary).
418 	 */
419 	i--;
420 	if (rspbuf[i] != 0)
421 		rspbuf[i] = 0;
422 
423 	/*
424 	 * Now display the identification strings, if they changed.
425 	 */
426 	if (i != sc->sc_identlen || memcmp(rspbuf, sc->sc_ident, i) != 0) {
427 		sc->sc_layout = KB_US;
428 		sc->sc_identlen = i;
429 		memcpy(sc->sc_ident, rspbuf, i);
430 
431 		if (cold == 0)
432 			aprint_normal_dev(sc->sc_dev, "");
433 		aprint_normal("model ");
434 		word = rspbuf;
435 		for (i = 0; i < 3; i++) {
436 			end = strchr(word, '\r');
437 			if (end == NULL)
438 				break;
439 			*end++ = '\0';
440 			aprint_normal("<%s> ", word);
441 			/*
442 			 * Parse the layout code if applicable
443 			 */
444 			if (i == 1 && *word++ == '3') {
445 				if (*word == '-')
446 					word++;
447 				switch (*word) {
448 #if 0
449 				default:
450 				case ' ':
451 					sc->sc_layout = KB_US;
452 					break;
453 #endif
454 				case 'a':
455 					sc->sc_layout = KB_DE;
456 					break;
457 				case 'b':
458 					sc->sc_layout = KB_FR;
459 					break;
460 				case 'c':
461 					sc->sc_layout = KB_DK;
462 					break;
463 				case 'd':
464 					sc->sc_layout = KB_SV;
465 					break;
466 				case 'e':
467 					sc->sc_layout = KB_UK;
468 					break;
469 				case 'f':
470 					sc->sc_layout = KB_JP;
471 					break;
472 				case 'g':
473 					sc->sc_layout = KB_SG;
474 					break;
475 				}
476 			}
477 			word = end;
478 		}
479 		aprint_normal("\n");
480 	}
481 
482 	/*
483 	 * Ready to work, the default channel is the keyboard.
484 	 */
485 	sc->sc_state = STATE_KEYBOARD;
486 
487 out:
488 	s = spltty();
489 	sc->sc_flags = flags;
490 	splx(s);
491 
492 	return rc;
493 }
494 
495 /*
496  * State machine.
497  *
498  * In raw mode, the keyboard may feed us the following sequences:
499  * - on the keyboard channel:
500  *   + a raw key code, in the range 0x01-0x7e, or'ed with 0x80 if key release.
501  *   + the key repeat sequence 0x7f.
502  * - on the mouse channel:
503  *   + a 3 byte mouse sequence (buttons state, dx move, dy move).
504  * - at any time:
505  *   + a 2 byte channel sequence (0xff followed by the channel number) telling
506  *     us which device the following input will come from.
507  *   + if we get 0xff but an invalid channel number, this is a command echo.
508  *     Currently we only handle this for bell commands, which size are known.
509  *     Other commands are issued through dnkbd_send() which ``eats'' the echo.
510  *
511  * Older keyboards reset the channel to the keyboard (by sending ff 01) after
512  * every mouse packet.
513  */
514 
515 dnevent
516 dnkbd_input(struct dnkbd_softc *sc, int dat)
517 {
518 	dnevent event = EVENT_NONE;
519 
520 	switch (sc->sc_state) {
521 	case STATE_KEYBOARD:
522 		switch (dat) {
523 		case DNKEY_REPEAT:
524 			/*
525 			 * We ignore event repeats, as wskbd does its own
526 			 * soft repeat processing.
527 			 */
528 			break;
529 		case DNKEY_CHANNEL:
530 			sc->sc_prevstate = sc->sc_state;
531 			sc->sc_state = STATE_CHANNEL;
532 			break;
533 		default:
534 			event = EVENT_KEYBOARD;
535 			break;
536 		}
537 		break;
538 
539 	case STATE_MOUSE:
540 		if (dat == DNKEY_CHANNEL && sc->sc_mousepos == 0) {
541 			sc->sc_prevstate = sc->sc_state;
542 			sc->sc_state = STATE_CHANNEL;
543 		} else {
544 			sc->sc_mousepkt[sc->sc_mousepos++] = dat;
545 			if (sc->sc_mousepos == sizeof(sc->sc_mousepkt)) {
546 				sc->sc_mousepos = 0;
547 				event = EVENT_MOUSE;
548 			}
549 		}
550 		break;
551 
552 	case STATE_CHANNEL:
553 		switch (dat) {
554 		case DNKEY_CHANNEL:
555 			/*
556 			 * During hotplug, we might get spurious 0xff bytes.
557 			 * Ignore them.
558 			 */
559 			break;
560 		case DNCHANNEL_RESET:
561 			/*
562 			 * Identify the keyboard again. This will switch it to
563 			 * raw mode again. If this fails, we'll consider the
564 			 * keyboard as unplugged (to ignore further events until
565 			 * a successful reset).
566 			 */
567 			if (dnkbd_probe(sc) == 0) {
568 				/*
569 				 * We need to attach wskbd and wsmouse children
570 				 * if this is a live first plug.
571 				 */
572 				if (!ISSET(sc->sc_flags, SF_ATTACHED))
573 					dnkbd_attach_subdevices(sc);
574 				SET(sc->sc_flags, SF_PLUGGED);
575 			} else {
576 				CLR(sc->sc_flags, SF_PLUGGED);
577 			}
578 
579 			sc->sc_state = STATE_KEYBOARD;
580 			break;
581 		case DNCHANNEL_KBD:
582 			sc->sc_state = STATE_KEYBOARD;
583 			break;
584 		case DNCHANNEL_MOUSE:
585 			sc->sc_state = STATE_MOUSE;
586 			sc->sc_mousepos = 0;	/* just in case */
587 			break;
588 		case DNCMD_BELL:
589 			/*
590 			 * We are getting a bell command echoed to us.
591 			 * Ignore it.
592 			 */
593 			sc->sc_state = STATE_ECHO;
594 			sc->sc_echolen = 1;	/* one byte to follow */
595 			break;
596 		default:
597 			printf("%s: unexpected channel byte %02x\n",
598 			    device_xname(sc->sc_dev), dat);
599 			break;
600 		}
601 		break;
602 
603 	case STATE_ECHO:
604 		if (--sc->sc_echolen == 0) {
605 			/* get back to the state we were in before the echo */
606 			sc->sc_state = sc->sc_prevstate;
607 		}
608 		break;
609 	}
610 
611 	return event;
612 }
613 
614 /*
615  * Event breakers.
616  */
617 
618 void
619 dnkbd_decode(int keycode, u_int *type, int *key)
620 {
621 	*type = (keycode & DNKEY_RELEASE) ?
622 	    WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN;
623 	*key = (keycode & ~DNKEY_RELEASE);
624 }
625 
626 void
627 dnevent_kbd(struct dnkbd_softc *sc, int dat)
628 {
629 	if (!ISSET(sc->sc_flags, SF_PLUGGED))
630 		return;
631 
632 	if (sc->sc_wskbddev == NULL)
633 		return;
634 
635 	if (!ISSET(sc->sc_flags, SF_ENABLED))
636 		return;
637 
638 	/*
639 	 * Even in raw mode, the caps lock key is treated specially:
640 	 * first key press causes event 0x7e, release causes no event;
641 	 * then a new key press causes nothing, and release causes
642 	 * event 0xfe. Moreover, while kept down, it does not produce
643 	 * repeat events.
644 	 *
645 	 * So the best we can do is fake the missed events, but this
646 	 * will not allow the capslock key to be remapped as a control
647 	 * key since it will not be possible to chord it with anything.
648 	 */
649 	dnevent_kbd_internal(sc, dat);
650 	if ((dat & ~DNKEY_RELEASE) == DNKEY_CAPSLOCK)
651 		dnevent_kbd_internal(sc, dat ^ DNKEY_RELEASE);
652 }
653 
654 void
655 dnevent_kbd_internal(struct dnkbd_softc *sc, int dat)
656 {
657 	u_int type;
658 	int key;
659 	int s;
660 
661 	dnkbd_decode(dat, &type, &key);
662 
663 #ifdef WSDISPLAY_COMPAT_RAWKBD
664 	if (sc->sc_rawkbd) {
665 		u_char cbuf[2];
666 		int c, j = 0;
667 
668 		c = dnkbd_raw[key];
669 		if (c != 0) {
670 			/* fake extended scancode if necessary */
671 			if (c & 0x80)
672 				cbuf[j++] = 0xe0;
673 			cbuf[j] = c & 0x7f;
674 			if (type == WSCONS_EVENT_KEY_UP)
675 				cbuf[j] |= 0x80;
676 			else {
677 				/* remember pressed key for autorepeat */
678 				memcpy(sc->sc_rep, cbuf, sizeof(sc->sc_rep));
679 			}
680 			j++;
681 		}
682 
683 		if (j != 0) {
684 			s = spltty();
685 			wskbd_rawinput(sc->sc_wskbddev, cbuf, j);
686 			splx(s);
687 			callout_stop(&sc->sc_rawrepeat_ch);
688 			sc->sc_nrep = j;
689 			callout_schedule(&sc->sc_rawrepeat_ch,
690 			    mstohz(REP_DELAY1));
691 		}
692 	} else
693 #endif
694 	{
695 		s = spltty();
696 		wskbd_input(sc->sc_wskbddev, type, key);
697 		splx(s);
698 	}
699 }
700 
701 #ifdef WSDISPLAY_COMPAT_RAWKBD
702 void
703 dnkbd_rawrepeat(void *v)
704 {
705 	struct dnkbd_softc *sc = v;
706 	int s;
707 
708 	s = spltty();
709 	wskbd_rawinput(sc->sc_wskbddev, sc->sc_rep, sc->sc_nrep);
710 	splx(s);
711 
712 	callout_schedule(&sc->sc_rawrepeat_ch, mstohz(REP_DELAYN));
713 }
714 #endif
715 
716 #if NWSMOUSE > 0
717 void
718 dnevent_mouse(struct dnkbd_softc *sc, uint8_t *dat)
719 {
720 	if (!ISSET(sc->sc_flags, SF_PLUGGED))
721 		return;
722 
723 	if (sc->sc_wsmousedev == NULL)
724 		return;
725 
726 	if (!ISSET(sc->sc_flags, SF_MOUSE))
727 		return;
728 
729 	/*
730 	 * First byte is button status. It has the 0x80 bit always set, and
731 	 * the next 3 bits are *cleared* when the mouse buttons are pressed.
732 	 */
733 #ifdef DEBUG
734 	if (!ISSET(*dat, 0x80)) {
735 		printf("%s: incorrect mouse packet %02x %02x %02x\n",
736 		    device_xname(sc->sc_dev), dat[0], dat[1], dat[2]);
737 		return;
738 	}
739 #endif
740 
741 	wsmouse_input(sc->sc_wsmousedev,
742 	    (~dat[0] & (DNBUTTON_L | DNBUTTON_M | DNBUTTON_R)) >> 4,
743 	    (int8_t)dat[1], (int8_t)dat[2], 0, 0, WSMOUSE_INPUT_DELTA);
744 }
745 #endif
746 
747 /*
748  * Low-level communication routines.
749  */
750 
751 int
752 dnkbd_pollin(struct dnkbd_softc *sc, u_int tries)
753 {
754 	bus_space_tag_t bst;
755 	bus_space_handle_t bsh;
756 	u_int cnt;
757 
758 	bst = sc->sc_bst;
759 	bsh = sc->sc_bsh;
760 
761 	for (cnt = tries; cnt != 0; cnt--) {
762 		if (bus_space_read_1(bst, bsh, com_lsr) & LSR_RXRDY)
763 			break;
764 		DELAY(10);
765 	}
766 
767 	if (cnt == 0)
768 		return -1;
769 	else
770 		return (int)bus_space_read_1(bst, bsh, com_data);
771 }
772 
773 int
774 dnkbd_pollout(struct dnkbd_softc *sc, int dat)
775 {
776 	bus_space_tag_t bst;
777 	bus_space_handle_t bsh;
778 	u_int cnt;
779 
780 	bst = sc->sc_bst;
781 	bsh = sc->sc_bsh;
782 
783 	for (cnt = 10000; cnt != 0; cnt--) {
784 		if (bus_space_read_1(bst, bsh, com_lsr) & LSR_TXRDY)
785 			break;
786 		DELAY(10);
787 	}
788 	if (cnt == 0)
789 		return EBUSY;
790 	else {
791 		bus_space_write_1(bst, bsh, com_data, dat);
792 		return 0;
793 	}
794 }
795 
796 int
797 dnkbd_send(struct dnkbd_softc *sc, const uint8_t *cmdbuf, size_t cmdlen)
798 {
799 	int cnt, rc, dat;
800 	u_int cmdpos;
801 
802 	/* drain rxfifo */
803 	for (cnt = 10; cnt != 0; cnt--) {
804 		if (dnkbd_pollin(sc, 10) == -1)
805 			break;
806 	}
807 	if (cnt == 0)
808 		return EBUSY;
809 
810 	/* send command escape */
811 	if ((rc = dnkbd_pollout(sc, DNCMD_PREFIX)) != 0)
812 		return rc;
813 
814 	/* send command buffer */
815 	for (cmdpos = 0; cmdpos < cmdlen; cmdpos++) {
816 		if ((rc = dnkbd_pollout(sc, cmdbuf[cmdpos])) != 0)
817 			return rc;
818 	}
819 
820 	/* wait for command echo */
821 	do {
822 		dat = dnkbd_pollin(sc, 10000);
823 		if (dat == -1)
824 			return EIO;
825 	} while (dat != DNCMD_PREFIX);
826 
827 	for (cmdpos = 0; cmdpos < cmdlen; cmdpos++) {
828 		dat = dnkbd_pollin(sc, 10000);
829 		if (dat != cmdbuf[cmdpos])
830 			return EIO;
831 	}
832 
833 	return 0;
834 }
835 
836 int
837 dnkbd_intr(void *v)
838 {
839 	struct dnkbd_softc *sc = v;
840 	bus_space_tag_t bst;
841 	bus_space_handle_t bsh;
842 	uint8_t iir, lsr, c;
843 	int claimed = 0;
844 
845 	bst = sc->sc_bst;
846 	bsh = sc->sc_bsh;
847 
848 	for (;;) {
849 		iir = bus_space_read_1(bst, bsh, com_iir);
850 
851 		switch (iir & IIR_IMASK) {
852 		case IIR_RLS:
853 			/*
854 			 * Line status change. This should never happen,
855 			 * so silently ack the interrupt.
856 			 */
857 			c = bus_space_read_1(bst, bsh, com_lsr);
858 			break;
859 
860 		case IIR_RXRDY:
861 		case IIR_RXTOUT:
862 			/*
863 			 * Data available. We process it byte by byte,
864 			 * unless we are doing polling work...
865 			 */
866 			if (ISSET(sc->sc_flags, SF_POLLING)) {
867 				return 1;
868 			}
869 
870 			for (;;) {
871 				c = bus_space_read_1(bst, bsh, com_data);
872 				switch (dnkbd_input(sc, c)) {
873 				case EVENT_KEYBOARD:
874 					dnevent_kbd(sc, c);
875 					break;
876 #if NWSMOUSE > 0
877 				case EVENT_MOUSE:
878 					dnevent_mouse(sc, sc->sc_mousepkt);
879 					break;
880 #endif
881 				default:	/* appease gcc */
882 					break;
883 				}
884 				lsr = bus_space_read_1(bst, bsh, com_lsr) &
885 				    LSR_RCV_MASK;
886 				if (lsr == 0)
887 					break;
888 				else if (lsr != LSR_RXRDY) {
889 					/* ignore error */
890 					break;
891 				}
892 			}
893 			break;
894 
895 		case IIR_TXRDY:
896 			/*
897 			 * Transmit available. Since we do all our commands
898 			 * in polling mode, we do not need to do anything here.
899 			 */
900 			break;
901 
902 		default:
903 			if (iir & IIR_NOPEND)
904 				return claimed;
905 			/* FALLTHROUGH */
906 
907 		case IIR_MLSC:
908 			/*
909 			 * Modem status change. This should never happen,
910 			 * so silently ack the interrupt.
911 			 */
912 			c = bus_space_read_1(bst, bsh, com_msr);
913 			break;
914 		}
915 
916 		claimed = 1;
917 	}
918 }
919 
920 /*
921  * Wskbd callbacks
922  */
923 
924 int
925 dnkbd_enable(void *v, int on)
926 {
927 	struct dnkbd_softc *sc = v;
928 
929 	if (on) {
930 		if (ISSET(sc->sc_flags, SF_ENABLED))
931 			return EBUSY;
932 		SET(sc->sc_flags, SF_ENABLED);
933 	} else {
934 		if (ISSET(sc->sc_flags, SF_CONSOLE))
935 			return EBUSY;
936 		CLR(sc->sc_flags, SF_ENABLED);
937 	}
938 
939 	return 0;
940 }
941 
942 void
943 dnkbd_set_leds(void *v, int leds)
944 {
945 	/*
946 	 * Not supported. There is only one LED on this keyboard, and
947 	 * is hardware tied to the caps lock key.
948 	 */
949 }
950 
951 int
952 dnkbd_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
953 {
954 #ifdef WSDISPLAY_COMPAT_RAWKBD
955 	struct dnkbd_softc *sc = v;
956 #endif
957 
958 #define WSKBD_TYPE_UNKNOWN	0
959 
960 	switch (cmd) {
961 	case WSKBDIO_GTYPE:
962 		*(int *)data = WSKBD_TYPE_UNKNOWN;	/* XXX */
963 		return 0;
964 	case WSKBDIO_SETLEDS:
965 		return ENXIO;
966 	case WSKBDIO_GETLEDS:
967 		*(int *)data = 0;
968 		return 0;
969 	case WSKBDIO_COMPLEXBELL:
970 #define	d	((struct wskbd_bell_data *)data)
971 		dnkbd_bell(v, d->period, d->pitch, d->volume);
972 #undef d
973 		return 0;
974 #ifdef WSDISPLAY_COMPAT_RAWKBD
975 	case WSKBDIO_SETMODE:
976 		sc->sc_rawkbd = *(int *)data == WSKBD_RAW;
977 		callout_stop(&sc->sc_rawrepeat_ch);
978 		return 0;
979 #endif
980 	}
981 
982 	return EPASSTHROUGH;
983 }
984 
985 #if NWSMOUSE > 0
986 /*
987  * Wsmouse callbacks
988  */
989 
990 int
991 dnmouse_enable(void *v)
992 {
993 	struct dnkbd_softc *sc = v;
994 
995 	if (ISSET(sc->sc_flags, SF_MOUSE))
996 		return EBUSY;
997 	SET(sc->sc_flags, SF_MOUSE);
998 
999 	return 0;
1000 }
1001 
1002 int
1003 dnmouse_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
1004 {
1005 #if 0
1006 	struct dnkbd_softc *sc = v;
1007 #endif
1008 
1009 #define WSMOUSE_TYPE_UNKNOWN	0
1010 
1011 	switch (cmd) {
1012 	case WSMOUSEIO_GTYPE:
1013 		*(int *)data = WSMOUSE_TYPE_UNKNOWN;	/* XXX */
1014 		return 0;
1015 	}
1016 
1017 	return -1;
1018 }
1019 
1020 void
1021 dnmouse_disable(void *v)
1022 {
1023 	struct dnkbd_softc *sc = v;
1024 
1025 	CLR(sc->sc_flags, SF_MOUSE);
1026 }
1027 #endif
1028 
1029 /*
1030  * Console support
1031  */
1032 
1033 void
1034 dnkbd_cngetc(void *v, u_int *type, int *data)
1035 {
1036 	static int lastdat = 0;
1037 	struct dnkbd_softc *sc = v;
1038 	int s;
1039 	int dat;
1040 
1041 	/* Take care of caps lock */
1042 	if ((lastdat & ~DNKEY_RELEASE) == DNKEY_CAPSLOCK) {
1043 		dat = lastdat ^ DNKEY_RELEASE;
1044 		lastdat = 0;
1045 	} else {
1046 		for (;;) {
1047 			s = splhigh();
1048 			dat = dnkbd_pollin(sc, 10000);
1049 			if (dat != -1) {
1050 				if (dnkbd_input(sc, dat) == EVENT_KEYBOARD) {
1051 					splx(s);
1052 					break;
1053 				}
1054 			}
1055 			splx(s);
1056 		}
1057 		lastdat = dat;
1058 	}
1059 
1060 	dnkbd_decode(dat, type, data);
1061 }
1062 
1063 void
1064 dnkbd_cnpollc(void *v, int on)
1065 {
1066 	struct dnkbd_softc *sc = v;
1067 
1068 	if (on)
1069 		SET(sc->sc_flags, SF_POLLING);
1070 	else
1071 		CLR(sc->sc_flags, SF_POLLING);
1072 }
1073 
1074 /*
1075  * Bell routines.
1076  */
1077 void
1078 dnkbd_bell(void *v, u_int period, u_int pitch, u_int volume)
1079 {
1080 	struct dnkbd_softc *sc = v;
1081 	int s;
1082 
1083 	s = spltty();
1084 
1085 	if (pitch == 0 || period == 0 || volume == 0) {
1086 		if (ISSET(sc->sc_flags, SF_BELL_TMO)) {
1087 			callout_stop(&sc->sc_bellstop_tmo);
1088 			dnkbd_bellstop(v);
1089 		}
1090 	} else {
1091 
1092 		if (!ISSET(sc->sc_flags, SF_BELL)) {
1093 			dnkbd_pollout(sc, DNCMD_PREFIX);
1094 			dnkbd_pollout(sc, DNCMD_BELL);
1095 			dnkbd_pollout(sc, DNCMD_BELL_ON);
1096 			SET(sc->sc_flags, SF_BELL);
1097 		}
1098 
1099 		if (ISSET(sc->sc_flags, SF_BELL_TMO))
1100 			callout_stop(&sc->sc_bellstop_tmo);
1101 		callout_schedule(&sc->sc_bellstop_tmo, period);
1102 		SET(sc->sc_flags, SF_BELL_TMO);
1103 	}
1104 
1105 	splx(s);
1106 }
1107 
1108 void
1109 dnkbd_bellstop(void *v)
1110 {
1111 	struct dnkbd_softc *sc = v;
1112 	int s;
1113 
1114 	s = spltty();
1115 
1116 	dnkbd_pollout(sc, DNCMD_PREFIX);
1117 	dnkbd_pollout(sc, DNCMD_BELL);
1118 	dnkbd_pollout(sc, DNCMD_BELL_OFF);
1119 	CLR(sc->sc_flags, SF_BELL);
1120 	CLR(sc->sc_flags, SF_BELL_TMO);
1121 
1122 	splx(s);
1123 }
1124