1122470Sjake/*-
2122470Sjake * Copyright (c) 2003 Jake Burkholder.
3122470Sjake * All rights reserved.
4122470Sjake *
5122470Sjake * Redistribution and use in source and binary forms, with or without
6122470Sjake * modification, are permitted provided that the following conditions
7122470Sjake * are met:
8122470Sjake * 1. Redistributions of source code must retain the above copyright
9122470Sjake *    notice, this list of conditions and the following disclaimer.
10122470Sjake * 2. Redistributions in binary form must reproduce the above copyright
11122470Sjake *    notice, this list of conditions and the following disclaimer in the
12122470Sjake *    documentation and/or other materials provided with the distribution.
13122470Sjake *
14122470Sjake * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15122470Sjake * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16122470Sjake * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17122470Sjake * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18122470Sjake * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19122470Sjake * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20122470Sjake * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21122470Sjake * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22122470Sjake * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23122470Sjake * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24122470Sjake * SUCH DAMAGE.
25122470Sjake */
26122470Sjake
27146475Smarius#include <sys/cdefs.h>
28146475Smarius__FBSDID("$FreeBSD: releng/10.3/sys/dev/uart/uart_kbd_sun.c 224126 2011-07-17 08:19:19Z ed $");
29146475Smarius
30162711Sru#include "opt_compat.h"
31122470Sjake#include "opt_kbd.h"
32163890Smarius#include "opt_sunkbd.h"
33122470Sjake
34163890Smarius#if (defined(SUNKBD_EMULATE_ATKBD) && defined(SUNKBD_DFLT_KEYMAP)) ||	\
35163890Smarius    !defined(SUNKBD_EMULATE_ATKBD)
36163890Smarius#define	KBD_DFLT_KEYMAP
37163890Smarius#endif
38163890Smarius
39122470Sjake#include <sys/param.h>
40122470Sjake#include <sys/systm.h>
41122470Sjake#include <sys/bus.h>
42122470Sjake#include <sys/interrupt.h>
43122470Sjake#include <sys/kbio.h>
44122470Sjake#include <sys/kernel.h>
45163890Smarius#include <sys/limits.h>
46122470Sjake
47122470Sjake#include <machine/bus.h>
48122470Sjake
49122470Sjake#include <dev/kbd/kbdreg.h>
50163890Smarius#include <dev/kbd/kbdtables.h>
51122470Sjake
52122470Sjake#include <dev/uart/uart.h>
53122470Sjake#include <dev/uart/uart_bus.h>
54122470Sjake#include <dev/uart/uart_cpu.h>
55122470Sjake
56122470Sjake#include <dev/uart/uart_kbd_sun.h>
57163890Smarius#if !defined(SUNKBD_EMULATE_ATKBD)
58122470Sjake#include <dev/uart/uart_kbd_sun_tables.h>
59163890Smarius#endif
60122470Sjake
61163890Smarius#if defined(SUNKBD_EMULATE_ATKBD) && defined(SUNKBD_DFLT_KEYMAP)
62163890Smarius#include "sunkbdmap.h"
63163890Smarius#endif
64122470Sjake#include "uart_if.h"
65122470Sjake
66163890Smarius#define	SUNKBD_DRIVER_NAME	"sunkbd"
67122470Sjake
68122470Sjake#define	TODO	printf("%s: unimplemented", __func__)
69122470Sjake
70122470Sjakestruct sunkbd_softc {
71122470Sjake	keyboard_t		sc_kbd;
72122470Sjake	struct uart_softc	*sc_uart;
73122470Sjake	struct uart_devinfo	*sc_sysdev;
74122470Sjake
75122470Sjake	struct callout		sc_repeat_callout;
76122470Sjake	int			sc_repeat_key;
77122470Sjake
78122470Sjake	int			sc_accents;
79163890Smarius	int			sc_composed_char;
80163890Smarius	int			sc_flags;
81163890Smarius#define	KPCOMPOSE			(1 << 0)
82122470Sjake	int			sc_mode;
83122470Sjake	int			sc_polling;
84122470Sjake	int			sc_repeating;
85122470Sjake	int			sc_state;
86163890Smarius
87163890Smarius#if defined(SUNKBD_EMULATE_ATKBD)
88163890Smarius	int			sc_buffered_char[2];
89163890Smarius#endif
90122470Sjake};
91122470Sjake
92122470Sjakestatic int sunkbd_configure(int flags);
93122470Sjakestatic int sunkbd_probe_keyboard(struct uart_devinfo *di);
94122470Sjake
95122470Sjakestatic int sunkbd_probe(int unit, void *arg, int flags);
96122470Sjakestatic int sunkbd_init(int unit, keyboard_t **kbdp, void *arg, int flags);
97122470Sjakestatic int sunkbd_term(keyboard_t *kbd);
98122470Sjakestatic int sunkbd_intr(keyboard_t *kbd, void *arg);
99122470Sjakestatic int sunkbd_test_if(keyboard_t *kbd);
100122470Sjakestatic int sunkbd_enable(keyboard_t *kbd);
101122470Sjakestatic int sunkbd_disable(keyboard_t *kbd);
102122470Sjakestatic int sunkbd_read(keyboard_t *kbd, int wait);
103122470Sjakestatic int sunkbd_check(keyboard_t *kbd);
104122470Sjakestatic u_int sunkbd_read_char(keyboard_t *kbd, int wait);
105122470Sjakestatic int sunkbd_check_char(keyboard_t *kbd);
106122470Sjakestatic int sunkbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t data);
107122470Sjakestatic int sunkbd_lock(keyboard_t *kbd, int lock);
108122470Sjakestatic void sunkbd_clear_state(keyboard_t *kbd);
109122470Sjakestatic int sunkbd_get_state(keyboard_t *kbd, void *buf, size_t len);
110122470Sjakestatic int sunkbd_set_state(keyboard_t *kbd, void *buf, size_t len);
111122470Sjakestatic int sunkbd_poll_mode(keyboard_t *kbd, int on);
112122470Sjakestatic void sunkbd_diag(keyboard_t *kbd, int level);
113122470Sjake
114122470Sjakestatic void sunkbd_repeat(void *v);
115163890Smarius#if defined(SUNKBD_EMULATE_ATKBD)
116163890Smariusstatic int keycode2scancode(int keycode, int shift, int up);
117163890Smarius#endif
118122470Sjake
119122470Sjakestatic keyboard_switch_t sunkbdsw = {
120122470Sjake	sunkbd_probe,
121122470Sjake	sunkbd_init,
122122470Sjake	sunkbd_term,
123122470Sjake	sunkbd_intr,
124122470Sjake	sunkbd_test_if,
125122470Sjake	sunkbd_enable,
126122470Sjake	sunkbd_disable,
127122470Sjake	sunkbd_read,
128122470Sjake	sunkbd_check,
129122470Sjake	sunkbd_read_char,
130122470Sjake	sunkbd_check_char,
131122470Sjake	sunkbd_ioctl,
132122470Sjake	sunkbd_lock,
133122470Sjake	sunkbd_clear_state,
134122470Sjake	sunkbd_get_state,
135122470Sjake	sunkbd_set_state,
136122470Sjake	genkbd_get_fkeystr,
137122470Sjake	sunkbd_poll_mode,
138122470Sjake	sunkbd_diag
139122470Sjake};
140122470Sjake
141122470SjakeKEYBOARD_DRIVER(sunkbd, sunkbdsw, sunkbd_configure);
142122470Sjake
143122470Sjakestatic struct sunkbd_softc sunkbd_softc;
144122470Sjakestatic struct uart_devinfo uart_keyboard;
145122470Sjake
146163890Smarius#if defined(SUNKBD_EMULATE_ATKBD)
147163890Smarius
148163890Smarius#define	SCAN_PRESS		0x000
149163890Smarius#define	SCAN_RELEASE		0x080
150163890Smarius#define	SCAN_PREFIX_E0		0x100
151163890Smarius#define	SCAN_PREFIX_E1		0x200
152163890Smarius#define	SCAN_PREFIX_CTL		0x400
153163890Smarius#define	SCAN_PREFIX_SHIFT	0x800
154163890Smarius#define	SCAN_PREFIX		(SCAN_PREFIX_E0 | SCAN_PREFIX_E1 |	\
155163890Smarius				SCAN_PREFIX_CTL | SCAN_PREFIX_SHIFT)
156163890Smarius
157163890Smarius#define	NOTR	0x0	/* no translation */
158163890Smarius
159163890Smariusstatic const uint8_t sunkbd_trtab[] = {
160163890Smarius	NOTR, 0x6d, 0x78, 0x6e, 0x79, 0x3b, 0x3c, 0x44, /* 0x00 - 0x07 */
161163890Smarius	0x3d, 0x57, 0x3e, 0x58, 0x3f, 0x5d, 0x40, NOTR, /* 0x08 - 0x0f */
162163890Smarius	0x41, 0x42, 0x43, 0x38, 0x5f, 0x68, 0x5c, 0x46, /* 0x10 - 0x17 */
163169173Smarius	0x61, 0x6f, 0x70, 0x64, 0x62, 0x01, 0x02, 0x03, /* 0x18 - 0x1f */
164163890Smarius	0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, /* 0x20 - 0x27 */
165163890Smarius	0x0c, 0x0d, 0x29, 0x0e, 0x66, 0x77, 0x5b, 0x37, /* 0x28 - 0x2f */
166169173Smarius	0x7a, 0x71, 0x53, 0x74, 0x5e, 0x0f, 0x10, 0x11, /* 0x30 - 0x37 */
167163890Smarius	0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, /* 0x38 - 0x3f */
168163890Smarius	0x1a, 0x1b, 0x67, 0x6b, 0x47, 0x48, 0x49, 0x4a, /* 0x40 - 0x47 */
169169173Smarius	0x73, 0x72, 0x63, NOTR, 0x1d, 0x1e, 0x1f, 0x20, /* 0x48 - 0x4f */
170163890Smarius	0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, /* 0x50 - 0x57 */
171163890Smarius	0x2b, 0x1c, 0x59, 0x4b, 0x4c, 0x4d, 0x52, 0x75, /* 0x58 - 0x5f */
172163890Smarius	0x60, 0x76, 0x45, 0x2a, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x60 - 0x67 */
173163890Smarius	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, NOTR, /* 0x68 - 0x6f */
174163890Smarius	0x4f, 0x50, 0x51, NOTR, NOTR, NOTR, 0x6c, 0x3a, /* 0x70 - 0x77 */
175163890Smarius	0x69, 0x39, 0x6a, 0x65, 0x56, 0x4e, NOTR, NOTR  /* 0x78 - 0x7f */
176122470Sjake};
177122470Sjake
178163890Smarius#endif
179163890Smarius
180122470Sjakestatic int
181122470Sjakesunkbd_probe_keyboard(struct uart_devinfo *di)
182122470Sjake{
183163890Smarius	int c, id, ltries, tries;
184122470Sjake
185122470Sjake	for (tries = 5; tries != 0; tries--) {
186122470Sjake		uart_putc(di, SKBD_CMD_RESET);
187122470Sjake		for (ltries = 1000; ltries != 0; ltries--) {
188122470Sjake			if (uart_poll(di) == SKBD_RSP_RESET)
189122470Sjake				break;
190122470Sjake			DELAY(1000);
191122470Sjake		}
192122470Sjake		if (ltries == 0)
193122470Sjake			continue;
194163890Smarius		id = -1;
195122470Sjake		for (ltries = 1000; ltries != 0; ltries--) {
196163890Smarius			switch (c = uart_poll(di)) {
197163890Smarius			case -1:
198122470Sjake				break;
199163890Smarius			case SKBD_RSP_IDLE:
200163890Smarius				return (id);
201163890Smarius			default:
202163890Smarius				id = c;
203163890Smarius			}
204122470Sjake			DELAY(1000);
205122470Sjake		}
206122470Sjake	}
207122470Sjake	return (-1);
208122470Sjake}
209122470Sjake
210122470Sjakestatic int sunkbd_attach(struct uart_softc *sc);
211122470Sjakestatic void sunkbd_uart_intr(void *arg);
212122470Sjake
213122470Sjakestatic int
214122470Sjakesunkbd_configure(int flags)
215122470Sjake{
216122470Sjake	struct sunkbd_softc *sc;
217122470Sjake
218146975Smarius	/*
219146975Smarius	 * We are only prepared to be used for the high-level console
220146975Smarius	 * when the keyboard is both configured and attached.
221146975Smarius	 */
222146975Smarius	if (!(flags & KB_CONF_PROBE_ONLY)) {
223146975Smarius		if (KBD_IS_INITIALIZED(&sunkbd_softc.sc_kbd))
224146975Smarius			goto found;
225146975Smarius		else
226146475Smarius			return (0);
227146475Smarius	}
228146475Smarius
229146975Smarius	if (uart_cpu_getdev(UART_DEV_KEYBOARD, &uart_keyboard))
230146975Smarius		return (0);
231146975Smarius	if (uart_probe(&uart_keyboard))
232146975Smarius		return (0);
233146975Smarius	uart_init(&uart_keyboard);
234146975Smarius
235146975Smarius	uart_keyboard.type = UART_DEV_KEYBOARD;
236146975Smarius	uart_keyboard.attach = sunkbd_attach;
237146975Smarius	uart_add_sysdev(&uart_keyboard);
238146975Smarius
239163890Smarius	if (sunkbd_probe_keyboard(&uart_keyboard) != KB_SUN4)
240141081Smarcel		return (0);
241141081Smarcel
242122470Sjake	sc = &sunkbd_softc;
243122470Sjake	callout_init(&sc->sc_repeat_callout, 0);
244163890Smarius	sunkbd_clear_state(&sc->sc_kbd);
245122470Sjake
246163890Smarius#if defined(SUNKBD_EMULATE_ATKBD)
247163890Smarius	kbd_init_struct(&sc->sc_kbd, SUNKBD_DRIVER_NAME, KB_101, 0, 0, 0, 0);
248163890Smarius	kbd_set_maps(&sc->sc_kbd, &key_map, &accent_map, fkey_tab,
249163890Smarius	    sizeof(fkey_tab) / sizeof(fkey_tab[0]));
250163890Smarius#else
251163890Smarius	kbd_init_struct(&sc->sc_kbd, SUNKBD_DRIVER_NAME, KB_OTHER, 0, 0, 0, 0);
252122470Sjake	kbd_set_maps(&sc->sc_kbd, &keymap_sun_us_unix_kbd,
253122470Sjake	    &accentmap_sun_us_unix_kbd, fkey_tab,
254122470Sjake	    sizeof(fkey_tab) / sizeof(fkey_tab[0]));
255163890Smarius#endif
256122470Sjake	sc->sc_mode = K_XLATE;
257122470Sjake	kbd_register(&sc->sc_kbd);
258122470Sjake
259122470Sjake	sc->sc_sysdev = &uart_keyboard;
260122470Sjake
261146475Smarius found:
262146475Smarius	/* Return number of found keyboards. */
263146475Smarius	return (1);
264122470Sjake}
265122470Sjake
266122470Sjakestatic int
267122470Sjakesunkbd_attach(struct uart_softc *sc)
268122470Sjake{
269122470Sjake
270141081Smarcel	/*
271141081Smarcel	 * Don't attach if we didn't probe the keyboard. Note that
272141081Smarcel	 * the UART is still marked as a system device in that case.
273141081Smarcel	 */
274141081Smarcel	if (sunkbd_softc.sc_sysdev == NULL) {
275141081Smarcel		device_printf(sc->sc_dev, "keyboard not present\n");
276141081Smarcel		return (0);
277141081Smarcel	}
278141081Smarcel
279122470Sjake	if (sc->sc_sysdev != NULL) {
280122470Sjake		sunkbd_softc.sc_uart = sc;
281122470Sjake
282127740Smarcel#ifdef KBD_INSTALL_CDEV
283122470Sjake		kbd_attach(&sunkbd_softc.sc_kbd);
284127740Smarcel#endif
285122470Sjake		sunkbd_enable(&sunkbd_softc.sc_kbd);
286122470Sjake
287151658Sjhb		swi_add(&tty_intr_event, uart_driver_name, sunkbd_uart_intr,
288122470Sjake		    &sunkbd_softc, SWI_TTY, INTR_TYPE_TTY, &sc->sc_softih);
289122470Sjake
290122470Sjake		sc->sc_opened = 1;
291146975Smarius		KBD_INIT_DONE(&sunkbd_softc.sc_kbd);
292122470Sjake	}
293122470Sjake
294122470Sjake	return (0);
295122470Sjake}
296122470Sjake
297122470Sjakestatic void
298122470Sjakesunkbd_uart_intr(void *arg)
299122470Sjake{
300122470Sjake	struct sunkbd_softc *sc = arg;
301122470Sjake	int pend;
302122470Sjake
303122470Sjake	if (sc->sc_uart->sc_leaving)
304122470Sjake		return;
305122470Sjake
306122470Sjake	pend = atomic_readandclear_32(&sc->sc_uart->sc_ttypend);
307155971Smarcel	if (!(pend & SER_INT_MASK))
308122470Sjake		return;
309122470Sjake
310155971Smarcel	if (pend & SER_INT_RXREADY) {
311122470Sjake		if (KBD_IS_ACTIVE(&sc->sc_kbd) && KBD_IS_BUSY(&sc->sc_kbd)) {
312122470Sjake			sc->sc_kbd.kb_callback.kc_func(&sc->sc_kbd,
313122470Sjake			    KBDIO_KEYINPUT, sc->sc_kbd.kb_callback.kc_arg);
314122470Sjake		}
315122470Sjake	}
316122470Sjake}
317122470Sjake
318122470Sjakestatic int
319122470Sjakesunkbd_probe(int unit, void *arg, int flags)
320122470Sjake{
321163890Smarius
322122470Sjake	TODO;
323122470Sjake	return (0);
324122470Sjake}
325122470Sjake
326122470Sjakestatic int
327122470Sjakesunkbd_init(int unit, keyboard_t **kbdp, void *arg, int flags)
328122470Sjake{
329163890Smarius
330122470Sjake	TODO;
331122470Sjake	return (0);
332122470Sjake}
333122470Sjake
334122470Sjakestatic int
335122470Sjakesunkbd_term(keyboard_t *kbd)
336122470Sjake{
337163890Smarius
338122470Sjake	TODO;
339122470Sjake	return (0);
340122470Sjake}
341122470Sjake
342122470Sjakestatic int
343122470Sjakesunkbd_intr(keyboard_t *kbd, void *arg)
344122470Sjake{
345163890Smarius
346122470Sjake	TODO;
347122470Sjake	return (0);
348122470Sjake}
349122470Sjake
350122470Sjakestatic int
351122470Sjakesunkbd_test_if(keyboard_t *kbd)
352122470Sjake{
353163890Smarius
354122470Sjake	TODO;
355122470Sjake	return (0);
356122470Sjake}
357122470Sjake
358122470Sjakestatic int
359122470Sjakesunkbd_enable(keyboard_t *kbd)
360122470Sjake{
361163890Smarius
362122470Sjake	KBD_ACTIVATE(kbd);
363122470Sjake	return (0);
364122470Sjake}
365122470Sjake
366122470Sjakestatic int
367122470Sjakesunkbd_disable(keyboard_t *kbd)
368122470Sjake{
369163890Smarius
370122470Sjake	KBD_DEACTIVATE(kbd);
371122470Sjake	return (0);
372122470Sjake}
373122470Sjake
374122470Sjakestatic int
375122470Sjakesunkbd_read(keyboard_t *kbd, int wait)
376122470Sjake{
377163890Smarius
378122470Sjake	TODO;
379122470Sjake	return (0);
380122470Sjake}
381122470Sjake
382122470Sjakestatic int
383122470Sjakesunkbd_check(keyboard_t *kbd)
384122470Sjake{
385163890Smarius	struct sunkbd_softc *sc;
386163890Smarius
387163890Smarius	if (!KBD_IS_ACTIVE(kbd))
388163890Smarius		return (FALSE);
389163890Smarius
390163890Smarius	sc = (struct sunkbd_softc *)kbd;
391163890Smarius
392163890Smarius#if defined(SUNKBD_EMULATE_ATKBD)
393163890Smarius	if (sc->sc_buffered_char[0])
394163890Smarius		return (TRUE);
395163890Smarius#endif
396163890Smarius
397163890Smarius	if (sc->sc_repeating)
398163890Smarius		return (TRUE);
399163890Smarius
400163890Smarius	if (sc->sc_uart != NULL && !uart_rx_empty(sc->sc_uart))
401163890Smarius		return (TRUE);
402163890Smarius
403163890Smarius	if (sc->sc_polling != 0 && sc->sc_sysdev != NULL &&
404166100Smarius	    uart_rxready(sc->sc_sysdev))
405163890Smarius		return (TRUE);
406163890Smarius
407163890Smarius	return (FALSE);
408122470Sjake}
409122470Sjake
410122470Sjakestatic u_int
411122470Sjakesunkbd_read_char(keyboard_t *kbd, int wait)
412122470Sjake{
413122470Sjake	struct sunkbd_softc *sc;
414163890Smarius	int key, release, repeated, suncode;
415122470Sjake
416122470Sjake	sc = (struct sunkbd_softc *)kbd;
417163890Smarius
418163890Smarius#if defined(SUNKBD_EMULATE_ATKBD)
419163890Smarius	if (sc->sc_mode == K_RAW && sc->sc_buffered_char[0]) {
420163890Smarius		key = sc->sc_buffered_char[0];
421163890Smarius		if (key & SCAN_PREFIX) {
422163890Smarius			sc->sc_buffered_char[0] = key & ~SCAN_PREFIX;
423163890Smarius			return ((key & SCAN_PREFIX_E0) ? 0xe0 : 0xe1);
424163890Smarius		} else {
425163890Smarius			sc->sc_buffered_char[0] = sc->sc_buffered_char[1];
426163890Smarius			sc->sc_buffered_char[1] = 0;
427163890Smarius			return (key);
428163890Smarius		}
429163890Smarius	}
430163890Smarius#endif
431163890Smarius
432163890Smarius	repeated = 0;
433122470Sjake	if (sc->sc_repeating) {
434163890Smarius		repeated = 1;
435122470Sjake		sc->sc_repeating = 0;
436122470Sjake		callout_reset(&sc->sc_repeat_callout, hz / 10,
437122470Sjake		    sunkbd_repeat, sc);
438163890Smarius		suncode = sc->sc_repeat_key;
439163890Smarius		goto process_code;
440122470Sjake	}
441122470Sjake
442122470Sjake	for (;;) {
443163890Smarius next_code:
444163890Smarius		if (!(sc->sc_flags & KPCOMPOSE) && (sc->sc_composed_char > 0)) {
445163890Smarius			key = sc->sc_composed_char;
446163890Smarius			sc->sc_composed_char = 0;
447163890Smarius			if (key > UCHAR_MAX)
448163890Smarius				return (ERRKEY);
449163890Smarius			return (key);
450163890Smarius		}
451122470Sjake
452122470Sjake		if (sc->sc_uart != NULL && !uart_rx_empty(sc->sc_uart)) {
453163890Smarius			suncode = uart_rx_get(sc->sc_uart);
454122470Sjake		} else if (sc->sc_polling != 0 && sc->sc_sysdev != NULL) {
455122470Sjake			if (wait)
456163890Smarius				suncode = uart_getc(sc->sc_sysdev);
457163890Smarius			else if ((suncode = uart_poll(sc->sc_sysdev)) == -1)
458122470Sjake				return (NOKEY);
459122470Sjake		} else {
460122470Sjake			return (NOKEY);
461122470Sjake		}
462122470Sjake
463163890Smarius		switch (suncode) {
464122470Sjake		case SKBD_RSP_IDLE:
465122470Sjake			break;
466122470Sjake		default:
467163890Smarius process_code:
468122470Sjake			++kbd->kb_count;
469163890Smarius			key = SKBD_KEY_CHAR(suncode);
470163890Smarius			release = suncode & SKBD_KEY_RELEASE;
471163890Smarius			if (!repeated) {
472163890Smarius				if (release == 0) {
473163890Smarius					callout_reset(&sc->sc_repeat_callout,
474163890Smarius					    hz / 2, sunkbd_repeat, sc);
475163890Smarius					sc->sc_repeat_key = suncode;
476163890Smarius				} else if (sc->sc_repeat_key == key) {
477122470Sjake					callout_stop(&sc->sc_repeat_callout);
478122470Sjake					sc->sc_repeat_key = -1;
479122470Sjake				}
480122470Sjake			}
481122470Sjake
482163890Smarius#if defined(SUNKBD_EMULATE_ATKBD)
483163890Smarius			key = sunkbd_trtab[key];
484163890Smarius			if (key == NOTR)
485163890Smarius				return (NOKEY);
486163890Smarius
487163890Smarius			if (!repeated) {
488163890Smarius				switch (key) {
489163890Smarius				case 0x1d:	/* ctrl */
490163890Smarius					if (release != 0)
491163890Smarius						sc->sc_flags &= ~CTLS;
492163890Smarius					else
493163890Smarius						sc->sc_flags |= CTLS;
494163890Smarius					break;
495163890Smarius				case 0x2a:	/* left shift */
496163890Smarius				case 0x36:	/* right shift */
497163890Smarius					if (release != 0)
498163890Smarius						sc->sc_flags &= ~SHIFTS;
499163890Smarius					else
500163890Smarius						sc->sc_flags |= SHIFTS;
501163890Smarius					break;
502163890Smarius				case 0x38:	/* alt */
503163890Smarius				case 0x5d:	/* altgr */
504163890Smarius					if (release != 0)
505163890Smarius						sc->sc_flags &= ~ALTS;
506163890Smarius					else
507163890Smarius						sc->sc_flags |= ALTS;
508163890Smarius					break;
509163890Smarius				}
510163890Smarius			}
511163890Smarius			if (sc->sc_mode == K_RAW) {
512163890Smarius				key = keycode2scancode(key, sc->sc_flags,
513163890Smarius				    release);
514163890Smarius				if (key & SCAN_PREFIX) {
515163890Smarius					if (key & SCAN_PREFIX_CTL) {
516163890Smarius						sc->sc_buffered_char[0] =
517163890Smarius						    0x1d | (key & SCAN_RELEASE);
518163890Smarius						sc->sc_buffered_char[1] =
519163890Smarius						    key & ~SCAN_PREFIX;
520163890Smarius					} else if (key & SCAN_PREFIX_SHIFT) {
521163890Smarius						sc->sc_buffered_char[0] =
522163890Smarius						    0x2a | (key & SCAN_RELEASE);
523163890Smarius						sc->sc_buffered_char[1] =
524163890Smarius						    key & ~SCAN_PREFIX_SHIFT;
525163890Smarius					} else {
526163890Smarius						sc->sc_buffered_char[0] =
527163890Smarius						    key & ~SCAN_PREFIX;
528163890Smarius						sc->sc_buffered_char[1] = 0;
529163890Smarius					}
530163890Smarius					return ((key & SCAN_PREFIX_E0) ?
531163890Smarius					    0xe0 : 0xe1);
532163890Smarius				}
533122470Sjake				return (key);
534163890Smarius			}
535163890Smarius			switch (key) {
536163890Smarius			case 0x5c:	/* print screen */
537163890Smarius				if (sc->sc_flags & ALTS)
538163890Smarius					key = 0x54;	/* sysrq */
539163890Smarius				break;
540163890Smarius			case 0x68:	/* pause/break */
541163890Smarius				if (sc->sc_flags & CTLS)
542163890Smarius					key = 0x6c;	/* break */
543163890Smarius				break;
544163890Smarius			}
545122470Sjake
546163890Smarius			if (sc->sc_mode == K_CODE)
547163890Smarius				return (key | release);
548163890Smarius#else
549163890Smarius			if (sc->sc_mode == K_RAW || sc->sc_mode == K_CODE)
550163890Smarius				return (suncode);
551163890Smarius#endif
552163890Smarius
553163890Smarius#if defined(SUNKBD_EMULATE_ATKBD)
554163890Smarius			if (key == 0x38) {	/* left alt (KP compose key) */
555163890Smarius#else
556163890Smarius			if (key == 0x13) {	/* left alt (KP compose key) */
557163890Smarius#endif
558163890Smarius				if (release != 0) {
559166100Smarius					if (sc->sc_flags & KPCOMPOSE) {
560166100Smarius						sc->sc_flags &= ~KPCOMPOSE;
561166100Smarius						if (sc->sc_composed_char >
562166100Smarius						    UCHAR_MAX)
563166100Smarius							sc->sc_composed_char =
564166100Smarius							    0;
565163890Smarius					}
566163890Smarius				} else {
567163890Smarius					if (!(sc->sc_flags & KPCOMPOSE)) {
568163890Smarius						sc->sc_flags |= KPCOMPOSE;
569163890Smarius						sc->sc_composed_char = 0;
570163890Smarius					}
571163890Smarius				}
572163890Smarius			}
573163890Smarius			if (sc->sc_flags & KPCOMPOSE) {
574163890Smarius				switch (suncode) {
575163890Smarius				case 0x44:			/* KP 7 */
576163890Smarius				case 0x45:			/* KP 8 */
577163890Smarius				case 0x46:			/* KP 9 */
578163890Smarius					sc->sc_composed_char *= 10;
579163890Smarius					sc->sc_composed_char += suncode - 0x3d;
580163890Smarius					if (sc->sc_composed_char > UCHAR_MAX)
581163890Smarius						return (ERRKEY);
582163890Smarius					goto next_code;
583163890Smarius				case 0x5b:			/* KP 4 */
584163890Smarius				case 0x5c:			/* KP 5 */
585163890Smarius				case 0x5d:			/* KP 6 */
586163890Smarius					sc->sc_composed_char *= 10;
587163890Smarius					sc->sc_composed_char += suncode - 0x58;
588163890Smarius					if (sc->sc_composed_char > UCHAR_MAX)
589163890Smarius						return (ERRKEY);
590163890Smarius					goto next_code;
591163890Smarius				case 0x70:			/* KP 1 */
592163890Smarius				case 0x71:			/* KP 2 */
593163890Smarius				case 0x72:			/* KP 3 */
594163890Smarius					sc->sc_composed_char *= 10;
595163890Smarius					sc->sc_composed_char += suncode - 0x6f;
596163890Smarius					if (sc->sc_composed_char > UCHAR_MAX)
597163890Smarius						return (ERRKEY);
598163890Smarius					goto next_code;
599163890Smarius				case 0x5e:			/* KP 0 */
600163890Smarius					sc->sc_composed_char *= 10;
601163890Smarius					if (sc->sc_composed_char > UCHAR_MAX)
602163890Smarius						return (ERRKEY);
603163890Smarius					goto next_code;
604163890Smarius
605163890Smarius				case 0x44 | SKBD_KEY_RELEASE:	/* KP 7 */
606163890Smarius				case 0x45 | SKBD_KEY_RELEASE:	/* KP 8 */
607163890Smarius				case 0x46 | SKBD_KEY_RELEASE:	/* KP 9 */
608163890Smarius				case 0x5b | SKBD_KEY_RELEASE:	/* KP 4 */
609163890Smarius				case 0x5c | SKBD_KEY_RELEASE:	/* KP 5 */
610163890Smarius				case 0x5d | SKBD_KEY_RELEASE:	/* KP 6 */
611163890Smarius				case 0x70 | SKBD_KEY_RELEASE:	/* KP 1 */
612163890Smarius				case 0x71 | SKBD_KEY_RELEASE:	/* KP 2 */
613163890Smarius				case 0x72 | SKBD_KEY_RELEASE:	/* KP 3 */
614163890Smarius				case 0x5e | SKBD_KEY_RELEASE:	/* KP 0 */
615163890Smarius					goto next_code;
616163890Smarius				default:
617163890Smarius					if (sc->sc_composed_char > 0) {
618163890Smarius						sc->sc_flags &= ~KPCOMPOSE;
619163890Smarius						sc->sc_composed_char = 0;
620163890Smarius						return (ERRKEY);
621163890Smarius					}
622163890Smarius				}
623163890Smarius			}
624163890Smarius
625163890Smarius			key = genkbd_keyaction(kbd, key, release,
626122470Sjake			    &sc->sc_state, &sc->sc_accents);
627163890Smarius			if (key != NOKEY || repeated)
628163890Smarius				return (key);
629122470Sjake		}
630122470Sjake	}
631122470Sjake	return (0);
632122470Sjake}
633122470Sjake
634122470Sjakestatic int
635122470Sjakesunkbd_check_char(keyboard_t *kbd)
636122470Sjake{
637163890Smarius	struct sunkbd_softc *sc;
638163890Smarius
639163890Smarius	if (!KBD_IS_ACTIVE(kbd))
640163890Smarius		return (FALSE);
641163890Smarius
642163890Smarius	sc = (struct sunkbd_softc *)kbd;
643163890Smarius	if (!(sc->sc_flags & KPCOMPOSE) && (sc->sc_composed_char > 0))
644163890Smarius		return (TRUE);
645163890Smarius
646163890Smarius	return (sunkbd_check(kbd));
647122470Sjake}
648122470Sjake
649122470Sjakestatic int
650122470Sjakesunkbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t data)
651122470Sjake{
652122470Sjake	struct sunkbd_softc *sc;
653163890Smarius	int c, error;
654162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5)
655162711Sru	int ival;
656162711Sru#endif
657122470Sjake
658122470Sjake	sc = (struct sunkbd_softc *)kbd;
659122470Sjake	error = 0;
660122470Sjake	switch (cmd) {
661122470Sjake	case KDGKBMODE:
662122470Sjake		*(int *)data = sc->sc_mode;
663122470Sjake		break;
664162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5)
665162711Sru	case _IO('K', 7):
666162711Sru		ival = IOCPARM_IVAL(data);
667162711Sru		data = (caddr_t)&ival;
668162711Sru		/* FALLTHROUGH */
669162711Sru#endif
670122470Sjake	case KDSKBMODE:
671122470Sjake		switch (*(int *)data) {
672122470Sjake		case K_XLATE:
673122470Sjake			if (sc->sc_mode != K_XLATE) {
674122470Sjake				/* make lock key state and LED state match */
675122470Sjake				sc->sc_state &= ~LOCK_MASK;
676122470Sjake				sc->sc_state |= KBD_LED_VAL(kbd);
677122470Sjake			}
678122470Sjake			/* FALLTHROUGH */
679122470Sjake		case K_RAW:
680122470Sjake		case K_CODE:
681122470Sjake			if (sc->sc_mode != *(int *)data) {
682122470Sjake				sunkbd_clear_state(kbd);
683122470Sjake				sc->sc_mode = *(int *)data;
684122470Sjake			}
685122470Sjake			break;
686122470Sjake		default:
687122470Sjake			error = EINVAL;
688122470Sjake			break;
689122470Sjake		}
690122470Sjake		break;
691122470Sjake	case KDGETLED:
692122470Sjake		*(int *)data = KBD_LED_VAL(kbd);
693122470Sjake		break;
694162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5)
695162711Sru	case _IO('K', 66):
696162711Sru		ival = IOCPARM_IVAL(data);
697162711Sru		data = (caddr_t)&ival;
698162711Sru		/* FALLTHROUGH */
699162711Sru#endif
700122470Sjake	case KDSETLED:
701122470Sjake		if (*(int *)data & ~LOCK_MASK) {
702122470Sjake			error = EINVAL;
703122470Sjake			break;
704122470Sjake		}
705163890Smarius		if (sc->sc_sysdev == NULL)
706122470Sjake			break;
707163890Smarius		c = 0;
708122470Sjake		if (*(int *)data & CLKED)
709163890Smarius			c |= SKBD_LED_CAPSLOCK;
710122470Sjake		if (*(int *)data & NLKED)
711163890Smarius			c |= SKBD_LED_NUMLOCK;
712122470Sjake		if (*(int *)data & SLKED)
713163890Smarius			c |= SKBD_LED_SCROLLLOCK;
714163890Smarius		uart_lock(sc->sc_sysdev->hwmtx);
715168281Smarcel		sc->sc_sysdev->ops->putc(&sc->sc_sysdev->bas, SKBD_CMD_SETLED);
716168281Smarcel		sc->sc_sysdev->ops->putc(&sc->sc_sysdev->bas, c);
717163890Smarius		uart_unlock(sc->sc_sysdev->hwmtx);
718122470Sjake		KBD_LED_VAL(kbd) = *(int *)data;
719122470Sjake		break;
720122470Sjake	case KDGKBSTATE:
721122470Sjake		*(int *)data = sc->sc_state & LOCK_MASK;
722122470Sjake		break;
723162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5)
724162711Sru	case _IO('K', 20):
725162711Sru		ival = IOCPARM_IVAL(data);
726162711Sru		data = (caddr_t)&ival;
727162711Sru		/* FALLTHROUGH */
728162711Sru#endif
729122470Sjake	case KDSKBSTATE:
730122470Sjake		if (*(int *)data & ~LOCK_MASK) {
731122470Sjake			error = EINVAL;
732122470Sjake			break;
733122470Sjake		}
734122470Sjake		sc->sc_state &= ~LOCK_MASK;
735122470Sjake		sc->sc_state |= *(int *)data;
736162711Sru		/* set LEDs and quit */
737162711Sru		return (sunkbd_ioctl(kbd, KDSETLED, data));
738122470Sjake	case KDSETREPEAT:
739122470Sjake	case KDSETRAD:
740122470Sjake		break;
741122470Sjake	case PIO_KEYMAP:
742224126Sed	case OPIO_KEYMAP:
743122470Sjake	case PIO_KEYMAPENT:
744122470Sjake	case PIO_DEADKEYMAP:
745122470Sjake	default:
746122470Sjake		return (genkbd_commonioctl(kbd, cmd, data));
747122470Sjake	}
748122470Sjake	return (error);
749122470Sjake}
750122470Sjake
751122470Sjakestatic int
752122470Sjakesunkbd_lock(keyboard_t *kbd, int lock)
753122470Sjake{
754163890Smarius
755122470Sjake	TODO;
756122470Sjake	return (0);
757122470Sjake}
758122470Sjake
759122470Sjakestatic void
760122470Sjakesunkbd_clear_state(keyboard_t *kbd)
761122470Sjake{
762163890Smarius	struct sunkbd_softc *sc;
763163890Smarius
764163890Smarius	sc = (struct sunkbd_softc *)kbd;
765163890Smarius	sc->sc_repeat_key = -1;
766163890Smarius	sc->sc_accents = 0;
767163890Smarius	sc->sc_composed_char = 0;
768163890Smarius	sc->sc_flags = 0;
769163890Smarius	sc->sc_polling = 0;
770163890Smarius	sc->sc_repeating = 0;
771163890Smarius	sc->sc_state &= LOCK_MASK;	/* Preserve locking key state. */
772163890Smarius
773163890Smarius#if defined(SUNKBD_EMULATE_ATKBD)
774163890Smarius	sc->sc_buffered_char[0] = 0;
775163890Smarius	sc->sc_buffered_char[1] = 0;
776163890Smarius#endif
777122470Sjake}
778122470Sjake
779122470Sjakestatic int
780122470Sjakesunkbd_get_state(keyboard_t *kbd, void *buf, size_t len)
781122470Sjake{
782163890Smarius
783122470Sjake	TODO;
784122470Sjake	return (0);
785122470Sjake}
786122470Sjake
787122470Sjakestatic int
788122470Sjakesunkbd_set_state(keyboard_t *kbd, void *buf, size_t len)
789122470Sjake{
790163890Smarius
791122470Sjake	TODO;
792122470Sjake	return (0);
793122470Sjake}
794122470Sjake
795122470Sjakestatic int
796122470Sjakesunkbd_poll_mode(keyboard_t *kbd, int on)
797122470Sjake{
798122470Sjake	struct sunkbd_softc *sc;
799122470Sjake
800122470Sjake	sc = (struct sunkbd_softc *)kbd;
801122470Sjake	if (on)
802122470Sjake		sc->sc_polling++;
803122470Sjake	else
804122470Sjake		sc->sc_polling--;
805122470Sjake	return (0);
806122470Sjake}
807122470Sjake
808122470Sjakestatic void
809122470Sjakesunkbd_diag(keyboard_t *kbd, int level)
810122470Sjake{
811163890Smarius
812122470Sjake	TODO;
813122470Sjake}
814122470Sjake
815122470Sjakestatic void
816122470Sjakesunkbd_repeat(void *v)
817122470Sjake{
818122470Sjake	struct sunkbd_softc *sc = v;
819122470Sjake
820162424Semax	if (KBD_IS_ACTIVE(&sc->sc_kbd) && KBD_IS_BUSY(&sc->sc_kbd)) {
821162424Semax		if (sc->sc_repeat_key != -1) {
822162424Semax			sc->sc_repeating = 1;
823162424Semax			sc->sc_kbd.kb_callback.kc_func(&sc->sc_kbd,
824162424Semax			    KBDIO_KEYINPUT, sc->sc_kbd.kb_callback.kc_arg);
825162424Semax		}
826122470Sjake	}
827122470Sjake}
828163890Smarius
829163890Smarius#if defined(SUNKBD_EMULATE_ATKBD)
830163890Smariusstatic int
831163890Smariuskeycode2scancode(int keycode, int shift, int up)
832163890Smarius{
833163890Smarius	static const int scan[] = {
834163890Smarius		/* KP enter, right ctrl, KP divide */
835163890Smarius		0x1c , 0x1d , 0x35 ,
836163890Smarius		/* print screen */
837163890Smarius		0x37 | SCAN_PREFIX_SHIFT,
838163890Smarius		/* right alt, home, up, page up, left, right, end */
839163890Smarius		0x38, 0x47, 0x48, 0x49, 0x4b, 0x4d, 0x4f,
840163890Smarius		/* down, page down, insert, delete */
841163890Smarius		0x50, 0x51, 0x52, 0x53,
842163890Smarius		/* pause/break (see also below) */
843163890Smarius		0x46,
844163890Smarius		/*
845163890Smarius		 * MS: left window, right window, menu
846163890Smarius		 * also Sun: left meta, right meta, compose
847163890Smarius		 */
848163890Smarius		0x5b, 0x5c, 0x5d,
849163890Smarius		/* Sun type 6 USB */
850163890Smarius		/* help, stop, again, props, undo, front, copy */
851163890Smarius		0x68, 0x5e, 0x5f, 0x60,	0x61, 0x62, 0x63,
852163890Smarius		/* open, paste, find, cut, audiomute, audiolower, audioraise */
853163890Smarius		0x64, 0x65, 0x66, 0x67, 0x25, 0x1f, 0x1e,
854163890Smarius		/* power */
855163890Smarius		0x20
856163890Smarius	};
857163890Smarius	int scancode;
858163890Smarius
859163890Smarius	scancode = keycode;
860163890Smarius	if ((keycode >= 89) && (keycode < 89 + sizeof(scan) / sizeof(scan[0])))
861163890Smarius	scancode = scan[keycode - 89] | SCAN_PREFIX_E0;
862163890Smarius	/* pause/break */
863163890Smarius	if ((keycode == 104) && !(shift & CTLS))
864163890Smarius		scancode = 0x45 | SCAN_PREFIX_E1 | SCAN_PREFIX_CTL;
865163890Smarius	if (shift & SHIFTS)
866163890Smarius		scancode &= ~SCAN_PREFIX_SHIFT;
867163890Smarius	return (scancode | (up ? SCAN_RELEASE : SCAN_PRESS));
868163890Smarius}
869163890Smarius#endif
870