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