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