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