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