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