xref: /freebsd-12.1/sys/dev/uart/uart_kbd_sun.c (revision add72477)
1 /*-
2  * Copyright (c) 2003 Jake Burkholder.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include "opt_compat.h"
31 #include "opt_kbd.h"
32 #include "opt_sunkbd.h"
33 
34 #if (defined(SUNKBD_EMULATE_ATKBD) && defined(SUNKBD_DFLT_KEYMAP)) ||	\
35     !defined(SUNKBD_EMULATE_ATKBD)
36 #define	KBD_DFLT_KEYMAP
37 #endif
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/bus.h>
42 #include <sys/interrupt.h>
43 #include <sys/kbio.h>
44 #include <sys/kernel.h>
45 #include <sys/limits.h>
46 
47 #include <machine/bus.h>
48 
49 #include <dev/kbd/kbdreg.h>
50 #include <dev/kbd/kbdtables.h>
51 
52 #include <dev/uart/uart.h>
53 #include <dev/uart/uart_bus.h>
54 #include <dev/uart/uart_cpu.h>
55 
56 #include <dev/uart/uart_kbd_sun.h>
57 #if !defined(SUNKBD_EMULATE_ATKBD)
58 #include <dev/uart/uart_kbd_sun_tables.h>
59 #endif
60 
61 #if defined(SUNKBD_EMULATE_ATKBD) && defined(SUNKBD_DFLT_KEYMAP)
62 #include "sunkbdmap.h"
63 #endif
64 #include "uart_if.h"
65 
66 #define	SUNKBD_DRIVER_NAME	"sunkbd"
67 
68 #define	TODO	printf("%s: unimplemented", __func__)
69 
70 struct sunkbd_softc {
71 	keyboard_t		sc_kbd;
72 	struct uart_softc	*sc_uart;
73 	struct uart_devinfo	*sc_sysdev;
74 
75 	int			sc_checked_key;
76 
77 	struct callout		sc_repeat_callout;
78 	int			sc_repeat_key;
79 
80 	int			sc_accents;
81 	int			sc_composed_char;
82 	int			sc_flags;
83 #define	KPCOMPOSE			(1 << 0)
84 	int			sc_mode;
85 	int			sc_polling;
86 	int			sc_repeating;
87 	int			sc_state;
88 
89 #if defined(SUNKBD_EMULATE_ATKBD)
90 	int			sc_buffered_char[2];
91 #endif
92 };
93 
94 static int sunkbd_configure(int flags);
95 static int sunkbd_probe_keyboard(struct uart_devinfo *di);
96 
97 static int sunkbd_probe(int unit, void *arg, int flags);
98 static int sunkbd_init(int unit, keyboard_t **kbdp, void *arg, int flags);
99 static int sunkbd_term(keyboard_t *kbd);
100 static int sunkbd_intr(keyboard_t *kbd, void *arg);
101 static int sunkbd_test_if(keyboard_t *kbd);
102 static int sunkbd_enable(keyboard_t *kbd);
103 static int sunkbd_disable(keyboard_t *kbd);
104 static int sunkbd_read(keyboard_t *kbd, int wait);
105 static int sunkbd_check(keyboard_t *kbd);
106 static u_int sunkbd_read_char(keyboard_t *kbd, int wait);
107 static int sunkbd_check_char(keyboard_t *kbd);
108 static int sunkbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t data);
109 static int sunkbd_lock(keyboard_t *kbd, int lock);
110 static void sunkbd_clear_state(keyboard_t *kbd);
111 static int sunkbd_get_state(keyboard_t *kbd, void *buf, size_t len);
112 static int sunkbd_set_state(keyboard_t *kbd, void *buf, size_t len);
113 static int sunkbd_poll_mode(keyboard_t *kbd, int on);
114 static void sunkbd_diag(keyboard_t *kbd, int level);
115 
116 static void sunkbd_repeat(void *v);
117 #if defined(SUNKBD_EMULATE_ATKBD)
118 static int keycode2scancode(int keycode, int shift, int up);
119 #endif
120 
121 static keyboard_switch_t sunkbdsw = {
122 	sunkbd_probe,
123 	sunkbd_init,
124 	sunkbd_term,
125 	sunkbd_intr,
126 	sunkbd_test_if,
127 	sunkbd_enable,
128 	sunkbd_disable,
129 	sunkbd_read,
130 	sunkbd_check,
131 	sunkbd_read_char,
132 	sunkbd_check_char,
133 	sunkbd_ioctl,
134 	sunkbd_lock,
135 	sunkbd_clear_state,
136 	sunkbd_get_state,
137 	sunkbd_set_state,
138 	genkbd_get_fkeystr,
139 	sunkbd_poll_mode,
140 	sunkbd_diag
141 };
142 
143 KEYBOARD_DRIVER(sunkbd, sunkbdsw, sunkbd_configure);
144 
145 static struct sunkbd_softc sunkbd_softc;
146 static struct uart_devinfo uart_keyboard;
147 
148 #if defined(SUNKBD_EMULATE_ATKBD)
149 
150 #define	SCAN_PRESS		0x000
151 #define	SCAN_RELEASE		0x080
152 #define	SCAN_PREFIX_E0		0x100
153 #define	SCAN_PREFIX_E1		0x200
154 #define	SCAN_PREFIX_CTL		0x400
155 #define	SCAN_PREFIX_SHIFT	0x800
156 #define	SCAN_PREFIX		(SCAN_PREFIX_E0 | SCAN_PREFIX_E1 |	\
157 				SCAN_PREFIX_CTL | SCAN_PREFIX_SHIFT)
158 
159 #define	NOTR	0x0	/* no translation */
160 
161 static const uint8_t sunkbd_trtab[] = {
162 	NOTR, 0x6d, 0x78, 0x6e, 0x79, 0x3b, 0x3c, 0x44, /* 0x00 - 0x07 */
163 	0x3d, 0x57, 0x3e, 0x58, 0x3f, 0x5d, 0x40, NOTR, /* 0x08 - 0x0f */
164 	0x41, 0x42, 0x43, 0x38, 0x5f, 0x68, 0x5c, 0x46, /* 0x10 - 0x17 */
165 	0x61, 0x6e, 0x70, 0x64, 0x62, 0x01, 0x02, 0x03, /* 0x18 - 0x1f */
166 	0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, /* 0x20 - 0x27 */
167 	0x0c, 0x0d, 0x29, 0x0e, 0x66, 0x77, 0x5b, 0x37, /* 0x28 - 0x2f */
168 	0x7a, 0x71, 0x53, 0x72, 0x5e, 0x0f, 0x10, 0x11, /* 0x30 - 0x37 */
169 	0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, /* 0x38 - 0x3f */
170 	0x1a, 0x1b, 0x67, 0x6b, 0x47, 0x48, 0x49, 0x4a, /* 0x40 - 0x47 */
171 	0x73, 0x74, 0x63, NOTR, 0x1d, 0x1e, 0x1f, 0x20, /* 0x48 - 0x4f */
172 	0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, /* 0x50 - 0x57 */
173 	0x2b, 0x1c, 0x59, 0x4b, 0x4c, 0x4d, 0x52, 0x75, /* 0x58 - 0x5f */
174 	0x60, 0x76, 0x45, 0x2a, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x60 - 0x67 */
175 	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, NOTR, /* 0x68 - 0x6f */
176 	0x4f, 0x50, 0x51, NOTR, NOTR, NOTR, 0x6c, 0x3a, /* 0x70 - 0x77 */
177 	0x69, 0x39, 0x6a, 0x65, 0x56, 0x4e, NOTR, NOTR  /* 0x78 - 0x7f */
178 };
179 
180 #endif
181 
182 static int
183 sunkbd_probe_keyboard(struct uart_devinfo *di)
184 {
185 	int c, id, ltries, tries;
186 
187 	for (tries = 5; tries != 0; tries--) {
188 		uart_putc(di, SKBD_CMD_RESET);
189 		for (ltries = 1000; ltries != 0; ltries--) {
190 			if (uart_poll(di) == SKBD_RSP_RESET)
191 				break;
192 			DELAY(1000);
193 		}
194 		if (ltries == 0)
195 			continue;
196 		id = -1;
197 		for (ltries = 1000; ltries != 0; ltries--) {
198 			switch (c = uart_poll(di)) {
199 			case -1:
200 				break;
201 			case SKBD_RSP_IDLE:
202 				return (id);
203 			default:
204 				id = c;
205 			}
206 			DELAY(1000);
207 		}
208 	}
209 	return (-1);
210 }
211 
212 static int sunkbd_attach(struct uart_softc *sc);
213 static void sunkbd_uart_intr(void *arg);
214 
215 static int
216 sunkbd_configure(int flags)
217 {
218 	struct sunkbd_softc *sc;
219 
220 	/*
221 	 * We are only prepared to be used for the high-level console
222 	 * when the keyboard is both configured and attached.
223 	 */
224 	if (!(flags & KB_CONF_PROBE_ONLY)) {
225 		if (KBD_IS_INITIALIZED(&sunkbd_softc.sc_kbd))
226 			goto found;
227 		else
228 			return (0);
229 	}
230 
231 	if (uart_cpu_getdev(UART_DEV_KEYBOARD, &uart_keyboard))
232 		return (0);
233 	if (uart_probe(&uart_keyboard))
234 		return (0);
235 	uart_init(&uart_keyboard);
236 
237 	uart_keyboard.type = UART_DEV_KEYBOARD;
238 	uart_keyboard.attach = sunkbd_attach;
239 	uart_add_sysdev(&uart_keyboard);
240 
241 	if (sunkbd_probe_keyboard(&uart_keyboard) != KB_SUN4)
242 		return (0);
243 
244 	sc = &sunkbd_softc;
245 	callout_init(&sc->sc_repeat_callout, 0);
246 	sunkbd_clear_state(&sc->sc_kbd);
247 
248 #if defined(SUNKBD_EMULATE_ATKBD)
249 	kbd_init_struct(&sc->sc_kbd, SUNKBD_DRIVER_NAME, KB_101, 0, 0, 0, 0);
250 	kbd_set_maps(&sc->sc_kbd, &key_map, &accent_map, fkey_tab,
251 	    sizeof(fkey_tab) / sizeof(fkey_tab[0]));
252 #else
253 	kbd_init_struct(&sc->sc_kbd, SUNKBD_DRIVER_NAME, KB_OTHER, 0, 0, 0, 0);
254 	kbd_set_maps(&sc->sc_kbd, &keymap_sun_us_unix_kbd,
255 	    &accentmap_sun_us_unix_kbd, fkey_tab,
256 	    sizeof(fkey_tab) / sizeof(fkey_tab[0]));
257 #endif
258 	sc->sc_mode = K_XLATE;
259 	kbd_register(&sc->sc_kbd);
260 
261 	sc->sc_sysdev = &uart_keyboard;
262 
263  found:
264 	/* Return number of found keyboards. */
265 	return (1);
266 }
267 
268 static int
269 sunkbd_attach(struct uart_softc *sc)
270 {
271 
272 	/*
273 	 * Don't attach if we didn't probe the keyboard. Note that
274 	 * the UART is still marked as a system device in that case.
275 	 */
276 	if (sunkbd_softc.sc_sysdev == NULL) {
277 		device_printf(sc->sc_dev, "keyboard not present\n");
278 		return (0);
279 	}
280 
281 	if (sc->sc_sysdev != NULL) {
282 		sunkbd_softc.sc_uart = sc;
283 
284 #ifdef KBD_INSTALL_CDEV
285 		kbd_attach(&sunkbd_softc.sc_kbd);
286 #endif
287 		sunkbd_enable(&sunkbd_softc.sc_kbd);
288 
289 		swi_add(&tty_intr_event, uart_driver_name, sunkbd_uart_intr,
290 		    &sunkbd_softc, SWI_TTY, INTR_TYPE_TTY, &sc->sc_softih);
291 
292 		sc->sc_opened = 1;
293 		KBD_INIT_DONE(&sunkbd_softc.sc_kbd);
294 	}
295 
296 	return (0);
297 }
298 
299 static void
300 sunkbd_uart_intr(void *arg)
301 {
302 	struct sunkbd_softc *sc = arg;
303 	int pend;
304 
305 	if (sc->sc_uart->sc_leaving)
306 		return;
307 
308 	pend = atomic_readandclear_32(&sc->sc_uart->sc_ttypend);
309 	if (!(pend & SER_INT_MASK))
310 		return;
311 
312 	if (pend & SER_INT_RXREADY) {
313 		if (KBD_IS_ACTIVE(&sc->sc_kbd) && KBD_IS_BUSY(&sc->sc_kbd)) {
314 			sc->sc_kbd.kb_callback.kc_func(&sc->sc_kbd,
315 			    KBDIO_KEYINPUT, sc->sc_kbd.kb_callback.kc_arg);
316 		}
317 	}
318 }
319 
320 static int
321 sunkbd_probe(int unit, void *arg, int flags)
322 {
323 
324 	TODO;
325 	return (0);
326 }
327 
328 static int
329 sunkbd_init(int unit, keyboard_t **kbdp, void *arg, int flags)
330 {
331 
332 	TODO;
333 	return (0);
334 }
335 
336 static int
337 sunkbd_term(keyboard_t *kbd)
338 {
339 
340 	TODO;
341 	return (0);
342 }
343 
344 static int
345 sunkbd_intr(keyboard_t *kbd, void *arg)
346 {
347 
348 	TODO;
349 	return (0);
350 }
351 
352 static int
353 sunkbd_test_if(keyboard_t *kbd)
354 {
355 
356 	TODO;
357 	return (0);
358 }
359 
360 static int
361 sunkbd_enable(keyboard_t *kbd)
362 {
363 
364 	KBD_ACTIVATE(kbd);
365 	return (0);
366 }
367 
368 static int
369 sunkbd_disable(keyboard_t *kbd)
370 {
371 
372 	KBD_DEACTIVATE(kbd);
373 	return (0);
374 }
375 
376 static int
377 sunkbd_read(keyboard_t *kbd, int wait)
378 {
379 
380 	TODO;
381 	return (0);
382 }
383 
384 static int
385 sunkbd_check(keyboard_t *kbd)
386 {
387 	struct sunkbd_softc *sc;
388 
389 	if (!KBD_IS_ACTIVE(kbd))
390 		return (FALSE);
391 
392 	sc = (struct sunkbd_softc *)kbd;
393 
394 #if defined(SUNKBD_EMULATE_ATKBD)
395 	if (sc->sc_buffered_char[0])
396 		return (TRUE);
397 #endif
398 
399 	if (sc->sc_repeating)
400 		return (TRUE);
401 
402 	if (sc->sc_uart != NULL && !uart_rx_empty(sc->sc_uart))
403 		return (TRUE);
404 
405 	if (sc->sc_polling != 0 && sc->sc_sysdev != NULL &&
406 	    (sc->sc_checked_key = uart_poll(sc->sc_sysdev)) != -1)
407 		return (TRUE);
408 
409 	return (FALSE);
410 }
411 
412 static u_int
413 sunkbd_read_char(keyboard_t *kbd, int wait)
414 {
415 	struct sunkbd_softc *sc;
416 	int key, release, repeated, suncode;
417 
418 	sc = (struct sunkbd_softc *)kbd;
419 
420 #if defined(SUNKBD_EMULATE_ATKBD)
421 	if (sc->sc_mode == K_RAW && sc->sc_buffered_char[0]) {
422 		key = sc->sc_buffered_char[0];
423 		if (key & SCAN_PREFIX) {
424 			sc->sc_buffered_char[0] = key & ~SCAN_PREFIX;
425 			return ((key & SCAN_PREFIX_E0) ? 0xe0 : 0xe1);
426 		} else {
427 			sc->sc_buffered_char[0] = sc->sc_buffered_char[1];
428 			sc->sc_buffered_char[1] = 0;
429 			return (key);
430 		}
431 	}
432 #endif
433 
434 	repeated = 0;
435 	if (sc->sc_repeating) {
436 		repeated = 1;
437 		sc->sc_repeating = 0;
438 		callout_reset(&sc->sc_repeat_callout, hz / 10,
439 		    sunkbd_repeat, sc);
440 		suncode = sc->sc_repeat_key;
441 		goto process_code;
442 	}
443 
444 	if (sc->sc_checked_key != -1) {
445 		suncode = sc->sc_checked_key;
446 		sc->sc_checked_key = -1;
447 		goto process_code;
448 	}
449 
450 	for (;;) {
451  next_code:
452 		if (!(sc->sc_flags & KPCOMPOSE) && (sc->sc_composed_char > 0)) {
453 			key = sc->sc_composed_char;
454 			sc->sc_composed_char = 0;
455 			if (key > UCHAR_MAX)
456 				return (ERRKEY);
457 			return (key);
458 		}
459 
460 		if (sc->sc_uart != NULL && !uart_rx_empty(sc->sc_uart)) {
461 			suncode = uart_rx_get(sc->sc_uart);
462 		} else if (sc->sc_polling != 0 && sc->sc_sysdev != NULL) {
463 			if (wait)
464 				suncode = uart_getc(sc->sc_sysdev);
465 			else if ((suncode = uart_poll(sc->sc_sysdev)) == -1)
466 				return (NOKEY);
467 		} else {
468 			return (NOKEY);
469 		}
470 
471 		switch (suncode) {
472 		case SKBD_RSP_IDLE:
473 			break;
474 		default:
475 
476  process_code:
477 			++kbd->kb_count;
478 			key = SKBD_KEY_CHAR(suncode);
479 			release = suncode & SKBD_KEY_RELEASE;
480 			if (!repeated) {
481 				if (release == 0) {
482 					callout_reset(&sc->sc_repeat_callout,
483 					    hz / 2, sunkbd_repeat, sc);
484 					sc->sc_repeat_key = suncode;
485 				} else if (sc->sc_repeat_key == key) {
486 					callout_stop(&sc->sc_repeat_callout);
487 					sc->sc_repeat_key = -1;
488 				}
489 			}
490 
491 #if defined(SUNKBD_EMULATE_ATKBD)
492 			key = sunkbd_trtab[key];
493 			if (key == NOTR)
494 				return (NOKEY);
495 
496 			if (!repeated) {
497 				switch (key) {
498 				case 0x1d:	/* ctrl */
499 					if (release != 0)
500 						sc->sc_flags &= ~CTLS;
501 					else
502 						sc->sc_flags |= CTLS;
503 					break;
504 				case 0x2a:	/* left shift */
505 				case 0x36:	/* right shift */
506 					if (release != 0)
507 						sc->sc_flags &= ~SHIFTS;
508 					else
509 						sc->sc_flags |= SHIFTS;
510 					break;
511 				case 0x38:	/* alt */
512 				case 0x5d:	/* altgr */
513 					if (release != 0)
514 						sc->sc_flags &= ~ALTS;
515 					else
516 						sc->sc_flags |= ALTS;
517 					break;
518 				}
519 			}
520 			if (sc->sc_mode == K_RAW) {
521 				key = keycode2scancode(key, sc->sc_flags,
522 				    release);
523 				if (key & SCAN_PREFIX) {
524 					if (key & SCAN_PREFIX_CTL) {
525 						sc->sc_buffered_char[0] =
526 						    0x1d | (key & SCAN_RELEASE);
527 						sc->sc_buffered_char[1] =
528 						    key & ~SCAN_PREFIX;
529 					} else if (key & SCAN_PREFIX_SHIFT) {
530 						sc->sc_buffered_char[0] =
531 						    0x2a | (key & SCAN_RELEASE);
532 						sc->sc_buffered_char[1] =
533 						    key & ~SCAN_PREFIX_SHIFT;
534 					} else {
535 						sc->sc_buffered_char[0] =
536 						    key & ~SCAN_PREFIX;
537 						sc->sc_buffered_char[1] = 0;
538 					}
539 					return ((key & SCAN_PREFIX_E0) ?
540 					    0xe0 : 0xe1);
541 				}
542 				return (key);
543 			}
544 			switch (key) {
545 			case 0x5c:	/* print screen */
546 				if (sc->sc_flags & ALTS)
547 					key = 0x54;	/* sysrq */
548 				break;
549 			case 0x68:	/* pause/break */
550 				if (sc->sc_flags & CTLS)
551 					key = 0x6c;	/* break */
552 				break;
553 			}
554 
555 			if (sc->sc_mode == K_CODE)
556 				return (key | release);
557 #else
558 			if (sc->sc_mode == K_RAW || sc->sc_mode == K_CODE)
559 				return (suncode);
560 #endif
561 
562 #if defined(SUNKBD_EMULATE_ATKBD)
563 			if (key == 0x38) {	/* left alt (KP compose key) */
564 #else
565 			if (key == 0x13) {	/* left alt (KP compose key) */
566 #endif
567 				if (release != 0) {
568 				    if (sc->sc_flags & KPCOMPOSE) {
569 					sc->sc_flags &= ~KPCOMPOSE;
570 					if (sc->sc_composed_char > UCHAR_MAX)
571 						sc->sc_composed_char = 0;
572 					}
573 				} else {
574 					if (!(sc->sc_flags & KPCOMPOSE)) {
575 						sc->sc_flags |= KPCOMPOSE;
576 						sc->sc_composed_char = 0;
577 					}
578 				}
579 			}
580 			if (sc->sc_flags & KPCOMPOSE) {
581 				switch (suncode) {
582 				case 0x44:			/* KP 7 */
583 				case 0x45:			/* KP 8 */
584 				case 0x46:			/* KP 9 */
585 					sc->sc_composed_char *= 10;
586 					sc->sc_composed_char += suncode - 0x3d;
587 					if (sc->sc_composed_char > UCHAR_MAX)
588 						return (ERRKEY);
589 					goto next_code;
590 				case 0x5b:			/* KP 4 */
591 				case 0x5c:			/* KP 5 */
592 				case 0x5d:			/* KP 6 */
593 					sc->sc_composed_char *= 10;
594 					sc->sc_composed_char += suncode - 0x58;
595 					if (sc->sc_composed_char > UCHAR_MAX)
596 						return (ERRKEY);
597 					goto next_code;
598 				case 0x70:			/* KP 1 */
599 				case 0x71:			/* KP 2 */
600 				case 0x72:			/* KP 3 */
601 					sc->sc_composed_char *= 10;
602 					sc->sc_composed_char += suncode - 0x6f;
603 					if (sc->sc_composed_char > UCHAR_MAX)
604 						return (ERRKEY);
605 					goto next_code;
606 				case 0x5e:			/* KP 0 */
607 					sc->sc_composed_char *= 10;
608 					if (sc->sc_composed_char > UCHAR_MAX)
609 						return (ERRKEY);
610 					goto next_code;
611 
612 				case 0x44 | SKBD_KEY_RELEASE:	/* KP 7 */
613 				case 0x45 | SKBD_KEY_RELEASE:	/* KP 8 */
614 				case 0x46 | SKBD_KEY_RELEASE:	/* KP 9 */
615 				case 0x5b | SKBD_KEY_RELEASE:	/* KP 4 */
616 				case 0x5c | SKBD_KEY_RELEASE:	/* KP 5 */
617 				case 0x5d | SKBD_KEY_RELEASE:	/* KP 6 */
618 				case 0x70 | SKBD_KEY_RELEASE:	/* KP 1 */
619 				case 0x71 | SKBD_KEY_RELEASE:	/* KP 2 */
620 				case 0x72 | SKBD_KEY_RELEASE:	/* KP 3 */
621 				case 0x5e | SKBD_KEY_RELEASE:	/* KP 0 */
622 					goto next_code;
623 				default:
624 					if (sc->sc_composed_char > 0) {
625 						sc->sc_flags &= ~KPCOMPOSE;
626 						sc->sc_composed_char = 0;
627 						return (ERRKEY);
628 					}
629 				}
630 			}
631 
632 			key = genkbd_keyaction(kbd, key, release,
633 			    &sc->sc_state, &sc->sc_accents);
634 			if (key != NOKEY || repeated)
635 				return (key);
636 		}
637 	}
638 	return (0);
639 }
640 
641 static int
642 sunkbd_check_char(keyboard_t *kbd)
643 {
644 	struct sunkbd_softc *sc;
645 
646 	if (!KBD_IS_ACTIVE(kbd))
647 		return (FALSE);
648 
649 	sc = (struct sunkbd_softc *)kbd;
650 	if (!(sc->sc_flags & KPCOMPOSE) && (sc->sc_composed_char > 0))
651 		return (TRUE);
652 
653 	return (sunkbd_check(kbd));
654 }
655 
656 static int
657 sunkbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t data)
658 {
659 	struct sunkbd_softc *sc;
660 	int c, error;
661 #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5)
662 	int ival;
663 #endif
664 
665 	sc = (struct sunkbd_softc *)kbd;
666 	error = 0;
667 	switch (cmd) {
668 	case KDGKBMODE:
669 		*(int *)data = sc->sc_mode;
670 		break;
671 #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5)
672 	case _IO('K', 7):
673 		ival = IOCPARM_IVAL(data);
674 		data = (caddr_t)&ival;
675 		/* FALLTHROUGH */
676 #endif
677 	case KDSKBMODE:
678 		switch (*(int *)data) {
679 		case K_XLATE:
680 			if (sc->sc_mode != K_XLATE) {
681 				/* make lock key state and LED state match */
682 				sc->sc_state &= ~LOCK_MASK;
683 				sc->sc_state |= KBD_LED_VAL(kbd);
684 			}
685 			/* FALLTHROUGH */
686 		case K_RAW:
687 		case K_CODE:
688 			if (sc->sc_mode != *(int *)data) {
689 				sunkbd_clear_state(kbd);
690 				sc->sc_mode = *(int *)data;
691 			}
692 			break;
693 		default:
694 			error = EINVAL;
695 			break;
696 		}
697 		break;
698 	case KDGETLED:
699 		*(int *)data = KBD_LED_VAL(kbd);
700 		break;
701 #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5)
702 	case _IO('K', 66):
703 		ival = IOCPARM_IVAL(data);
704 		data = (caddr_t)&ival;
705 		/* FALLTHROUGH */
706 #endif
707 	case KDSETLED:
708 		if (*(int *)data & ~LOCK_MASK) {
709 			error = EINVAL;
710 			break;
711 		}
712 		if (sc->sc_sysdev == NULL)
713 			break;
714 		c = 0;
715 		if (*(int *)data & CLKED)
716 			c |= SKBD_LED_CAPSLOCK;
717 		if (*(int *)data & NLKED)
718 			c |= SKBD_LED_NUMLOCK;
719 		if (*(int *)data & SLKED)
720 			c |= SKBD_LED_SCROLLLOCK;
721 		uart_lock(sc->sc_sysdev->hwmtx);
722 		sc->sc_sysdev->ops.putc(&sc->sc_sysdev->bas, SKBD_CMD_SETLED);
723 		sc->sc_sysdev->ops.putc(&sc->sc_sysdev->bas, c);
724 		uart_unlock(sc->sc_sysdev->hwmtx);
725 		KBD_LED_VAL(kbd) = *(int *)data;
726 		break;
727 	case KDGKBSTATE:
728 		*(int *)data = sc->sc_state & LOCK_MASK;
729 		break;
730 #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5)
731 	case _IO('K', 20):
732 		ival = IOCPARM_IVAL(data);
733 		data = (caddr_t)&ival;
734 		/* FALLTHROUGH */
735 #endif
736 	case KDSKBSTATE:
737 		if (*(int *)data & ~LOCK_MASK) {
738 			error = EINVAL;
739 			break;
740 		}
741 		sc->sc_state &= ~LOCK_MASK;
742 		sc->sc_state |= *(int *)data;
743 		/* set LEDs and quit */
744 		return (sunkbd_ioctl(kbd, KDSETLED, data));
745 	case KDSETREPEAT:
746 	case KDSETRAD:
747 		break;
748 	case PIO_KEYMAP:
749 	case PIO_KEYMAPENT:
750 	case PIO_DEADKEYMAP:
751 	default:
752 		return (genkbd_commonioctl(kbd, cmd, data));
753 	}
754 	return (error);
755 }
756 
757 static int
758 sunkbd_lock(keyboard_t *kbd, int lock)
759 {
760 
761 	TODO;
762 	return (0);
763 }
764 
765 static void
766 sunkbd_clear_state(keyboard_t *kbd)
767 {
768 	struct sunkbd_softc *sc;
769 
770 	sc = (struct sunkbd_softc *)kbd;
771 	sc->sc_checked_key = -1;
772 	sc->sc_repeat_key = -1;
773 	sc->sc_accents = 0;
774 	sc->sc_composed_char = 0;
775 	sc->sc_flags = 0;
776 	sc->sc_polling = 0;
777 	sc->sc_repeating = 0;
778 	sc->sc_state &= LOCK_MASK;	/* Preserve locking key state. */
779 
780 #if defined(SUNKBD_EMULATE_ATKBD)
781 	sc->sc_buffered_char[0] = 0;
782 	sc->sc_buffered_char[1] = 0;
783 #endif
784 }
785 
786 static int
787 sunkbd_get_state(keyboard_t *kbd, void *buf, size_t len)
788 {
789 
790 	TODO;
791 	return (0);
792 }
793 
794 static int
795 sunkbd_set_state(keyboard_t *kbd, void *buf, size_t len)
796 {
797 
798 	TODO;
799 	return (0);
800 }
801 
802 static int
803 sunkbd_poll_mode(keyboard_t *kbd, int on)
804 {
805 	struct sunkbd_softc *sc;
806 
807 	sc = (struct sunkbd_softc *)kbd;
808 	if (on)
809 		sc->sc_polling++;
810 	else
811 		sc->sc_polling--;
812 	return (0);
813 }
814 
815 static void
816 sunkbd_diag(keyboard_t *kbd, int level)
817 {
818 
819 	TODO;
820 }
821 
822 static void
823 sunkbd_repeat(void *v)
824 {
825 	struct sunkbd_softc *sc = v;
826 
827 	if (KBD_IS_ACTIVE(&sc->sc_kbd) && KBD_IS_BUSY(&sc->sc_kbd)) {
828 		if (sc->sc_repeat_key != -1) {
829 			sc->sc_repeating = 1;
830 			sc->sc_kbd.kb_callback.kc_func(&sc->sc_kbd,
831 			    KBDIO_KEYINPUT, sc->sc_kbd.kb_callback.kc_arg);
832 		}
833 	}
834 }
835 
836 #if defined(SUNKBD_EMULATE_ATKBD)
837 static int
838 keycode2scancode(int keycode, int shift, int up)
839 {
840 	static const int scan[] = {
841 		/* KP enter, right ctrl, KP divide */
842 		0x1c , 0x1d , 0x35 ,
843 		/* print screen */
844 		0x37 | SCAN_PREFIX_SHIFT,
845 		/* right alt, home, up, page up, left, right, end */
846 		0x38, 0x47, 0x48, 0x49, 0x4b, 0x4d, 0x4f,
847 		/* down, page down, insert, delete */
848 		0x50, 0x51, 0x52, 0x53,
849 		/* pause/break (see also below) */
850 		0x46,
851 		/*
852 		 * MS: left window, right window, menu
853 		 * also Sun: left meta, right meta, compose
854 		 */
855 		0x5b, 0x5c, 0x5d,
856 		/* Sun type 6 USB */
857 		/* help, stop, again, props, undo, front, copy */
858 		0x68, 0x5e, 0x5f, 0x60,	0x61, 0x62, 0x63,
859 		/* open, paste, find, cut, audiomute, audiolower, audioraise */
860 		0x64, 0x65, 0x66, 0x67, 0x25, 0x1f, 0x1e,
861 		/* power */
862 		0x20
863 	};
864 	int scancode;
865 
866 	scancode = keycode;
867 	if ((keycode >= 89) && (keycode < 89 + sizeof(scan) / sizeof(scan[0])))
868 	scancode = scan[keycode - 89] | SCAN_PREFIX_E0;
869 	/* pause/break */
870 	if ((keycode == 104) && !(shift & CTLS))
871 		scancode = 0x45 | SCAN_PREFIX_E1 | SCAN_PREFIX_CTL;
872 	if (shift & SHIFTS)
873 		scancode &= ~SCAN_PREFIX_SHIFT;
874 	return (scancode | (up ? SCAN_RELEASE : SCAN_PRESS));
875 }
876 #endif
877