pckbd.c revision 1.23
1/* $OpenBSD: pckbd.c,v 1.23 2009/11/23 15:21:41 deraadt Exp $ */
2/* $NetBSD: pckbd.c,v 1.24 2000/06/05 22:20:57 sommerfeld Exp $ */
3
4/*-
5 * Copyright (c) 1998 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Charles M. Hannum.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33/*-
34 * Copyright (c) 1990 The Regents of the University of California.
35 * All rights reserved.
36 *
37 * This code is derived from software contributed to Berkeley by
38 * William Jolitz and Don Ahn.
39 *
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
42 * are met:
43 * 1. Redistributions of source code must retain the above copyright
44 *    notice, this list of conditions and the following disclaimer.
45 * 2. Redistributions in binary form must reproduce the above copyright
46 *    notice, this list of conditions and the following disclaimer in the
47 *    documentation and/or other materials provided with the distribution.
48 * 3. Neither the name of the University nor the names of its contributors
49 *    may be used to endorse or promote products derived from this software
50 *    without specific prior written permission.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * SUCH DAMAGE.
63 *
64 *	@(#)pccons.c	5.11 (Berkeley) 5/21/91
65 */
66
67/*
68 * code to work keyboard for PC-style console
69 */
70
71#include <sys/param.h>
72#include <sys/systm.h>
73#include <sys/device.h>
74#include <sys/malloc.h>
75#include <sys/ioctl.h>
76
77#include <machine/bus.h>
78
79#include <dev/ic/pckbcvar.h>
80#include <dev/pckbc/pckbdreg.h>
81#include <dev/pckbc/pckbdvar.h>
82
83#include <dev/wscons/wsconsio.h>
84#include <dev/wscons/wskbdvar.h>
85#include <dev/wscons/wsksymdef.h>
86#include <dev/wscons/wsksymvar.h>
87
88#include <dev/pckbc/wskbdmap_mfii.h>
89
90struct pckbd_internal {
91	int t_isconsole;
92	pckbc_tag_t t_kbctag;
93	pckbc_slot_t t_kbcslot;
94
95	int t_translating;
96	int t_table;
97
98	int t_lastchar;
99	int t_extended;
100	int t_extended1;
101	int t_releasing;
102
103	struct pckbd_softc *t_sc; /* back pointer */
104};
105
106struct pckbd_softc {
107        struct  device sc_dev;
108
109	struct pckbd_internal *id;
110	int sc_enabled;
111
112	int sc_ledstate;
113
114	struct device *sc_wskbddev;
115#ifdef WSDISPLAY_COMPAT_RAWKBD
116	int	rawkbd;
117	u_int	sc_rawcnt;
118	char	sc_rawbuf[3];
119#endif
120};
121
122static int pckbd_is_console(pckbc_tag_t, pckbc_slot_t);
123
124int pckbdprobe(struct device *, void *, void *);
125void pckbdattach(struct device *, struct device *, void *);
126int pckbd_activate(struct device *, int);
127
128struct cfattach pckbd_ca = {
129	sizeof(struct pckbd_softc),
130	pckbdprobe,
131	pckbdattach,
132	NULL,
133	pckbd_activate
134};
135
136int	pckbd_enable(void *, int);
137void	pckbd_set_leds(void *, int);
138int	pckbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
139
140const struct wskbd_accessops pckbd_accessops = {
141	pckbd_enable,
142	pckbd_set_leds,
143	pckbd_ioctl,
144};
145
146void	pckbd_cngetc(void *, u_int *, int *);
147void	pckbd_cnpollc(void *, int);
148void	pckbd_cnbell(void *, u_int, u_int, u_int);
149
150const struct wskbd_consops pckbd_consops = {
151	pckbd_cngetc,
152	pckbd_cnpollc,
153	pckbd_cnbell,
154};
155
156const struct wskbd_mapdata pckbd_keymapdata = {
157	pckbd_keydesctab,
158#ifdef PCKBD_LAYOUT
159	PCKBD_LAYOUT,
160#else
161	KB_US,
162#endif
163};
164
165/*
166 * Hackish support for a bell on the PC Keyboard; when a suitable feeper
167 * is found, it attaches itself into the pckbd driver here.
168 */
169void	(*pckbd_bell_fn)(void *, u_int, u_int, u_int, int);
170void	*pckbd_bell_fn_arg;
171
172void	pckbd_bell(u_int, u_int, u_int, int);
173
174int	pckbd_scancode_translate(struct pckbd_internal *, int);
175int	pckbd_set_xtscancode(pckbc_tag_t, pckbc_slot_t,
176	    struct pckbd_internal *);
177int	pckbd_init(struct pckbd_internal *, pckbc_tag_t, pckbc_slot_t, int);
178void	pckbd_input(void *, int);
179
180static int	pckbd_decode(struct pckbd_internal *, int,
181				  u_int *, int *);
182static int	pckbd_led_encode(int);
183static int	pckbd_led_decode(int);
184
185struct pckbd_internal pckbd_consdata;
186
187int
188pckbd_set_xtscancode(pckbc_tag_t kbctag, pckbc_slot_t kbcslot,
189    struct pckbd_internal *id)
190{
191	/* default to have the 8042 translate the keyboard with table 3. */
192	int table = 3;
193
194	if (pckbc_xt_translation(kbctag, kbcslot, 1)) {
195		if (id != NULL)
196			id->t_translating = 1;
197	} else {
198#ifdef DEBUG
199		printf("pckbd: enabling of translation failed\n");
200#endif
201		/*
202		 * Since the keyboard controller can not translate scan
203		 * codes to the XT set (#1), we would like to request
204		 * this exact set. However it is likely that the
205		 * controller does not support it either.
206		 *
207		 * So try scan code set #2 as well, which this driver
208		 * knows how to translate.
209		 */
210		table = 2;
211		if (id != NULL)
212			id->t_translating = 0;
213	}
214
215	/* keep falling back until we hit a table that looks usable. */
216	for (; table >= 1; table--) {
217		u_char cmd[2];
218#ifdef DEBUG
219		printf("pckbd: trying table %d\n", table);
220#endif
221		cmd[0] = KBC_SETTABLE;
222		cmd[1] = table;
223		if (pckbc_poll_cmd(kbctag, kbcslot, cmd, 2, 0, NULL, 0)) {
224#ifdef DEBUG
225			printf("pckbd: table set of %d failed\n", table);
226#endif
227			if (table > 1) {
228				cmd[0] = KBC_RESET;
229				(void)pckbc_poll_cmd(kbctag, kbcslot, cmd,
230				    1, 1, NULL, 1);
231				pckbc_flush(kbctag, kbcslot);
232
233				continue;
234			}
235		}
236
237		/*
238		 * the 8042 took the table set request, however, not all that
239		 * report they can work with table 3 actually work, so ask what
240		 * table it reports it's in.
241		 */
242		if (table == 3) {
243			u_char resp[1];
244
245			cmd[0] = KBC_SETTABLE;
246			cmd[1] = 0;
247			if (pckbc_poll_cmd(kbctag, kbcslot, cmd, 2, 1, resp, 0)) {
248				/*
249				 * query failed, step down to table 2 to be
250				 * safe.
251				 */
252#ifdef DEBUG
253				printf("pckbd: table 3 verification failed\n");
254#endif
255				continue;
256			} else if (resp[0] == 3) {
257#ifdef DEBUG
258				printf("pckbd: settling on table 3\n");
259#endif
260				break;
261			}
262#ifdef DEBUG
263			else
264				printf("pckbd: table \"%x\" != 3, trying 2\n",
265					resp[0]);
266#endif
267		} else {
268#ifdef DEBUG
269			printf("pckbd: settling on table %d\n", table);
270#endif
271			break;
272		}
273	}
274
275	if (table == 0)
276		return (1);
277
278	if (id != NULL)
279		id->t_table = table;
280
281	return (0);
282}
283
284static int
285pckbd_is_console(tag, slot)
286	pckbc_tag_t tag;
287	pckbc_slot_t slot;
288{
289	return (pckbd_consdata.t_isconsole &&
290		(tag == pckbd_consdata.t_kbctag) &&
291		(slot == pckbd_consdata.t_kbcslot));
292}
293
294/*
295 * these are both bad jokes
296 */
297int
298pckbdprobe(parent, match, aux)
299	struct device *parent;
300	void *match;
301	void *aux;
302{
303	struct cfdata *cf = match;
304	struct pckbc_attach_args *pa = aux;
305	u_char cmd[1], resp[1];
306	int res;
307
308	/*
309	 * XXX There are rumours that a keyboard can be connected
310	 * to the aux port as well. For me, this didn't work.
311	 * For further experiments, allow it if explicitly
312	 * wired in the config file.
313	 */
314	if ((pa->pa_slot != PCKBC_KBD_SLOT) &&
315	    (cf->cf_loc[PCKBCCF_SLOT] == PCKBCCF_SLOT_DEFAULT))
316		return (0);
317
318	/* Flush any garbage. */
319	pckbc_flush(pa->pa_tag, pa->pa_slot);
320
321	/* Reset the keyboard. */
322	cmd[0] = KBC_RESET;
323	res = pckbc_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 1, resp, 1);
324	if (res) {
325#ifdef DEBUG
326		printf("pckbdprobe: reset error %d\n", res);
327#endif
328		/*
329		 * There is probably no keyboard connected.
330		 * Let the probe succeed if the keyboard is used
331		 * as console input - it can be connected later.
332		 */
333#if defined(__i386__) || defined(__amd64__)
334		/*
335		 * However, on legacy-free PCs, there might really
336		 * be no PS/2 connector at all; in that case, do not
337		 * even try to attach; ukbd will take over as console.
338		 */
339		if (res == ENXIO)
340			return 0;
341#endif
342		return (pckbd_is_console(pa->pa_tag, pa->pa_slot) ? 1 : 0);
343	}
344	if (resp[0] != KBR_RSTDONE) {
345		printf("pckbdprobe: reset response 0x%x\n", resp[0]);
346		return (0);
347	}
348
349	/*
350	 * Some keyboards seem to leave a second ack byte after the reset.
351	 * This is kind of stupid, but we account for them anyway by just
352	 * flushing the buffer.
353	 */
354	pckbc_flush(pa->pa_tag, pa->pa_slot);
355
356	if (pckbd_set_xtscancode(pa->pa_tag, pa->pa_slot, NULL))
357		return (0);
358
359	return (2);
360}
361
362void
363pckbdattach(parent, self, aux)
364	struct device *parent, *self;
365	void *aux;
366{
367	struct pckbd_softc *sc = (void *)self;
368	struct pckbc_attach_args *pa = aux;
369	int isconsole;
370	struct wskbddev_attach_args a;
371	u_char cmd[1];
372
373	printf("\n");
374
375	isconsole = pckbd_is_console(pa->pa_tag, pa->pa_slot);
376
377	if (isconsole) {
378		sc->id = &pckbd_consdata;
379		/*
380		 * Some keyboards are not enabled after a reset,
381		 * so make sure it is enabled now.
382		 */
383		cmd[0] = KBC_ENABLE;
384		(void) pckbc_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
385		    cmd, 1, 0, NULL, 0);
386		sc->sc_enabled = 1;
387	} else {
388		sc->id = malloc(sizeof(struct pckbd_internal),
389				M_DEVBUF, M_WAITOK);
390		(void) pckbd_init(sc->id, pa->pa_tag, pa->pa_slot, 0);
391
392		/* no interrupts until enabled */
393		cmd[0] = KBC_DISABLE;
394		(void) pckbc_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
395				      cmd, 1, 0, NULL, 0);
396		sc->sc_enabled = 0;
397	}
398
399	sc->id->t_sc = sc;
400
401	pckbc_set_inputhandler(sc->id->t_kbctag, sc->id->t_kbcslot,
402			       pckbd_input, sc, sc->sc_dev.dv_xname);
403
404	a.console = isconsole;
405
406	a.keymap = &pckbd_keymapdata;
407
408	a.accessops = &pckbd_accessops;
409	a.accesscookie = sc;
410
411	/*
412	 * Attach the wskbd, saving a handle to it.
413	 */
414	sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
415}
416
417int
418pckbd_activate(struct device *self, int act)
419{
420	switch (act) {
421	case DVACT_SUSPEND:
422		pckbd_enable(self, 0);
423		break;
424	case DVACT_RESUME:
425		pckbd_enable(self, 1);
426		break;
427	}
428	return (0);
429}
430
431int
432pckbd_enable(v, on)
433	void *v;
434	int on;
435{
436	struct pckbd_softc *sc = v;
437	u_char cmd[1];
438	int res;
439
440	if (on) {
441		if (sc->sc_enabled)
442			return (EBUSY);
443
444		pckbc_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 1);
445
446		cmd[0] = KBC_ENABLE;
447		res = pckbc_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
448					cmd, 1, 0, NULL, 0);
449		if (res) {
450			printf("pckbd_enable: command error\n");
451			return (res);
452		}
453
454		res = pckbd_set_xtscancode(sc->id->t_kbctag,
455					   sc->id->t_kbcslot, sc->id);
456		if (res)
457			return (res);
458
459		sc->sc_enabled = 1;
460	} else {
461		if (sc->id->t_isconsole)
462			return (EBUSY);
463
464		cmd[0] = KBC_DISABLE;
465		res = pckbc_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
466					cmd, 1, 0, 1, 0);
467		if (res) {
468			printf("pckbd_disable: command error\n");
469			return (res);
470		}
471
472		pckbc_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 0);
473
474		sc->sc_enabled = 0;
475	}
476
477	return (0);
478}
479
480const u_int8_t pckbd_xtbl[] = {
481/* 0x00 */
482	0,
483	0x43,		/* F9 */
484	0,
485	0x3f,		/* F5 */
486	0x3d,		/* F3 */
487	0x3b,		/* F1 */
488	0x3c,		/* F2 */
489	0x58,		/* F12 */
490	0x40,		/* F6 according to documentation */
491	0x44,		/* F10 */
492	0x42,		/* F8 */
493	0x40,		/* F6 according to experimentation */
494	0x3e,		/* F4 */
495	0x0f,		/* Tab */
496	0x29,		/* ` ~ */
497	0,
498/* 0x10 */
499	0,
500	0x38,		/* Left Alt */
501	0x2a,		/* Left Shift */
502	0,
503	0x1d,		/* Left Ctrl */
504	0x10,		/* q */
505	0x02,		/* 1 ! */
506	0,
507	0,
508	0,
509	0x2c,		/* z */
510	0x1f,		/* s */
511	0x1e,		/* a */
512	0x11,		/* w */
513	0x03,		/* 2 @ */
514	0,
515/* 0x20 */
516	0,
517	0x2e,		/* c */
518	0x2d,		/* x */
519	0x20,		/* d */
520	0x12,		/* e */
521	0x05,		/* 4 $ */
522	0x04,		/* 3 # */
523	0,
524	0,
525	0x39,		/* Space */
526	0x2f,		/* v */
527	0x21,		/* f */
528	0x14,		/* t */
529	0x13,		/* r */
530	0x06,		/* 5 % */
531	0,
532/* 0x30 */
533	0,
534	0x31,		/* n */
535	0x30,		/* b */
536	0x23,		/* h */
537	0x22,		/* g */
538	0x15,		/* y */
539	0x07,		/* 6 ^ */
540	0,
541	0,
542	0,
543	0x32,		/* m */
544	0x24,		/* j */
545	0x16,		/* u */
546	0x08,		/* 7 & */
547	0x09,		/* 8 * */
548	0,
549/* 0x40 */
550	0,
551	0x33,		/* , < */
552	0x25,		/* k */
553	0x17,		/* i */
554	0x18,		/* o */
555	0x0b,		/* 0 ) */
556	0x0a,		/* 9 ( */
557	0,
558	0,
559	0x34,		/* . > */
560	0x35,		/* / ? */
561	0x26,		/* l */
562	0x27,		/* ; : */
563	0x19,		/* p */
564	0x0c,		/* - _ */
565	0,
566/* 0x50 */
567	0,
568	0,
569	0x28,		/* ' " */
570	0,
571	0x1a,		/* [ { */
572	0x0d,		/* = + */
573	0,
574	0,
575	0x3a,		/* Caps Lock */
576	0x36,		/* Right Shift */
577	0x1c,		/* Return */
578	0x1b,		/* ] } */
579	0,
580	0x2b,		/* \ | */
581	0,
582	0,
583/* 0x60 */
584	0,
585	0,
586	0,
587	0,
588	0,
589	0,
590	0x0e,		/* Back Space */
591	0,
592	0,
593	0x4f,		/* KP 1 */
594	0,
595	0x4b,		/* KP 4 */
596	0x47,		/* KP 7 */
597	0,
598	0,
599	0,
600/* 0x70 */
601	0x52,		/* KP 0 */
602	0x53,		/* KP . */
603	0x50,		/* KP 2 */
604	0x4c,		/* KP 5 */
605	0x4d,		/* KP 6 */
606	0x48,		/* KP 8 */
607	0x01,		/* Escape */
608	0x45,		/* Num Lock */
609	0x57,		/* F11 */
610	0x4e,		/* KP + */
611	0x51,		/* KP 3 */
612	0x4a,		/* KP - */
613	0x37,		/* KP * */
614	0x49,		/* KP 9 */
615	0x46,		/* Scroll Lock */
616	0,
617/* 0x80 */
618	0,
619	0,
620	0,
621	0x41,		/* F7 (produced as an actual 8 bit code) */
622	0		/* Alt-Print Screen */
623};
624
625const u_int8_t pckbd_xtbl_ext[] = {
626/* 0x00 */
627	0,
628	0,
629	0,
630	0,
631	0,
632	0,
633	0,
634	0,
635	0,
636	0,
637	0,
638	0,
639	0,
640	0,
641	0,
642/* 0x10 */
643	0,
644	0x38,		/* Right Alt */
645	0,		/* E0 12, to be ignored */
646	0,
647	0x1d,		/* Right Ctrl */
648	0,
649	0,
650	0,
651	0,
652	0,
653	0,
654	0,
655	0,
656	0,
657	0,
658	0,
659/* 0x20 */
660	0,
661	0,
662	0,
663	0,
664	0,
665	0,
666	0,
667	0,
668	0,
669	0,
670	0,
671	0,
672	0,
673	0,
674	0,
675	0,
676/* 0x30 */
677	0,
678	0,
679	0,
680	0,
681	0,
682	0,
683	0,
684	0,
685	0,
686	0,
687	0,
688	0,
689	0,
690	0,
691	0,
692	0,
693/* 0x40 */
694	0,
695	0,
696	0,
697	0,
698	0,
699	0,
700	0,
701	0,
702	0,
703	0,
704	0x55,		/* KP / */
705	0,
706	0,
707	0,
708	0,
709	0,
710/* 0x50 */
711	0,
712	0,
713	0,
714	0,
715	0,
716	0,
717	0,
718	0,
719	0,
720	0,
721	0x1c,		/* KP Return */
722	0,
723	0,
724	0,
725	0,
726	0,
727/* 0x60 */
728	0,
729	0,
730	0,
731	0,
732	0,
733	0,
734	0,
735	0,
736	0,
737	0x4f,		/* End */
738	0,
739	0x4b,		/* Left */
740	0x47,		/* Home */
741	0,
742	0,
743	0,
744/* 0x70 */
745	0x52,		/* Insert */
746	0x53,		/* Delete */
747	0x50,		/* Down */
748	0,
749	0x4d,		/* Right */
750	0x48,		/* Up */
751	0,
752	0,
753	0,
754	0,
755	0x51,		/* Page Down */
756	0,
757	0x37,		/* Print Screen */
758	0x49,		/* Page Up */
759	0x46,		/* Ctrl-Break */
760	0
761};
762
763/*
764 * Translate scan codes from set 2 to set 1
765 */
766int
767pckbd_scancode_translate(struct pckbd_internal *id, int datain)
768{
769	if (id->t_translating != 0 || id->t_table == 1)
770		return datain;
771
772	if (datain == KBR_BREAK) {
773		id->t_releasing = 0x80;	/* next keycode is a release */
774		return 0;	/* consume scancode */
775	}
776
777	/*
778	 * Convert BREAK sequence (14 77 -> 1D 45)
779	 */
780	if (id->t_extended1 == 2 && datain == 0x14)
781		return 0x1d | id->t_releasing;
782	else if (id->t_extended1 == 1 && datain == 0x77)
783		return 0x77 | id->t_releasing;
784
785	if (id->t_extended != 0) {
786		if (datain >= sizeof pckbd_xtbl_ext)
787			datain = 0;
788		else
789			datain = pckbd_xtbl_ext[datain];
790	} else {
791		if (datain >= sizeof pckbd_xtbl)
792			datain = 0;
793		else
794			datain = pckbd_xtbl[datain];
795	}
796
797	if (datain == 0) {
798		/*
799		 * We don't know how to translate this scan code, but
800		 * we can't silently eat it either (because there might
801		 * have been an extended byte transmitted already).
802		 * Hopefully this value will be harmless to the upper
803		 * layers.
804		 */
805		return 0xff;
806	}
807
808	return datain | id->t_releasing;
809}
810
811static int
812pckbd_decode(id, datain, type, dataout)
813	struct pckbd_internal *id;
814	int datain;
815	u_int *type;
816	int *dataout;
817{
818	int key;
819	int releasing;
820
821	if (datain == KBR_EXTENDED0) {
822		id->t_extended = 0x80;
823		return 0;
824	} else if (datain == KBR_EXTENDED1) {
825		id->t_extended1 = 2;
826		return 0;
827	}
828
829	releasing = datain & 0x80;
830	datain &= 0x7f;
831
832	/*
833	 * process BREAK key sequence (EXT1 1D 45 / EXT1 9D C5):
834	 * map to (unused) code 7F
835	 */
836	if (id->t_extended1 == 2 && datain == 0x1d) {
837		id->t_extended1 = 1;
838		return 0;
839	} else if (id->t_extended1 == 1 && datain == 0x45) {
840		id->t_extended1 = 0;
841		datain = 0x7f;
842	} else
843		id->t_extended1 = 0;
844
845	if (id->t_translating != 0 || id->t_table == 1) {
846		id->t_releasing = releasing;
847	} else {
848		/* id->t_releasing computed in pckbd_scancode_translate() */
849	}
850
851	/* map extended keys to (unused) codes 128-254 */
852	key = datain | id->t_extended;
853	id->t_extended = 0;
854
855	if (id->t_releasing) {
856		id->t_releasing = 0;
857		id->t_lastchar = 0;
858		*type = WSCONS_EVENT_KEY_UP;
859	} else {
860		/* Always ignore typematic keys */
861		if (key == id->t_lastchar)
862			return(0);
863		id->t_lastchar = key;
864		*type = WSCONS_EVENT_KEY_DOWN;
865	}
866
867	*dataout = key;
868	return 1;
869}
870
871int
872pckbd_init(t, kbctag, kbcslot, console)
873	struct pckbd_internal *t;
874	pckbc_tag_t kbctag;
875	pckbc_slot_t kbcslot;
876	int console;
877{
878	bzero(t, sizeof(struct pckbd_internal));
879
880	t->t_isconsole = console;
881	t->t_kbctag = kbctag;
882	t->t_kbcslot = kbcslot;
883
884	return (pckbd_set_xtscancode(kbctag, kbcslot, t));
885}
886
887static int
888pckbd_led_encode(led)
889	int led;
890{
891	int res;
892
893	res = 0;
894
895	if (led & WSKBD_LED_SCROLL)
896		res |= 0x01;
897	if (led & WSKBD_LED_NUM)
898		res |= 0x02;
899	if (led & WSKBD_LED_CAPS)
900		res |= 0x04;
901	return(res);
902}
903
904static int
905pckbd_led_decode(led)
906	int led;
907{
908	int res;
909
910	res = 0;
911	if (led & 0x01)
912		res |= WSKBD_LED_SCROLL;
913	if (led & 0x02)
914		res |= WSKBD_LED_NUM;
915	if (led & 0x04)
916		res |= WSKBD_LED_CAPS;
917	return(res);
918}
919
920void
921pckbd_set_leds(v, leds)
922	void *v;
923	int leds;
924{
925	struct pckbd_softc *sc = v;
926	u_char cmd[2];
927
928	cmd[0] = KBC_MODEIND;
929	cmd[1] = pckbd_led_encode(leds);
930	sc->sc_ledstate = cmd[1];
931
932	(void) pckbc_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
933				 cmd, 2, 0, 0, 0);
934}
935
936/*
937 * Got a console receive interrupt -
938 * the console processor wants to give us a character.
939 */
940void
941pckbd_input(vsc, data)
942	void *vsc;
943	int data;
944{
945	struct pckbd_softc *sc = vsc;
946	int rc, type, key;
947
948	data = pckbd_scancode_translate(sc->id, data);
949	if (data == 0)
950		return;
951
952	rc = pckbd_decode(sc->id, data, &type, &key);
953
954#ifdef WSDISPLAY_COMPAT_RAWKBD
955	if (sc->rawkbd) {
956		sc->sc_rawbuf[sc->sc_rawcnt++] = (char)data;
957
958		if (rc != 0 || sc->sc_rawcnt == sizeof(sc->sc_rawbuf)) {
959			wskbd_rawinput(sc->sc_wskbddev, sc->sc_rawbuf,
960			    sc->sc_rawcnt);
961			sc->sc_rawcnt = 0;
962		}
963
964		/*
965		 * Pass audio keys to wskbd_input anyway.
966		 */
967		if (rc == 0 || (key != 160 && key != 174 && key != 176))
968			return;
969	}
970#endif
971	if (rc != 0)
972		wskbd_input(sc->sc_wskbddev, type, key);
973}
974
975int
976pckbd_ioctl(v, cmd, data, flag, p)
977	void *v;
978	u_long cmd;
979	caddr_t data;
980	int flag;
981	struct proc *p;
982{
983	struct pckbd_softc *sc = v;
984
985	switch (cmd) {
986	    case WSKBDIO_GTYPE:
987		*(int *)data = WSKBD_TYPE_PC_XT;
988		return 0;
989	    case WSKBDIO_SETLEDS: {
990		char cmd[2];
991		int res;
992		cmd[0] = KBC_MODEIND;
993		cmd[1] = pckbd_led_encode(*(int *)data);
994		sc->sc_ledstate = cmd[1];
995		res = pckbc_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
996					cmd, 2, 0, 1, 0);
997		return (res);
998		}
999	    case WSKBDIO_GETLEDS:
1000		*(int *)data = pckbd_led_decode(sc->sc_ledstate);
1001		return (0);
1002	    case WSKBDIO_COMPLEXBELL:
1003#define d ((struct wskbd_bell_data *)data)
1004		/*
1005		 * Keyboard can't beep directly; we have an
1006		 * externally-provided global hook to do this.
1007		 */
1008		pckbd_bell(d->pitch, d->period, d->volume, 0);
1009#undef d
1010		return (0);
1011#ifdef WSDISPLAY_COMPAT_RAWKBD
1012	    case WSKBDIO_SETMODE:
1013		sc->rawkbd = (*(int *)data == WSKBD_RAW);
1014		return (0);
1015#endif
1016	}
1017	return -1;
1018}
1019
1020void
1021pckbd_bell(pitch, period, volume, poll)
1022	u_int pitch, period, volume;
1023	int poll;
1024{
1025
1026	if (pckbd_bell_fn != NULL)
1027		(*pckbd_bell_fn)(pckbd_bell_fn_arg, pitch, period,
1028		    volume, poll);
1029}
1030
1031void
1032pckbd_hookup_bell(fn, arg)
1033	void (*fn)(void *, u_int, u_int, u_int, int);
1034	void *arg;
1035{
1036
1037	if (pckbd_bell_fn == NULL) {
1038		pckbd_bell_fn = fn;
1039		pckbd_bell_fn_arg = arg;
1040	}
1041}
1042
1043int
1044pckbd_cnattach(kbctag, kbcslot)
1045	pckbc_tag_t kbctag;
1046	int kbcslot;
1047{
1048	char cmd[1];
1049	int res;
1050
1051	res = pckbd_init(&pckbd_consdata, kbctag, kbcslot, 1);
1052#if 0 /* we allow the console to be attached if no keyboard is present */
1053	if (res)
1054		return (res);
1055#endif
1056
1057	/* Just to be sure. */
1058	cmd[0] = KBC_ENABLE;
1059	res = pckbc_poll_cmd(kbctag, kbcslot, cmd, 1, 0, NULL, 0);
1060#if 0
1061	if (res)
1062		return (res);
1063#endif
1064
1065	wskbd_cnattach(&pckbd_consops, &pckbd_consdata, &pckbd_keymapdata);
1066
1067	return (0);
1068}
1069
1070/* ARGSUSED */
1071void
1072pckbd_cngetc(v, type, data)
1073	void *v;
1074	u_int *type;
1075	int *data;
1076{
1077        struct pckbd_internal *t = v;
1078	int val;
1079
1080	for (;;) {
1081		val = pckbc_poll_data(t->t_kbctag, t->t_kbcslot);
1082		if (val == -1)
1083			continue;
1084
1085		val = pckbd_scancode_translate(t, val);
1086		if (val == 0)
1087			continue;
1088
1089		if (pckbd_decode(t, val, type, data))
1090			return;
1091	}
1092}
1093
1094void
1095pckbd_cnpollc(v, on)
1096	void *v;
1097        int on;
1098{
1099	struct pckbd_internal *t = v;
1100
1101	pckbc_set_poll(t->t_kbctag, t->t_kbcslot, on);
1102}
1103
1104void
1105pckbd_cnbell(v, pitch, period, volume)
1106	void *v;
1107	u_int pitch, period, volume;
1108{
1109
1110	pckbd_bell(pitch, period, volume, 1);
1111}
1112
1113struct cfdriver pckbd_cd = {
1114	NULL, "pckbd", DV_DULL
1115};
1116