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