FreeBSD/Linux Kernel Cross Reference
sys/pc98/cbus/pckbd.c
1 /*-
2 * Copyright (c) 1999 FreeBSD(98) port team.
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 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * $FreeBSD$
29 */
30
31 #include "opt_compat.h"
32 #include "opt_kbd.h"
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/module.h>
38 #include <sys/bus.h>
39 #include <machine/bus.h>
40 #include <sys/rman.h>
41 #include <sys/kbio.h>
42
43 #include <machine/resource.h>
44
45 #include <dev/kbd/kbdreg.h>
46
47 #include <pc98/cbus/cbus.h>
48 #include <isa/isavar.h>
49
50 #define DRIVER_NAME "pckbd"
51
52 /* device configuration flags */
53 #define KB_CONF_FAIL_IF_NO_KBD (1 << 0) /* don't install if no kbd is found */
54
55 typedef caddr_t KBDC;
56
57 typedef struct pckbd_state {
58 KBDC kbdc; /* keyboard controller */
59 int ks_mode; /* input mode (K_XLATE,K_RAW,K_CODE) */
60 int ks_flags; /* flags */
61 #define COMPOSE (1 << 0)
62 int ks_state; /* shift/lock key state */
63 int ks_accents; /* accent key index (> 0) */
64 u_int ks_composed_char; /* composed char code (> 0) */
65 struct callout ks_timer;
66 } pckbd_state_t;
67
68 static devclass_t pckbd_devclass;
69
70 static int pckbdprobe(device_t dev);
71 static int pckbdattach(device_t dev);
72 static int pckbdresume(device_t dev);
73 static void pckbd_isa_intr(void *arg);
74
75 static device_method_t pckbd_methods[] = {
76 /* Device interface */
77 DEVMETHOD(device_probe, pckbdprobe),
78 DEVMETHOD(device_attach, pckbdattach),
79 DEVMETHOD(device_resume, pckbdresume),
80 { 0, 0 }
81 };
82
83 static driver_t pckbd_driver = {
84 DRIVER_NAME,
85 pckbd_methods,
86 1,
87 };
88
89 DRIVER_MODULE(pckbd, isa, pckbd_driver, pckbd_devclass, 0, 0);
90
91 static bus_addr_t pckbd_iat[] = {0, 2};
92
93 static int pckbd_probe_unit(device_t dev, int port, int irq,
94 int flags);
95 static int pckbd_attach_unit(device_t dev, keyboard_t **kbd,
96 int port, int irq, int flags);
97 static timeout_t pckbd_timeout;
98
99
100 static int
101 pckbdprobe(device_t dev)
102 {
103 struct resource *res;
104 int error, rid;
105
106 /* Check isapnp ids */
107 if (isa_get_vendorid(dev))
108 return (ENXIO);
109
110 device_set_desc(dev, "PC-98 Keyboard");
111
112 rid = 0;
113 res = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, pckbd_iat, 2,
114 RF_ACTIVE);
115 if (res == NULL)
116 return ENXIO;
117 isa_load_resourcev(res, pckbd_iat, 2);
118
119 error = pckbd_probe_unit(dev,
120 isa_get_port(dev),
121 (1 << isa_get_irq(dev)),
122 device_get_flags(dev));
123
124 bus_release_resource(dev, SYS_RES_IOPORT, rid, res);
125
126 return (error);
127 }
128
129 static int
130 pckbdattach(device_t dev)
131 {
132 keyboard_t *kbd;
133 void *ih;
134 struct resource *res;
135 int error, rid;
136
137 rid = 0;
138 res = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, pckbd_iat, 2,
139 RF_ACTIVE);
140 if (res == NULL)
141 return ENXIO;
142 isa_load_resourcev(res, pckbd_iat, 2);
143
144 error = pckbd_attach_unit(dev, &kbd,
145 isa_get_port(dev),
146 (1 << isa_get_irq(dev)),
147 device_get_flags(dev));
148
149 rid = 0;
150 res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
151 if (res == NULL)
152 return ENXIO;
153 bus_setup_intr(dev, res, INTR_TYPE_TTY, NULL, pckbd_isa_intr, kbd, &ih);
154
155 return 0;
156 }
157
158 static int
159 pckbdresume(device_t dev)
160 {
161 keyboard_t *kbd;
162
163 kbd = kbd_get_keyboard(kbd_find_keyboard(DRIVER_NAME,
164 device_get_unit(dev)));
165 if (kbd)
166 kbdd_clear_state(kbd);
167
168 return (0);
169 }
170
171 static void
172 pckbd_isa_intr(void *arg)
173 {
174 keyboard_t *kbd = arg;
175
176 kbdd_intr(kbd, NULL);
177 }
178
179 static int
180 pckbd_probe_unit(device_t dev, int port, int irq, int flags)
181 {
182 keyboard_switch_t *sw;
183 int args[2];
184 int error;
185
186 sw = kbd_get_switch(DRIVER_NAME);
187 if (sw == NULL)
188 return ENXIO;
189
190 args[0] = port;
191 args[1] = irq;
192 error = (*sw->probe)(device_get_unit(dev), args, flags);
193 if (error)
194 return error;
195 return 0;
196 }
197
198 static int
199 pckbd_attach_unit(device_t dev, keyboard_t **kbd, int port, int irq, int flags)
200 {
201 keyboard_switch_t *sw;
202 pckbd_state_t *state;
203 int args[2];
204 int error;
205 int unit;
206
207 sw = kbd_get_switch(DRIVER_NAME);
208 if (sw == NULL)
209 return ENXIO;
210
211 /* reset, initialize and enable the device */
212 unit = device_get_unit(dev);
213 args[0] = port;
214 args[1] = irq;
215 *kbd = NULL;
216 error = (*sw->probe)(unit, args, flags);
217 if (error)
218 return error;
219 error = (*sw->init)(unit, kbd, args, flags);
220 if (error)
221 return error;
222 (*sw->enable)(*kbd);
223
224 #ifdef KBD_INSTALL_CDEV
225 /* attach a virtual keyboard cdev */
226 error = kbd_attach(*kbd);
227 if (error)
228 return error;
229 #endif /* KBD_INSTALL_CDEV */
230
231 /*
232 * This is a kludge to compensate for lost keyboard interrupts.
233 * A similar code used to be in syscons. See below. XXX
234 */
235 state = (pckbd_state_t *)(*kbd)->kb_data;
236 callout_init(&state->ks_timer, 0);
237 pckbd_timeout(*kbd);
238
239 if (bootverbose)
240 (*sw->diag)(*kbd, bootverbose);
241
242 return 0;
243 }
244
245 static void
246 pckbd_timeout(void *arg)
247 {
248 pckbd_state_t *state;
249 keyboard_t *kbd;
250 int s;
251
252 /* The following comments are extracted from syscons.c (1.287) */
253 /*
254 * With release 2.1 of the Xaccel server, the keyboard is left
255 * hanging pretty often. Apparently an interrupt from the
256 * keyboard is lost, and I don't know why (yet).
257 * This ugly hack calls scintr if input is ready for the keyboard
258 * and conveniently hides the problem. XXX
259 */
260 /*
261 * Try removing anything stuck in the keyboard controller; whether
262 * it's a keyboard scan code or mouse data. `scintr()' doesn't
263 * read the mouse data directly, but `kbdio' routines will, as a
264 * side effect.
265 */
266 s = spltty();
267 kbd = (keyboard_t *)arg;
268 if (kbdd_lock(kbd, TRUE)) {
269 /*
270 * We have seen the lock flag is not set. Let's reset
271 * the flag early, otherwise the LED update routine fails
272 * which may want the lock during the interrupt routine.
273 */
274 kbdd_lock(kbd, FALSE);
275 if (kbdd_check_char(kbd))
276 kbdd_intr(kbd, NULL);
277 }
278 splx(s);
279 state = (pckbd_state_t *)kbd->kb_data;
280 callout_reset(&state->ks_timer, hz / 10, pckbd_timeout, arg);
281 }
282
283 /* LOW-LEVEL */
284
285 #include <sys/limits.h>
286
287 #define PC98KBD_DEFAULT 0
288
289 /* keyboard driver declaration */
290 static int pckbd_configure(int flags);
291 static kbd_probe_t pckbd_probe;
292 static kbd_init_t pckbd_init;
293 static kbd_term_t pckbd_term;
294 static kbd_intr_t pckbd_intr;
295 static kbd_test_if_t pckbd_test_if;
296 static kbd_enable_t pckbd_enable;
297 static kbd_disable_t pckbd_disable;
298 static kbd_read_t pckbd_read;
299 static kbd_check_t pckbd_check;
300 static kbd_read_char_t pckbd_read_char;
301 static kbd_check_char_t pckbd_check_char;
302 static kbd_ioctl_t pckbd_ioctl;
303 static kbd_lock_t pckbd_lock;
304 static kbd_clear_state_t pckbd_clear_state;
305 static kbd_get_state_t pckbd_get_state;
306 static kbd_set_state_t pckbd_set_state;
307 static kbd_poll_mode_t pckbd_poll;
308
309 keyboard_switch_t pckbdsw = {
310 pckbd_probe,
311 pckbd_init,
312 pckbd_term,
313 pckbd_intr,
314 pckbd_test_if,
315 pckbd_enable,
316 pckbd_disable,
317 pckbd_read,
318 pckbd_check,
319 pckbd_read_char,
320 pckbd_check_char,
321 pckbd_ioctl,
322 pckbd_lock,
323 pckbd_clear_state,
324 pckbd_get_state,
325 pckbd_set_state,
326 genkbd_get_fkeystr,
327 pckbd_poll,
328 genkbd_diag,
329 };
330
331 KEYBOARD_DRIVER(pckbd, pckbdsw, pckbd_configure);
332
333 struct kbdc_softc {
334 int port; /* base port address */
335 int lock; /* FIXME: XXX not quite a semaphore... */
336 };
337
338 /* local functions */
339 static int probe_keyboard(KBDC kbdc, int flags);
340 static int init_keyboard(KBDC kbdc, int *type, int flags);
341 static KBDC kbdc_open(int port);
342 static int kbdc_lock(KBDC kbdc, int lock);
343 static int kbdc_data_ready(KBDC kbdc);
344 static int read_kbd_data(KBDC kbdc);
345 static int read_kbd_data_no_wait(KBDC kbdc);
346 static int wait_for_kbd_data(struct kbdc_softc *kbdc);
347
348 /* local variables */
349
350 /* the initial key map, accent map and fkey strings */
351 #include <pc98/cbus/pckbdtables.h>
352
353 /* structures for the default keyboard */
354 static keyboard_t default_kbd;
355 static pckbd_state_t default_kbd_state;
356 static keymap_t default_keymap;
357 static accentmap_t default_accentmap;
358 static fkeytab_t default_fkeytab[NUM_FKEYS];
359
360 /*
361 * The back door to the keyboard driver!
362 * This function is called by the console driver, via the kbdio module,
363 * to tickle keyboard drivers when the low-level console is being initialized.
364 * Almost nothing in the kernel has been initialied yet. Try to probe
365 * keyboards if possible.
366 * NOTE: because of the way the low-level conole is initialized, this routine
367 * may be called more than once!!
368 */
369 static int
370 pckbd_configure(int flags)
371 {
372 keyboard_t *kbd;
373 int arg[2];
374 int i;
375
376 /* XXX: a kludge to obtain the device configuration flags */
377 if (resource_int_value(DRIVER_NAME, 0, "flags", &i) == 0) {
378 flags |= i;
379 /* if the driver is disabled, unregister the keyboard if any */
380 if (resource_disabled(DRIVER_NAME, 0)) {
381 i = kbd_find_keyboard(DRIVER_NAME, PC98KBD_DEFAULT);
382 if (i >= 0) {
383 kbd = kbd_get_keyboard(i);
384 kbd_unregister(kbd);
385 kbd->kb_flags &= ~KB_REGISTERED;
386 return 0;
387 }
388 }
389 }
390
391 /* probe the default keyboard */
392 arg[0] = -1;
393 arg[1] = -1;
394 kbd = NULL;
395 if (pckbd_probe(PC98KBD_DEFAULT, arg, flags))
396 return 0;
397 if (pckbd_init(PC98KBD_DEFAULT, &kbd, arg, flags))
398 return 0;
399
400 /* return the number of found keyboards */
401 return 1;
402 }
403
404 /* low-level functions */
405
406 /* detect a keyboard */
407 static int
408 pckbd_probe(int unit, void *arg, int flags)
409 {
410 KBDC kbdc;
411 int *data = (int *)arg;
412
413 if (unit != PC98KBD_DEFAULT)
414 return ENXIO;
415 if (KBD_IS_PROBED(&default_kbd))
416 return 0;
417
418 kbdc = kbdc_open(data[0]);
419 if (kbdc == NULL)
420 return ENXIO;
421 if (probe_keyboard(kbdc, flags)) {
422 if (flags & KB_CONF_FAIL_IF_NO_KBD)
423 return ENXIO;
424 }
425 return 0;
426 }
427
428 /* reset and initialize the device */
429 static int
430 pckbd_init(int unit, keyboard_t **kbdp, void *arg, int flags)
431 {
432 keyboard_t *kbd;
433 pckbd_state_t *state;
434 keymap_t *keymap;
435 accentmap_t *accmap;
436 fkeytab_t *fkeymap;
437 int fkeymap_size;
438 int *data = (int *)arg;
439
440 if (unit != PC98KBD_DEFAULT) /* shouldn't happen */
441 return ENXIO;
442
443 *kbdp = kbd = &default_kbd;
444 state = &default_kbd_state;
445 if (!KBD_IS_PROBED(kbd)) {
446 keymap = &default_keymap;
447 accmap = &default_accentmap;
448 fkeymap = default_fkeytab;
449 fkeymap_size = nitems(default_fkeytab);
450
451 state->kbdc = kbdc_open(data[0]);
452 if (state->kbdc == NULL)
453 return ENXIO;
454 kbd_init_struct(kbd, DRIVER_NAME, KB_OTHER, unit, flags,
455 data[0], IO_KBDSIZE);
456 bcopy(&key_map, keymap, sizeof(key_map));
457 bcopy(&accent_map, accmap, sizeof(accent_map));
458 bcopy(fkey_tab, fkeymap,
459 imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab)));
460 kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size);
461 kbd->kb_data = (void *)state;
462
463 if (probe_keyboard(state->kbdc, flags)) {/* shouldn't happen */
464 if (flags & KB_CONF_FAIL_IF_NO_KBD)
465 return ENXIO;
466 } else {
467 KBD_FOUND_DEVICE(kbd);
468 }
469 pckbd_clear_state(kbd);
470 state->ks_mode = K_XLATE;
471 KBD_PROBE_DONE(kbd);
472 }
473 if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) {
474 if (KBD_HAS_DEVICE(kbd)
475 && init_keyboard(state->kbdc, &kbd->kb_type, kbd->kb_config)
476 && (kbd->kb_config & KB_CONF_FAIL_IF_NO_KBD))
477 return ENXIO;
478 pckbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state);
479 KBD_INIT_DONE(kbd);
480 }
481 if (!KBD_IS_CONFIGURED(kbd)) {
482 if (kbd_register(kbd) < 0)
483 return ENXIO;
484 KBD_CONFIG_DONE(kbd);
485 }
486
487 return 0;
488 }
489
490 /* finish using this keyboard */
491 static int
492 pckbd_term(keyboard_t *kbd)
493 {
494 pckbd_state_t *state = (pckbd_state_t *)kbd->kb_data;
495
496 kbd_unregister(kbd);
497 callout_drain(&state->ks_timer);
498 return 0;
499 }
500
501 /* keyboard interrupt routine */
502 static int
503 pckbd_intr(keyboard_t *kbd, void *arg)
504 {
505 int c;
506
507 if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) {
508 /* let the callback function to process the input */
509 (*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT,
510 kbd->kb_callback.kc_arg);
511 } else {
512 /* read and discard the input; no one is waiting for input */
513 do {
514 c = pckbd_read_char(kbd, FALSE);
515 } while (c != NOKEY);
516 }
517 return 0;
518 }
519
520 /* test the interface to the device */
521 static int
522 pckbd_test_if(keyboard_t *kbd)
523 {
524 return 0;
525 }
526
527 /*
528 * Enable the access to the device; until this function is called,
529 * the client cannot read from the keyboard.
530 */
531 static int
532 pckbd_enable(keyboard_t *kbd)
533 {
534 int s;
535
536 s = spltty();
537 KBD_ACTIVATE(kbd);
538 splx(s);
539 return 0;
540 }
541
542 /* disallow the access to the device */
543 static int
544 pckbd_disable(keyboard_t *kbd)
545 {
546 int s;
547
548 s = spltty();
549 KBD_DEACTIVATE(kbd);
550 splx(s);
551 return 0;
552 }
553
554 /* read one byte from the keyboard if it's allowed */
555 static int
556 pckbd_read(keyboard_t *kbd, int wait)
557 {
558 int c;
559
560 if (wait)
561 c = read_kbd_data(((pckbd_state_t *)kbd->kb_data)->kbdc);
562 else
563 c = read_kbd_data_no_wait(((pckbd_state_t *)kbd->kb_data)->kbdc);
564 if (c != -1)
565 ++kbd->kb_count;
566 return (KBD_IS_ACTIVE(kbd) ? c : -1);
567 }
568
569 /* check if data is waiting */
570 static int
571 pckbd_check(keyboard_t *kbd)
572 {
573 if (!KBD_IS_ACTIVE(kbd))
574 return FALSE;
575 return kbdc_data_ready(((pckbd_state_t *)kbd->kb_data)->kbdc);
576 }
577
578 /* read char from the keyboard */
579 static u_int
580 pckbd_read_char(keyboard_t *kbd, int wait)
581 {
582 pckbd_state_t *state;
583 u_int action;
584 int scancode;
585 int keycode;
586
587 state = (pckbd_state_t *)kbd->kb_data;
588 next_code:
589 /* do we have a composed char to return? */
590 if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) {
591 action = state->ks_composed_char;
592 state->ks_composed_char = 0;
593 if (action > UCHAR_MAX)
594 return ERRKEY;
595 return action;
596 }
597
598 /* see if there is something in the keyboard port */
599 if (wait) {
600 do {
601 scancode = read_kbd_data(state->kbdc);
602 } while (scancode == -1);
603 } else {
604 scancode = read_kbd_data_no_wait(state->kbdc);
605 if (scancode == -1)
606 return NOKEY;
607 }
608 ++kbd->kb_count;
609
610 #if 0
611 printf("pckbd_read_char(): scancode:0x%x\n", scancode);
612 #endif
613
614 /* return the byte as is for the K_RAW mode */
615 if (state->ks_mode == K_RAW)
616 return scancode;
617
618 /* translate the scan code into a keycode */
619 keycode = scancode & 0x7F;
620 switch(scancode) {
621 case 0xF3: /* GRPH (compose key) released */
622 if (state->ks_flags & COMPOSE) {
623 state->ks_flags &= ~COMPOSE;
624 if (state->ks_composed_char > UCHAR_MAX)
625 state->ks_composed_char = 0;
626 }
627 break;
628 case 0x73: /* GRPH (compose key) pressed */
629 if (!(state->ks_flags & COMPOSE)) {
630 state->ks_flags |= COMPOSE;
631 state->ks_composed_char = 0;
632 }
633 break;
634 }
635
636 /* return the key code in the K_CODE mode */
637 if (state->ks_mode == K_CODE)
638 return (keycode | (scancode & 0x80));
639
640 /* compose a character code */
641 if (state->ks_flags & COMPOSE) {
642 switch (scancode) {
643 /* key pressed, process it */
644 case 0x42: case 0x43: case 0x44: /* keypad 7,8,9 */
645 state->ks_composed_char *= 10;
646 state->ks_composed_char += scancode - 0x3B;
647 if (state->ks_composed_char > UCHAR_MAX)
648 return ERRKEY;
649 goto next_code;
650 case 0x46: case 0x47: case 0x48: /* keypad 4,5,6 */
651 state->ks_composed_char *= 10;
652 state->ks_composed_char += scancode - 0x42;
653 if (state->ks_composed_char > UCHAR_MAX)
654 return ERRKEY;
655 goto next_code;
656 case 0x4A: case 0x4B: case 0x4C: /* keypad 1,2,3 */
657 state->ks_composed_char *= 10;
658 state->ks_composed_char += scancode - 0x49;
659 if (state->ks_composed_char > UCHAR_MAX)
660 return ERRKEY;
661 goto next_code;
662 case 0x4E: /* keypad 0 */
663 state->ks_composed_char *= 10;
664 if (state->ks_composed_char > UCHAR_MAX)
665 return ERRKEY;
666 goto next_code;
667
668 /* key released, no interest here */
669 case 0xC2: case 0xC3: case 0xC4: /* keypad 7,8,9 */
670 case 0xC6: case 0xC7: case 0xC8: /* keypad 4,5,6 */
671 case 0xCA: case 0xCB: case 0xCC: /* keypad 1,2,3 */
672 case 0xCE: /* keypad 0 */
673 goto next_code;
674
675 case 0x73: /* GRPH key */
676 break;
677
678 default:
679 if (state->ks_composed_char > 0) {
680 state->ks_flags &= ~COMPOSE;
681 state->ks_composed_char = 0;
682 return ERRKEY;
683 }
684 break;
685 }
686 }
687
688 /* keycode to key action */
689 action = genkbd_keyaction(kbd, keycode, scancode & 0x80,
690 &state->ks_state, &state->ks_accents);
691 if (action == NOKEY)
692 goto next_code;
693 else
694 return action;
695 }
696
697 /* check if char is waiting */
698 static int
699 pckbd_check_char(keyboard_t *kbd)
700 {
701 pckbd_state_t *state;
702
703 if (!KBD_IS_ACTIVE(kbd))
704 return FALSE;
705 state = (pckbd_state_t *)kbd->kb_data;
706 if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0))
707 return TRUE;
708 return kbdc_data_ready(state->kbdc);
709 }
710
711 /* some useful control functions */
712 static int
713 pckbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
714 {
715 pckbd_state_t *state = kbd->kb_data;
716 int s;
717 int i;
718 #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
719 defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
720 int ival;
721 #endif
722
723 s = spltty();
724 switch (cmd) {
725
726 case KDGKBMODE: /* get keyboard mode */
727 *(int *)arg = state->ks_mode;
728 break;
729 #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
730 defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
731 case _IO('K', 7):
732 ival = IOCPARM_IVAL(arg);
733 arg = (caddr_t)&ival;
734 /* FALLTHROUGH */
735 #endif
736 case KDSKBMODE: /* set keyboard mode */
737 switch (*(int *)arg) {
738 case K_XLATE:
739 if (state->ks_mode != K_XLATE) {
740 /* make lock key state and LED state match */
741 state->ks_state &= ~LOCK_MASK;
742 state->ks_state |= KBD_LED_VAL(kbd);
743 }
744 /* FALLTHROUGH */
745 case K_RAW:
746 case K_CODE:
747 if (state->ks_mode != *(int *)arg) {
748 pckbd_clear_state(kbd);
749 state->ks_mode = *(int *)arg;
750 }
751 break;
752 default:
753 splx(s);
754 return EINVAL;
755 }
756 break;
757
758 case KDGETLED: /* get keyboard LED */
759 *(int *)arg = KBD_LED_VAL(kbd);
760 break;
761 #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
762 defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
763 case _IO('K', 66):
764 ival = IOCPARM_IVAL(arg);
765 arg = (caddr_t)&ival;
766 /* FALLTHROUGH */
767 #endif
768 case KDSETLED: /* set keyboard LED */
769 /* NOTE: lock key state in ks_state won't be changed */
770 if (*(int *)arg & ~LOCK_MASK) {
771 splx(s);
772 return EINVAL;
773 }
774 i = *(int *)arg;
775 /* replace CAPS LED with ALTGR LED for ALTGR keyboards */
776 if (kbd->kb_keymap->n_keys > ALTGR_OFFSET) {
777 if (i & ALKED)
778 i |= CLKED;
779 else
780 i &= ~CLKED;
781 }
782 KBD_LED_VAL(kbd) = *(int *)arg;
783 break;
784
785 case KDGKBSTATE: /* get lock key state */
786 *(int *)arg = state->ks_state & LOCK_MASK;
787 break;
788 #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
789 defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
790 case _IO('K', 20):
791 ival = IOCPARM_IVAL(arg);
792 arg = (caddr_t)&ival;
793 /* FALLTHROUGH */
794 #endif
795 case KDSKBSTATE: /* set lock key state */
796 if (*(int *)arg & ~LOCK_MASK) {
797 splx(s);
798 return EINVAL;
799 }
800 state->ks_state &= ~LOCK_MASK;
801 state->ks_state |= *(int *)arg;
802 splx(s);
803 /* set LEDs and quit */
804 return pckbd_ioctl(kbd, KDSETLED, arg);
805
806 case KDSETRAD: /* set keyboard repeat rate (old interface)*/
807 break;
808 case KDSETREPEAT: /* set keyboard repeat rate (new interface) */
809 break;
810
811 case PIO_KEYMAP: /* set keyboard translation table */
812 case OPIO_KEYMAP: /* set keyboard translation table (compat) */
813 case PIO_KEYMAPENT: /* set keyboard translation table entry */
814 case PIO_DEADKEYMAP: /* set accent key translation table */
815 state->ks_accents = 0;
816 /* FALLTHROUGH */
817 default:
818 splx(s);
819 return genkbd_commonioctl(kbd, cmd, arg);
820 }
821
822 splx(s);
823 return 0;
824 }
825
826 /* lock the access to the keyboard */
827 static int
828 pckbd_lock(keyboard_t *kbd, int lock)
829 {
830 return kbdc_lock(((pckbd_state_t *)kbd->kb_data)->kbdc, lock);
831 }
832
833 /* clear the internal state of the keyboard */
834 static void
835 pckbd_clear_state(keyboard_t *kbd)
836 {
837 pckbd_state_t *state;
838
839 state = (pckbd_state_t *)kbd->kb_data;
840 state->ks_flags = 0;
841 state->ks_state &= LOCK_MASK; /* preserve locking key state */
842 state->ks_accents = 0;
843 state->ks_composed_char = 0;
844 }
845
846 /* save the internal state */
847 static int
848 pckbd_get_state(keyboard_t *kbd, void *buf, size_t len)
849 {
850 if (len == 0)
851 return sizeof(pckbd_state_t);
852 if (len < sizeof(pckbd_state_t))
853 return -1;
854 bcopy(kbd->kb_data, buf, sizeof(pckbd_state_t));
855 return 0;
856 }
857
858 /* set the internal state */
859 static int
860 pckbd_set_state(keyboard_t *kbd, void *buf, size_t len)
861 {
862 if (len < sizeof(pckbd_state_t))
863 return ENOMEM;
864 if (((pckbd_state_t *)kbd->kb_data)->kbdc
865 != ((pckbd_state_t *)buf)->kbdc)
866 return ENOMEM;
867 bcopy(buf, kbd->kb_data, sizeof(pckbd_state_t));
868 return 0;
869 }
870
871 /* set polling mode */
872 static int
873 pckbd_poll(keyboard_t *kbd, int on)
874 {
875 return 0;
876 }
877
878 /* local functions */
879
880 static int
881 probe_keyboard(KBDC kbdc, int flags)
882 {
883 return 0;
884 }
885
886 static int
887 init_keyboard(KBDC kbdc, int *type, int flags)
888 {
889 *type = KB_OTHER;
890 return 0;
891 }
892
893 /* keyboard I/O routines */
894
895 /* retry count */
896 #ifndef KBD_MAXRETRY
897 #define KBD_MAXRETRY 3
898 #endif
899
900 /* timing parameters */
901 #ifndef KBD_RESETDELAY
902 #define KBD_RESETDELAY 200 /* wait 200msec after kbd/mouse reset */
903 #endif
904 #ifndef KBD_MAXWAIT
905 #define KBD_MAXWAIT 5 /* wait 5 times at most after reset */
906 #endif
907
908 /* I/O recovery time */
909 #define KBDC_DELAYTIME 37
910 #define KBDD_DELAYTIME 37
911
912 /* I/O ports */
913 #define KBD_STATUS_PORT 2 /* status port, read */
914 #define KBD_DATA_PORT 0 /* data port, read */
915
916 /* status bits (KBD_STATUS_PORT) */
917 #define KBDS_BUFFER_FULL 0x0002
918
919 /* macros */
920
921 #define kbdcp(p) ((struct kbdc_softc *)(p))
922
923 /* local variables */
924
925 static struct kbdc_softc kbdc_softc[1] = { { 0 }, };
926
927 /* associate a port number with a KBDC */
928
929 static KBDC
930 kbdc_open(int port)
931 {
932 if (port <= 0)
933 port = IO_KBD;
934
935 /* PC-98 has only one keyboard I/F */
936 kbdc_softc[0].port = port;
937 kbdc_softc[0].lock = FALSE;
938 return (KBDC)&kbdc_softc[0];
939 }
940
941 /* set/reset polling lock */
942 static int
943 kbdc_lock(KBDC p, int lock)
944 {
945 int prevlock;
946
947 prevlock = kbdcp(p)->lock;
948 kbdcp(p)->lock = lock;
949
950 return (prevlock != lock);
951 }
952
953 /* check if any data is waiting to be processed */
954 static int
955 kbdc_data_ready(KBDC p)
956 {
957 return (inb(kbdcp(p)->port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL);
958 }
959
960 /* wait for data from the keyboard */
961 static int
962 wait_for_kbd_data(struct kbdc_softc *kbdc)
963 {
964 /* CPU will stay inside the loop for 200msec at most */
965 int retry = 10000;
966 int port = kbdc->port;
967
968 while (!(inb(port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL)) {
969 DELAY(KBDD_DELAYTIME);
970 DELAY(KBDC_DELAYTIME);
971 if (--retry < 0)
972 return 0;
973 }
974 DELAY(KBDD_DELAYTIME);
975 return 1;
976 }
977
978 /* read one byte from the keyboard */
979 static int
980 read_kbd_data(KBDC p)
981 {
982 if (!wait_for_kbd_data(kbdcp(p)))
983 return -1; /* timeout */
984 DELAY(KBDC_DELAYTIME);
985 return inb(kbdcp(p)->port + KBD_DATA_PORT);
986 }
987
988 /* read one byte from the keyboard, but return immediately if
989 * no data is waiting
990 */
991 static int
992 read_kbd_data_no_wait(KBDC p)
993 {
994 if (inb(kbdcp(p)->port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL) {
995 DELAY(KBDD_DELAYTIME);
996 return inb(kbdcp(p)->port + KBD_DATA_PORT);
997 }
998 return -1; /* no data */
999 }
Cache object: cbeee0af4cc5a2b40970ff2d33862fa5
|