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
70struct 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
92static int sunkbd_configure(int flags);
93static int sunkbd_probe_keyboard(struct uart_devinfo *di);
94
95static int sunkbd_probe(int unit, void *arg, int flags);
96static int sunkbd_init(int unit, keyboard_t **kbdp, void *arg, int flags);
97static int sunkbd_term(keyboard_t *kbd);
98static int sunkbd_intr(keyboard_t *kbd, void *arg);
99static int sunkbd_test_if(keyboard_t *kbd);
100static int sunkbd_enable(keyboard_t *kbd);
101static int sunkbd_disable(keyboard_t *kbd);
102static int sunkbd_read(keyboard_t *kbd, int wait);
103static int sunkbd_check(keyboard_t *kbd);
104static u_int sunkbd_read_char(keyboard_t *kbd, int wait);
105static int sunkbd_check_char(keyboard_t *kbd);
106static int sunkbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t data);
107static int sunkbd_lock(keyboard_t *kbd, int lock);
108static void sunkbd_clear_state(keyboard_t *kbd);
109static int sunkbd_get_state(keyboard_t *kbd, void *buf, size_t len);
110static int sunkbd_set_state(keyboard_t *kbd, void *buf, size_t len);
111static int sunkbd_poll_mode(keyboard_t *kbd, int on);
112static void sunkbd_diag(keyboard_t *kbd, int level);
113
114static void sunkbd_repeat(void *v);
115#if defined(SUNKBD_EMULATE_ATKBD)
116static int keycode2scancode(int keycode, int shift, int up);
117#endif
118
119static 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
141KEYBOARD_DRIVER(sunkbd, sunkbdsw, sunkbd_configure);
142
143static struct sunkbd_softc sunkbd_softc;
144static 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
159static 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
180static int
181sunkbd_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
210static int sunkbd_attach(struct uart_softc *sc);
211static void sunkbd_uart_intr(void *arg);
212
213static int
214sunkbd_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
266static int
267sunkbd_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
297static void
298sunkbd_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
318static int
319sunkbd_probe(int unit, void *arg, int flags)
320{
321
322	TODO;
323	return (0);
324}
325
326static int
327sunkbd_init(int unit, keyboard_t **kbdp, void *arg, int flags)
328{
329
330	TODO;
331	return (0);
332}
333
334static int
335sunkbd_term(keyboard_t *kbd)
336{
337
338	TODO;
339	return (0);
340}
341
342static int
343sunkbd_intr(keyboard_t *kbd, void *arg)
344{
345
346	TODO;
347	return (0);
348}
349
350static int
351sunkbd_test_if(keyboard_t *kbd)
352{
353
354	TODO;
355	return (0);
356}
357
358static int
359sunkbd_enable(keyboard_t *kbd)
360{
361
362	KBD_ACTIVATE(kbd);
363	return (0);
364}
365
366static int
367sunkbd_disable(keyboard_t *kbd)
368{
369
370	KBD_DEACTIVATE(kbd);
371	return (0);
372}
373
374static int
375sunkbd_read(keyboard_t *kbd, int wait)
376{
377
378	TODO;
379	return (0);
380}
381
382static int
383sunkbd_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
410static u_int
411sunkbd_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
634static int
635sunkbd_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
649static int
650sunkbd_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
751static int
752sunkbd_lock(keyboard_t *kbd, int lock)
753{
754
755	TODO;
756	return (0);
757}
758
759static void
760sunkbd_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
779static int
780sunkbd_get_state(keyboard_t *kbd, void *buf, size_t len)
781{
782
783	TODO;
784	return (0);
785}
786
787static int
788sunkbd_set_state(keyboard_t *kbd, void *buf, size_t len)
789{
790
791	TODO;
792	return (0);
793}
794
795static int
796sunkbd_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
808static void
809sunkbd_diag(keyboard_t *kbd, int level)
810{
811
812	TODO;
813}
814
815static void
816sunkbd_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)
830static int
831keycode2scancode(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