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