Deleted Added
full compact
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 * $Id: $
26 * $Id: kbd.c,v 1.1 1999/01/09 02:44:50 yokota Exp $
27 */
28
29#include "kbd.h"
30#include "opt_kbd.h"
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/kernel.h>
35#include <sys/malloc.h>
36#include <sys/conf.h>
37#include <sys/proc.h>
38#include <sys/tty.h>
39#include <sys/poll.h>
40#include <sys/vnode.h>
41#include <sys/uio.h>
42
43#include <machine/console.h>
44
45#include <dev/kbd/kbdreg.h>
46
47/* local arrays */
48
49/*
50 * We need at least one entry each in order to initialize a keyboard
51 * for the kernel console. The arrays will be increased dynamically
52 * when necessary.
53 */
54static keyboard_t *kbd_ini;
55static keyboard_switch_t *kbdsw_ini;
56static struct cdevsw *kbdcdevsw_ini;
54
58static keyboard_t **keyboard = &kbd_ini;
55static int keyboards = 1;
56static keyboard_t *kbd_ini;
57static keyboard_t **keyboard = &kbd_ini;
58static keyboard_switch_t *kbdsw_ini;
59 keyboard_switch_t **kbdsw = &kbdsw_ini;
61static struct cdevsw **kbdcdevsw = &kbdcdevsw_ini;
60
61#ifdef KBD_INSTALL_CDEV
62
63#define ARRAY_DELTA 4
64
65static struct cdevsw *kbdcdevsw_ini;
66static struct cdevsw **kbdcdevsw = &kbdcdevsw_ini;
67
68static void
69kbd_realloc_array(void)
70{
71 keyboard_t **new_kbd;
72 keyboard_switch_t **new_kbdsw;
73 struct cdevsw **new_cdevsw;
74 int newsize;
75 int s;
76
77 s = spltty();
78 newsize = ((keyboards + ARRAY_DELTA)/ARRAY_DELTA)*ARRAY_DELTA;
79 new_kbd = malloc(sizeof(*new_kbd)*newsize, M_DEVBUF, M_NOWAIT);
80 new_kbdsw = malloc(sizeof(*new_kbdsw)*newsize, M_DEVBUF, M_NOWAIT);
81 new_cdevsw = malloc(sizeof(*new_cdevsw)*newsize, M_DEVBUF, M_NOWAIT);
82 bzero(new_kbd, sizeof(*new_kbd)*newsize);
83 bzero(new_kbdsw, sizeof(*new_kbdsw)*newsize);
84 bzero(new_cdevsw, sizeof(*new_cdevsw)*newsize);
85 bcopy(keyboard, new_kbd, sizeof(*keyboard)*keyboards);
86 bcopy(kbdsw, new_kbdsw, sizeof(*kbdsw)*keyboards);
87 bcopy(kbdcdevsw, new_cdevsw, sizeof(*kbdcdevsw)*keyboards);
88 if (keyboards > 1) {
89 free(keyboard, M_DEVBUF);
90 free(kbdsw, M_DEVBUF);
91 free(kbdcdevsw, M_DEVBUF);
92 }
93 keyboard = new_kbd;
94 kbdsw = new_kbdsw;
95 kbdcdevsw = new_cdevsw;
96 keyboards = newsize;
97 splx(s);
98
99 if (bootverbose)
100 printf("kbd: new array size %d\n", keyboards);
101}
102
103#endif /* KBD_INSTALL_CDEV */
104
105/*
106 * Low-level keyboard driver functions
107 * Keyboard subdrivers, such as the AT keyboard driver and the USB keyboard
108 * driver, call these functions to initialize the keyboard_t structure
109 * and register it to the virtual keyboard driver `kbd'.
110 */
111
112/* initialize the keyboard_t structure */
113void
114kbd_init_struct(keyboard_t *kbd, char *name, int type, int unit, int config,
115 int port, int port_size)
116{
117 kbd->kb_flags = KB_NO_DEVICE; /* device has not been found */
118 kbd->kb_name = name;
119 kbd->kb_type = type;
120 kbd->kb_unit = unit;
121 kbd->kb_config = config;
122 kbd->kb_led = 0; /* unknown */
123 kbd->kb_io_base = port;
124 kbd->kb_io_size = port_size;
125 kbd->kb_data = NULL;
126 kbd->kb_keymap = NULL;
127 kbd->kb_accentmap = NULL;
128 kbd->kb_fkeytab = NULL;
129 kbd->kb_fkeytab_size = 0;
130}
131
132void
133kbd_set_maps(keyboard_t *kbd, keymap_t *keymap, accentmap_t *accmap,
134 fkeytab_t *fkeymap, int fkeymap_size)
135{
136 kbd->kb_keymap = keymap;
137 kbd->kb_accentmap = accmap;
138 kbd->kb_fkeytab = fkeymap;
139 kbd->kb_fkeytab_size = fkeymap_size;
140}
141
142/* register a keyboard and associate it with a function table */
143int
144kbd_register(keyboard_t *kbd)
145{
146 keyboard_driver_t **list;
147 keyboard_driver_t *p;
148 int index;
149
150 for (index = 0; index < keyboards; ++index) {
151 if (keyboard[index] == NULL)
152 break;
153 }
154 if (index >= keyboards)
155 return -1;
156
157 kbd->kb_index = index;
158 KBD_UNBUSY(kbd);
159 KBD_VALID(kbd);
160 kbd->kb_active = 0; /* disabled until someone calls kbd_enable() */
161 kbd->kb_token = NULL;
162 kbd->kb_callback.kc_func = NULL;
163 kbd->kb_callback.kc_arg = NULL;
164
165 list = (keyboard_driver_t **)kbddriver_set.ls_items;
166 while ((p = *list++) != NULL) {
167 if (strcmp(p->name, kbd->kb_name) == 0) {
168 keyboard[index] = kbd;
169 kbdsw[index] = p->kbdsw;
170 return index;
171 }
172 }
173
174 return -1;
175}
176
177int
178kbd_unregister(keyboard_t *kbd)
179{
180 int error;
181 int s;
182
183 if ((kbd->kb_index < 0) || (kbd->kb_index >= keyboards))
184 return ENOENT;
185 if (keyboard[kbd->kb_index] != kbd)
186 return ENOENT;
187
188 s = spltty();
189 if (KBD_IS_BUSY(kbd)) {
190 error = (*kbd->kb_callback.kc_func)(kbd, KBDIO_UNLOADING,
191 kbd->kb_callback.kc_arg);
192 if (error) {
193 splx(s);
194 return error;
195 }
196 if (KBD_IS_BUSY(kbd)) {
197 splx(s);
198 return EBUSY;
199 }
200 }
201 KBD_INVALID(kbd);
202 keyboard[kbd->kb_index] = NULL;
203 kbdsw[kbd->kb_index] = NULL;
204
205 splx(s);
206 return 0;
207}
208
209/* find a funciton table by the driver name */
210keyboard_switch_t
211*kbd_get_switch(char *driver)
212{
213 keyboard_driver_t **list;
214 keyboard_driver_t *p;
215
216 list = (keyboard_driver_t **)kbddriver_set.ls_items;
217 while ((p = *list++) != NULL) {
218 if (strcmp(p->name, driver) == 0)
219 return p->kbdsw;
220 }
221
222 return NULL;
223}
224
225/*
226 * Keyboard client functions
227 * Keyboard clients, such as the console driver `syscons' and the keyboard
228 * cdev driver, use these functions to claim and release a keyboard for
229 * exclusive use.
230 */
231
232/* find the keyboard specified by a driver name and a unit number */
233int
234kbd_find_keyboard(char *driver, int unit)
235{
236 int i;
237
238 for (i = 0; i < keyboards; ++i) {
239 if (keyboard[i] == NULL)
240 continue;
241 if (!KBD_IS_VALID(keyboard[i]))
242 continue;
243 if (strcmp("*", driver) && strcmp(keyboard[i]->kb_name, driver))
244 continue;
245 if ((unit != -1) && (keyboard[i]->kb_unit != unit))
246 continue;
247 return i;
248 }
249 return -1;
250}
251
252/* allocate a keyboard */
253int
254kbd_allocate(char *driver, int unit, void *id, kbd_callback_func_t *func,
255 void *arg)
256{
257 int index;
258 int s;
259
260 if (func == NULL)
261 return -1;
262
263 s = spltty();
264 index = kbd_find_keyboard(driver, unit);
265 if (index >= 0) {
266 if (KBD_IS_BUSY(keyboard[index])) {
267 splx(s);
268 return -1;
269 }
270 keyboard[index]->kb_token = id;
271 KBD_BUSY(keyboard[index]);
272 keyboard[index]->kb_callback.kc_func = func;
273 keyboard[index]->kb_callback.kc_arg = arg;
274 (*kbdsw[index]->clear_state)(keyboard[index]);
275 }
276 splx(s);
277 return index;
278}
279
280int
281kbd_release(keyboard_t *kbd, void *id)
282{
283 int error;
284 int s;
285
286 s = spltty();
287 if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) {
288 error = EINVAL;
289 } else if (kbd->kb_token != id) {
290 error = EPERM;
291 } else {
292 kbd->kb_token = NULL;
293 KBD_UNBUSY(kbd);
294 kbd->kb_callback.kc_func = NULL;
295 kbd->kb_callback.kc_arg = NULL;
296 (*kbdsw[kbd->kb_index]->clear_state)(kbd);
297 error = 0;
298 }
299 splx(s);
300 return error;
301}
302
303int
304kbd_change_callback(keyboard_t *kbd, void *id, kbd_callback_func_t *func,
305 void *arg)
306{
307 int error;
308 int s;
309
310 s = spltty();
311 if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) {
312 error = EINVAL;
313 } else if (kbd->kb_token != id) {
314 error = EPERM;
315 } else if (func == NULL) {
316 error = EINVAL;
317 } else {
318 kbd->kb_callback.kc_func = func;
319 kbd->kb_callback.kc_arg = arg;
320 error = 0;
321 }
322 splx(s);
323 return error;
324}
325
326/* get a keyboard structure */
327keyboard_t
328*kbd_get_keyboard(int index)
329{
330 if ((index < 0) || (index >= keyboards))
331 return NULL;
332 if (!KBD_IS_VALID(keyboard[index]))
333 return NULL;
334 return keyboard[index];
335}
336
337/*
338 * The back door for the console driver; configure keyboards
339 * This function is for the kernel console to initialize keyboards
340 * at very early stage.
341 */
342
343int
344kbd_configure(int flags)
345{
346 keyboard_driver_t **list;
347 keyboard_driver_t *p;
348
349 list = (keyboard_driver_t **)kbddriver_set.ls_items;
350 while ((p = *list++) != NULL) {
351 if (p->configure != NULL)
352 (*p->configure)(flags);
353 }
354
355 return 0;
356}
357
358#ifdef KBD_INSTALL_CDEV
359
360/*
361 * Virtual keyboard cdev driver functions
362 * The virtual keyboard driver dispatches driver functions to
363 * appropriate subdrivers.
364 */
365
366#define KBD_UNIT(dev) minor(dev)
367
368static d_open_t kbdopen;
369static d_close_t kbdclose;
370static d_read_t kbdread;
371static d_write_t kbdwrite;
372static d_ioctl_t kbdioctl;
373static d_reset_t kbdreset;
374static d_devtotty_t kbddevtotty;
375static d_poll_t kbdpoll;
376static d_mmap_t kbdmmap;
377
378#define CDEV_MAJOR 112
379
380static struct cdevsw kbd_cdevsw = {
381 kbdopen, kbdclose, kbdread, kbdwrite, /* ??? */
382 kbdioctl, nullstop, kbdreset, kbddevtotty,
383 kbdpoll, kbdmmap, nostrategy, "kbd",
384 NULL, -1, nodump, nopsize,
385};
386
387static void
388vkbdattach(void *arg)
389{
390 static int kbd_devsw_installed = FALSE;
391 dev_t dev;
392
393 if (!kbd_devsw_installed) {
394 dev = makedev(CDEV_MAJOR, 0);
395 cdevsw_add(&dev, &kbd_cdevsw, NULL);
396 kbd_devsw_installed = TRUE;
397 }
398}
399
400PSEUDO_SET(vkbdattach, kbd);
401
402int
403kbd_attach(dev_t dev, keyboard_t *kbd, struct cdevsw *cdevsw)
404{
405 int s;
406
407 if (kbd->kb_index >= keyboards)
408 return EINVAL;
409 if (keyboard[kbd->kb_index] != kbd)
410 return EINVAL;
411
412 s = spltty();
413 kbd->kb_minor = minor(dev);
414 kbdcdevsw[kbd->kb_index] = cdevsw;
415 splx(s);
416
417 /* XXX: DEVFS? */
418
419 if (kbd->kb_index + 1 >= keyboards)
420 kbd_realloc_array();
421
422 printf("kbd%d at %s%d\n", kbd->kb_index, kbd->kb_name, kbd->kb_unit);
423 return 0;
424}
425
426int
427kbd_detach(dev_t dev, keyboard_t *kbd, struct cdevsw *cdevsw)
428{
429 int s;
430
431 if (kbd->kb_index >= keyboards)
432 return EINVAL;
433 if (keyboard[kbd->kb_index] != kbd)
434 return EINVAL;
435 if (kbdcdevsw[kbd->kb_index] != cdevsw)
436 return EINVAL;
437
438 s = spltty();
439 (*kbdsw[kbd->kb_index]->term)(kbd);
440 kbdcdevsw[kbd->kb_index] = NULL;
441 splx(s);
442 return 0;
443}
444
445static int
446kbdopen(dev_t dev, int flag, int mode, struct proc *p)
447{
448 int unit;
449
450 unit = KBD_UNIT(dev);
451 if (unit >= keyboards)
452 return ENXIO;
453 if (kbdcdevsw[unit] == NULL)
454 return ENXIO;
455 if (KBD_IS_BUSY(keyboard[unit]))
456 return EBUSY;
457 return (*kbdcdevsw[unit]->d_open)(makedev(0, keyboard[unit]->kb_minor),
458 flag, mode, p);
459}
460
461static int
462kbdclose(dev_t dev, int flag, int mode, struct proc *p)
463{
464 int unit;
465
466 unit = KBD_UNIT(dev);
467 if (kbdcdevsw[unit] == NULL)
468 return ENXIO;
469 return (*kbdcdevsw[unit]->d_close)(makedev(0, keyboard[unit]->kb_minor),
470 flag, mode, p);
471}
472
473static int
474kbdread(dev_t dev, struct uio *uio, int flag)
475{
476 int unit;
477
478 unit = KBD_UNIT(dev);
479 if (kbdcdevsw[unit] == NULL)
480 return ENXIO;
481 return (*kbdcdevsw[unit]->d_read)(makedev(0, keyboard[unit]->kb_minor),
482 uio, flag);
483}
484
485static int
486kbdwrite(dev_t dev, struct uio *uio, int flag)
487{
488 int unit;
489
490 unit = KBD_UNIT(dev);
491 if (kbdcdevsw[unit] == NULL)
492 return ENXIO;
493 return (*kbdcdevsw[unit]->d_write)(makedev(0, keyboard[unit]->kb_minor),
494 uio, flag);
495}
496
497static int
498kbdioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p)
499{
500 int unit;
501
502 unit = KBD_UNIT(dev);
503 if (kbdcdevsw[unit] == NULL)
504 return ENXIO;
505 return (*kbdcdevsw[unit]->d_ioctl)(makedev(0, keyboard[unit]->kb_minor),
506 cmd, arg, flag, p);
507}
508
509static int
510kbdreset(dev_t dev)
511{
512 int unit;
513
514 unit = KBD_UNIT(dev);
515 if (kbdcdevsw[unit] == NULL)
516 return ENXIO;
517 return (*kbdcdevsw[unit]->d_reset)(makedev(0, keyboard[unit]->kb_minor));
518}
519
520static struct tty
521*kbddevtotty(dev_t dev)
522{
523 int unit;
524
525 unit = KBD_UNIT(dev);
526 if (kbdcdevsw[unit] == NULL)
527 return NULL;
528 return (*kbdcdevsw[unit]->d_devtotty)(makedev(0, keyboard[unit]->kb_minor));
529}
530
531static int
532kbdpoll(dev_t dev, int event, struct proc *p)
533{
534 int unit;
535
536 unit = KBD_UNIT(dev);
537 if (kbdcdevsw[unit] == NULL)
538 return ENXIO;
539 return (*kbdcdevsw[unit]->d_poll)(makedev(0, keyboard[unit]->kb_minor),
540 event, p);
541}
542
543static int
544kbdmmap(dev_t dev, vm_offset_t offset, int nprot)
545{
546 int unit;
547
548 unit = KBD_UNIT(dev);
549 if (kbdcdevsw[unit] == NULL)
550 return ENXIO;
551 return (*kbdcdevsw[unit]->d_mmap)(makedev(0, keyboard[unit]->kb_minor),
552 offset, nprot);
553}
554
555/*
556 * Generic keyboard cdev driver functions
557 * Keyboard subdrivers may call these functions to implement common
558 * driver functions.
559 */
560
561#define KB_QSIZE 512
562#define KB_BUFSIZE 64
563
564static kbd_callback_func_t genkbd_event;
565
566int
567genkbdopen(genkbd_softc_t *sc, keyboard_t *kbd, int mode, int flag,
568 struct proc *p)
569{
570 int s;
571 int i;
572
573 s = spltty();
574 if (!KBD_IS_VALID(kbd)) {
575 splx(s);
576 return ENXIO;
577 }
578 i = kbd_allocate(kbd->kb_name, kbd->kb_unit, sc,
579 genkbd_event, (void *)sc);
580 if (i < 0) {
581 splx(s);
582 return EBUSY;
583 }
584 /* assert(i == kbd->kb_index) */
585 /* assert(kbd == kbd_get_keyboard(i)) */
586
587 /*
588 * NOTE: even when we have successfully claimed a keyboard,
589 * the device may still be missing (!KBD_HAS_DEVICE(kbd)).
590 */
591
592#if 0
593 bzero(&sc->gkb_q, sizeof(sc->gkb_q));
594#endif
595 clist_alloc_cblocks(&sc->gkb_q, KB_QSIZE, KB_QSIZE/2); /* XXX */
596 sc->gkb_rsel.si_flags = 0;
597 sc->gkb_rsel.si_pid = 0;
598 splx(s);
599
600 return 0;
601}
602
603int
604genkbdclose(genkbd_softc_t *sc, keyboard_t *kbd, int mode, int flag,
605 struct proc *p)
606{
607 int s;
608
609 /*
610 * NOTE: the device may have already become invalid.
611 * !KBD_IS_VALID(kbd)
612 */
613 s = spltty();
614 kbd_release(kbd, (void *)sc);
615#if 0
616 clist_free_cblocks(&sc->gkb_q);
617#endif
618 splx(s);
619
620 return 0;
621}
622
623int
624genkbdread(genkbd_softc_t *sc, keyboard_t *kbd, struct uio *uio, int flag)
625{
626 u_char buffer[KB_BUFSIZE];
627 int len;
628 int error;
629 int s;
630
631 /* wait for input */
632 s = spltty();
633 while (sc->gkb_q.c_cc == 0) {
634 if (!KBD_IS_VALID(kbd)) {
635 splx(s);
636 return EIO;
637 }
638 if (flag & IO_NDELAY) {
639 splx(s);
640 return EWOULDBLOCK;
641 }
642 sc->gkb_flags |= KB_ASLEEP;
643 error = tsleep((caddr_t)sc, PZERO | PCATCH, "kbdrea", 0);
644 if (error) {
645 sc->gkb_flags &= ~KB_ASLEEP;
646 splx(s);
647 return error;
648 }
649 }
650 splx(s);
651
652 /* copy as much input as possible */
653 error = 0;
654 while (uio->uio_resid > 0) {
655 len = imin(uio->uio_resid, sizeof(buffer));
656 len = q_to_b(&sc->gkb_q, buffer, len);
657 if (len <= 0)
658 break;
659 error = uiomove(buffer, len, uio);
660 if (error)
661 break;
662 }
663
664 return error;
665}
666
667int
668genkbdwrite(genkbd_softc_t *sc, keyboard_t *kbd, struct uio *uio, int flag)
669{
670 if (!KBD_IS_VALID(kbd))
671 return ENXIO;
672 return ENODEV;
673}
674
675int
676genkbdioctl(genkbd_softc_t *sc, keyboard_t *kbd, u_long cmd, caddr_t arg,
677 int flag, struct proc *p)
678{
679 int error;
680
681 if (kbd == NULL) /* XXX */
682 return ENXIO;
683 if (!KBD_IS_VALID(kbd))
684 return ENXIO;
685 error = (*kbdsw[kbd->kb_index]->ioctl)(kbd, cmd, arg);
686 if (error == ENOIOCTL)
687 error = ENODEV;
688 return error;
689}
690
691int
692genkbdpoll(genkbd_softc_t *sc, keyboard_t *kbd, int events, struct proc *p)
693{
694 int revents;
695 int s;
696
697 revents = 0;
698 s = spltty();
699 if (events & (POLLIN | POLLRDNORM)) {
700 if ((sc->gkb_q.c_cc > 0) || !KBD_IS_VALID(kbd))
701 revents |= (POLLIN | POLLRDNORM);
702 else
703 selrecord(p, &sc->gkb_rsel);
704 }
705 splx(s);
706 return revents;
707}
708
709static int
710genkbd_event(keyboard_t *kbd, int event, void *arg)
711{
712 genkbd_softc_t *sc;
713 size_t len;
714 u_char *cp;
715 int mode;
716 int c;
717
718 /* assert(KBD_IS_VALID(kbd)) */
719 sc = (genkbd_softc_t *)arg;
720
721 switch (event) {
722 case KBDIO_KEYINPUT:
723 break;
724 case KBDIO_UNLOADING:
725 /* the keyboard is going... */
726 kbd_release(kbd, (void *)sc);
727 return 0;
728 default:
729 return EINVAL;
730 }
731
732 /* obtain the current key input mode */
733 if ((*kbdsw[kbd->kb_index]->ioctl)(kbd, KDGKBMODE, (caddr_t)&mode))
734 mode = K_XLATE;
735
736 /* read all pending input */
737 while ((*kbdsw[kbd->kb_index]->check_char)(kbd)) {
738 c = (*kbdsw[kbd->kb_index]->read_char)(kbd, FALSE);
739 if (c == NOKEY)
740 continue;
741 if (c == ERRKEY) /* XXX: ring bell? */
742 continue;
743 if (!KBD_IS_BUSY(kbd))
744 /* the device is not open, discard the input */
745 continue;
746
747 /* store the byte as is for K_RAW and K_CODE modes */
748 if (mode != K_XLATE) {
749 putc(KEYCHAR(c), &sc->gkb_q);
750 continue;
751 }
752
753 /* K_XLATE */
754 if (c & RELKEY) /* key release is ignored */
755 continue;
756
757 /* process special keys; most of them are just ignored... */
758 if (c & SPCLKEY) {
759 switch (KEYCHAR(c)) {
760 /* locking keys */
761 case NLK: case CLK: case SLK: case ALK:
762 /* shift keys */
763 case LSH: case RSH: case LCTR: case RCTR:
764 case LALT: case RALT: case ASH: case META:
765 /* other special keys */
766 case NOP: case SPSC: case RBT: case SUSP:
767 case STBY: case DBG: case NEXT:
768 /* ignore them... */
769 continue;
770 case BTAB: /* a backtab: ESC [ Z */
771 putc(0x1b, &sc->gkb_q);
772 putc('[', &sc->gkb_q);
773 putc('Z', &sc->gkb_q);
774 continue;
775 }
776 }
777
778 /* normal chars, normal chars with the META, function keys */
779 switch (KEYFLAGS(c)) {
780 case 0: /* a normal char */
781 putc(KEYCHAR(c), &sc->gkb_q);
782 break;
783 case MKEY: /* the META flag: prepend ESC */
784 putc(0x1b, &sc->gkb_q);
785 putc(KEYCHAR(c), &sc->gkb_q);
786 break;
787 case FKEY | SPCLKEY: /* a function key, return string */
788 cp = (*kbdsw[kbd->kb_index]->get_fkeystr)(kbd,
789 KEYCHAR(c), &len);
790 if (cp != NULL) {
791 while (len-- > 0)
792 putc(*cp++, &sc->gkb_q);
793 }
794 break;
795 }
796 }
797
798 /* wake up sleeping/polling processes */
799 if (sc->gkb_q.c_cc > 0) {
800 if (sc->gkb_flags & KB_ASLEEP) {
801 sc->gkb_flags &= ~KB_ASLEEP;
802 wakeup((caddr_t)sc);
803 }
804 selwakeup(&sc->gkb_rsel);
805 }
806
807 return 0;
808}
809
810#endif /* KBD_INSTALL_CDEV */
811
812/*
813 * Generic low-level keyboard functions
814 * The low-level functions in the keyboard subdriver may use these
815 * functions.
816 */
817
818int
819genkbd_commonioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
820{
821 keyarg_t *keyp;
822 fkeyarg_t *fkeyp;
823 int s;
824 int i;
825
826 s = spltty();
827 switch (cmd) {
828
829 case KDGKBINFO: /* get keyboard information */
830 ((keyboard_info_t *)arg)->kb_index = kbd->kb_index;
831 i = imin(strlen(kbd->kb_name) + 1,
832 sizeof(((keyboard_info_t *)arg)->kb_name));
833 bcopy(kbd->kb_name, ((keyboard_info_t *)arg)->kb_name, i);
834 ((keyboard_info_t *)arg)->kb_unit = kbd->kb_unit;
835 ((keyboard_info_t *)arg)->kb_type = kbd->kb_type;
836 ((keyboard_info_t *)arg)->kb_config = kbd->kb_config;
837 ((keyboard_info_t *)arg)->kb_flags = kbd->kb_flags;
838 break;
839
840 case KDGKBTYPE: /* get keyboard type */
841 *(int *)arg = kbd->kb_type;
842 break;
843
844 case GIO_KEYMAP: /* get keyboard translation table */
845 bcopy(kbd->kb_keymap, arg, sizeof(*kbd->kb_keymap));
846 break;
847 case PIO_KEYMAP: /* set keyboard translation table */
848 bzero(kbd->kb_accentmap, sizeof(*kbd->kb_accentmap));
849 bcopy(arg, kbd->kb_keymap, sizeof(*kbd->kb_keymap));
850 break;
851
852 case GIO_KEYMAPENT: /* get keyboard translation table entry */
853 keyp = (keyarg_t *)arg;
854 if (keyp->keynum >= sizeof(kbd->kb_keymap->key)
855 /sizeof(kbd->kb_keymap->key[0])) {
856 splx(s);
857 return EINVAL;
858 }
859 bcopy(&kbd->kb_keymap[keyp->keynum], &keyp->key,
860 sizeof(keyp->key));
861 break;
862 case PIO_KEYMAPENT: /* set keyboard translation table entry */
863 keyp = (keyarg_t *)arg;
864 if (keyp->keynum >= sizeof(kbd->kb_keymap->key)
865 /sizeof(kbd->kb_keymap->key[0])) {
866 splx(s);
867 return EINVAL;
868 }
869 bcopy(&keyp->key, &kbd->kb_keymap[keyp->keynum],
870 sizeof(keyp->key));
871 break;
872
873 case GIO_DEADKEYMAP: /* get accent key translation table */
874 bcopy(kbd->kb_accentmap, arg, sizeof(*kbd->kb_accentmap));
875 break;
876 case PIO_DEADKEYMAP: /* set accent key translation table */
877 bcopy(arg, kbd->kb_accentmap, sizeof(*kbd->kb_accentmap));
878 break;
879
880 case GETFKEY: /* get functionkey string */
881 fkeyp = (fkeyarg_t *)arg;
882 if (fkeyp->keynum >= kbd->kb_fkeytab_size) {
883 splx(s);
884 return EINVAL;
885 }
886 bcopy(kbd->kb_fkeytab[fkeyp->keynum].str, fkeyp->keydef,
887 kbd->kb_fkeytab[fkeyp->keynum].len);
888 fkeyp->flen = kbd->kb_fkeytab[fkeyp->keynum].len;
889 break;
890 case SETFKEY: /* set functionkey string */
891 fkeyp = (fkeyarg_t *)arg;
892 if (fkeyp->keynum >= kbd->kb_fkeytab_size) {
893 splx(s);
894 return EINVAL;
895 }
896 kbd->kb_fkeytab[fkeyp->keynum].len = imin(fkeyp->flen, MAXFK);
897 bcopy(fkeyp->keydef, kbd->kb_fkeytab[fkeyp->keynum].str,
898 kbd->kb_fkeytab[fkeyp->keynum].len);
899 break;
900
901 default:
902 splx(s);
903 return ENOIOCTL;
904 }
905
906 splx(s);
907 return 0;
908}
909
910/* get a pointer to the string associated with the given function key */
911u_char
912*genkbd_get_fkeystr(keyboard_t *kbd, int fkey, size_t *len)
913{
914 if (kbd == NULL)
915 return NULL;
916 fkey -= F_FN;
917 if (fkey > kbd->kb_fkeytab_size)
918 return NULL;
919 *len = kbd->kb_fkeytab[fkey].len;
920 return kbd->kb_fkeytab[fkey].str;
921}
922
923/* diagnostic dump */
924static char
925*get_kbd_type_name(int type)
926{
927 static struct {
928 int type;
929 char *name;
930 } name_table[] = {
931 { KB_84, "AT 84" },
932 { KB_101, "AT 101/102" },
933 { KB_OTHER, "generic" },
934 };
935 int i;
936
937 for (i = 0; i < sizeof(name_table)/sizeof(name_table[0]); ++i) {
938 if (type == name_table[i].type)
939 return name_table[i].name;
940 }
941 return "unknown";
942}
943
944void
945genkbd_diag(keyboard_t *kbd, int level)
946{
947 if (level > 0) {
948 printf("kbd%d: %s%d, %s (%d), config:0x%x, flags:0x%x",
949 kbd->kb_index, kbd->kb_name, kbd->kb_unit,
950 get_kbd_type_name(kbd->kb_type), kbd->kb_type,
951 kbd->kb_config, kbd->kb_flags);
952 if (kbd->kb_io_base > 0)
953 printf(", port:0x%x-0x%x", kbd->kb_io_base,
954 kbd->kb_io_base + kbd->kb_io_size - 1);
955 printf("\n");
956 }
957}
958
959#define set_lockkey_state(k, s, l) \
960 if (!((s) & l ## DOWN)) { \
961 int i; \
962 (s) |= l ## DOWN; \
963 (s) ^= l ## ED; \
964 i = (s) & LOCK_MASK; \
965 (*kbdsw[(k)->kb_index]->ioctl)((k), KDSETLED, (caddr_t)&i); \
966 }
967
968static u_int
969save_accent_key(keyboard_t *kbd, u_int key, int *accents)
970{
971 int i;
972
973 /* make an index into the accent map */
974 i = key - F_ACC + 1;
975 if ((i > kbd->kb_accentmap->n_accs)
976 || (kbd->kb_accentmap->acc[i - 1].accchar == 0)) {
977 /* the index is out of range or pointing to an empty entry */
978 *accents = 0;
979 return ERRKEY;
980 }
981
982 /*
983 * If the same accent key has been hit twice, produce the accent char
984 * itself.
985 */
986 if (i == *accents) {
987 key = kbd->kb_accentmap->acc[i - 1].accchar;
988 *accents = 0;
989 return key;
990 }
991
992 /* remember the index and wait for the next key */
993 *accents = i;
994 return NOKEY;
995}
996
997static u_int
998make_accent_char(keyboard_t *kbd, u_int ch, int *accents)
999{
1000 struct acc_t *acc;
1001 int i;
1002
1003 acc = &kbd->kb_accentmap->acc[*accents - 1];
1004 *accents = 0;
1005
1006 /*
1007 * If the accent key is followed by the space key,
1008 * produce the accent char itself.
1009 */
1010 if (ch == ' ')
1011 return acc->accchar;
1012
1013 /* scan the accent map */
1014 for (i = 0; i < NUM_ACCENTCHARS; ++i) {
1015 if (acc->map[i][0] == 0) /* end of table */
1016 break;
1017 if (acc->map[i][0] == ch)
1018 return acc->map[i][1];
1019 }
1020 /* this char cannot be accented... */
1021 return ERRKEY;
1022}
1023
1024int
1025genkbd_keyaction(keyboard_t *kbd, int keycode, int up, int *shiftstate,
1026 int *accents)
1027{
1028 struct keyent_t *key;
1029 int state = *shiftstate;
1030 int action;
1031 int f;
1032 int i;
1033
1034 f = state & (AGRS | ALKED);
1035 if ((f == AGRS1) || (f == AGRS2) || (f == ALKED))
1036 keycode += ALTGR_OFFSET;
1037 key = &kbd->kb_keymap->key[keycode];
1038 i = ((state & SHIFTS) ? 1 : 0)
1039 | ((state & CTLS) ? 2 : 0)
1040 | ((state & ALTS) ? 4 : 0);
1041 if (((key->flgs & FLAG_LOCK_C) && (state & CLKED))
1042 || ((key->flgs & FLAG_LOCK_N) && (state & NLKED)) )
1043 i ^= 1;
1044
1045 action = key->map[i];
1046 if (up) { /* break: key released */
1047 if (key->spcl & (0x80 >> i)) {
1048 /* special keys */
1049 switch (action) {
1050 case LSH:
1051 state &= ~SHIFTS1;
1052 break;
1053 case RSH:
1054 state &= ~SHIFTS2;
1055 break;
1056 case LCTR:
1057 state &= ~CTLS1;
1058 break;
1059 case RCTR:
1060 state &= ~CTLS2;
1061 break;
1062 case LALT:
1063 state &= ~ALTS1;
1064 break;
1065 case RALT:
1066 state &= ~ALTS2;
1067 break;
1068 case ASH:
1069 state &= ~AGRS1;
1070 break;
1071 case META:
1072 state &= ~METAS1;
1073 break;
1074 case NLK:
1075 state &= ~NLKDOWN;
1076 break;
1077 case CLK:
1078#ifndef PC98
1079 state &= ~CLKDOWN;
1080#else
1081 state &= ~CLKED;
1082 i = state & LOCK_MASK;
1083 (*kbdsw[kbd->kb_index]->ioctl)(kbd, KDSETLED,
1084 (caddr_t)&i);
1085#endif
1086 break;
1087 case SLK:
1088 state &= ~SLKDOWN;
1089 break;
1090 case ALK:
1091 state &= ~ALKDOWN;
1092 break;
1093 }
1094 *shiftstate = state;
1095 return (SPCLKEY | RELKEY | action);
1096 }
1097 /* release events of regular keys are not reported */
1098 return NOKEY;
1099 } else { /* make: key pressed */
1100 if (key->spcl & (0x80 >> i)) {
1101 /* special keys */
1102 switch (action) {
1103 /* LOCKING KEYS */
1104 case NLK:
1105 set_lockkey_state(kbd, state, NLK);
1106 break;
1107 case CLK:
1108#ifndef PC98
1109 set_lockkey_state(kbd, state, CLK);
1110#else
1111 state |= CLKED;
1112 i = state & LOCK_MASK;
1113 (*kbdsw[kbd->kb_index]->ioctl)(kbd, KDSETLED,
1114 (caddr_t)&i);
1115#endif
1116 break;
1117 case SLK:
1118 set_lockkey_state(kbd, state, SLK);
1119 break;
1120 case ALK:
1121 set_lockkey_state(kbd, state, ALK);
1122 break;
1123 /* NON-LOCKING KEYS */
1124 case SPSC: case RBT: case SUSP: case STBY:
1125 case DBG: case NEXT:
1126 *accents = 0;
1127 break;
1128 case BTAB:
1129 *accents = 0;
1130 action |= BKEY;
1131 break;
1132 case LSH:
1133 state |= SHIFTS1;
1134 break;
1135 case RSH:
1136 state |= SHIFTS2;
1137 break;
1138 case LCTR:
1139 state |= CTLS1;
1140 break;
1141 case RCTR:
1142 state |= CTLS2;
1143 break;
1144 case LALT:
1145 state |= ALTS1;
1146 break;
1147 case RALT:
1148 state |= ALTS2;
1149 break;
1150 case ASH:
1151 state |= AGRS1;
1152 break;
1153 case META:
1154 state |= METAS1;
1155 break;
1156 default:
1157 /* is this an accent (dead) key? */
1158 if (action >= F_ACC && action <= L_ACC) {
1159 action = save_accent_key(kbd, action,
1160 accents);
1161 switch (action) {
1162 case NOKEY:
1163 case ERRKEY:
1164 return action;
1165 default:
1166 if (state & METAS)
1167 return (action | MKEY);
1168 else
1169 return action;
1170 }
1171 /* NOT REACHED */
1172 }
1173 /* other special keys */
1174 if (*accents > 0) {
1175 *accents = 0;
1176 return ERRKEY;
1177 }
1178 if (action >= F_FN && action <= L_FN)
1179 action |= FKEY;
1180 /* XXX: return fkey string for the FKEY? */
1181 }
1182 *shiftstate = state;
1183 return (SPCLKEY | action);
1184 } else {
1185 /* regular keys */
1186 if (*accents > 0) {
1187 /* make an accented char */
1188 action = make_accent_char(kbd, action, accents);
1189 if (action == ERRKEY)
1190 return action;
1191 }
1192 if (state & METAS)
1193 action |= MKEY;
1194 return action;
1195 }
1196 }
1197 /* NOT REACHED */
1198}