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