]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/pc98/cbus/pckbd.c
Merge xz 5.2.0.
[FreeBSD/FreeBSD.git] / 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 =
450                         sizeof(default_fkeytab)/sizeof(default_fkeytab[0]);
451
452                 state->kbdc = kbdc_open(data[0]);
453                 if (state->kbdc == NULL)
454                         return ENXIO;
455                 kbd_init_struct(kbd, DRIVER_NAME, KB_OTHER, unit, flags,
456                                 data[0], IO_KBDSIZE);
457                 bcopy(&key_map, keymap, sizeof(key_map));
458                 bcopy(&accent_map, accmap, sizeof(accent_map));
459                 bcopy(fkey_tab, fkeymap,
460                       imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab)));
461                 kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size);
462                 kbd->kb_data = (void *)state;
463
464                 if (probe_keyboard(state->kbdc, flags)) {/* shouldn't happen */
465                         if (flags & KB_CONF_FAIL_IF_NO_KBD)
466                                 return ENXIO;
467                 } else {
468                         KBD_FOUND_DEVICE(kbd);
469                 }
470                 pckbd_clear_state(kbd);
471                 state->ks_mode = K_XLATE;
472                 KBD_PROBE_DONE(kbd);
473         }
474         if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) {
475                 if (KBD_HAS_DEVICE(kbd)
476                     && init_keyboard(state->kbdc, &kbd->kb_type, kbd->kb_config)
477                     && (kbd->kb_config & KB_CONF_FAIL_IF_NO_KBD))
478                         return ENXIO;
479                 pckbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state);
480                 KBD_INIT_DONE(kbd);
481         }
482         if (!KBD_IS_CONFIGURED(kbd)) {
483                 if (kbd_register(kbd) < 0)
484                         return ENXIO;
485                 KBD_CONFIG_DONE(kbd);
486         }
487
488         return 0;
489 }
490
491 /* finish using this keyboard */
492 static int
493 pckbd_term(keyboard_t *kbd)
494 {
495         pckbd_state_t *state = (pckbd_state_t *)kbd->kb_data;
496
497         kbd_unregister(kbd);
498         callout_drain(&state->ks_timer);
499         return 0;
500 }
501
502 /* keyboard interrupt routine */
503 static int
504 pckbd_intr(keyboard_t *kbd, void *arg)
505 {
506         int c;
507
508         if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) {
509                 /* let the callback function to process the input */
510                 (*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT,
511                                             kbd->kb_callback.kc_arg);
512         } else {
513                 /* read and discard the input; no one is waiting for input */
514                 do {
515                         c = pckbd_read_char(kbd, FALSE);
516                 } while (c != NOKEY);
517         }
518         return 0;
519 }
520
521 /* test the interface to the device */
522 static int
523 pckbd_test_if(keyboard_t *kbd)
524 {
525         return 0;
526 }
527
528 /* 
529  * Enable the access to the device; until this function is called,
530  * the client cannot read from the keyboard.
531  */
532 static int
533 pckbd_enable(keyboard_t *kbd)
534 {
535         int s;
536
537         s = spltty();
538         KBD_ACTIVATE(kbd);
539         splx(s);
540         return 0;
541 }
542
543 /* disallow the access to the device */
544 static int
545 pckbd_disable(keyboard_t *kbd)
546 {
547         int s;
548
549         s = spltty();
550         KBD_DEACTIVATE(kbd);
551         splx(s);
552         return 0;
553 }
554
555 /* read one byte from the keyboard if it's allowed */
556 static int
557 pckbd_read(keyboard_t *kbd, int wait)
558 {
559         int c;
560
561         if (wait)
562                 c = read_kbd_data(((pckbd_state_t *)kbd->kb_data)->kbdc);
563         else
564                 c = read_kbd_data_no_wait(((pckbd_state_t *)kbd->kb_data)->kbdc);
565         if (c != -1)
566                 ++kbd->kb_count;
567         return (KBD_IS_ACTIVE(kbd) ? c : -1);
568 }
569
570 /* check if data is waiting */
571 static int
572 pckbd_check(keyboard_t *kbd)
573 {
574         if (!KBD_IS_ACTIVE(kbd))
575                 return FALSE;
576         return kbdc_data_ready(((pckbd_state_t *)kbd->kb_data)->kbdc);
577 }
578
579 /* read char from the keyboard */
580 static u_int
581 pckbd_read_char(keyboard_t *kbd, int wait)
582 {
583         pckbd_state_t *state;
584         u_int action;
585         int scancode;
586         int keycode;
587
588         state = (pckbd_state_t *)kbd->kb_data;
589 next_code:
590         /* do we have a composed char to return? */
591         if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) {
592                 action = state->ks_composed_char;
593                 state->ks_composed_char = 0;
594                 if (action > UCHAR_MAX)
595                         return ERRKEY;
596                 return action;
597         }
598
599         /* see if there is something in the keyboard port */
600         if (wait) {
601                 do {
602                         scancode = read_kbd_data(state->kbdc);
603                 } while (scancode == -1);
604         } else {
605                 scancode = read_kbd_data_no_wait(state->kbdc);
606                 if (scancode == -1)
607                         return NOKEY;
608         }
609         ++kbd->kb_count;
610
611 #if 0
612         printf("pckbd_read_char(): scancode:0x%x\n", scancode);
613 #endif
614
615         /* return the byte as is for the K_RAW mode */
616         if (state->ks_mode == K_RAW)
617                 return scancode;
618
619         /* translate the scan code into a keycode */
620         keycode = scancode & 0x7F;
621         switch(scancode) {
622         case 0xF3:      /* GRPH (compose key) released */
623                 if (state->ks_flags & COMPOSE) {
624                         state->ks_flags &= ~COMPOSE;
625                         if (state->ks_composed_char > UCHAR_MAX)
626                                 state->ks_composed_char = 0;
627                 }
628                 break;
629         case 0x73:      /* GRPH (compose key) pressed */
630                 if (!(state->ks_flags & COMPOSE)) {
631                         state->ks_flags |= COMPOSE;
632                         state->ks_composed_char = 0;
633                 }
634                 break;
635         }
636
637         /* return the key code in the K_CODE mode */
638         if (state->ks_mode == K_CODE)
639                 return (keycode | (scancode & 0x80));
640
641         /* compose a character code */
642         if (state->ks_flags & COMPOSE) {
643                 switch (scancode) {
644                 /* key pressed, process it */
645                 case 0x42: case 0x43: case 0x44:        /* keypad 7,8,9 */
646                         state->ks_composed_char *= 10;
647                         state->ks_composed_char += scancode - 0x3B;
648                         if (state->ks_composed_char > UCHAR_MAX)
649                                 return ERRKEY;
650                         goto next_code;
651                 case 0x46: case 0x47: case 0x48:        /* keypad 4,5,6 */
652                         state->ks_composed_char *= 10;
653                         state->ks_composed_char += scancode - 0x42;
654                         if (state->ks_composed_char > UCHAR_MAX)
655                                 return ERRKEY;
656                         goto next_code;
657                 case 0x4A: case 0x4B: case 0x4C:        /* keypad 1,2,3 */
658                         state->ks_composed_char *= 10;
659                         state->ks_composed_char += scancode - 0x49;
660                         if (state->ks_composed_char > UCHAR_MAX)
661                                 return ERRKEY;
662                         goto next_code;
663                 case 0x4E:                              /* keypad 0 */
664                         state->ks_composed_char *= 10;
665                         if (state->ks_composed_char > UCHAR_MAX)
666                                 return ERRKEY;
667                         goto next_code;
668
669                 /* key released, no interest here */
670                 case 0xC2: case 0xC3: case 0xC4:        /* keypad 7,8,9 */
671                 case 0xC6: case 0xC7: case 0xC8:        /* keypad 4,5,6 */
672                 case 0xCA: case 0xCB: case 0xCC:        /* keypad 1,2,3 */
673                 case 0xCE:                              /* keypad 0 */
674                         goto next_code;
675
676                 case 0x73:                              /* GRPH key */
677                         break;
678
679                 default:
680                         if (state->ks_composed_char > 0) {
681                                 state->ks_flags &= ~COMPOSE;
682                                 state->ks_composed_char = 0;
683                                 return ERRKEY;
684                         }
685                         break;
686                 }
687         }
688
689         /* keycode to key action */
690         action = genkbd_keyaction(kbd, keycode, scancode & 0x80,
691                                   &state->ks_state, &state->ks_accents);
692         if (action == NOKEY)
693                 goto next_code;
694         else
695                 return action;
696 }
697
698 /* check if char is waiting */
699 static int
700 pckbd_check_char(keyboard_t *kbd)
701 {
702         pckbd_state_t *state;
703
704         if (!KBD_IS_ACTIVE(kbd))
705                 return FALSE;
706         state = (pckbd_state_t *)kbd->kb_data;
707         if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0))
708                 return TRUE;
709         return kbdc_data_ready(state->kbdc);
710 }
711
712 /* some useful control functions */
713 static int
714 pckbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
715 {
716         pckbd_state_t *state = kbd->kb_data;
717         int s;
718         int i;
719 #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
720     defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
721         int ival;
722 #endif
723
724         s = spltty();
725         switch (cmd) {
726
727         case KDGKBMODE:         /* get keyboard mode */
728                 *(int *)arg = state->ks_mode;
729                 break;
730 #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
731     defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
732         case _IO('K', 7):
733                 ival = IOCPARM_IVAL(arg);
734                 arg = (caddr_t)&ival;
735                 /* FALLTHROUGH */
736 #endif
737         case KDSKBMODE:         /* set keyboard mode */
738                 switch (*(int *)arg) {
739                 case K_XLATE:
740                         if (state->ks_mode != K_XLATE) {
741                                 /* make lock key state and LED state match */
742                                 state->ks_state &= ~LOCK_MASK;
743                                 state->ks_state |= KBD_LED_VAL(kbd);
744                         }
745                         /* FALLTHROUGH */
746                 case K_RAW:
747                 case K_CODE:
748                         if (state->ks_mode != *(int *)arg) {
749                                 pckbd_clear_state(kbd);
750                                 state->ks_mode = *(int *)arg;
751                         }
752                         break;
753                 default:
754                         splx(s);
755                         return EINVAL;
756                 }
757                 break;
758
759         case KDGETLED:          /* get keyboard LED */
760                 *(int *)arg = KBD_LED_VAL(kbd);
761                 break;
762 #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
763     defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
764         case _IO('K', 66):
765                 ival = IOCPARM_IVAL(arg);
766                 arg = (caddr_t)&ival;
767                 /* FALLTHROUGH */
768 #endif
769         case KDSETLED:          /* set keyboard LED */
770                 /* NOTE: lock key state in ks_state won't be changed */
771                 if (*(int *)arg & ~LOCK_MASK) {
772                         splx(s);
773                         return EINVAL;
774                 }
775                 i = *(int *)arg;
776                 /* replace CAPS LED with ALTGR LED for ALTGR keyboards */
777                 if (kbd->kb_keymap->n_keys > ALTGR_OFFSET) {
778                         if (i & ALKED)
779                                 i |= CLKED;
780                         else
781                                 i &= ~CLKED;
782                 }
783                 KBD_LED_VAL(kbd) = *(int *)arg;
784                 break;
785
786         case KDGKBSTATE:        /* get lock key state */
787                 *(int *)arg = state->ks_state & LOCK_MASK;
788                 break;
789 #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
790     defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
791         case _IO('K', 20):
792                 ival = IOCPARM_IVAL(arg);
793                 arg = (caddr_t)&ival;
794                 /* FALLTHROUGH */
795 #endif
796         case KDSKBSTATE:        /* set lock key state */
797                 if (*(int *)arg & ~LOCK_MASK) {
798                         splx(s);
799                         return EINVAL;
800                 }
801                 state->ks_state &= ~LOCK_MASK;
802                 state->ks_state |= *(int *)arg;
803                 splx(s);
804                 /* set LEDs and quit */
805                 return pckbd_ioctl(kbd, KDSETLED, arg);
806
807         case KDSETRAD:          /* set keyboard repeat rate (old interface)*/
808                 break;
809         case KDSETREPEAT:       /* set keyboard repeat rate (new interface) */
810                 break;
811
812         case PIO_KEYMAP:        /* set keyboard translation table */
813         case OPIO_KEYMAP:       /* set keyboard translation table (compat) */
814         case PIO_KEYMAPENT:     /* set keyboard translation table entry */
815         case PIO_DEADKEYMAP:    /* set accent key translation table */
816                 state->ks_accents = 0;
817                 /* FALLTHROUGH */
818         default:
819                 splx(s);
820                 return genkbd_commonioctl(kbd, cmd, arg);
821         }
822
823         splx(s);
824         return 0;
825 }
826
827 /* lock the access to the keyboard */
828 static int
829 pckbd_lock(keyboard_t *kbd, int lock)
830 {
831         return kbdc_lock(((pckbd_state_t *)kbd->kb_data)->kbdc, lock);
832 }
833
834 /* clear the internal state of the keyboard */
835 static void
836 pckbd_clear_state(keyboard_t *kbd)
837 {
838         pckbd_state_t *state;
839
840         state = (pckbd_state_t *)kbd->kb_data;
841         state->ks_flags = 0;
842         state->ks_state &= LOCK_MASK;   /* preserve locking key state */
843         state->ks_accents = 0;
844         state->ks_composed_char = 0;
845 }
846
847 /* save the internal state */
848 static int
849 pckbd_get_state(keyboard_t *kbd, void *buf, size_t len)
850 {
851         if (len == 0)
852                 return sizeof(pckbd_state_t);
853         if (len < sizeof(pckbd_state_t))
854                 return -1;
855         bcopy(kbd->kb_data, buf, sizeof(pckbd_state_t));
856         return 0;
857 }
858
859 /* set the internal state */
860 static int
861 pckbd_set_state(keyboard_t *kbd, void *buf, size_t len)
862 {
863         if (len < sizeof(pckbd_state_t))
864                 return ENOMEM;
865         if (((pckbd_state_t *)kbd->kb_data)->kbdc
866                 != ((pckbd_state_t *)buf)->kbdc)
867                 return ENOMEM;
868         bcopy(buf, kbd->kb_data, sizeof(pckbd_state_t));
869         return 0;
870 }
871
872 /* set polling mode */
873 static int
874 pckbd_poll(keyboard_t *kbd, int on)
875 {
876         return 0;
877 }
878
879 /* local functions */
880
881 static int
882 probe_keyboard(KBDC kbdc, int flags)
883 {
884         return 0;
885 }
886
887 static int
888 init_keyboard(KBDC kbdc, int *type, int flags)
889 {
890         *type = KB_OTHER;
891         return 0;
892 }
893
894 /* keyboard I/O routines */
895
896 /* retry count */
897 #ifndef KBD_MAXRETRY
898 #define KBD_MAXRETRY    3
899 #endif
900
901 /* timing parameters */
902 #ifndef KBD_RESETDELAY
903 #define KBD_RESETDELAY  200     /* wait 200msec after kbd/mouse reset */
904 #endif
905 #ifndef KBD_MAXWAIT
906 #define KBD_MAXWAIT     5       /* wait 5 times at most after reset */
907 #endif
908
909 /* I/O recovery time */
910 #define KBDC_DELAYTIME  37
911 #define KBDD_DELAYTIME  37
912
913 /* I/O ports */
914 #define KBD_STATUS_PORT         2       /* status port, read */
915 #define KBD_DATA_PORT           0       /* data port, read */
916
917 /* status bits (KBD_STATUS_PORT) */
918 #define KBDS_BUFFER_FULL        0x0002
919
920 /* macros */
921
922 #define kbdcp(p)                ((struct kbdc_softc *)(p))
923
924 /* local variables */
925
926 static struct kbdc_softc kbdc_softc[1] = { { 0 }, };
927
928 /* associate a port number with a KBDC */
929
930 static KBDC
931 kbdc_open(int port)
932 {
933         if (port <= 0)
934                 port = IO_KBD;
935
936         /* PC-98 has only one keyboard I/F */
937         kbdc_softc[0].port = port;
938         kbdc_softc[0].lock = FALSE;
939         return (KBDC)&kbdc_softc[0];
940 }
941
942 /* set/reset polling lock */
943 static int 
944 kbdc_lock(KBDC p, int lock)
945 {
946     int prevlock;
947
948     prevlock = kbdcp(p)->lock;
949     kbdcp(p)->lock = lock;
950
951     return (prevlock != lock);
952 }
953
954 /* check if any data is waiting to be processed */
955 static int
956 kbdc_data_ready(KBDC p)
957 {
958         return (inb(kbdcp(p)->port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL);
959 }
960
961 /* wait for data from the keyboard */
962 static int
963 wait_for_kbd_data(struct kbdc_softc *kbdc)
964 {
965     /* CPU will stay inside the loop for 200msec at most */
966     int retry = 10000;
967     int port = kbdc->port;
968
969     while (!(inb(port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL)) {
970         DELAY(KBDD_DELAYTIME);
971         DELAY(KBDC_DELAYTIME);
972         if (--retry < 0)
973             return 0;
974     }
975     DELAY(KBDD_DELAYTIME);
976     return 1;
977 }
978
979 /* read one byte from the keyboard */
980 static int
981 read_kbd_data(KBDC p)
982 {
983     if (!wait_for_kbd_data(kbdcp(p)))
984         return -1;              /* timeout */
985     DELAY(KBDC_DELAYTIME);
986     return inb(kbdcp(p)->port + KBD_DATA_PORT);
987 }
988
989 /* read one byte from the keyboard, but return immediately if 
990  * no data is waiting
991  */
992 static int
993 read_kbd_data_no_wait(KBDC p)
994 {
995     if (inb(kbdcp(p)->port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL) {
996         DELAY(KBDD_DELAYTIME);
997         return inb(kbdcp(p)->port + KBD_DATA_PORT);
998     }
999     return -1;          /* no data */
1000 }