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