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