Commit | Line | Data |
---|---|---|
984263bc MD |
1 | /*- |
2 | * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp> | |
3 | * All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer as | |
10 | * the first lines of this file unmodified. | |
11 | * 2. Redistributions in binary form must reproduce the above copyright | |
12 | * notice, this list of conditions and the following disclaimer in the | |
13 | * documentation and/or other materials provided with the distribution. | |
14 | * | |
15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR | |
16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
18 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
25 | * | |
26 | * $FreeBSD: src/sys/dev/kbd/kbd.c,v 1.17.2.2 2001/07/30 16:46:43 yokota Exp $ | |
028066b1 | 27 | * $DragonFly: src/sys/dev/misc/kbd/kbd.c,v 1.23 2007/05/08 02:31:39 dillon Exp $ |
a38e57d5 MD |
28 | */ |
29 | /* | |
30 | * Generic keyboard driver. | |
31 | * | |
32 | * Interrupt note: keyboards use clist functions and since usb keyboard | |
33 | * interrupts are not protected by spltty(), we must use a critical section | |
34 | * to protect against corruption. | |
bcc53404 | 35 | * XXX: this keyboard driver doesn't use clist functions anymore! |
984263bc MD |
36 | */ |
37 | ||
38 | #include "opt_kbd.h" | |
39 | ||
40 | #include <sys/param.h> | |
41 | #include <sys/systm.h> | |
42 | #include <sys/kernel.h> | |
43 | #include <sys/malloc.h> | |
44 | #include <sys/conf.h> | |
45 | #include <sys/proc.h> | |
46 | #include <sys/tty.h> | |
25fef0f3 | 47 | #include <sys/event.h> |
984263bc MD |
48 | #include <sys/vnode.h> |
49 | #include <sys/uio.h> | |
a38e57d5 MD |
50 | #include <sys/thread.h> |
51 | #include <sys/thread2.h> | |
984263bc MD |
52 | |
53 | #include <machine/console.h> | |
54 | ||
1f2de5d4 | 55 | #include "kbdreg.h" |
984263bc MD |
56 | |
57 | #define KBD_INDEX(dev) minor(dev) | |
58 | ||
bcc53404 AH |
59 | #define KB_QSIZE 512 |
60 | #define KB_BUFSIZE 64 | |
61 | ||
8a0a8f43 | 62 | struct genkbd_softc { |
984263bc MD |
63 | int gkb_flags; /* flag/status bits */ |
64 | #define KB_ASLEEP (1 << 0) | |
5b22f1a7 | 65 | struct kqinfo gkb_rkq; |
bcc53404 AH |
66 | char gkb_q[KB_QSIZE]; /* input queue */ |
67 | unsigned int gkb_q_start; | |
68 | unsigned int gkb_q_length; | |
8a0a8f43 MD |
69 | }; |
70 | ||
71 | typedef struct genkbd_softc *genkbd_softc_t; | |
984263bc MD |
72 | |
73 | static SLIST_HEAD(, keyboard_driver) keyboard_drivers = | |
74 | SLIST_HEAD_INITIALIZER(keyboard_drivers); | |
75 | ||
dc62b251 MD |
76 | SET_DECLARE(kbddriver_set, const keyboard_driver_t); |
77 | ||
984263bc MD |
78 | /* local arrays */ |
79 | ||
80 | /* | |
81 | * We need at least one entry each in order to initialize a keyboard | |
82 | * for the kernel console. The arrays will be increased dynamically | |
83 | * when necessary. | |
84 | */ | |
85 | ||
86 | static int keyboards = 1; | |
87 | static keyboard_t *kbd_ini; | |
88 | static keyboard_t **keyboard = &kbd_ini; | |
89 | static keyboard_switch_t *kbdsw_ini; | |
90 | keyboard_switch_t **kbdsw = &kbdsw_ini; | |
91 | ||
92 | #define ARRAY_DELTA 4 | |
93 | ||
94 | static int | |
95 | kbd_realloc_array(void) | |
96 | { | |
97 | keyboard_t **new_kbd; | |
98 | keyboard_switch_t **new_kbdsw; | |
99 | int newsize; | |
984263bc | 100 | |
984263bc | 101 | newsize = ((keyboards + ARRAY_DELTA)/ARRAY_DELTA)*ARRAY_DELTA; |
efda3bd0 | 102 | new_kbd = kmalloc(sizeof(*new_kbd) * newsize, M_DEVBUF, |
bf22d4c1 | 103 | M_WAITOK | M_ZERO); |
efda3bd0 | 104 | new_kbdsw = kmalloc(sizeof(*new_kbdsw) * newsize, M_DEVBUF, |
bf22d4c1 | 105 | M_WAITOK | M_ZERO); |
984263bc MD |
106 | bcopy(keyboard, new_kbd, sizeof(*keyboard)*keyboards); |
107 | bcopy(kbdsw, new_kbdsw, sizeof(*kbdsw)*keyboards); | |
a38e57d5 | 108 | crit_enter(); |
984263bc | 109 | if (keyboards > 1) { |
efda3bd0 MD |
110 | kfree(keyboard, M_DEVBUF); |
111 | kfree(kbdsw, M_DEVBUF); | |
984263bc MD |
112 | } |
113 | keyboard = new_kbd; | |
114 | kbdsw = new_kbdsw; | |
115 | keyboards = newsize; | |
a38e57d5 | 116 | crit_exit(); |
984263bc MD |
117 | |
118 | if (bootverbose) | |
e3869ec7 | 119 | kprintf("kbd: new array size %d\n", keyboards); |
984263bc MD |
120 | |
121 | return 0; | |
122 | } | |
123 | ||
124 | /* | |
e30db56f MD |
125 | * Low-level keyboard driver functions. |
126 | * | |
984263bc MD |
127 | * Keyboard subdrivers, such as the AT keyboard driver and the USB keyboard |
128 | * driver, call these functions to initialize the keyboard_t structure | |
129 | * and register it to the virtual keyboard driver `kbd'. | |
e30db56f MD |
130 | * |
131 | * The reinit call is made when a driver has partially detached a keyboard | |
132 | * but does not unregistered it, then wishes to reinitialize it later on. | |
133 | * This is how the USB keyboard driver handles the 'default' keyboard, | |
134 | * because unregistering the keyboard associated with the console will | |
135 | * destroy its console association forever. | |
984263bc | 136 | */ |
984263bc | 137 | void |
e30db56f | 138 | kbd_reinit_struct(keyboard_t *kbd, int config, int pref) |
984263bc | 139 | { |
e30db56f | 140 | kbd->kb_flags |= KB_NO_DEVICE; /* device has not been found */ |
984263bc MD |
141 | kbd->kb_config = config & ~KB_CONF_PROBE_ONLY; |
142 | kbd->kb_led = 0; /* unknown */ | |
984263bc MD |
143 | kbd->kb_data = NULL; |
144 | kbd->kb_keymap = NULL; | |
145 | kbd->kb_accentmap = NULL; | |
146 | kbd->kb_fkeytab = NULL; | |
147 | kbd->kb_fkeytab_size = 0; | |
148 | kbd->kb_delay1 = KB_DELAY1; /* these values are advisory only */ | |
149 | kbd->kb_delay2 = KB_DELAY2; | |
e30db56f MD |
150 | kbd->kb_count = 0; |
151 | kbd->kb_pref = pref; | |
984263bc MD |
152 | bzero(kbd->kb_lastact, sizeof(kbd->kb_lastact)); |
153 | } | |
154 | ||
e30db56f MD |
155 | /* initialize the keyboard_t structure */ |
156 | void | |
157 | kbd_init_struct(keyboard_t *kbd, char *name, int type, int unit, int config, | |
158 | int pref, int port, int port_size) | |
159 | { | |
160 | kbd->kb_flags = 0; | |
161 | kbd->kb_name = name; | |
162 | kbd->kb_type = type; | |
163 | kbd->kb_unit = unit; | |
164 | kbd->kb_io_base = port; | |
165 | kbd->kb_io_size = port_size; | |
166 | kbd_reinit_struct(kbd, config, pref); | |
167 | } | |
168 | ||
984263bc MD |
169 | void |
170 | kbd_set_maps(keyboard_t *kbd, keymap_t *keymap, accentmap_t *accmap, | |
171 | fkeytab_t *fkeymap, int fkeymap_size) | |
172 | { | |
173 | kbd->kb_keymap = keymap; | |
174 | kbd->kb_accentmap = accmap; | |
175 | kbd->kb_fkeytab = fkeymap; | |
176 | kbd->kb_fkeytab_size = fkeymap_size; | |
177 | } | |
178 | ||
179 | /* declare a new keyboard driver */ | |
180 | int | |
181 | kbd_add_driver(keyboard_driver_t *driver) | |
182 | { | |
183 | if (SLIST_NEXT(driver, link)) | |
184 | return EINVAL; | |
185 | SLIST_INSERT_HEAD(&keyboard_drivers, driver, link); | |
186 | return 0; | |
187 | } | |
188 | ||
189 | int | |
190 | kbd_delete_driver(keyboard_driver_t *driver) | |
191 | { | |
192 | SLIST_REMOVE(&keyboard_drivers, driver, keyboard_driver, link); | |
193 | SLIST_NEXT(driver, link) = NULL; | |
194 | return 0; | |
195 | } | |
196 | ||
197 | /* register a keyboard and associate it with a function table */ | |
198 | int | |
199 | kbd_register(keyboard_t *kbd) | |
200 | { | |
201 | const keyboard_driver_t **list; | |
202 | const keyboard_driver_t *p; | |
bcc53404 AH |
203 | keyboard_t *mux; |
204 | keyboard_info_t ki; | |
984263bc MD |
205 | int index; |
206 | ||
bcc53404 AH |
207 | mux = kbd_get_keyboard(kbd_find_keyboard("kbdmux", -1)); |
208 | ||
984263bc MD |
209 | for (index = 0; index < keyboards; ++index) { |
210 | if (keyboard[index] == NULL) | |
211 | break; | |
212 | } | |
213 | if (index >= keyboards) { | |
214 | if (kbd_realloc_array()) | |
215 | return -1; | |
216 | } | |
217 | ||
218 | kbd->kb_index = index; | |
219 | KBD_UNBUSY(kbd); | |
220 | KBD_VALID(kbd); | |
221 | kbd->kb_active = 0; /* disabled until someone calls kbd_enable() */ | |
222 | kbd->kb_token = NULL; | |
223 | kbd->kb_callback.kc_func = NULL; | |
224 | kbd->kb_callback.kc_arg = NULL; | |
c5e92a81 | 225 | callout_init(&kbd->kb_atkbd_timeout_ch); |
984263bc MD |
226 | |
227 | SLIST_FOREACH(p, &keyboard_drivers, link) { | |
228 | if (strcmp(p->name, kbd->kb_name) == 0) { | |
229 | keyboard[index] = kbd; | |
230 | kbdsw[index] = p->kbdsw; | |
bcc53404 AH |
231 | |
232 | if (mux != NULL) { | |
233 | bzero(&ki, sizeof(ki)); | |
234 | strcpy(ki.kb_name, kbd->kb_name); | |
235 | ki.kb_unit = kbd->kb_unit; | |
236 | kbd_ioctl(mux, KBADDKBD, (caddr_t) &ki); | |
237 | } | |
238 | ||
984263bc MD |
239 | return index; |
240 | } | |
241 | } | |
dc62b251 MD |
242 | SET_FOREACH(list, kbddriver_set) { |
243 | p = *list; | |
984263bc MD |
244 | if (strcmp(p->name, kbd->kb_name) == 0) { |
245 | keyboard[index] = kbd; | |
246 | kbdsw[index] = p->kbdsw; | |
bcc53404 AH |
247 | |
248 | if (mux != NULL) { | |
249 | bzero(&ki, sizeof(ki)); | |
250 | strcpy(ki.kb_name, kbd->kb_name); | |
251 | ki.kb_unit = kbd->kb_unit; | |
252 | kbd_ioctl(mux, KBADDKBD, (caddr_t) &ki); | |
253 | } | |
254 | ||
984263bc MD |
255 | return index; |
256 | } | |
257 | } | |
258 | ||
259 | return -1; | |
260 | } | |
261 | ||
262 | int | |
263 | kbd_unregister(keyboard_t *kbd) | |
264 | { | |
265 | int error; | |
984263bc MD |
266 | |
267 | if ((kbd->kb_index < 0) || (kbd->kb_index >= keyboards)) | |
268 | return ENOENT; | |
269 | if (keyboard[kbd->kb_index] != kbd) | |
270 | return ENOENT; | |
271 | ||
a38e57d5 | 272 | crit_enter(); |
c5e92a81 | 273 | callout_stop(&kbd->kb_atkbd_timeout_ch); |
984263bc MD |
274 | if (KBD_IS_BUSY(kbd)) { |
275 | error = (*kbd->kb_callback.kc_func)(kbd, KBDIO_UNLOADING, | |
276 | kbd->kb_callback.kc_arg); | |
277 | if (error) { | |
a38e57d5 | 278 | crit_exit(); |
984263bc MD |
279 | return error; |
280 | } | |
281 | if (KBD_IS_BUSY(kbd)) { | |
a38e57d5 | 282 | crit_exit(); |
984263bc MD |
283 | return EBUSY; |
284 | } | |
285 | } | |
286 | KBD_INVALID(kbd); | |
287 | keyboard[kbd->kb_index] = NULL; | |
288 | kbdsw[kbd->kb_index] = NULL; | |
289 | ||
a38e57d5 | 290 | crit_exit(); |
984263bc MD |
291 | return 0; |
292 | } | |
293 | ||
294 | /* find a funciton table by the driver name */ | |
3d8ba483 SW |
295 | keyboard_switch_t * |
296 | kbd_get_switch(char *driver) | |
984263bc MD |
297 | { |
298 | const keyboard_driver_t **list; | |
299 | const keyboard_driver_t *p; | |
300 | ||
301 | SLIST_FOREACH(p, &keyboard_drivers, link) { | |
302 | if (strcmp(p->name, driver) == 0) | |
303 | return p->kbdsw; | |
304 | } | |
dc62b251 MD |
305 | SET_FOREACH(list, kbddriver_set) { |
306 | p = *list; | |
984263bc MD |
307 | if (strcmp(p->name, driver) == 0) |
308 | return p->kbdsw; | |
309 | } | |
310 | ||
311 | return NULL; | |
312 | } | |
313 | ||
314 | /* | |
315 | * Keyboard client functions | |
316 | * Keyboard clients, such as the console driver `syscons' and the keyboard | |
317 | * cdev driver, use these functions to claim and release a keyboard for | |
318 | * exclusive use. | |
319 | */ | |
bcc53404 AH |
320 | /* |
321 | * find the keyboard specified by a driver name and a unit number | |
322 | * starting at given index | |
323 | */ | |
984263bc | 324 | int |
bcc53404 | 325 | kbd_find_keyboard2(char *driver, int unit, int index, int legacy) |
984263bc MD |
326 | { |
327 | int i; | |
e30db56f MD |
328 | int pref; |
329 | int pref_index; | |
330 | ||
331 | pref = 0; | |
332 | pref_index = -1; | |
984263bc | 333 | |
bcc53404 AH |
334 | if ((index < 0) || (index >= keyboards)) |
335 | return (-1); | |
336 | ||
337 | for (i = index; i < keyboards; ++i) { | |
984263bc MD |
338 | if (keyboard[i] == NULL) |
339 | continue; | |
340 | if (!KBD_IS_VALID(keyboard[i])) | |
341 | continue; | |
342 | if (strcmp("*", driver) && strcmp(keyboard[i]->kb_name, driver)) | |
343 | continue; | |
344 | if ((unit != -1) && (keyboard[i]->kb_unit != unit)) | |
345 | continue; | |
bcc53404 AH |
346 | /* |
347 | * If we are in legacy mode, we do the old preference magic and | |
348 | * don't return on the first found unit. | |
349 | */ | |
350 | if (legacy) { | |
351 | if (pref <= keyboard[i]->kb_pref) { | |
352 | pref = keyboard[i]->kb_pref; | |
353 | pref_index = i; | |
354 | } | |
355 | } else { | |
356 | return i; | |
e30db56f | 357 | } |
984263bc | 358 | } |
bcc53404 AH |
359 | |
360 | if (!legacy) | |
361 | KKASSERT(pref_index == -1); | |
362 | ||
e30db56f | 363 | return (pref_index); |
984263bc MD |
364 | } |
365 | ||
bcc53404 AH |
366 | /* find the keyboard specified by a driver name and a unit number */ |
367 | int | |
368 | kbd_find_keyboard(char *driver, int unit) | |
369 | { | |
370 | return (kbd_find_keyboard2(driver, unit, 0, 1)); | |
371 | } | |
372 | ||
984263bc MD |
373 | /* allocate a keyboard */ |
374 | int | |
375 | kbd_allocate(char *driver, int unit, void *id, kbd_callback_func_t *func, | |
376 | void *arg) | |
377 | { | |
378 | int index; | |
984263bc MD |
379 | |
380 | if (func == NULL) | |
381 | return -1; | |
382 | ||
a38e57d5 | 383 | crit_enter(); |
984263bc MD |
384 | index = kbd_find_keyboard(driver, unit); |
385 | if (index >= 0) { | |
386 | if (KBD_IS_BUSY(keyboard[index])) { | |
a38e57d5 | 387 | crit_exit(); |
984263bc MD |
388 | return -1; |
389 | } | |
390 | keyboard[index]->kb_token = id; | |
391 | KBD_BUSY(keyboard[index]); | |
392 | keyboard[index]->kb_callback.kc_func = func; | |
393 | keyboard[index]->kb_callback.kc_arg = arg; | |
bcc53404 | 394 | kbd_clear_state(keyboard[index]); |
984263bc | 395 | } |
a38e57d5 | 396 | crit_exit(); |
984263bc MD |
397 | return index; |
398 | } | |
399 | ||
400 | int | |
401 | kbd_release(keyboard_t *kbd, void *id) | |
402 | { | |
403 | int error; | |
984263bc | 404 | |
a38e57d5 | 405 | crit_enter(); |
984263bc MD |
406 | if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) { |
407 | error = EINVAL; | |
408 | } else if (kbd->kb_token != id) { | |
409 | error = EPERM; | |
410 | } else { | |
411 | kbd->kb_token = NULL; | |
412 | KBD_UNBUSY(kbd); | |
413 | kbd->kb_callback.kc_func = NULL; | |
414 | kbd->kb_callback.kc_arg = NULL; | |
bcc53404 | 415 | kbd_clear_state(kbd); |
984263bc MD |
416 | error = 0; |
417 | } | |
a38e57d5 | 418 | crit_exit(); |
984263bc MD |
419 | return error; |
420 | } | |
421 | ||
422 | int | |
423 | kbd_change_callback(keyboard_t *kbd, void *id, kbd_callback_func_t *func, | |
424 | void *arg) | |
425 | { | |
426 | int error; | |
984263bc | 427 | |
a38e57d5 | 428 | crit_enter(); |
984263bc MD |
429 | if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) { |
430 | error = EINVAL; | |
431 | } else if (kbd->kb_token != id) { | |
432 | error = EPERM; | |
433 | } else if (func == NULL) { | |
434 | error = EINVAL; | |
435 | } else { | |
436 | kbd->kb_callback.kc_func = func; | |
437 | kbd->kb_callback.kc_arg = arg; | |
438 | error = 0; | |
439 | } | |
a38e57d5 | 440 | crit_exit(); |
984263bc MD |
441 | return error; |
442 | } | |
443 | ||
444 | /* get a keyboard structure */ | |
3d8ba483 SW |
445 | keyboard_t * |
446 | kbd_get_keyboard(int index) | |
984263bc MD |
447 | { |
448 | if ((index < 0) || (index >= keyboards)) | |
449 | return NULL; | |
450 | if (keyboard[index] == NULL) | |
451 | return NULL; | |
452 | if (!KBD_IS_VALID(keyboard[index])) | |
453 | return NULL; | |
454 | return keyboard[index]; | |
455 | } | |
456 | ||
457 | /* | |
458 | * The back door for the console driver; configure keyboards | |
459 | * This function is for the kernel console to initialize keyboards | |
460 | * at very early stage. | |
461 | */ | |
462 | ||
463 | int | |
464 | kbd_configure(int flags) | |
465 | { | |
466 | const keyboard_driver_t **list; | |
467 | const keyboard_driver_t *p; | |
468 | ||
469 | SLIST_FOREACH(p, &keyboard_drivers, link) { | |
470 | if (p->configure != NULL) | |
471 | (*p->configure)(flags); | |
472 | } | |
dc62b251 MD |
473 | SET_FOREACH(list, kbddriver_set) { |
474 | p = *list; | |
984263bc MD |
475 | if (p->configure != NULL) |
476 | (*p->configure)(flags); | |
477 | } | |
478 | ||
479 | return 0; | |
480 | } | |
481 | ||
482 | #ifdef KBD_INSTALL_CDEV | |
483 | ||
484 | /* | |
485 | * Virtual keyboard cdev driver functions | |
486 | * The virtual keyboard driver dispatches driver functions to | |
487 | * appropriate subdrivers. | |
488 | */ | |
489 | ||
490 | #define KBD_UNIT(dev) minor(dev) | |
491 | ||
492 | static d_open_t genkbdopen; | |
493 | static d_close_t genkbdclose; | |
494 | static d_read_t genkbdread; | |
495 | static d_write_t genkbdwrite; | |
496 | static d_ioctl_t genkbdioctl; | |
25fef0f3 SG |
497 | static d_kqfilter_t genkbdkqfilter; |
498 | ||
499 | static void genkbdfiltdetach(struct knote *); | |
500 | static int genkbdfilter(struct knote *, long); | |
984263bc MD |
501 | |
502 | #define CDEV_MAJOR 112 | |
503 | ||
fef8985e | 504 | static struct dev_ops kbd_ops = { |
d4b8aec4 | 505 | { "kbd", CDEV_MAJOR, 0 }, |
fef8985e MD |
506 | .d_open = genkbdopen, |
507 | .d_close = genkbdclose, | |
508 | .d_read = genkbdread, | |
509 | .d_write = genkbdwrite, | |
510 | .d_ioctl = genkbdioctl, | |
25fef0f3 | 511 | .d_kqfilter = genkbdkqfilter |
984263bc MD |
512 | }; |
513 | ||
8a0a8f43 MD |
514 | /* |
515 | * Attach a keyboard. | |
516 | * | |
517 | * NOTE: The usb driver does not detach the default keyboard if it is | |
518 | * unplugged, but calls kbd_attach() when it is plugged back in. | |
519 | */ | |
984263bc MD |
520 | int |
521 | kbd_attach(keyboard_t *kbd) | |
522 | { | |
b13267a5 | 523 | cdev_t dev; |
984263bc MD |
524 | |
525 | if (kbd->kb_index >= keyboards) | |
526 | return EINVAL; | |
527 | if (keyboard[kbd->kb_index] != kbd) | |
528 | return EINVAL; | |
529 | ||
8a0a8f43 MD |
530 | if (kbd->kb_dev == NULL) { |
531 | kbd->kb_dev = make_dev(&kbd_ops, kbd->kb_index, | |
532 | UID_ROOT, GID_WHEEL, 0600, | |
533 | "kbd%r", kbd->kb_index); | |
534 | } | |
535 | dev = kbd->kb_dev; | |
536 | if (dev->si_drv1 == NULL) { | |
537 | dev->si_drv1 = kmalloc(sizeof(struct genkbd_softc), M_DEVBUF, | |
538 | M_WAITOK); | |
539 | } | |
540 | bzero(dev->si_drv1, sizeof(struct genkbd_softc)); | |
984263bc | 541 | |
e3869ec7 | 542 | kprintf("kbd%d at %s%d\n", kbd->kb_index, kbd->kb_name, kbd->kb_unit); |
984263bc MD |
543 | return 0; |
544 | } | |
545 | ||
546 | int | |
547 | kbd_detach(keyboard_t *kbd) | |
548 | { | |
b13267a5 | 549 | cdev_t dev; |
984263bc MD |
550 | |
551 | if (kbd->kb_index >= keyboards) | |
552 | return EINVAL; | |
553 | if (keyboard[kbd->kb_index] != kbd) | |
554 | return EINVAL; | |
555 | ||
8a0a8f43 | 556 | if ((dev = kbd->kb_dev) != NULL) { |
e4c9c0c8 | 557 | if (dev->si_drv1) { |
efda3bd0 | 558 | kfree(dev->si_drv1, M_DEVBUF); |
e4c9c0c8 MD |
559 | dev->si_drv1 = NULL; |
560 | } | |
8a0a8f43 | 561 | kbd->kb_dev = NULL; |
e4c9c0c8 | 562 | } |
cd29885a | 563 | dev_ops_remove_minor(&kbd_ops, kbd->kb_index); |
984263bc MD |
564 | return 0; |
565 | } | |
566 | ||
567 | /* | |
568 | * Generic keyboard cdev driver functions | |
569 | * Keyboard subdrivers may call these functions to implement common | |
570 | * driver functions. | |
571 | */ | |
572 | ||
bcc53404 AH |
573 | static void |
574 | genkbd_putc(genkbd_softc_t sc, char c) | |
575 | { | |
576 | unsigned int p; | |
577 | ||
578 | if (sc->gkb_q_length == KB_QSIZE) | |
579 | return; | |
580 | ||
581 | p = (sc->gkb_q_start + sc->gkb_q_length) % KB_QSIZE; | |
582 | sc->gkb_q[p] = c; | |
583 | sc->gkb_q_length++; | |
584 | } | |
585 | ||
586 | static size_t | |
587 | genkbd_getc(genkbd_softc_t sc, char *buf, size_t len) | |
588 | { | |
589 | ||
590 | /* Determine copy size. */ | |
591 | if (sc->gkb_q_length == 0) | |
592 | return (0); | |
593 | if (len >= sc->gkb_q_length) | |
594 | len = sc->gkb_q_length; | |
595 | if (len >= KB_QSIZE - sc->gkb_q_start) | |
596 | len = KB_QSIZE - sc->gkb_q_start; | |
597 | ||
598 | /* Copy out data and progress offset. */ | |
599 | memcpy(buf, sc->gkb_q + sc->gkb_q_start, len); | |
600 | sc->gkb_q_start = (sc->gkb_q_start + len) % KB_QSIZE; | |
601 | sc->gkb_q_length -= len; | |
602 | ||
603 | return (len); | |
604 | } | |
984263bc MD |
605 | |
606 | static kbd_callback_func_t genkbd_event; | |
607 | ||
608 | static int | |
fef8985e | 609 | genkbdopen(struct dev_open_args *ap) |
984263bc | 610 | { |
b13267a5 | 611 | cdev_t dev = ap->a_head.a_dev; |
984263bc | 612 | keyboard_t *kbd; |
8a0a8f43 | 613 | genkbd_softc_t sc; |
984263bc MD |
614 | int i; |
615 | ||
a38e57d5 | 616 | crit_enter(); |
984263bc MD |
617 | sc = dev->si_drv1; |
618 | kbd = kbd_get_keyboard(KBD_INDEX(dev)); | |
619 | if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { | |
a38e57d5 | 620 | crit_exit(); |
984263bc MD |
621 | return ENXIO; |
622 | } | |
623 | i = kbd_allocate(kbd->kb_name, kbd->kb_unit, sc, | |
624 | genkbd_event, (void *)sc); | |
625 | if (i < 0) { | |
a38e57d5 | 626 | crit_exit(); |
984263bc MD |
627 | return EBUSY; |
628 | } | |
629 | /* assert(i == kbd->kb_index) */ | |
630 | /* assert(kbd == kbd_get_keyboard(i)) */ | |
631 | ||
632 | /* | |
633 | * NOTE: even when we have successfully claimed a keyboard, | |
634 | * the device may still be missing (!KBD_HAS_DEVICE(kbd)). | |
635 | */ | |
636 | ||
bcc53404 | 637 | sc->gkb_q_length = 0; |
a38e57d5 | 638 | crit_exit(); |
984263bc MD |
639 | |
640 | return 0; | |
641 | } | |
642 | ||
643 | static int | |
fef8985e | 644 | genkbdclose(struct dev_close_args *ap) |
984263bc | 645 | { |
b13267a5 | 646 | cdev_t dev = ap->a_head.a_dev; |
984263bc | 647 | keyboard_t *kbd; |
8a0a8f43 | 648 | genkbd_softc_t sc; |
984263bc MD |
649 | |
650 | /* | |
651 | * NOTE: the device may have already become invalid. | |
652 | * kbd == NULL || !KBD_IS_VALID(kbd) | |
653 | */ | |
a38e57d5 | 654 | crit_enter(); |
984263bc MD |
655 | sc = dev->si_drv1; |
656 | kbd = kbd_get_keyboard(KBD_INDEX(dev)); | |
657 | if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { | |
658 | /* XXX: we shall be forgiving and don't report error... */ | |
659 | } else { | |
660 | kbd_release(kbd, (void *)sc); | |
984263bc | 661 | } |
a38e57d5 | 662 | crit_exit(); |
984263bc MD |
663 | return 0; |
664 | } | |
665 | ||
666 | static int | |
fef8985e | 667 | genkbdread(struct dev_read_args *ap) |
984263bc | 668 | { |
b13267a5 | 669 | cdev_t dev = ap->a_head.a_dev; |
fef8985e | 670 | struct uio *uio = ap->a_uio; |
984263bc | 671 | keyboard_t *kbd; |
8a0a8f43 | 672 | genkbd_softc_t sc; |
984263bc MD |
673 | u_char buffer[KB_BUFSIZE]; |
674 | int len; | |
675 | int error; | |
984263bc MD |
676 | |
677 | /* wait for input */ | |
a38e57d5 | 678 | crit_enter(); |
984263bc MD |
679 | sc = dev->si_drv1; |
680 | kbd = kbd_get_keyboard(KBD_INDEX(dev)); | |
681 | if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { | |
a38e57d5 | 682 | crit_exit(); |
984263bc MD |
683 | return ENXIO; |
684 | } | |
bcc53404 AH |
685 | while (sc->gkb_q_length == 0) { |
686 | if (ap->a_ioflag & IO_NDELAY) { /* O_NONBLOCK? */ | |
a38e57d5 | 687 | crit_exit(); |
984263bc MD |
688 | return EWOULDBLOCK; |
689 | } | |
690 | sc->gkb_flags |= KB_ASLEEP; | |
377d4740 | 691 | error = tsleep((caddr_t)sc, PCATCH, "kbdrea", 0); |
984263bc MD |
692 | kbd = kbd_get_keyboard(KBD_INDEX(dev)); |
693 | if ((kbd == NULL) || !KBD_IS_VALID(kbd)) { | |
a38e57d5 | 694 | crit_exit(); |
984263bc MD |
695 | return ENXIO; /* our keyboard has gone... */ |
696 | } | |
697 | if (error) { | |
698 | sc->gkb_flags &= ~KB_ASLEEP; | |
a38e57d5 | 699 | crit_exit(); |
984263bc MD |
700 | return error; |
701 | } | |
702 | } | |
a38e57d5 | 703 | crit_exit(); |
984263bc MD |
704 | |
705 | /* copy as much input as possible */ | |
706 | error = 0; | |
707 | while (uio->uio_resid > 0) { | |
e54488bb | 708 | len = (int)szmin(uio->uio_resid, sizeof(buffer)); |
bcc53404 AH |
709 | len = genkbd_getc(sc, buffer, len); |
710 | if (len <= 0) | |
984263bc | 711 | break; |
e54488bb | 712 | error = uiomove(buffer, (size_t)len, uio); |
984263bc MD |
713 | if (error) |
714 | break; | |
715 | } | |
716 | ||
717 | return error; | |
718 | } | |
719 | ||
720 | static int | |
fef8985e | 721 | genkbdwrite(struct dev_write_args *ap) |
984263bc | 722 | { |
b13267a5 | 723 | cdev_t dev = ap->a_head.a_dev; |
984263bc MD |
724 | keyboard_t *kbd; |
725 | ||
726 | kbd = kbd_get_keyboard(KBD_INDEX(dev)); | |
727 | if ((kbd == NULL) || !KBD_IS_VALID(kbd)) | |
728 | return ENXIO; | |
729 | return ENODEV; | |
730 | } | |
731 | ||
732 | static int | |
fef8985e | 733 | genkbdioctl(struct dev_ioctl_args *ap) |
984263bc | 734 | { |
b13267a5 | 735 | cdev_t dev = ap->a_head.a_dev; |
984263bc MD |
736 | keyboard_t *kbd; |
737 | int error; | |
738 | ||
739 | kbd = kbd_get_keyboard(KBD_INDEX(dev)); | |
740 | if ((kbd == NULL) || !KBD_IS_VALID(kbd)) | |
741 | return ENXIO; | |
bcc53404 | 742 | error = kbd_ioctl(kbd, ap->a_cmd, ap->a_data); |
984263bc MD |
743 | if (error == ENOIOCTL) |
744 | error = ENODEV; | |
745 | return error; | |
746 | } | |
747 | ||
25fef0f3 | 748 | static struct filterops genkbdfiltops = |
4c91dbc9 | 749 | { FILTEROP_ISFD, NULL, genkbdfiltdetach, genkbdfilter }; |
25fef0f3 SG |
750 | |
751 | static int | |
752 | genkbdkqfilter(struct dev_kqfilter_args *ap) | |
753 | { | |
754 | cdev_t dev = ap->a_head.a_dev; | |
755 | struct knote *kn = ap->a_kn; | |
756 | genkbd_softc_t sc; | |
757 | struct klist *klist; | |
758 | ||
759 | ap->a_result = 0; | |
760 | ||
761 | switch (kn->kn_filter) { | |
762 | case EVFILT_READ: | |
763 | kn->kn_fop = &genkbdfiltops; | |
764 | kn->kn_hook = (caddr_t)dev; | |
765 | break; | |
766 | default: | |
b287d649 | 767 | ap->a_result = EOPNOTSUPP; |
25fef0f3 SG |
768 | return (0); |
769 | } | |
770 | ||
25fef0f3 | 771 | sc = dev->si_drv1; |
5b22f1a7 SG |
772 | klist = &sc->gkb_rkq.ki_note; |
773 | knote_insert(klist, kn); | |
25fef0f3 SG |
774 | |
775 | return (0); | |
776 | } | |
777 | ||
778 | static void | |
779 | genkbdfiltdetach(struct knote *kn) | |
780 | { | |
781 | cdev_t dev = (cdev_t)kn->kn_hook; | |
782 | genkbd_softc_t sc; | |
783 | struct klist *klist; | |
784 | ||
25fef0f3 | 785 | sc = dev->si_drv1; |
5b22f1a7 SG |
786 | klist = &sc->gkb_rkq.ki_note; |
787 | knote_remove(klist, kn); | |
25fef0f3 SG |
788 | } |
789 | ||
790 | static int | |
791 | genkbdfilter(struct knote *kn, long hint) | |
792 | { | |
793 | cdev_t dev = (cdev_t)kn->kn_hook; | |
794 | keyboard_t *kbd; | |
795 | genkbd_softc_t sc; | |
796 | int ready = 0; | |
797 | ||
798 | crit_enter(); | |
799 | sc = dev->si_drv1; | |
800 | kbd = kbd_get_keyboard(KBD_INDEX(dev)); | |
801 | if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { | |
802 | kn->kn_flags |= EV_EOF; /* the keyboard has gone */ | |
803 | ready = 1; | |
804 | } else { | |
805 | if (sc->gkb_q_length > 0) | |
806 | ready = 1; | |
807 | } | |
808 | crit_exit(); | |
809 | ||
810 | return (ready); | |
811 | } | |
812 | ||
984263bc MD |
813 | static int |
814 | genkbd_event(keyboard_t *kbd, int event, void *arg) | |
815 | { | |
8a0a8f43 | 816 | genkbd_softc_t sc; |
984263bc MD |
817 | size_t len; |
818 | u_char *cp; | |
819 | int mode; | |
820 | int c; | |
821 | ||
822 | /* assert(KBD_IS_VALID(kbd)) */ | |
8a0a8f43 | 823 | sc = (genkbd_softc_t)arg; |
984263bc MD |
824 | |
825 | switch (event) { | |
826 | case KBDIO_KEYINPUT: | |
827 | break; | |
828 | case KBDIO_UNLOADING: | |
829 | /* the keyboard is going... */ | |
830 | kbd_release(kbd, (void *)sc); | |
831 | if (sc->gkb_flags & KB_ASLEEP) { | |
832 | sc->gkb_flags &= ~KB_ASLEEP; | |
833 | wakeup((caddr_t)sc); | |
834 | } | |
5b22f1a7 | 835 | KNOTE(&sc->gkb_rkq.ki_note, 0); |
984263bc MD |
836 | return 0; |
837 | default: | |
838 | return EINVAL; | |
839 | } | |
840 | ||
841 | /* obtain the current key input mode */ | |
bcc53404 | 842 | if (kbd_ioctl(kbd, KDGKBMODE, (caddr_t)&mode)) |
984263bc MD |
843 | mode = K_XLATE; |
844 | ||
845 | /* read all pending input */ | |
bcc53404 AH |
846 | while (kbd_check_char(kbd)) { |
847 | c = kbd_read_char(kbd, FALSE); | |
984263bc MD |
848 | if (c == NOKEY) |
849 | continue; | |
850 | if (c == ERRKEY) /* XXX: ring bell? */ | |
851 | continue; | |
852 | if (!KBD_IS_BUSY(kbd)) | |
853 | /* the device is not open, discard the input */ | |
854 | continue; | |
855 | ||
856 | /* store the byte as is for K_RAW and K_CODE modes */ | |
857 | if (mode != K_XLATE) { | |
bcc53404 | 858 | genkbd_putc(sc, KEYCHAR(c)); |
984263bc MD |
859 | continue; |
860 | } | |
861 | ||
862 | /* K_XLATE */ | |
863 | if (c & RELKEY) /* key release is ignored */ | |
864 | continue; | |
865 | ||
866 | /* process special keys; most of them are just ignored... */ | |
867 | if (c & SPCLKEY) { | |
868 | switch (KEYCHAR(c)) { | |
869 | default: | |
870 | /* ignore them... */ | |
871 | continue; | |
872 | case BTAB: /* a backtab: ESC [ Z */ | |
bcc53404 AH |
873 | genkbd_putc(sc, 0x1b); |
874 | genkbd_putc(sc, '['); | |
875 | genkbd_putc(sc, 'Z'); | |
984263bc MD |
876 | continue; |
877 | } | |
878 | } | |
879 | ||
880 | /* normal chars, normal chars with the META, function keys */ | |
881 | switch (KEYFLAGS(c)) { | |
882 | case 0: /* a normal char */ | |
bcc53404 | 883 | genkbd_putc(sc, KEYCHAR(c)); |
984263bc MD |
884 | break; |
885 | case MKEY: /* the META flag: prepend ESC */ | |
bcc53404 AH |
886 | genkbd_putc(sc, 0x1b); |
887 | genkbd_putc(sc, KEYCHAR(c)); | |
984263bc MD |
888 | break; |
889 | case FKEY | SPCLKEY: /* a function key, return string */ | |
bcc53404 | 890 | cp = kbd_get_fkeystr(kbd, KEYCHAR(c), &len); |
984263bc MD |
891 | if (cp != NULL) { |
892 | while (len-- > 0) | |
bcc53404 | 893 | genkbd_putc(sc, *cp++); |
984263bc MD |
894 | } |
895 | break; | |
896 | } | |
897 | } | |
898 | ||
899 | /* wake up sleeping/polling processes */ | |
bcc53404 | 900 | if (sc->gkb_q_length > 0) { |
984263bc MD |
901 | if (sc->gkb_flags & KB_ASLEEP) { |
902 | sc->gkb_flags &= ~KB_ASLEEP; | |
903 | wakeup((caddr_t)sc); | |
904 | } | |
5b22f1a7 | 905 | KNOTE(&sc->gkb_rkq.ki_note, 0); |
984263bc MD |
906 | } |
907 | ||
908 | return 0; | |
909 | } | |
910 | ||
911 | #endif /* KBD_INSTALL_CDEV */ | |
912 | ||
913 | /* | |
914 | * Generic low-level keyboard functions | |
915 | * The low-level functions in the keyboard subdriver may use these | |
916 | * functions. | |
917 | */ | |
918 | ||
919 | int | |
920 | genkbd_commonioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) | |
921 | { | |
922 | keyarg_t *keyp; | |
923 | fkeyarg_t *fkeyp; | |
984263bc MD |
924 | int i; |
925 | ||
a38e57d5 | 926 | crit_enter(); |
984263bc MD |
927 | switch (cmd) { |
928 | ||
929 | case KDGKBINFO: /* get keyboard information */ | |
930 | ((keyboard_info_t *)arg)->kb_index = kbd->kb_index; | |
931 | i = imin(strlen(kbd->kb_name) + 1, | |
932 | sizeof(((keyboard_info_t *)arg)->kb_name)); | |
933 | bcopy(kbd->kb_name, ((keyboard_info_t *)arg)->kb_name, i); | |
934 | ((keyboard_info_t *)arg)->kb_unit = kbd->kb_unit; | |
935 | ((keyboard_info_t *)arg)->kb_type = kbd->kb_type; | |
936 | ((keyboard_info_t *)arg)->kb_config = kbd->kb_config; | |
937 | ((keyboard_info_t *)arg)->kb_flags = kbd->kb_flags; | |
938 | break; | |
939 | ||
940 | case KDGKBTYPE: /* get keyboard type */ | |
941 | *(int *)arg = kbd->kb_type; | |
942 | break; | |
943 | ||
944 | case KDGETREPEAT: /* get keyboard repeat rate */ | |
945 | ((int *)arg)[0] = kbd->kb_delay1; | |
946 | ((int *)arg)[1] = kbd->kb_delay2; | |
947 | break; | |
948 | ||
949 | case GIO_KEYMAP: /* get keyboard translation table */ | |
950 | bcopy(kbd->kb_keymap, arg, sizeof(*kbd->kb_keymap)); | |
951 | break; | |
952 | case PIO_KEYMAP: /* set keyboard translation table */ | |
953 | #ifndef KBD_DISABLE_KEYMAP_LOAD | |
954 | bzero(kbd->kb_accentmap, sizeof(*kbd->kb_accentmap)); | |
955 | bcopy(arg, kbd->kb_keymap, sizeof(*kbd->kb_keymap)); | |
956 | break; | |
957 | #else | |
a38e57d5 | 958 | crit_exit(); |
984263bc MD |
959 | return ENODEV; |
960 | #endif | |
961 | ||
962 | case GIO_KEYMAPENT: /* get keyboard translation table entry */ | |
963 | keyp = (keyarg_t *)arg; | |
964 | if (keyp->keynum >= sizeof(kbd->kb_keymap->key) | |
965 | /sizeof(kbd->kb_keymap->key[0])) { | |
a38e57d5 | 966 | crit_exit(); |
984263bc MD |
967 | return EINVAL; |
968 | } | |
969 | bcopy(&kbd->kb_keymap->key[keyp->keynum], &keyp->key, | |
970 | sizeof(keyp->key)); | |
971 | break; | |
972 | case PIO_KEYMAPENT: /* set keyboard translation table entry */ | |
973 | #ifndef KBD_DISABLE_KEYMAP_LOAD | |
974 | keyp = (keyarg_t *)arg; | |
975 | if (keyp->keynum >= sizeof(kbd->kb_keymap->key) | |
976 | /sizeof(kbd->kb_keymap->key[0])) { | |
a38e57d5 | 977 | crit_exit(); |
984263bc MD |
978 | return EINVAL; |
979 | } | |
980 | bcopy(&keyp->key, &kbd->kb_keymap->key[keyp->keynum], | |
981 | sizeof(keyp->key)); | |
982 | break; | |
983 | #else | |
a38e57d5 | 984 | crit_exit(); |
984263bc MD |
985 | return ENODEV; |
986 | #endif | |
987 | ||
988 | case GIO_DEADKEYMAP: /* get accent key translation table */ | |
989 | bcopy(kbd->kb_accentmap, arg, sizeof(*kbd->kb_accentmap)); | |
990 | break; | |
991 | case PIO_DEADKEYMAP: /* set accent key translation table */ | |
992 | #ifndef KBD_DISABLE_KEYMAP_LOAD | |
993 | bcopy(arg, kbd->kb_accentmap, sizeof(*kbd->kb_accentmap)); | |
994 | break; | |
995 | #else | |
a38e57d5 | 996 | crit_exit(); |
984263bc MD |
997 | return ENODEV; |
998 | #endif | |
999 | ||
1000 | case GETFKEY: /* get functionkey string */ | |
1001 | fkeyp = (fkeyarg_t *)arg; | |
1002 | if (fkeyp->keynum >= kbd->kb_fkeytab_size) { | |
a38e57d5 | 1003 | crit_exit(); |
984263bc MD |
1004 | return EINVAL; |
1005 | } | |
1006 | bcopy(kbd->kb_fkeytab[fkeyp->keynum].str, fkeyp->keydef, | |
1007 | kbd->kb_fkeytab[fkeyp->keynum].len); | |
1008 | fkeyp->flen = kbd->kb_fkeytab[fkeyp->keynum].len; | |
1009 | break; | |
1010 | case SETFKEY: /* set functionkey string */ | |
1011 | #ifndef KBD_DISABLE_KEYMAP_LOAD | |
1012 | fkeyp = (fkeyarg_t *)arg; | |
1013 | if (fkeyp->keynum >= kbd->kb_fkeytab_size) { | |
a38e57d5 | 1014 | crit_exit(); |
984263bc MD |
1015 | return EINVAL; |
1016 | } | |
1017 | kbd->kb_fkeytab[fkeyp->keynum].len = imin(fkeyp->flen, MAXFK); | |
1018 | bcopy(fkeyp->keydef, kbd->kb_fkeytab[fkeyp->keynum].str, | |
1019 | kbd->kb_fkeytab[fkeyp->keynum].len); | |
1020 | break; | |
1021 | #else | |
a38e57d5 | 1022 | crit_exit(); |
984263bc MD |
1023 | return ENODEV; |
1024 | #endif | |
1025 | ||
1026 | default: | |
a38e57d5 | 1027 | crit_exit(); |
984263bc MD |
1028 | return ENOIOCTL; |
1029 | } | |
1030 | ||
a38e57d5 | 1031 | crit_exit(); |
984263bc MD |
1032 | return 0; |
1033 | } | |
1034 | ||
1035 | /* get a pointer to the string associated with the given function key */ | |
3d8ba483 SW |
1036 | u_char * |
1037 | genkbd_get_fkeystr(keyboard_t *kbd, int fkey, size_t *len) | |
984263bc MD |
1038 | { |
1039 | if (kbd == NULL) | |
1040 | return NULL; | |
1041 | fkey -= F_FN; | |
1042 | if (fkey > kbd->kb_fkeytab_size) | |
1043 | return NULL; | |
1044 | *len = kbd->kb_fkeytab[fkey].len; | |
1045 | return kbd->kb_fkeytab[fkey].str; | |
1046 | } | |
1047 | ||
1048 | /* diagnostic dump */ | |
3d8ba483 SW |
1049 | static char * |
1050 | get_kbd_type_name(int type) | |
984263bc MD |
1051 | { |
1052 | static struct { | |
1053 | int type; | |
1054 | char *name; | |
1055 | } name_table[] = { | |
1056 | { KB_84, "AT 84" }, | |
1057 | { KB_101, "AT 101/102" }, | |
1058 | { KB_OTHER, "generic" }, | |
1059 | }; | |
1060 | int i; | |
1061 | ||
1062 | for (i = 0; i < sizeof(name_table)/sizeof(name_table[0]); ++i) { | |
1063 | if (type == name_table[i].type) | |
1064 | return name_table[i].name; | |
1065 | } | |
1066 | return "unknown"; | |
1067 | } | |
1068 | ||
1069 | void | |
1070 | genkbd_diag(keyboard_t *kbd, int level) | |
1071 | { | |
1072 | if (level > 0) { | |
e3869ec7 | 1073 | kprintf("kbd%d: %s%d, %s (%d), config:0x%x, flags:0x%x", |
984263bc MD |
1074 | kbd->kb_index, kbd->kb_name, kbd->kb_unit, |
1075 | get_kbd_type_name(kbd->kb_type), kbd->kb_type, | |
1076 | kbd->kb_config, kbd->kb_flags); | |
1077 | if (kbd->kb_io_base > 0) | |
e3869ec7 | 1078 | kprintf(", port:0x%x-0x%x", kbd->kb_io_base, |
984263bc | 1079 | kbd->kb_io_base + kbd->kb_io_size - 1); |
e3869ec7 | 1080 | kprintf("\n"); |
984263bc MD |
1081 | } |
1082 | } | |
1083 | ||
1084 | #define set_lockkey_state(k, s, l) \ | |
1085 | if (!((s) & l ## DOWN)) { \ | |
1086 | int i; \ | |
1087 | (s) |= l ## DOWN; \ | |
1088 | (s) ^= l ## ED; \ | |
1089 | i = (s) & LOCK_MASK; \ | |
bcc53404 | 1090 | kbd_ioctl((k), KDSETLED, (caddr_t)&i); \ |
984263bc MD |
1091 | } |
1092 | ||
1093 | static u_int | |
1094 | save_accent_key(keyboard_t *kbd, u_int key, int *accents) | |
1095 | { | |
1096 | int i; | |
1097 | ||
1098 | /* make an index into the accent map */ | |
1099 | i = key - F_ACC + 1; | |
1100 | if ((i > kbd->kb_accentmap->n_accs) | |
1101 | || (kbd->kb_accentmap->acc[i - 1].accchar == 0)) { | |
1102 | /* the index is out of range or pointing to an empty entry */ | |
1103 | *accents = 0; | |
1104 | return ERRKEY; | |
1105 | } | |
1106 | ||
1107 | /* | |
1108 | * If the same accent key has been hit twice, produce the accent char | |
1109 | * itself. | |
1110 | */ | |
1111 | if (i == *accents) { | |
1112 | key = kbd->kb_accentmap->acc[i - 1].accchar; | |
1113 | *accents = 0; | |
1114 | return key; | |
1115 | } | |
1116 | ||
1117 | /* remember the index and wait for the next key */ | |
1118 | *accents = i; | |
1119 | return NOKEY; | |
1120 | } | |
1121 | ||
1122 | static u_int | |
1123 | make_accent_char(keyboard_t *kbd, u_int ch, int *accents) | |
1124 | { | |
1125 | struct acc_t *acc; | |
1126 | int i; | |
1127 | ||
1128 | acc = &kbd->kb_accentmap->acc[*accents - 1]; | |
1129 | *accents = 0; | |
1130 | ||
1131 | /* | |
1132 | * If the accent key is followed by the space key, | |
1133 | * produce the accent char itself. | |
1134 | */ | |
1135 | if (ch == ' ') | |
1136 | return acc->accchar; | |
1137 | ||
1138 | /* scan the accent map */ | |
1139 | for (i = 0; i < NUM_ACCENTCHARS; ++i) { | |
1140 | if (acc->map[i][0] == 0) /* end of table */ | |
1141 | break; | |
1142 | if (acc->map[i][0] == ch) | |
1143 | return acc->map[i][1]; | |
1144 | } | |
1145 | /* this char cannot be accented... */ | |
1146 | return ERRKEY; | |
1147 | } | |
1148 | ||
1149 | int | |
1150 | genkbd_keyaction(keyboard_t *kbd, int keycode, int up, int *shiftstate, | |
1151 | int *accents) | |
1152 | { | |
1153 | struct keyent_t *key; | |
1154 | int state = *shiftstate; | |
1155 | int action; | |
1156 | int f; | |
1157 | int i; | |
1158 | ||
1159 | i = keycode; | |
1160 | f = state & (AGRS | ALKED); | |
1161 | if ((f == AGRS1) || (f == AGRS2) || (f == ALKED)) | |
1162 | i += ALTGR_OFFSET; | |
1163 | key = &kbd->kb_keymap->key[i]; | |
1164 | i = ((state & SHIFTS) ? 1 : 0) | |
1165 | | ((state & CTLS) ? 2 : 0) | |
1166 | | ((state & ALTS) ? 4 : 0); | |
1167 | if (((key->flgs & FLAG_LOCK_C) && (state & CLKED)) | |
1168 | || ((key->flgs & FLAG_LOCK_N) && (state & NLKED)) ) | |
1169 | i ^= 1; | |
1170 | ||
1171 | if (up) { /* break: key released */ | |
1172 | action = kbd->kb_lastact[keycode]; | |
1173 | kbd->kb_lastact[keycode] = NOP; | |
1174 | switch (action) { | |
1175 | case LSHA: | |
1176 | if (state & SHIFTAON) { | |
1177 | set_lockkey_state(kbd, state, ALK); | |
1178 | state &= ~ALKDOWN; | |
1179 | } | |
1180 | action = LSH; | |
1181 | /* FALL THROUGH */ | |
1182 | case LSH: | |
1183 | state &= ~SHIFTS1; | |
1184 | break; | |
1185 | case RSHA: | |
1186 | if (state & SHIFTAON) { | |
1187 | set_lockkey_state(kbd, state, ALK); | |
1188 | state &= ~ALKDOWN; | |
1189 | } | |
1190 | action = RSH; | |
1191 | /* FALL THROUGH */ | |
1192 | case RSH: | |
1193 | state &= ~SHIFTS2; | |
1194 | break; | |
1195 | case LCTRA: | |
1196 | if (state & SHIFTAON) { | |
1197 | set_lockkey_state(kbd, state, ALK); | |
1198 | state &= ~ALKDOWN; | |
1199 | } | |
1200 | action = LCTR; | |
1201 | /* FALL THROUGH */ | |
1202 | case LCTR: | |
1203 | state &= ~CTLS1; | |
1204 | break; | |
1205 | case RCTRA: | |
1206 | if (state & SHIFTAON) { | |
1207 | set_lockkey_state(kbd, state, ALK); | |
1208 | state &= ~ALKDOWN; | |
1209 | } | |
1210 | action = RCTR; | |
1211 | /* FALL THROUGH */ | |
1212 | case RCTR: | |
1213 | state &= ~CTLS2; | |
1214 | break; | |
1215 | case LALTA: | |
1216 | if (state & SHIFTAON) { | |
1217 | set_lockkey_state(kbd, state, ALK); | |
1218 | state &= ~ALKDOWN; | |
1219 | } | |
1220 | action = LALT; | |
1221 | /* FALL THROUGH */ | |
1222 | case LALT: | |
1223 | state &= ~ALTS1; | |
1224 | break; | |
1225 | case RALTA: | |
1226 | if (state & SHIFTAON) { | |
1227 | set_lockkey_state(kbd, state, ALK); | |
1228 | state &= ~ALKDOWN; | |
1229 | } | |
1230 | action = RALT; | |
1231 | /* FALL THROUGH */ | |
1232 | case RALT: | |
1233 | state &= ~ALTS2; | |
1234 | break; | |
1235 | case ASH: | |
1236 | state &= ~AGRS1; | |
1237 | break; | |
1238 | case META: | |
1239 | state &= ~METAS1; | |
1240 | break; | |
1241 | case NLK: | |
1242 | state &= ~NLKDOWN; | |
1243 | break; | |
1244 | case CLK: | |
984263bc | 1245 | state &= ~CLKDOWN; |
984263bc MD |
1246 | break; |
1247 | case SLK: | |
1248 | state &= ~SLKDOWN; | |
1249 | break; | |
1250 | case ALK: | |
1251 | state &= ~ALKDOWN; | |
1252 | break; | |
1253 | case NOP: | |
1254 | /* release events of regular keys are not reported */ | |
1255 | *shiftstate &= ~SHIFTAON; | |
1256 | return NOKEY; | |
1257 | } | |
1258 | *shiftstate = state & ~SHIFTAON; | |
1259 | return (SPCLKEY | RELKEY | action); | |
1260 | } else { /* make: key pressed */ | |
1261 | action = key->map[i]; | |
1262 | state &= ~SHIFTAON; | |
1263 | if (key->spcl & (0x80 >> i)) { | |
1264 | /* special keys */ | |
1265 | if (kbd->kb_lastact[keycode] == NOP) | |
1266 | kbd->kb_lastact[keycode] = action; | |
1267 | if (kbd->kb_lastact[keycode] != action) | |
1268 | action = NOP; | |
1269 | switch (action) { | |
1270 | /* LOCKING KEYS */ | |
1271 | case NLK: | |
1272 | set_lockkey_state(kbd, state, NLK); | |
1273 | break; | |
1274 | case CLK: | |
984263bc | 1275 | set_lockkey_state(kbd, state, CLK); |
984263bc MD |
1276 | break; |
1277 | case SLK: | |
1278 | set_lockkey_state(kbd, state, SLK); | |
1279 | break; | |
1280 | case ALK: | |
1281 | set_lockkey_state(kbd, state, ALK); | |
1282 | break; | |
1283 | /* NON-LOCKING KEYS */ | |
1284 | case SPSC: case RBT: case SUSP: case STBY: | |
1285 | case DBG: case NEXT: case PREV: case PNC: | |
1286 | case HALT: case PDWN: | |
1287 | *accents = 0; | |
1288 | break; | |
1289 | case BTAB: | |
1290 | *accents = 0; | |
1291 | action |= BKEY; | |
1292 | break; | |
1293 | case LSHA: | |
1294 | state |= SHIFTAON; | |
1295 | action = LSH; | |
1296 | /* FALL THROUGH */ | |
1297 | case LSH: | |
1298 | state |= SHIFTS1; | |
1299 | break; | |
1300 | case RSHA: | |
1301 | state |= SHIFTAON; | |
1302 | action = RSH; | |
1303 | /* FALL THROUGH */ | |
1304 | case RSH: | |
1305 | state |= SHIFTS2; | |
1306 | break; | |
1307 | case LCTRA: | |
1308 | state |= SHIFTAON; | |
1309 | action = LCTR; | |
1310 | /* FALL THROUGH */ | |
1311 | case LCTR: | |
1312 | state |= CTLS1; | |
1313 | break; | |
1314 | case RCTRA: | |
1315 | state |= SHIFTAON; | |
1316 | action = RCTR; | |
1317 | /* FALL THROUGH */ | |
1318 | case RCTR: | |
1319 | state |= CTLS2; | |
1320 | break; | |
1321 | case LALTA: | |
1322 | state |= SHIFTAON; | |
1323 | action = LALT; | |
1324 | /* FALL THROUGH */ | |
1325 | case LALT: | |
1326 | state |= ALTS1; | |
1327 | break; | |
1328 | case RALTA: | |
1329 | state |= SHIFTAON; | |
1330 | action = RALT; | |
1331 | /* FALL THROUGH */ | |
1332 | case RALT: | |
1333 | state |= ALTS2; | |
1334 | break; | |
1335 | case ASH: | |
1336 | state |= AGRS1; | |
1337 | break; | |
1338 | case META: | |
1339 | state |= METAS1; | |
1340 | break; | |
1341 | case NOP: | |
1342 | *shiftstate = state; | |
1343 | return NOKEY; | |
1344 | default: | |
1345 | /* is this an accent (dead) key? */ | |
1346 | *shiftstate = state; | |
1347 | if (action >= F_ACC && action <= L_ACC) { | |
1348 | action = save_accent_key(kbd, action, | |
1349 | accents); | |
1350 | switch (action) { | |
1351 | case NOKEY: | |
1352 | case ERRKEY: | |
1353 | return action; | |
1354 | default: | |
1355 | if (state & METAS) | |
1356 | return (action | MKEY); | |
1357 | else | |
1358 | return action; | |
1359 | } | |
1360 | /* NOT REACHED */ | |
1361 | } | |
1362 | /* other special keys */ | |
1363 | if (*accents > 0) { | |
1364 | *accents = 0; | |
1365 | return ERRKEY; | |
1366 | } | |
1367 | if (action >= F_FN && action <= L_FN) | |
1368 | action |= FKEY; | |
1369 | /* XXX: return fkey string for the FKEY? */ | |
1370 | return (SPCLKEY | action); | |
1371 | } | |
1372 | *shiftstate = state; | |
1373 | return (SPCLKEY | action); | |
1374 | } else { | |
1375 | /* regular keys */ | |
1376 | kbd->kb_lastact[keycode] = NOP; | |
1377 | *shiftstate = state; | |
1378 | if (*accents > 0) { | |
1379 | /* make an accented char */ | |
1380 | action = make_accent_char(kbd, action, accents); | |
1381 | if (action == ERRKEY) | |
1382 | return action; | |
1383 | } | |
1384 | if (state & METAS) | |
1385 | action |= MKEY; | |
1386 | return action; | |
1387 | } | |
1388 | } | |
1389 | /* NOT REACHED */ | |
1390 | } |