iwn{,fw}.4: Remove trailing whitespace and an unneeded .Pp
[dragonfly.git] / sys / dev / misc / kbd / kbd.c
CommitLineData
984263bc
MD
1/*-
2 * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer as
10 * the first lines of this file unmodified.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 * $FreeBSD: src/sys/dev/kbd/kbd.c,v 1.17.2.2 2001/07/30 16:46:43 yokota Exp $
028066b1 27 * $DragonFly: src/sys/dev/misc/kbd/kbd.c,v 1.23 2007/05/08 02:31:39 dillon Exp $
a38e57d5
MD
28 */
29/*
30 * Generic keyboard driver.
31 *
32 * Interrupt note: keyboards use clist functions and since usb keyboard
33 * interrupts are not protected by spltty(), we must use a critical section
34 * to protect against corruption.
bcc53404 35 * XXX: this keyboard driver doesn't use clist functions anymore!
984263bc
MD
36 */
37
38#include "opt_kbd.h"
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/kernel.h>
43#include <sys/malloc.h>
44#include <sys/conf.h>
45#include <sys/proc.h>
46#include <sys/tty.h>
25fef0f3 47#include <sys/event.h>
984263bc
MD
48#include <sys/vnode.h>
49#include <sys/uio.h>
a38e57d5
MD
50#include <sys/thread.h>
51#include <sys/thread2.h>
984263bc
MD
52
53#include <machine/console.h>
54
1f2de5d4 55#include "kbdreg.h"
984263bc
MD
56
57#define KBD_INDEX(dev) minor(dev)
58
bcc53404
AH
59#define KB_QSIZE 512
60#define KB_BUFSIZE 64
61
8a0a8f43 62struct genkbd_softc {
984263bc
MD
63 int gkb_flags; /* flag/status bits */
64#define KB_ASLEEP (1 << 0)
984263bc 65 struct selinfo gkb_rsel;
bcc53404
AH
66 char gkb_q[KB_QSIZE]; /* input queue */
67 unsigned int gkb_q_start;
68 unsigned int gkb_q_length;
8a0a8f43
MD
69};
70
71typedef struct genkbd_softc *genkbd_softc_t;
984263bc
MD
72
73static SLIST_HEAD(, keyboard_driver) keyboard_drivers =
74 SLIST_HEAD_INITIALIZER(keyboard_drivers);
75
dc62b251
MD
76SET_DECLARE(kbddriver_set, const keyboard_driver_t);
77
984263bc
MD
78/* local arrays */
79
80/*
81 * We need at least one entry each in order to initialize a keyboard
82 * for the kernel console. The arrays will be increased dynamically
83 * when necessary.
84 */
85
86static int keyboards = 1;
87static keyboard_t *kbd_ini;
88static keyboard_t **keyboard = &kbd_ini;
89static keyboard_switch_t *kbdsw_ini;
90 keyboard_switch_t **kbdsw = &kbdsw_ini;
91
92#define ARRAY_DELTA 4
93
94static int
95kbd_realloc_array(void)
96{
97 keyboard_t **new_kbd;
98 keyboard_switch_t **new_kbdsw;
99 int newsize;
984263bc 100
984263bc 101 newsize = ((keyboards + ARRAY_DELTA)/ARRAY_DELTA)*ARRAY_DELTA;
efda3bd0 102 new_kbd = kmalloc(sizeof(*new_kbd) * newsize, M_DEVBUF,
bf22d4c1 103 M_WAITOK | M_ZERO);
efda3bd0 104 new_kbdsw = kmalloc(sizeof(*new_kbdsw) * newsize, M_DEVBUF,
bf22d4c1 105 M_WAITOK | M_ZERO);
984263bc
MD
106 bcopy(keyboard, new_kbd, sizeof(*keyboard)*keyboards);
107 bcopy(kbdsw, new_kbdsw, sizeof(*kbdsw)*keyboards);
a38e57d5 108 crit_enter();
984263bc 109 if (keyboards > 1) {
efda3bd0
MD
110 kfree(keyboard, M_DEVBUF);
111 kfree(kbdsw, M_DEVBUF);
984263bc
MD
112 }
113 keyboard = new_kbd;
114 kbdsw = new_kbdsw;
115 keyboards = newsize;
a38e57d5 116 crit_exit();
984263bc
MD
117
118 if (bootverbose)
e3869ec7 119 kprintf("kbd: new array size %d\n", keyboards);
984263bc
MD
120
121 return 0;
122}
123
124/*
e30db56f
MD
125 * Low-level keyboard driver functions.
126 *
984263bc
MD
127 * Keyboard subdrivers, such as the AT keyboard driver and the USB keyboard
128 * driver, call these functions to initialize the keyboard_t structure
129 * and register it to the virtual keyboard driver `kbd'.
e30db56f
MD
130 *
131 * The reinit call is made when a driver has partially detached a keyboard
132 * but does not unregistered it, then wishes to reinitialize it later on.
133 * This is how the USB keyboard driver handles the 'default' keyboard,
134 * because unregistering the keyboard associated with the console will
135 * destroy its console association forever.
984263bc 136 */
984263bc 137void
e30db56f 138kbd_reinit_struct(keyboard_t *kbd, int config, int pref)
984263bc 139{
e30db56f 140 kbd->kb_flags |= KB_NO_DEVICE; /* device has not been found */
984263bc
MD
141 kbd->kb_config = config & ~KB_CONF_PROBE_ONLY;
142 kbd->kb_led = 0; /* unknown */
984263bc
MD
143 kbd->kb_data = NULL;
144 kbd->kb_keymap = NULL;
145 kbd->kb_accentmap = NULL;
146 kbd->kb_fkeytab = NULL;
147 kbd->kb_fkeytab_size = 0;
148 kbd->kb_delay1 = KB_DELAY1; /* these values are advisory only */
149 kbd->kb_delay2 = KB_DELAY2;
e30db56f
MD
150 kbd->kb_count = 0;
151 kbd->kb_pref = pref;
984263bc
MD
152 bzero(kbd->kb_lastact, sizeof(kbd->kb_lastact));
153}
154
e30db56f
MD
155/* initialize the keyboard_t structure */
156void
157kbd_init_struct(keyboard_t *kbd, char *name, int type, int unit, int config,
158 int pref, int port, int port_size)
159{
160 kbd->kb_flags = 0;
161 kbd->kb_name = name;
162 kbd->kb_type = type;
163 kbd->kb_unit = unit;
164 kbd->kb_io_base = port;
165 kbd->kb_io_size = port_size;
166 kbd_reinit_struct(kbd, config, pref);
167}
168
984263bc
MD
169void
170kbd_set_maps(keyboard_t *kbd, keymap_t *keymap, accentmap_t *accmap,
171 fkeytab_t *fkeymap, int fkeymap_size)
172{
173 kbd->kb_keymap = keymap;
174 kbd->kb_accentmap = accmap;
175 kbd->kb_fkeytab = fkeymap;
176 kbd->kb_fkeytab_size = fkeymap_size;
177}
178
179/* declare a new keyboard driver */
180int
181kbd_add_driver(keyboard_driver_t *driver)
182{
183 if (SLIST_NEXT(driver, link))
184 return EINVAL;
185 SLIST_INSERT_HEAD(&keyboard_drivers, driver, link);
186 return 0;
187}
188
189int
190kbd_delete_driver(keyboard_driver_t *driver)
191{
192 SLIST_REMOVE(&keyboard_drivers, driver, keyboard_driver, link);
193 SLIST_NEXT(driver, link) = NULL;
194 return 0;
195}
196
197/* register a keyboard and associate it with a function table */
198int
199kbd_register(keyboard_t *kbd)
200{
201 const keyboard_driver_t **list;
202 const keyboard_driver_t *p;
bcc53404
AH
203 keyboard_t *mux;
204 keyboard_info_t ki;
984263bc
MD
205 int index;
206
bcc53404
AH
207 mux = kbd_get_keyboard(kbd_find_keyboard("kbdmux", -1));
208
984263bc
MD
209 for (index = 0; index < keyboards; ++index) {
210 if (keyboard[index] == NULL)
211 break;
212 }
213 if (index >= keyboards) {
214 if (kbd_realloc_array())
215 return -1;
216 }
217
218 kbd->kb_index = index;
219 KBD_UNBUSY(kbd);
220 KBD_VALID(kbd);
221 kbd->kb_active = 0; /* disabled until someone calls kbd_enable() */
222 kbd->kb_token = NULL;
223 kbd->kb_callback.kc_func = NULL;
224 kbd->kb_callback.kc_arg = NULL;
c5e92a81 225 callout_init(&kbd->kb_atkbd_timeout_ch);
984263bc
MD
226
227 SLIST_FOREACH(p, &keyboard_drivers, link) {
228 if (strcmp(p->name, kbd->kb_name) == 0) {
229 keyboard[index] = kbd;
230 kbdsw[index] = p->kbdsw;
bcc53404
AH
231
232 if (mux != NULL) {
233 bzero(&ki, sizeof(ki));
234 strcpy(ki.kb_name, kbd->kb_name);
235 ki.kb_unit = kbd->kb_unit;
236 kbd_ioctl(mux, KBADDKBD, (caddr_t) &ki);
237 }
238
984263bc
MD
239 return index;
240 }
241 }
dc62b251
MD
242 SET_FOREACH(list, kbddriver_set) {
243 p = *list;
984263bc
MD
244 if (strcmp(p->name, kbd->kb_name) == 0) {
245 keyboard[index] = kbd;
246 kbdsw[index] = p->kbdsw;
bcc53404
AH
247
248 if (mux != NULL) {
249 bzero(&ki, sizeof(ki));
250 strcpy(ki.kb_name, kbd->kb_name);
251 ki.kb_unit = kbd->kb_unit;
252 kbd_ioctl(mux, KBADDKBD, (caddr_t) &ki);
253 }
254
984263bc
MD
255 return index;
256 }
257 }
258
259 return -1;
260}
261
262int
263kbd_unregister(keyboard_t *kbd)
264{
265 int error;
984263bc
MD
266
267 if ((kbd->kb_index < 0) || (kbd->kb_index >= keyboards))
268 return ENOENT;
269 if (keyboard[kbd->kb_index] != kbd)
270 return ENOENT;
271
a38e57d5 272 crit_enter();
c5e92a81 273 callout_stop(&kbd->kb_atkbd_timeout_ch);
984263bc
MD
274 if (KBD_IS_BUSY(kbd)) {
275 error = (*kbd->kb_callback.kc_func)(kbd, KBDIO_UNLOADING,
276 kbd->kb_callback.kc_arg);
277 if (error) {
a38e57d5 278 crit_exit();
984263bc
MD
279 return error;
280 }
281 if (KBD_IS_BUSY(kbd)) {
a38e57d5 282 crit_exit();
984263bc
MD
283 return EBUSY;
284 }
285 }
286 KBD_INVALID(kbd);
287 keyboard[kbd->kb_index] = NULL;
288 kbdsw[kbd->kb_index] = NULL;
289
a38e57d5 290 crit_exit();
984263bc
MD
291 return 0;
292}
293
294/* find a funciton table by the driver name */
3d8ba483
SW
295keyboard_switch_t *
296kbd_get_switch(char *driver)
984263bc
MD
297{
298 const keyboard_driver_t **list;
299 const keyboard_driver_t *p;
300
301 SLIST_FOREACH(p, &keyboard_drivers, link) {
302 if (strcmp(p->name, driver) == 0)
303 return p->kbdsw;
304 }
dc62b251
MD
305 SET_FOREACH(list, kbddriver_set) {
306 p = *list;
984263bc
MD
307 if (strcmp(p->name, driver) == 0)
308 return p->kbdsw;
309 }
310
311 return NULL;
312}
313
314/*
315 * Keyboard client functions
316 * Keyboard clients, such as the console driver `syscons' and the keyboard
317 * cdev driver, use these functions to claim and release a keyboard for
318 * exclusive use.
319 */
bcc53404
AH
320/*
321 * find the keyboard specified by a driver name and a unit number
322 * starting at given index
323 */
984263bc 324int
bcc53404 325kbd_find_keyboard2(char *driver, int unit, int index, int legacy)
984263bc
MD
326{
327 int i;
e30db56f
MD
328 int pref;
329 int pref_index;
330
331 pref = 0;
332 pref_index = -1;
984263bc 333
bcc53404
AH
334 if ((index < 0) || (index >= keyboards))
335 return (-1);
336
337 for (i = index; i < keyboards; ++i) {
984263bc
MD
338 if (keyboard[i] == NULL)
339 continue;
340 if (!KBD_IS_VALID(keyboard[i]))
341 continue;
342 if (strcmp("*", driver) && strcmp(keyboard[i]->kb_name, driver))
343 continue;
344 if ((unit != -1) && (keyboard[i]->kb_unit != unit))
345 continue;
bcc53404
AH
346 /*
347 * If we are in legacy mode, we do the old preference magic and
348 * don't return on the first found unit.
349 */
350 if (legacy) {
351 if (pref <= keyboard[i]->kb_pref) {
352 pref = keyboard[i]->kb_pref;
353 pref_index = i;
354 }
355 } else {
356 return i;
e30db56f 357 }
984263bc 358 }
bcc53404
AH
359
360 if (!legacy)
361 KKASSERT(pref_index == -1);
362
e30db56f 363 return (pref_index);
984263bc
MD
364}
365
bcc53404
AH
366/* find the keyboard specified by a driver name and a unit number */
367int
368kbd_find_keyboard(char *driver, int unit)
369{
370 return (kbd_find_keyboard2(driver, unit, 0, 1));
371}
372
984263bc
MD
373/* allocate a keyboard */
374int
375kbd_allocate(char *driver, int unit, void *id, kbd_callback_func_t *func,
376 void *arg)
377{
378 int index;
984263bc
MD
379
380 if (func == NULL)
381 return -1;
382
a38e57d5 383 crit_enter();
984263bc
MD
384 index = kbd_find_keyboard(driver, unit);
385 if (index >= 0) {
386 if (KBD_IS_BUSY(keyboard[index])) {
a38e57d5 387 crit_exit();
984263bc
MD
388 return -1;
389 }
390 keyboard[index]->kb_token = id;
391 KBD_BUSY(keyboard[index]);
392 keyboard[index]->kb_callback.kc_func = func;
393 keyboard[index]->kb_callback.kc_arg = arg;
bcc53404 394 kbd_clear_state(keyboard[index]);
984263bc 395 }
a38e57d5 396 crit_exit();
984263bc
MD
397 return index;
398}
399
400int
401kbd_release(keyboard_t *kbd, void *id)
402{
403 int error;
984263bc 404
a38e57d5 405 crit_enter();
984263bc
MD
406 if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) {
407 error = EINVAL;
408 } else if (kbd->kb_token != id) {
409 error = EPERM;
410 } else {
411 kbd->kb_token = NULL;
412 KBD_UNBUSY(kbd);
413 kbd->kb_callback.kc_func = NULL;
414 kbd->kb_callback.kc_arg = NULL;
bcc53404 415 kbd_clear_state(kbd);
984263bc
MD
416 error = 0;
417 }
a38e57d5 418 crit_exit();
984263bc
MD
419 return error;
420}
421
422int
423kbd_change_callback(keyboard_t *kbd, void *id, kbd_callback_func_t *func,
424 void *arg)
425{
426 int error;
984263bc 427
a38e57d5 428 crit_enter();
984263bc
MD
429 if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) {
430 error = EINVAL;
431 } else if (kbd->kb_token != id) {
432 error = EPERM;
433 } else if (func == NULL) {
434 error = EINVAL;
435 } else {
436 kbd->kb_callback.kc_func = func;
437 kbd->kb_callback.kc_arg = arg;
438 error = 0;
439 }
a38e57d5 440 crit_exit();
984263bc
MD
441 return error;
442}
443
444/* get a keyboard structure */
3d8ba483
SW
445keyboard_t *
446kbd_get_keyboard(int index)
984263bc
MD
447{
448 if ((index < 0) || (index >= keyboards))
449 return NULL;
450 if (keyboard[index] == NULL)
451 return NULL;
452 if (!KBD_IS_VALID(keyboard[index]))
453 return NULL;
454 return keyboard[index];
455}
456
457/*
458 * The back door for the console driver; configure keyboards
459 * This function is for the kernel console to initialize keyboards
460 * at very early stage.
461 */
462
463int
464kbd_configure(int flags)
465{
466 const keyboard_driver_t **list;
467 const keyboard_driver_t *p;
468
469 SLIST_FOREACH(p, &keyboard_drivers, link) {
470 if (p->configure != NULL)
471 (*p->configure)(flags);
472 }
dc62b251
MD
473 SET_FOREACH(list, kbddriver_set) {
474 p = *list;
984263bc
MD
475 if (p->configure != NULL)
476 (*p->configure)(flags);
477 }
478
479 return 0;
480}
481
482#ifdef KBD_INSTALL_CDEV
483
484/*
485 * Virtual keyboard cdev driver functions
486 * The virtual keyboard driver dispatches driver functions to
487 * appropriate subdrivers.
488 */
489
490#define KBD_UNIT(dev) minor(dev)
491
492static d_open_t genkbdopen;
493static d_close_t genkbdclose;
494static d_read_t genkbdread;
495static d_write_t genkbdwrite;
496static d_ioctl_t genkbdioctl;
25fef0f3
SG
497static d_kqfilter_t genkbdkqfilter;
498
499static void genkbdfiltdetach(struct knote *);
500static int genkbdfilter(struct knote *, long);
984263bc
MD
501
502#define CDEV_MAJOR 112
503
fef8985e 504static struct dev_ops kbd_ops = {
25fef0f3 505 { "kbd", CDEV_MAJOR, D_KQFILTER },
fef8985e
MD
506 .d_open = genkbdopen,
507 .d_close = genkbdclose,
508 .d_read = genkbdread,
509 .d_write = genkbdwrite,
510 .d_ioctl = genkbdioctl,
25fef0f3 511 .d_kqfilter = genkbdkqfilter
984263bc
MD
512};
513
8a0a8f43
MD
514/*
515 * Attach a keyboard.
516 *
517 * NOTE: The usb driver does not detach the default keyboard if it is
518 * unplugged, but calls kbd_attach() when it is plugged back in.
519 */
984263bc
MD
520int
521kbd_attach(keyboard_t *kbd)
522{
b13267a5 523 cdev_t dev;
984263bc
MD
524
525 if (kbd->kb_index >= keyboards)
526 return EINVAL;
527 if (keyboard[kbd->kb_index] != kbd)
528 return EINVAL;
529
8a0a8f43
MD
530 if (kbd->kb_dev == NULL) {
531 kbd->kb_dev = make_dev(&kbd_ops, kbd->kb_index,
532 UID_ROOT, GID_WHEEL, 0600,
533 "kbd%r", kbd->kb_index);
534 }
535 dev = kbd->kb_dev;
536 if (dev->si_drv1 == NULL) {
537 dev->si_drv1 = kmalloc(sizeof(struct genkbd_softc), M_DEVBUF,
538 M_WAITOK);
539 }
540 bzero(dev->si_drv1, sizeof(struct genkbd_softc));
984263bc 541
e3869ec7 542 kprintf("kbd%d at %s%d\n", kbd->kb_index, kbd->kb_name, kbd->kb_unit);
984263bc
MD
543 return 0;
544}
545
546int
547kbd_detach(keyboard_t *kbd)
548{
b13267a5 549 cdev_t dev;
984263bc
MD
550
551 if (kbd->kb_index >= keyboards)
552 return EINVAL;
553 if (keyboard[kbd->kb_index] != kbd)
554 return EINVAL;
555
8a0a8f43 556 if ((dev = kbd->kb_dev) != NULL) {
e4c9c0c8 557 if (dev->si_drv1) {
efda3bd0 558 kfree(dev->si_drv1, M_DEVBUF);
e4c9c0c8
MD
559 dev->si_drv1 = NULL;
560 }
8a0a8f43 561 kbd->kb_dev = NULL;
e4c9c0c8 562 }
cd29885a 563 dev_ops_remove_minor(&kbd_ops, kbd->kb_index);
984263bc
MD
564 return 0;
565}
566
567/*
568 * Generic keyboard cdev driver functions
569 * Keyboard subdrivers may call these functions to implement common
570 * driver functions.
571 */
572
bcc53404
AH
573static void
574genkbd_putc(genkbd_softc_t sc, char c)
575{
576 unsigned int p;
577
578 if (sc->gkb_q_length == KB_QSIZE)
579 return;
580
581 p = (sc->gkb_q_start + sc->gkb_q_length) % KB_QSIZE;
582 sc->gkb_q[p] = c;
583 sc->gkb_q_length++;
584}
585
586static size_t
587genkbd_getc(genkbd_softc_t sc, char *buf, size_t len)
588{
589
590 /* Determine copy size. */
591 if (sc->gkb_q_length == 0)
592 return (0);
593 if (len >= sc->gkb_q_length)
594 len = sc->gkb_q_length;
595 if (len >= KB_QSIZE - sc->gkb_q_start)
596 len = KB_QSIZE - sc->gkb_q_start;
597
598 /* Copy out data and progress offset. */
599 memcpy(buf, sc->gkb_q + sc->gkb_q_start, len);
600 sc->gkb_q_start = (sc->gkb_q_start + len) % KB_QSIZE;
601 sc->gkb_q_length -= len;
602
603 return (len);
604}
984263bc
MD
605
606static kbd_callback_func_t genkbd_event;
607
608static int
fef8985e 609genkbdopen(struct dev_open_args *ap)
984263bc 610{
b13267a5 611 cdev_t dev = ap->a_head.a_dev;
984263bc 612 keyboard_t *kbd;
8a0a8f43 613 genkbd_softc_t sc;
984263bc
MD
614 int i;
615
a38e57d5 616 crit_enter();
984263bc
MD
617 sc = dev->si_drv1;
618 kbd = kbd_get_keyboard(KBD_INDEX(dev));
619 if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
a38e57d5 620 crit_exit();
984263bc
MD
621 return ENXIO;
622 }
623 i = kbd_allocate(kbd->kb_name, kbd->kb_unit, sc,
624 genkbd_event, (void *)sc);
625 if (i < 0) {
a38e57d5 626 crit_exit();
984263bc
MD
627 return EBUSY;
628 }
629 /* assert(i == kbd->kb_index) */
630 /* assert(kbd == kbd_get_keyboard(i)) */
631
632 /*
633 * NOTE: even when we have successfully claimed a keyboard,
634 * the device may still be missing (!KBD_HAS_DEVICE(kbd)).
635 */
636
bcc53404 637 sc->gkb_q_length = 0;
a38e57d5 638 crit_exit();
984263bc
MD
639
640 return 0;
641}
642
643static int
fef8985e 644genkbdclose(struct dev_close_args *ap)
984263bc 645{
b13267a5 646 cdev_t dev = ap->a_head.a_dev;
984263bc 647 keyboard_t *kbd;
8a0a8f43 648 genkbd_softc_t sc;
984263bc
MD
649
650 /*
651 * NOTE: the device may have already become invalid.
652 * kbd == NULL || !KBD_IS_VALID(kbd)
653 */
a38e57d5 654 crit_enter();
984263bc
MD
655 sc = dev->si_drv1;
656 kbd = kbd_get_keyboard(KBD_INDEX(dev));
657 if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
658 /* XXX: we shall be forgiving and don't report error... */
659 } else {
660 kbd_release(kbd, (void *)sc);
984263bc 661 }
a38e57d5 662 crit_exit();
984263bc
MD
663 return 0;
664}
665
666static int
fef8985e 667genkbdread(struct dev_read_args *ap)
984263bc 668{
b13267a5 669 cdev_t dev = ap->a_head.a_dev;
fef8985e 670 struct uio *uio = ap->a_uio;
984263bc 671 keyboard_t *kbd;
8a0a8f43 672 genkbd_softc_t sc;
984263bc
MD
673 u_char buffer[KB_BUFSIZE];
674 int len;
675 int error;
984263bc
MD
676
677 /* wait for input */
a38e57d5 678 crit_enter();
984263bc
MD
679 sc = dev->si_drv1;
680 kbd = kbd_get_keyboard(KBD_INDEX(dev));
681 if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
a38e57d5 682 crit_exit();
984263bc
MD
683 return ENXIO;
684 }
bcc53404
AH
685 while (sc->gkb_q_length == 0) {
686 if (ap->a_ioflag & IO_NDELAY) { /* O_NONBLOCK? */
a38e57d5 687 crit_exit();
984263bc
MD
688 return EWOULDBLOCK;
689 }
690 sc->gkb_flags |= KB_ASLEEP;
377d4740 691 error = tsleep((caddr_t)sc, PCATCH, "kbdrea", 0);
984263bc
MD
692 kbd = kbd_get_keyboard(KBD_INDEX(dev));
693 if ((kbd == NULL) || !KBD_IS_VALID(kbd)) {
a38e57d5 694 crit_exit();
984263bc
MD
695 return ENXIO; /* our keyboard has gone... */
696 }
697 if (error) {
698 sc->gkb_flags &= ~KB_ASLEEP;
a38e57d5 699 crit_exit();
984263bc
MD
700 return error;
701 }
702 }
a38e57d5 703 crit_exit();
984263bc
MD
704
705 /* copy as much input as possible */
706 error = 0;
707 while (uio->uio_resid > 0) {
e54488bb 708 len = (int)szmin(uio->uio_resid, sizeof(buffer));
bcc53404
AH
709 len = genkbd_getc(sc, buffer, len);
710 if (len <= 0)
984263bc 711 break;
e54488bb 712 error = uiomove(buffer, (size_t)len, uio);
984263bc
MD
713 if (error)
714 break;
715 }
716
717 return error;
718}
719
720static int
fef8985e 721genkbdwrite(struct dev_write_args *ap)
984263bc 722{
b13267a5 723 cdev_t dev = ap->a_head.a_dev;
984263bc
MD
724 keyboard_t *kbd;
725
726 kbd = kbd_get_keyboard(KBD_INDEX(dev));
727 if ((kbd == NULL) || !KBD_IS_VALID(kbd))
728 return ENXIO;
729 return ENODEV;
730}
731
732static int
fef8985e 733genkbdioctl(struct dev_ioctl_args *ap)
984263bc 734{
b13267a5 735 cdev_t dev = ap->a_head.a_dev;
984263bc
MD
736 keyboard_t *kbd;
737 int error;
738
739 kbd = kbd_get_keyboard(KBD_INDEX(dev));
740 if ((kbd == NULL) || !KBD_IS_VALID(kbd))
741 return ENXIO;
bcc53404 742 error = kbd_ioctl(kbd, ap->a_cmd, ap->a_data);
984263bc
MD
743 if (error == ENOIOCTL)
744 error = ENODEV;
745 return error;
746}
747
25fef0f3
SG
748static struct filterops genkbdfiltops =
749 { 1, NULL, genkbdfiltdetach, genkbdfilter };
750
751static int
752genkbdkqfilter(struct dev_kqfilter_args *ap)
753{
754 cdev_t dev = ap->a_head.a_dev;
755 struct knote *kn = ap->a_kn;
756 genkbd_softc_t sc;
757 struct klist *klist;
758
759 ap->a_result = 0;
760
761 switch (kn->kn_filter) {
762 case EVFILT_READ:
763 kn->kn_fop = &genkbdfiltops;
764 kn->kn_hook = (caddr_t)dev;
765 break;
766 default:
b287d649 767 ap->a_result = EOPNOTSUPP;
25fef0f3
SG
768 return (0);
769 }
770
771 crit_enter();
772 sc = dev->si_drv1;
773 klist = &sc->gkb_rsel.si_note;
774 SLIST_INSERT_HEAD(klist, kn, kn_selnext);
775 crit_exit();
776
777 return (0);
778}
779
780static void
781genkbdfiltdetach(struct knote *kn)
782{
783 cdev_t dev = (cdev_t)kn->kn_hook;
784 genkbd_softc_t sc;
785 struct klist *klist;
786
787 crit_enter();
788 sc = dev->si_drv1;
789 klist = &sc->gkb_rsel.si_note;
790 SLIST_REMOVE(klist, kn, knote, kn_selnext);
791 crit_exit();
792}
793
794static int
795genkbdfilter(struct knote *kn, long hint)
796{
797 cdev_t dev = (cdev_t)kn->kn_hook;
798 keyboard_t *kbd;
799 genkbd_softc_t sc;
800 int ready = 0;
801
802 crit_enter();
803 sc = dev->si_drv1;
804 kbd = kbd_get_keyboard(KBD_INDEX(dev));
805 if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
806 kn->kn_flags |= EV_EOF; /* the keyboard has gone */
807 ready = 1;
808 } else {
809 if (sc->gkb_q_length > 0)
810 ready = 1;
811 }
812 crit_exit();
813
814 return (ready);
815}
816
984263bc
MD
817static int
818genkbd_event(keyboard_t *kbd, int event, void *arg)
819{
8a0a8f43 820 genkbd_softc_t sc;
984263bc
MD
821 size_t len;
822 u_char *cp;
823 int mode;
824 int c;
825
826 /* assert(KBD_IS_VALID(kbd)) */
8a0a8f43 827 sc = (genkbd_softc_t)arg;
984263bc
MD
828
829 switch (event) {
830 case KBDIO_KEYINPUT:
831 break;
832 case KBDIO_UNLOADING:
833 /* the keyboard is going... */
834 kbd_release(kbd, (void *)sc);
835 if (sc->gkb_flags & KB_ASLEEP) {
836 sc->gkb_flags &= ~KB_ASLEEP;
837 wakeup((caddr_t)sc);
838 }
37fcf290 839 KNOTE(&sc->gkb_rsel.si_note, 0);
984263bc
MD
840 return 0;
841 default:
842 return EINVAL;
843 }
844
845 /* obtain the current key input mode */
bcc53404 846 if (kbd_ioctl(kbd, KDGKBMODE, (caddr_t)&mode))
984263bc
MD
847 mode = K_XLATE;
848
849 /* read all pending input */
bcc53404
AH
850 while (kbd_check_char(kbd)) {
851 c = kbd_read_char(kbd, FALSE);
984263bc
MD
852 if (c == NOKEY)
853 continue;
854 if (c == ERRKEY) /* XXX: ring bell? */
855 continue;
856 if (!KBD_IS_BUSY(kbd))
857 /* the device is not open, discard the input */
858 continue;
859
860 /* store the byte as is for K_RAW and K_CODE modes */
861 if (mode != K_XLATE) {
bcc53404 862 genkbd_putc(sc, KEYCHAR(c));
984263bc
MD
863 continue;
864 }
865
866 /* K_XLATE */
867 if (c & RELKEY) /* key release is ignored */
868 continue;
869
870 /* process special keys; most of them are just ignored... */
871 if (c & SPCLKEY) {
872 switch (KEYCHAR(c)) {
873 default:
874 /* ignore them... */
875 continue;
876 case BTAB: /* a backtab: ESC [ Z */
bcc53404
AH
877 genkbd_putc(sc, 0x1b);
878 genkbd_putc(sc, '[');
879 genkbd_putc(sc, 'Z');
984263bc
MD
880 continue;
881 }
882 }
883
884 /* normal chars, normal chars with the META, function keys */
885 switch (KEYFLAGS(c)) {
886 case 0: /* a normal char */
bcc53404 887 genkbd_putc(sc, KEYCHAR(c));
984263bc
MD
888 break;
889 case MKEY: /* the META flag: prepend ESC */
bcc53404
AH
890 genkbd_putc(sc, 0x1b);
891 genkbd_putc(sc, KEYCHAR(c));
984263bc
MD
892 break;
893 case FKEY | SPCLKEY: /* a function key, return string */
bcc53404 894 cp = kbd_get_fkeystr(kbd, KEYCHAR(c), &len);
984263bc
MD
895 if (cp != NULL) {
896 while (len-- > 0)
bcc53404 897 genkbd_putc(sc, *cp++);
984263bc
MD
898 }
899 break;
900 }
901 }
902
903 /* wake up sleeping/polling processes */
bcc53404 904 if (sc->gkb_q_length > 0) {
984263bc
MD
905 if (sc->gkb_flags & KB_ASLEEP) {
906 sc->gkb_flags &= ~KB_ASLEEP;
907 wakeup((caddr_t)sc);
908 }
37fcf290 909 KNOTE(&sc->gkb_rsel.si_note, 0);
984263bc
MD
910 }
911
912 return 0;
913}
914
915#endif /* KBD_INSTALL_CDEV */
916
917/*
918 * Generic low-level keyboard functions
919 * The low-level functions in the keyboard subdriver may use these
920 * functions.
921 */
922
923int
924genkbd_commonioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
925{
926 keyarg_t *keyp;
927 fkeyarg_t *fkeyp;
984263bc
MD
928 int i;
929
a38e57d5 930 crit_enter();
984263bc
MD
931 switch (cmd) {
932
933 case KDGKBINFO: /* get keyboard information */
934 ((keyboard_info_t *)arg)->kb_index = kbd->kb_index;
935 i = imin(strlen(kbd->kb_name) + 1,
936 sizeof(((keyboard_info_t *)arg)->kb_name));
937 bcopy(kbd->kb_name, ((keyboard_info_t *)arg)->kb_name, i);
938 ((keyboard_info_t *)arg)->kb_unit = kbd->kb_unit;
939 ((keyboard_info_t *)arg)->kb_type = kbd->kb_type;
940 ((keyboard_info_t *)arg)->kb_config = kbd->kb_config;
941 ((keyboard_info_t *)arg)->kb_flags = kbd->kb_flags;
942 break;
943
944 case KDGKBTYPE: /* get keyboard type */
945 *(int *)arg = kbd->kb_type;
946 break;
947
948 case KDGETREPEAT: /* get keyboard repeat rate */
949 ((int *)arg)[0] = kbd->kb_delay1;
950 ((int *)arg)[1] = kbd->kb_delay2;
951 break;
952
953 case GIO_KEYMAP: /* get keyboard translation table */
954 bcopy(kbd->kb_keymap, arg, sizeof(*kbd->kb_keymap));
955 break;
956 case PIO_KEYMAP: /* set keyboard translation table */
957#ifndef KBD_DISABLE_KEYMAP_LOAD
958 bzero(kbd->kb_accentmap, sizeof(*kbd->kb_accentmap));
959 bcopy(arg, kbd->kb_keymap, sizeof(*kbd->kb_keymap));
960 break;
961#else
a38e57d5 962 crit_exit();
984263bc
MD
963 return ENODEV;
964#endif
965
966 case GIO_KEYMAPENT: /* get keyboard translation table entry */
967 keyp = (keyarg_t *)arg;
968 if (keyp->keynum >= sizeof(kbd->kb_keymap->key)
969 /sizeof(kbd->kb_keymap->key[0])) {
a38e57d5 970 crit_exit();
984263bc
MD
971 return EINVAL;
972 }
973 bcopy(&kbd->kb_keymap->key[keyp->keynum], &keyp->key,
974 sizeof(keyp->key));
975 break;
976 case PIO_KEYMAPENT: /* set keyboard translation table entry */
977#ifndef KBD_DISABLE_KEYMAP_LOAD
978 keyp = (keyarg_t *)arg;
979 if (keyp->keynum >= sizeof(kbd->kb_keymap->key)
980 /sizeof(kbd->kb_keymap->key[0])) {
a38e57d5 981 crit_exit();
984263bc
MD
982 return EINVAL;
983 }
984 bcopy(&keyp->key, &kbd->kb_keymap->key[keyp->keynum],
985 sizeof(keyp->key));
986 break;
987#else
a38e57d5 988 crit_exit();
984263bc
MD
989 return ENODEV;
990#endif
991
992 case GIO_DEADKEYMAP: /* get accent key translation table */
993 bcopy(kbd->kb_accentmap, arg, sizeof(*kbd->kb_accentmap));
994 break;
995 case PIO_DEADKEYMAP: /* set accent key translation table */
996#ifndef KBD_DISABLE_KEYMAP_LOAD
997 bcopy(arg, kbd->kb_accentmap, sizeof(*kbd->kb_accentmap));
998 break;
999#else
a38e57d5 1000 crit_exit();
984263bc
MD
1001 return ENODEV;
1002#endif
1003
1004 case GETFKEY: /* get functionkey string */
1005 fkeyp = (fkeyarg_t *)arg;
1006 if (fkeyp->keynum >= kbd->kb_fkeytab_size) {
a38e57d5 1007 crit_exit();
984263bc
MD
1008 return EINVAL;
1009 }
1010 bcopy(kbd->kb_fkeytab[fkeyp->keynum].str, fkeyp->keydef,
1011 kbd->kb_fkeytab[fkeyp->keynum].len);
1012 fkeyp->flen = kbd->kb_fkeytab[fkeyp->keynum].len;
1013 break;
1014 case SETFKEY: /* set functionkey string */
1015#ifndef KBD_DISABLE_KEYMAP_LOAD
1016 fkeyp = (fkeyarg_t *)arg;
1017 if (fkeyp->keynum >= kbd->kb_fkeytab_size) {
a38e57d5 1018 crit_exit();
984263bc
MD
1019 return EINVAL;
1020 }
1021 kbd->kb_fkeytab[fkeyp->keynum].len = imin(fkeyp->flen, MAXFK);
1022 bcopy(fkeyp->keydef, kbd->kb_fkeytab[fkeyp->keynum].str,
1023 kbd->kb_fkeytab[fkeyp->keynum].len);
1024 break;
1025#else
a38e57d5 1026 crit_exit();
984263bc
MD
1027 return ENODEV;
1028#endif
1029
1030 default:
a38e57d5 1031 crit_exit();
984263bc
MD
1032 return ENOIOCTL;
1033 }
1034
a38e57d5 1035 crit_exit();
984263bc
MD
1036 return 0;
1037}
1038
1039/* get a pointer to the string associated with the given function key */
3d8ba483
SW
1040u_char *
1041genkbd_get_fkeystr(keyboard_t *kbd, int fkey, size_t *len)
984263bc
MD
1042{
1043 if (kbd == NULL)
1044 return NULL;
1045 fkey -= F_FN;
1046 if (fkey > kbd->kb_fkeytab_size)
1047 return NULL;
1048 *len = kbd->kb_fkeytab[fkey].len;
1049 return kbd->kb_fkeytab[fkey].str;
1050}
1051
1052/* diagnostic dump */
3d8ba483
SW
1053static char *
1054get_kbd_type_name(int type)
984263bc
MD
1055{
1056 static struct {
1057 int type;
1058 char *name;
1059 } name_table[] = {
1060 { KB_84, "AT 84" },
1061 { KB_101, "AT 101/102" },
1062 { KB_OTHER, "generic" },
1063 };
1064 int i;
1065
1066 for (i = 0; i < sizeof(name_table)/sizeof(name_table[0]); ++i) {
1067 if (type == name_table[i].type)
1068 return name_table[i].name;
1069 }
1070 return "unknown";
1071}
1072
1073void
1074genkbd_diag(keyboard_t *kbd, int level)
1075{
1076 if (level > 0) {
e3869ec7 1077 kprintf("kbd%d: %s%d, %s (%d), config:0x%x, flags:0x%x",
984263bc
MD
1078 kbd->kb_index, kbd->kb_name, kbd->kb_unit,
1079 get_kbd_type_name(kbd->kb_type), kbd->kb_type,
1080 kbd->kb_config, kbd->kb_flags);
1081 if (kbd->kb_io_base > 0)
e3869ec7 1082 kprintf(", port:0x%x-0x%x", kbd->kb_io_base,
984263bc 1083 kbd->kb_io_base + kbd->kb_io_size - 1);
e3869ec7 1084 kprintf("\n");
984263bc
MD
1085 }
1086}
1087
1088#define set_lockkey_state(k, s, l) \
1089 if (!((s) & l ## DOWN)) { \
1090 int i; \
1091 (s) |= l ## DOWN; \
1092 (s) ^= l ## ED; \
1093 i = (s) & LOCK_MASK; \
bcc53404 1094 kbd_ioctl((k), KDSETLED, (caddr_t)&i); \
984263bc
MD
1095 }
1096
1097static u_int
1098save_accent_key(keyboard_t *kbd, u_int key, int *accents)
1099{
1100 int i;
1101
1102 /* make an index into the accent map */
1103 i = key - F_ACC + 1;
1104 if ((i > kbd->kb_accentmap->n_accs)
1105 || (kbd->kb_accentmap->acc[i - 1].accchar == 0)) {
1106 /* the index is out of range or pointing to an empty entry */
1107 *accents = 0;
1108 return ERRKEY;
1109 }
1110
1111 /*
1112 * If the same accent key has been hit twice, produce the accent char
1113 * itself.
1114 */
1115 if (i == *accents) {
1116 key = kbd->kb_accentmap->acc[i - 1].accchar;
1117 *accents = 0;
1118 return key;
1119 }
1120
1121 /* remember the index and wait for the next key */
1122 *accents = i;
1123 return NOKEY;
1124}
1125
1126static u_int
1127make_accent_char(keyboard_t *kbd, u_int ch, int *accents)
1128{
1129 struct acc_t *acc;
1130 int i;
1131
1132 acc = &kbd->kb_accentmap->acc[*accents - 1];
1133 *accents = 0;
1134
1135 /*
1136 * If the accent key is followed by the space key,
1137 * produce the accent char itself.
1138 */
1139 if (ch == ' ')
1140 return acc->accchar;
1141
1142 /* scan the accent map */
1143 for (i = 0; i < NUM_ACCENTCHARS; ++i) {
1144 if (acc->map[i][0] == 0) /* end of table */
1145 break;
1146 if (acc->map[i][0] == ch)
1147 return acc->map[i][1];
1148 }
1149 /* this char cannot be accented... */
1150 return ERRKEY;
1151}
1152
1153int
1154genkbd_keyaction(keyboard_t *kbd, int keycode, int up, int *shiftstate,
1155 int *accents)
1156{
1157 struct keyent_t *key;
1158 int state = *shiftstate;
1159 int action;
1160 int f;
1161 int i;
1162
1163 i = keycode;
1164 f = state & (AGRS | ALKED);
1165 if ((f == AGRS1) || (f == AGRS2) || (f == ALKED))
1166 i += ALTGR_OFFSET;
1167 key = &kbd->kb_keymap->key[i];
1168 i = ((state & SHIFTS) ? 1 : 0)
1169 | ((state & CTLS) ? 2 : 0)
1170 | ((state & ALTS) ? 4 : 0);
1171 if (((key->flgs & FLAG_LOCK_C) && (state & CLKED))
1172 || ((key->flgs & FLAG_LOCK_N) && (state & NLKED)) )
1173 i ^= 1;
1174
1175 if (up) { /* break: key released */
1176 action = kbd->kb_lastact[keycode];
1177 kbd->kb_lastact[keycode] = NOP;
1178 switch (action) {
1179 case LSHA:
1180 if (state & SHIFTAON) {
1181 set_lockkey_state(kbd, state, ALK);
1182 state &= ~ALKDOWN;
1183 }
1184 action = LSH;
1185 /* FALL THROUGH */
1186 case LSH:
1187 state &= ~SHIFTS1;
1188 break;
1189 case RSHA:
1190 if (state & SHIFTAON) {
1191 set_lockkey_state(kbd, state, ALK);
1192 state &= ~ALKDOWN;
1193 }
1194 action = RSH;
1195 /* FALL THROUGH */
1196 case RSH:
1197 state &= ~SHIFTS2;
1198 break;
1199 case LCTRA:
1200 if (state & SHIFTAON) {
1201 set_lockkey_state(kbd, state, ALK);
1202 state &= ~ALKDOWN;
1203 }
1204 action = LCTR;
1205 /* FALL THROUGH */
1206 case LCTR:
1207 state &= ~CTLS1;
1208 break;
1209 case RCTRA:
1210 if (state & SHIFTAON) {
1211 set_lockkey_state(kbd, state, ALK);
1212 state &= ~ALKDOWN;
1213 }
1214 action = RCTR;
1215 /* FALL THROUGH */
1216 case RCTR:
1217 state &= ~CTLS2;
1218 break;
1219 case LALTA:
1220 if (state & SHIFTAON) {
1221 set_lockkey_state(kbd, state, ALK);
1222 state &= ~ALKDOWN;
1223 }
1224 action = LALT;
1225 /* FALL THROUGH */
1226 case LALT:
1227 state &= ~ALTS1;
1228 break;
1229 case RALTA:
1230 if (state & SHIFTAON) {
1231 set_lockkey_state(kbd, state, ALK);
1232 state &= ~ALKDOWN;
1233 }
1234 action = RALT;
1235 /* FALL THROUGH */
1236 case RALT:
1237 state &= ~ALTS2;
1238 break;
1239 case ASH:
1240 state &= ~AGRS1;
1241 break;
1242 case META:
1243 state &= ~METAS1;
1244 break;
1245 case NLK:
1246 state &= ~NLKDOWN;
1247 break;
1248 case CLK:
984263bc 1249 state &= ~CLKDOWN;
984263bc
MD
1250 break;
1251 case SLK:
1252 state &= ~SLKDOWN;
1253 break;
1254 case ALK:
1255 state &= ~ALKDOWN;
1256 break;
1257 case NOP:
1258 /* release events of regular keys are not reported */
1259 *shiftstate &= ~SHIFTAON;
1260 return NOKEY;
1261 }
1262 *shiftstate = state & ~SHIFTAON;
1263 return (SPCLKEY | RELKEY | action);
1264 } else { /* make: key pressed */
1265 action = key->map[i];
1266 state &= ~SHIFTAON;
1267 if (key->spcl & (0x80 >> i)) {
1268 /* special keys */
1269 if (kbd->kb_lastact[keycode] == NOP)
1270 kbd->kb_lastact[keycode] = action;
1271 if (kbd->kb_lastact[keycode] != action)
1272 action = NOP;
1273 switch (action) {
1274 /* LOCKING KEYS */
1275 case NLK:
1276 set_lockkey_state(kbd, state, NLK);
1277 break;
1278 case CLK:
984263bc 1279 set_lockkey_state(kbd, state, CLK);
984263bc
MD
1280 break;
1281 case SLK:
1282 set_lockkey_state(kbd, state, SLK);
1283 break;
1284 case ALK:
1285 set_lockkey_state(kbd, state, ALK);
1286 break;
1287 /* NON-LOCKING KEYS */
1288 case SPSC: case RBT: case SUSP: case STBY:
1289 case DBG: case NEXT: case PREV: case PNC:
1290 case HALT: case PDWN:
1291 *accents = 0;
1292 break;
1293 case BTAB:
1294 *accents = 0;
1295 action |= BKEY;
1296 break;
1297 case LSHA:
1298 state |= SHIFTAON;
1299 action = LSH;
1300 /* FALL THROUGH */
1301 case LSH:
1302 state |= SHIFTS1;
1303 break;
1304 case RSHA:
1305 state |= SHIFTAON;
1306 action = RSH;
1307 /* FALL THROUGH */
1308 case RSH:
1309 state |= SHIFTS2;
1310 break;
1311 case LCTRA:
1312 state |= SHIFTAON;
1313 action = LCTR;
1314 /* FALL THROUGH */
1315 case LCTR:
1316 state |= CTLS1;
1317 break;
1318 case RCTRA:
1319 state |= SHIFTAON;
1320 action = RCTR;
1321 /* FALL THROUGH */
1322 case RCTR:
1323 state |= CTLS2;
1324 break;
1325 case LALTA:
1326 state |= SHIFTAON;
1327 action = LALT;
1328 /* FALL THROUGH */
1329 case LALT:
1330 state |= ALTS1;
1331 break;
1332 case RALTA:
1333 state |= SHIFTAON;
1334 action = RALT;
1335 /* FALL THROUGH */
1336 case RALT:
1337 state |= ALTS2;
1338 break;
1339 case ASH:
1340 state |= AGRS1;
1341 break;
1342 case META:
1343 state |= METAS1;
1344 break;
1345 case NOP:
1346 *shiftstate = state;
1347 return NOKEY;
1348 default:
1349 /* is this an accent (dead) key? */
1350 *shiftstate = state;
1351 if (action >= F_ACC && action <= L_ACC) {
1352 action = save_accent_key(kbd, action,
1353 accents);
1354 switch (action) {
1355 case NOKEY:
1356 case ERRKEY:
1357 return action;
1358 default:
1359 if (state & METAS)
1360 return (action | MKEY);
1361 else
1362 return action;
1363 }
1364 /* NOT REACHED */
1365 }
1366 /* other special keys */
1367 if (*accents > 0) {
1368 *accents = 0;
1369 return ERRKEY;
1370 }
1371 if (action >= F_FN && action <= L_FN)
1372 action |= FKEY;
1373 /* XXX: return fkey string for the FKEY? */
1374 return (SPCLKEY | action);
1375 }
1376 *shiftstate = state;
1377 return (SPCLKEY | action);
1378 } else {
1379 /* regular keys */
1380 kbd->kb_lastact[keycode] = NOP;
1381 *shiftstate = state;
1382 if (*accents > 0) {
1383 /* make an accented char */
1384 action = make_accent_char(kbd, action, accents);
1385 if (action == ERRKEY)
1386 return action;
1387 }
1388 if (state & METAS)
1389 action |= MKEY;
1390 return action;
1391 }
1392 }
1393 /* NOT REACHED */
1394}