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