Initial import from FreeBSD RELENG_4:
[games.git] / sys / dev / misc / 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: src/sys/dev/kbd/kbd.c,v 1.17.2.2 2001/07/30 16:46:43 yokota Exp $
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/proc.h>
37 #include <sys/tty.h>
38 #include <sys/poll.h>
39 #include <sys/vnode.h>
40 #include <sys/uio.h>
41
42 #include <machine/console.h>
43
44 #include <dev/kbd/kbdreg.h>
45
46 #define KBD_INDEX(dev)  minor(dev)
47
48 typedef struct genkbd_softc {
49         int             gkb_flags;      /* flag/status bits */
50 #define KB_ASLEEP       (1 << 0)
51         struct clist    gkb_q;          /* input queue */
52         struct selinfo  gkb_rsel;
53 } genkbd_softc_t;
54
55 static  SLIST_HEAD(, keyboard_driver) keyboard_drivers =
56         SLIST_HEAD_INITIALIZER(keyboard_drivers);
57
58 /* local arrays */
59
60 /*
61  * We need at least one entry each in order to initialize a keyboard
62  * for the kernel console.  The arrays will be increased dynamically
63  * when necessary.
64  */
65
66 static int              keyboards = 1;
67 static keyboard_t       *kbd_ini;
68 static keyboard_t       **keyboard = &kbd_ini;
69 static keyboard_switch_t *kbdsw_ini;
70        keyboard_switch_t **kbdsw = &kbdsw_ini;
71
72 #define ARRAY_DELTA     4
73
74 static int
75 kbd_realloc_array(void)
76 {
77         keyboard_t **new_kbd;
78         keyboard_switch_t **new_kbdsw;
79         int newsize;
80         int s;
81
82         s = spltty();
83         newsize = ((keyboards + ARRAY_DELTA)/ARRAY_DELTA)*ARRAY_DELTA;
84         new_kbd = malloc(sizeof(*new_kbd)*newsize, M_DEVBUF, M_NOWAIT);
85         if (new_kbd == NULL) {
86                 splx(s);
87                 return ENOMEM;
88         }
89         new_kbdsw = malloc(sizeof(*new_kbdsw)*newsize, M_DEVBUF, M_NOWAIT);
90         if (new_kbdsw == NULL) {
91                 free(new_kbd, M_DEVBUF);
92                 splx(s);
93                 return ENOMEM;
94         }
95         bzero(new_kbd, sizeof(*new_kbd)*newsize);
96         bzero(new_kbdsw, sizeof(*new_kbdsw)*newsize);
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         list = (const keyboard_driver_t **)kbddriver_set.ls_items;
206         while ((p = *list++) != NULL) {
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         list = (const keyboard_driver_t **)kbddriver_set.ls_items;
261         while ((p = *list++) != NULL) {
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         list = (const keyboard_driver_t **)kbddriver_set.ls_items;
400         while ((p = *list++) != NULL) {
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         /* bmaj */      -1
442 };
443
444 int
445 kbd_attach(keyboard_t *kbd)
446 {
447         dev_t dev;
448
449         if (kbd->kb_index >= keyboards)
450                 return EINVAL;
451         if (keyboard[kbd->kb_index] != kbd)
452                 return EINVAL;
453
454         dev = make_dev(&kbd_cdevsw, kbd->kb_index, UID_ROOT, GID_WHEEL, 0600,
455                        "kbd%r", kbd->kb_index);
456         if (dev->si_drv1 == NULL)
457                 dev->si_drv1 = malloc(sizeof(genkbd_softc_t), M_DEVBUF,
458                                       M_WAITOK);
459         bzero(dev->si_drv1, sizeof(genkbd_softc_t));
460
461         printf("kbd%d at %s%d\n", kbd->kb_index, kbd->kb_name, kbd->kb_unit);
462         return 0;
463 }
464
465 int
466 kbd_detach(keyboard_t *kbd)
467 {
468         dev_t dev;
469
470         if (kbd->kb_index >= keyboards)
471                 return EINVAL;
472         if (keyboard[kbd->kb_index] != kbd)
473                 return EINVAL;
474
475         dev = makedev(kbd_cdevsw.d_maj, kbd->kb_index);
476         if (dev->si_drv1)
477                 free(dev->si_drv1, M_DEVBUF);
478         destroy_dev(dev);
479
480         return 0;
481 }
482
483 /*
484  * Generic keyboard cdev driver functions
485  * Keyboard subdrivers may call these functions to implement common
486  * driver functions.
487  */
488
489 #define KB_QSIZE        512
490 #define KB_BUFSIZE      64
491
492 static kbd_callback_func_t genkbd_event;
493
494 static int
495 genkbdopen(dev_t dev, int mode, int flag, struct proc *p)
496 {
497         keyboard_t *kbd;
498         genkbd_softc_t *sc;
499         int s;
500         int i;
501
502         s = spltty();
503         sc = dev->si_drv1;
504         kbd = kbd_get_keyboard(KBD_INDEX(dev));
505         if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
506                 splx(s);
507                 return ENXIO;
508         }
509         i = kbd_allocate(kbd->kb_name, kbd->kb_unit, sc,
510                          genkbd_event, (void *)sc);
511         if (i < 0) {
512                 splx(s);
513                 return EBUSY;
514         }
515         /* assert(i == kbd->kb_index) */
516         /* assert(kbd == kbd_get_keyboard(i)) */
517
518         /*
519          * NOTE: even when we have successfully claimed a keyboard,
520          * the device may still be missing (!KBD_HAS_DEVICE(kbd)).
521          */
522
523 #if 0
524         bzero(&sc->gkb_q, sizeof(sc->gkb_q));
525 #endif
526         clist_alloc_cblocks(&sc->gkb_q, KB_QSIZE, KB_QSIZE/2); /* XXX */
527         sc->gkb_rsel.si_flags = 0;
528         sc->gkb_rsel.si_pid = 0;
529         splx(s);
530
531         return 0;
532 }
533
534 static int
535 genkbdclose(dev_t dev, int mode, int flag, struct proc *p)
536 {
537         keyboard_t *kbd;
538         genkbd_softc_t *sc;
539         int s;
540
541         /*
542          * NOTE: the device may have already become invalid.
543          * kbd == NULL || !KBD_IS_VALID(kbd)
544          */
545         s = spltty();
546         sc = dev->si_drv1;
547         kbd = kbd_get_keyboard(KBD_INDEX(dev));
548         if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
549                 /* XXX: we shall be forgiving and don't report error... */
550         } else {
551                 kbd_release(kbd, (void *)sc);
552 #if 0
553                 clist_free_cblocks(&sc->gkb_q);
554 #endif
555         }
556         splx(s);
557         return 0;
558 }
559
560 static int
561 genkbdread(dev_t dev, struct uio *uio, int flag)
562 {
563         keyboard_t *kbd;
564         genkbd_softc_t *sc;
565         u_char buffer[KB_BUFSIZE];
566         int len;
567         int error;
568         int s;
569
570         /* wait for input */
571         s = spltty();
572         sc = dev->si_drv1;
573         kbd = kbd_get_keyboard(KBD_INDEX(dev));
574         if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
575                 splx(s);
576                 return ENXIO;
577         }
578         while (sc->gkb_q.c_cc == 0) {
579                 if (flag & IO_NDELAY) {
580                         splx(s);
581                         return EWOULDBLOCK;
582                 }
583                 sc->gkb_flags |= KB_ASLEEP;
584                 error = tsleep((caddr_t)sc, PZERO | PCATCH, "kbdrea", 0);
585                 kbd = kbd_get_keyboard(KBD_INDEX(dev));
586                 if ((kbd == NULL) || !KBD_IS_VALID(kbd)) {
587                         splx(s);
588                         return ENXIO;   /* our keyboard has gone... */
589                 }
590                 if (error) {
591                         sc->gkb_flags &= ~KB_ASLEEP;
592                         splx(s);
593                         return error;
594                 }
595         }
596         splx(s);
597
598         /* copy as much input as possible */
599         error = 0;
600         while (uio->uio_resid > 0) {
601                 len = imin(uio->uio_resid, sizeof(buffer));
602                 len = q_to_b(&sc->gkb_q, buffer, len);
603                 if (len <= 0)
604                         break;
605                 error = uiomove(buffer, len, uio);
606                 if (error)
607                         break;
608         }
609
610         return error;
611 }
612
613 static int
614 genkbdwrite(dev_t dev, struct uio *uio, int flag)
615 {
616         keyboard_t *kbd;
617
618         kbd = kbd_get_keyboard(KBD_INDEX(dev));
619         if ((kbd == NULL) || !KBD_IS_VALID(kbd))
620                 return ENXIO;
621         return ENODEV;
622 }
623
624 static int
625 genkbdioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p)
626 {
627         keyboard_t *kbd;
628         int error;
629
630         kbd = kbd_get_keyboard(KBD_INDEX(dev));
631         if ((kbd == NULL) || !KBD_IS_VALID(kbd))
632                 return ENXIO;
633         error = (*kbdsw[kbd->kb_index]->ioctl)(kbd, cmd, arg);
634         if (error == ENOIOCTL)
635                 error = ENODEV;
636         return error;
637 }
638
639 static int
640 genkbdpoll(dev_t dev, int events, struct proc *p)
641 {
642         keyboard_t *kbd;
643         genkbd_softc_t *sc;
644         int revents;
645         int s;
646
647         revents = 0;
648         s = spltty();
649         sc = dev->si_drv1;
650         kbd = kbd_get_keyboard(KBD_INDEX(dev));
651         if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
652                 revents =  POLLHUP;     /* the keyboard has gone */
653         } else if (events & (POLLIN | POLLRDNORM)) {
654                 if (sc->gkb_q.c_cc > 0)
655                         revents = events & (POLLIN | POLLRDNORM);
656                 else
657                         selrecord(p, &sc->gkb_rsel);
658         }
659         splx(s);
660         return revents;
661 }
662
663 static int
664 genkbd_event(keyboard_t *kbd, int event, void *arg)
665 {
666         genkbd_softc_t *sc;
667         size_t len;
668         u_char *cp;
669         int mode;
670         int c;
671
672         /* assert(KBD_IS_VALID(kbd)) */
673         sc = (genkbd_softc_t *)arg;
674
675         switch (event) {
676         case KBDIO_KEYINPUT:
677                 break;
678         case KBDIO_UNLOADING:
679                 /* the keyboard is going... */
680                 kbd_release(kbd, (void *)sc);
681                 if (sc->gkb_flags & KB_ASLEEP) {
682                         sc->gkb_flags &= ~KB_ASLEEP;
683                         wakeup((caddr_t)sc);
684                 }
685                 selwakeup(&sc->gkb_rsel);
686                 return 0;
687         default:
688                 return EINVAL;
689         }
690
691         /* obtain the current key input mode */
692         if ((*kbdsw[kbd->kb_index]->ioctl)(kbd, KDGKBMODE, (caddr_t)&mode))
693                 mode = K_XLATE;
694
695         /* read all pending input */
696         while ((*kbdsw[kbd->kb_index]->check_char)(kbd)) {
697                 c = (*kbdsw[kbd->kb_index]->read_char)(kbd, FALSE);
698                 if (c == NOKEY)
699                         continue;
700                 if (c == ERRKEY)        /* XXX: ring bell? */
701                         continue;
702                 if (!KBD_IS_BUSY(kbd))
703                         /* the device is not open, discard the input */
704                         continue;
705
706                 /* store the byte as is for K_RAW and K_CODE modes */
707                 if (mode != K_XLATE) {
708                         putc(KEYCHAR(c), &sc->gkb_q);
709                         continue;
710                 }
711
712                 /* K_XLATE */
713                 if (c & RELKEY) /* key release is ignored */
714                         continue;
715
716                 /* process special keys; most of them are just ignored... */
717                 if (c & SPCLKEY) {
718                         switch (KEYCHAR(c)) {
719                         default:
720                                 /* ignore them... */
721                                 continue;
722                         case BTAB:      /* a backtab: ESC [ Z */
723                                 putc(0x1b, &sc->gkb_q);
724                                 putc('[', &sc->gkb_q);
725                                 putc('Z', &sc->gkb_q);
726                                 continue;
727                         }
728                 }
729
730                 /* normal chars, normal chars with the META, function keys */
731                 switch (KEYFLAGS(c)) {
732                 case 0:                 /* a normal char */
733                         putc(KEYCHAR(c), &sc->gkb_q);
734                         break;
735                 case MKEY:              /* the META flag: prepend ESC */
736                         putc(0x1b, &sc->gkb_q);
737                         putc(KEYCHAR(c), &sc->gkb_q);
738                         break;
739                 case FKEY | SPCLKEY:    /* a function key, return string */
740                         cp = (*kbdsw[kbd->kb_index]->get_fkeystr)(kbd,
741                                                         KEYCHAR(c), &len);
742                         if (cp != NULL) {
743                                 while (len-- >  0)
744                                         putc(*cp++, &sc->gkb_q);
745                         }
746                         break;
747                 }
748         }
749
750         /* wake up sleeping/polling processes */
751         if (sc->gkb_q.c_cc > 0) {
752                 if (sc->gkb_flags & KB_ASLEEP) {
753                         sc->gkb_flags &= ~KB_ASLEEP;
754                         wakeup((caddr_t)sc);
755                 }
756                 selwakeup(&sc->gkb_rsel);
757         }
758
759         return 0;
760 }
761
762 #endif /* KBD_INSTALL_CDEV */
763
764 /*
765  * Generic low-level keyboard functions
766  * The low-level functions in the keyboard subdriver may use these
767  * functions.
768  */
769
770 int
771 genkbd_commonioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
772 {
773         keyarg_t *keyp;
774         fkeyarg_t *fkeyp;
775         int s;
776         int i;
777
778         s = spltty();
779         switch (cmd) {
780
781         case KDGKBINFO:         /* get keyboard information */
782                 ((keyboard_info_t *)arg)->kb_index = kbd->kb_index;
783                 i = imin(strlen(kbd->kb_name) + 1,
784                          sizeof(((keyboard_info_t *)arg)->kb_name));
785                 bcopy(kbd->kb_name, ((keyboard_info_t *)arg)->kb_name, i);
786                 ((keyboard_info_t *)arg)->kb_unit = kbd->kb_unit;
787                 ((keyboard_info_t *)arg)->kb_type = kbd->kb_type;
788                 ((keyboard_info_t *)arg)->kb_config = kbd->kb_config;
789                 ((keyboard_info_t *)arg)->kb_flags = kbd->kb_flags;
790                 break;
791
792         case KDGKBTYPE:         /* get keyboard type */
793                 *(int *)arg = kbd->kb_type;
794                 break;
795
796         case KDGETREPEAT:       /* get keyboard repeat rate */
797                 ((int *)arg)[0] = kbd->kb_delay1;
798                 ((int *)arg)[1] = kbd->kb_delay2; 
799                 break;
800
801         case GIO_KEYMAP:        /* get keyboard translation table */
802                 bcopy(kbd->kb_keymap, arg, sizeof(*kbd->kb_keymap));
803                 break;
804         case PIO_KEYMAP:        /* set keyboard translation table */
805 #ifndef KBD_DISABLE_KEYMAP_LOAD
806                 bzero(kbd->kb_accentmap, sizeof(*kbd->kb_accentmap));
807                 bcopy(arg, kbd->kb_keymap, sizeof(*kbd->kb_keymap));
808                 break;
809 #else
810                 splx(s);
811                 return ENODEV;
812 #endif
813
814         case GIO_KEYMAPENT:     /* get keyboard translation table entry */
815                 keyp = (keyarg_t *)arg;
816                 if (keyp->keynum >= sizeof(kbd->kb_keymap->key)
817                                         /sizeof(kbd->kb_keymap->key[0])) {
818                         splx(s);
819                         return EINVAL;
820                 }
821                 bcopy(&kbd->kb_keymap->key[keyp->keynum], &keyp->key,
822                       sizeof(keyp->key));
823                 break;
824         case PIO_KEYMAPENT:     /* set keyboard translation table entry */
825 #ifndef KBD_DISABLE_KEYMAP_LOAD
826                 keyp = (keyarg_t *)arg;
827                 if (keyp->keynum >= sizeof(kbd->kb_keymap->key)
828                                         /sizeof(kbd->kb_keymap->key[0])) {
829                         splx(s);
830                         return EINVAL;
831                 }
832                 bcopy(&keyp->key, &kbd->kb_keymap->key[keyp->keynum],
833                       sizeof(keyp->key));
834                 break;
835 #else
836                 splx(s);
837                 return ENODEV;
838 #endif
839
840         case GIO_DEADKEYMAP:    /* get accent key translation table */
841                 bcopy(kbd->kb_accentmap, arg, sizeof(*kbd->kb_accentmap));
842                 break;
843         case PIO_DEADKEYMAP:    /* set accent key translation table */
844 #ifndef KBD_DISABLE_KEYMAP_LOAD
845                 bcopy(arg, kbd->kb_accentmap, sizeof(*kbd->kb_accentmap));
846                 break;
847 #else
848                 splx(s);
849                 return ENODEV;
850 #endif
851
852         case GETFKEY:           /* get functionkey string */
853                 fkeyp = (fkeyarg_t *)arg;
854                 if (fkeyp->keynum >= kbd->kb_fkeytab_size) {
855                         splx(s);
856                         return EINVAL;
857                 }
858                 bcopy(kbd->kb_fkeytab[fkeyp->keynum].str, fkeyp->keydef,
859                       kbd->kb_fkeytab[fkeyp->keynum].len);
860                 fkeyp->flen = kbd->kb_fkeytab[fkeyp->keynum].len;
861                 break;
862         case SETFKEY:           /* set functionkey string */
863 #ifndef KBD_DISABLE_KEYMAP_LOAD
864                 fkeyp = (fkeyarg_t *)arg;
865                 if (fkeyp->keynum >= kbd->kb_fkeytab_size) {
866                         splx(s);
867                         return EINVAL;
868                 }
869                 kbd->kb_fkeytab[fkeyp->keynum].len = imin(fkeyp->flen, MAXFK);
870                 bcopy(fkeyp->keydef, kbd->kb_fkeytab[fkeyp->keynum].str,
871                       kbd->kb_fkeytab[fkeyp->keynum].len);
872                 break;
873 #else
874                 splx(s);
875                 return ENODEV;
876 #endif
877
878         default:
879                 splx(s);
880                 return ENOIOCTL;
881         }
882
883         splx(s);
884         return 0;
885 }
886
887 /* get a pointer to the string associated with the given function key */
888 u_char
889 *genkbd_get_fkeystr(keyboard_t *kbd, int fkey, size_t *len)
890 {
891         if (kbd == NULL)
892                 return NULL;
893         fkey -= F_FN;
894         if (fkey > kbd->kb_fkeytab_size)
895                 return NULL;
896         *len = kbd->kb_fkeytab[fkey].len;
897         return kbd->kb_fkeytab[fkey].str;
898 }
899
900 /* diagnostic dump */
901 static char
902 *get_kbd_type_name(int type)
903 {
904         static struct {
905                 int type;
906                 char *name;
907         } name_table[] = {
908                 { KB_84,        "AT 84" },
909                 { KB_101,       "AT 101/102" },
910                 { KB_OTHER,     "generic" },
911         };
912         int i;
913
914         for (i = 0; i < sizeof(name_table)/sizeof(name_table[0]); ++i) {
915                 if (type == name_table[i].type)
916                         return name_table[i].name;
917         }
918         return "unknown";
919 }
920
921 void
922 genkbd_diag(keyboard_t *kbd, int level)
923 {
924         if (level > 0) {
925                 printf("kbd%d: %s%d, %s (%d), config:0x%x, flags:0x%x", 
926                        kbd->kb_index, kbd->kb_name, kbd->kb_unit,
927                        get_kbd_type_name(kbd->kb_type), kbd->kb_type,
928                        kbd->kb_config, kbd->kb_flags);
929                 if (kbd->kb_io_base > 0)
930                         printf(", port:0x%x-0x%x", kbd->kb_io_base, 
931                                kbd->kb_io_base + kbd->kb_io_size - 1);
932                 printf("\n");
933         }
934 }
935
936 #define set_lockkey_state(k, s, l)                              \
937         if (!((s) & l ## DOWN)) {                               \
938                 int i;                                          \
939                 (s) |= l ## DOWN;                               \
940                 (s) ^= l ## ED;                                 \
941                 i = (s) & LOCK_MASK;                            \
942                 (*kbdsw[(k)->kb_index]->ioctl)((k), KDSETLED, (caddr_t)&i); \
943         }
944
945 static u_int
946 save_accent_key(keyboard_t *kbd, u_int key, int *accents)
947 {
948         int i;
949
950         /* make an index into the accent map */
951         i = key - F_ACC + 1;
952         if ((i > kbd->kb_accentmap->n_accs)
953             || (kbd->kb_accentmap->acc[i - 1].accchar == 0)) {
954                 /* the index is out of range or pointing to an empty entry */
955                 *accents = 0;
956                 return ERRKEY;
957         }
958
959         /* 
960          * If the same accent key has been hit twice, produce the accent char
961          * itself.
962          */
963         if (i == *accents) {
964                 key = kbd->kb_accentmap->acc[i - 1].accchar;
965                 *accents = 0;
966                 return key;
967         }
968
969         /* remember the index and wait for the next key  */
970         *accents = i; 
971         return NOKEY;
972 }
973
974 static u_int
975 make_accent_char(keyboard_t *kbd, u_int ch, int *accents)
976 {
977         struct acc_t *acc;
978         int i;
979
980         acc = &kbd->kb_accentmap->acc[*accents - 1];
981         *accents = 0;
982
983         /* 
984          * If the accent key is followed by the space key,
985          * produce the accent char itself.
986          */
987         if (ch == ' ')
988                 return acc->accchar;
989
990         /* scan the accent map */
991         for (i = 0; i < NUM_ACCENTCHARS; ++i) {
992                 if (acc->map[i][0] == 0)        /* end of table */
993                         break;
994                 if (acc->map[i][0] == ch)
995                         return acc->map[i][1];
996         }
997         /* this char cannot be accented... */
998         return ERRKEY;
999 }
1000
1001 int
1002 genkbd_keyaction(keyboard_t *kbd, int keycode, int up, int *shiftstate,
1003                  int *accents)
1004 {
1005         struct keyent_t *key;
1006         int state = *shiftstate;
1007         int action;
1008         int f;
1009         int i;
1010
1011         i = keycode;
1012         f = state & (AGRS | ALKED);
1013         if ((f == AGRS1) || (f == AGRS2) || (f == ALKED))
1014                 i += ALTGR_OFFSET;
1015         key = &kbd->kb_keymap->key[i];
1016         i = ((state & SHIFTS) ? 1 : 0)
1017             | ((state & CTLS) ? 2 : 0)
1018             | ((state & ALTS) ? 4 : 0);
1019         if (((key->flgs & FLAG_LOCK_C) && (state & CLKED))
1020                 || ((key->flgs & FLAG_LOCK_N) && (state & NLKED)) )
1021                 i ^= 1;
1022
1023         if (up) {       /* break: key released */
1024                 action = kbd->kb_lastact[keycode];
1025                 kbd->kb_lastact[keycode] = NOP;
1026                 switch (action) {
1027                 case LSHA:
1028                         if (state & SHIFTAON) {
1029                                 set_lockkey_state(kbd, state, ALK);
1030                                 state &= ~ALKDOWN;
1031                         }
1032                         action = LSH;
1033                         /* FALL THROUGH */
1034                 case LSH:
1035                         state &= ~SHIFTS1;
1036                         break;
1037                 case RSHA:
1038                         if (state & SHIFTAON) {
1039                                 set_lockkey_state(kbd, state, ALK);
1040                                 state &= ~ALKDOWN;
1041                         }
1042                         action = RSH;
1043                         /* FALL THROUGH */
1044                 case RSH:
1045                         state &= ~SHIFTS2;
1046                         break;
1047                 case LCTRA:
1048                         if (state & SHIFTAON) {
1049                                 set_lockkey_state(kbd, state, ALK);
1050                                 state &= ~ALKDOWN;
1051                         }
1052                         action = LCTR;
1053                         /* FALL THROUGH */
1054                 case LCTR:
1055                         state &= ~CTLS1;
1056                         break;
1057                 case RCTRA:
1058                         if (state & SHIFTAON) {
1059                                 set_lockkey_state(kbd, state, ALK);
1060                                 state &= ~ALKDOWN;
1061                         }
1062                         action = RCTR;
1063                         /* FALL THROUGH */
1064                 case RCTR:
1065                         state &= ~CTLS2;
1066                         break;
1067                 case LALTA:
1068                         if (state & SHIFTAON) {
1069                                 set_lockkey_state(kbd, state, ALK);
1070                                 state &= ~ALKDOWN;
1071                         }
1072                         action = LALT;
1073                         /* FALL THROUGH */
1074                 case LALT:
1075                         state &= ~ALTS1;
1076                         break;
1077                 case RALTA:
1078                         if (state & SHIFTAON) {
1079                                 set_lockkey_state(kbd, state, ALK);
1080                                 state &= ~ALKDOWN;
1081                         }
1082                         action = RALT;
1083                         /* FALL THROUGH */
1084                 case RALT:
1085                         state &= ~ALTS2;
1086                         break;
1087                 case ASH:
1088                         state &= ~AGRS1;
1089                         break;
1090                 case META:
1091                         state &= ~METAS1;
1092                         break;
1093                 case NLK:
1094                         state &= ~NLKDOWN;
1095                         break;
1096                 case CLK:
1097 #ifndef PC98
1098                         state &= ~CLKDOWN;
1099 #else
1100                         state &= ~CLKED;
1101                         i = state & LOCK_MASK;
1102                         (*kbdsw[kbd->kb_index]->ioctl)(kbd, KDSETLED,
1103                                                        (caddr_t)&i);
1104 #endif
1105                         break;
1106                 case SLK:
1107                         state &= ~SLKDOWN;
1108                         break;
1109                 case ALK:
1110                         state &= ~ALKDOWN;
1111                         break;
1112                 case NOP:
1113                         /* release events of regular keys are not reported */
1114                         *shiftstate &= ~SHIFTAON;
1115                         return NOKEY;
1116                 }
1117                 *shiftstate = state & ~SHIFTAON;
1118                 return (SPCLKEY | RELKEY | action);
1119         } else {        /* make: key pressed */
1120                 action = key->map[i];
1121                 state &= ~SHIFTAON;
1122                 if (key->spcl & (0x80 >> i)) {
1123                         /* special keys */
1124                         if (kbd->kb_lastact[keycode] == NOP)
1125                                 kbd->kb_lastact[keycode] = action;
1126                         if (kbd->kb_lastact[keycode] != action)
1127                                 action = NOP;
1128                         switch (action) {
1129                         /* LOCKING KEYS */
1130                         case NLK:
1131                                 set_lockkey_state(kbd, state, NLK);
1132                                 break;
1133                         case CLK:
1134 #ifndef PC98
1135                                 set_lockkey_state(kbd, state, CLK);
1136 #else
1137                                 state |= CLKED;
1138                                 i = state & LOCK_MASK;
1139                                 (*kbdsw[kbd->kb_index]->ioctl)(kbd, KDSETLED,
1140                                                                (caddr_t)&i);
1141 #endif
1142                                 break;
1143                         case SLK:
1144                                 set_lockkey_state(kbd, state, SLK);
1145                                 break;
1146                         case ALK:
1147                                 set_lockkey_state(kbd, state, ALK);
1148                                 break;
1149                         /* NON-LOCKING KEYS */
1150                         case SPSC: case RBT:  case SUSP: case STBY:
1151                         case DBG:  case NEXT: case PREV: case PNC:
1152                         case HALT: case PDWN:
1153                                 *accents = 0;
1154                                 break;
1155                         case BTAB:
1156                                 *accents = 0;
1157                                 action |= BKEY;
1158                                 break;
1159                         case LSHA:
1160                                 state |= SHIFTAON;
1161                                 action = LSH;
1162                                 /* FALL THROUGH */
1163                         case LSH:
1164                                 state |= SHIFTS1;
1165                                 break;
1166                         case RSHA:
1167                                 state |= SHIFTAON;
1168                                 action = RSH;
1169                                 /* FALL THROUGH */
1170                         case RSH:
1171                                 state |= SHIFTS2;
1172                                 break;
1173                         case LCTRA:
1174                                 state |= SHIFTAON;
1175                                 action = LCTR;
1176                                 /* FALL THROUGH */
1177                         case LCTR:
1178                                 state |= CTLS1;
1179                                 break;
1180                         case RCTRA:
1181                                 state |= SHIFTAON;
1182                                 action = RCTR;
1183                                 /* FALL THROUGH */
1184                         case RCTR:
1185                                 state |= CTLS2;
1186                                 break;
1187                         case LALTA:
1188                                 state |= SHIFTAON;
1189                                 action = LALT;
1190                                 /* FALL THROUGH */
1191                         case LALT:
1192                                 state |= ALTS1;
1193                                 break;
1194                         case RALTA:
1195                                 state |= SHIFTAON;
1196                                 action = RALT;
1197                                 /* FALL THROUGH */
1198                         case RALT:
1199                                 state |= ALTS2;
1200                                 break;
1201                         case ASH:
1202                                 state |= AGRS1;
1203                                 break;
1204                         case META:
1205                                 state |= METAS1;
1206                                 break;
1207                         case NOP:
1208                                 *shiftstate = state;
1209                                 return NOKEY;
1210                         default:
1211                                 /* is this an accent (dead) key? */
1212                                 *shiftstate = state;
1213                                 if (action >= F_ACC && action <= L_ACC) {
1214                                         action = save_accent_key(kbd, action,
1215                                                                  accents);
1216                                         switch (action) {
1217                                         case NOKEY:
1218                                         case ERRKEY:
1219                                                 return action;
1220                                         default:
1221                                                 if (state & METAS)
1222                                                         return (action | MKEY);
1223                                                 else
1224                                                         return action;
1225                                         }
1226                                         /* NOT REACHED */
1227                                 }
1228                                 /* other special keys */
1229                                 if (*accents > 0) {
1230                                         *accents = 0;
1231                                         return ERRKEY;
1232                                 }
1233                                 if (action >= F_FN && action <= L_FN)
1234                                         action |= FKEY;
1235                                 /* XXX: return fkey string for the FKEY? */
1236                                 return (SPCLKEY | action);
1237                         }
1238                         *shiftstate = state;
1239                         return (SPCLKEY | action);
1240                 } else {
1241                         /* regular keys */
1242                         kbd->kb_lastact[keycode] = NOP;
1243                         *shiftstate = state;
1244                         if (*accents > 0) {
1245                                 /* make an accented char */
1246                                 action = make_accent_char(kbd, action, accents);
1247                                 if (action == ERRKEY)
1248                                         return action;
1249                         }
1250                         if (state & METAS)
1251                                 action |= MKEY;
1252                         return action;
1253                 }
1254         }
1255         /* NOT REACHED */
1256 }