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