1/* $OpenBSD: pckbd.c,v 1.51 2023/08/13 21:54:02 miod 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/pmsreg.h>
82
83#include <dev/wscons/wsconsio.h>
84#include <dev/wscons/wskbdraw.h>
85#include <dev/wscons/wskbdvar.h>
86#include <dev/wscons/wsksymdef.h>
87#include <dev/wscons/wsksymvar.h>
88
89#include <dev/pckbc/wskbdmap_mfii.h>
90
91struct pckbd_internal {
92	int t_isconsole;
93	pckbc_tag_t t_kbctag;
94	pckbc_slot_t t_kbcslot;
95
96	int t_translating;	/* nonzero if hardware performs translation */
97	int t_table;		/* scan code set in use */
98
99	int t_lastchar;
100	int t_extended;
101	int t_extended1;
102	int t_releasing;
103
104	struct pckbd_softc *t_sc; /* back pointer */
105};
106
107struct pckbd_softc {
108        struct  device sc_dev;
109
110	struct pckbd_internal *id;
111	int sc_enabled;
112
113	int sc_ledstate;
114
115	struct device *sc_wskbddev;
116#ifdef WSDISPLAY_COMPAT_RAWKBD
117	int	rawkbd;
118	u_int	sc_rawcnt;
119	char	sc_rawbuf[3];
120#endif
121};
122
123static int pckbd_is_console(pckbc_tag_t, pckbc_slot_t);
124
125int pckbdprobe(struct device *, void *, void *);
126void pckbdattach(struct device *, struct device *, void *);
127int pckbdactivate(struct device *, int);
128
129const struct cfattach pckbd_ca = {
130	sizeof(struct pckbd_softc),
131	pckbdprobe,
132	pckbdattach,
133	NULL,
134	pckbdactivate
135};
136
137int	pckbd_enable(void *, int);
138void	pckbd_set_leds(void *, int);
139int	pckbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
140
141const struct wskbd_accessops pckbd_accessops = {
142	pckbd_enable,
143	pckbd_set_leds,
144	pckbd_ioctl,
145};
146
147void	pckbd_cngetc(void *, u_int *, int *);
148void	pckbd_cnpollc(void *, int);
149void	pckbd_cnbell(void *, u_int, u_int, u_int);
150
151const struct wskbd_consops pckbd_consops = {
152	pckbd_cngetc,
153	pckbd_cnpollc,
154	pckbd_cnbell,
155};
156
157const struct wskbd_mapdata pckbd_keymapdata = {
158	pckbd_keydesctab,
159#ifdef PCKBD_LAYOUT
160	PCKBD_LAYOUT,
161#else
162	KB_US | KB_DEFAULT,
163#endif
164};
165
166/*
167 * Hackish support for a bell on the PC Keyboard; when a suitable beeper
168 * is found, it attaches itself into the pckbd driver here.
169 */
170void	(*pckbd_bell_fn)(void *, u_int, u_int, u_int, int);
171void	*pckbd_bell_fn_arg;
172
173void	pckbd_bell(u_int, u_int, u_int, int);
174
175int	pckbd_scancode_translate(struct pckbd_internal *, int);
176int	pckbd_set_xtscancode(pckbc_tag_t, pckbc_slot_t,
177	    struct pckbd_internal *);
178void	pckbd_init(struct pckbd_internal *, pckbc_tag_t, pckbc_slot_t, int);
179void	pckbd_input(void *, int);
180
181static int	pckbd_decode(struct pckbd_internal *, int,
182				  u_int *, int *);
183static int	pckbd_led_encode(int);
184
185struct pckbd_internal pckbd_consdata;
186
187int
188pckbdactivate(struct device *self, int act)
189{
190	struct pckbd_softc *sc = (struct pckbd_softc *)self;
191	int rv = 0;
192	u_char cmd[1];
193
194	switch(act) {
195	case DVACT_RESUME:
196		if (sc->sc_enabled) {
197			/*
198			 * Some keyboards are not enabled after a reset,
199			 * so make sure it is enabled now.
200			 */
201			cmd[0] = KBC_ENABLE;
202			(void) pckbc_poll_cmd(sc->id->t_kbctag,
203			    sc->id->t_kbcslot, cmd, 1, 0, NULL, 0);
204			/* XXX - also invoke pckbd_set_xtscancode() too? */
205		}
206		break;
207	}
208
209	rv = config_activate_children(self, act);
210
211	return (rv);
212}
213
214int
215pckbd_set_xtscancode(pckbc_tag_t kbctag, pckbc_slot_t kbcslot,
216    struct pckbd_internal *id)
217{
218	int table = 0;
219
220	if (pckbc_xt_translation(kbctag, &table)) {
221#ifdef DEBUG
222		printf("pckbd: enabling of translation failed\n");
223#endif
224#ifdef __sparc64__ /* only pckbc@ebus on sparc64 uses this */
225		/*
226		 * If hardware lacks translation capability, stick to the
227		 * table it is using.
228		 */
229		if (table != 0) {
230			id->t_translating = 0;
231			id->t_table = table;
232			return 0;
233		}
234#endif
235		/*
236		 * Since the keyboard controller can not translate scan
237		 * codes to the XT set (#1), we would like to request
238		 * this exact set. However it is likely that the
239		 * controller does not support it either.
240		 *
241		 * So try scan code set #2 as well, which this driver
242		 * knows how to translate.
243		 */
244		table = 2;
245		if (id != NULL)
246			id->t_translating = 0;
247	} else {
248		table = 3;
249		if (id != NULL) {
250			id->t_translating = 1;
251			if (id->t_table == 0) {
252				/*
253				 * Don't bother explicitly setting into set 2,
254				 * it's the default.
255				 */
256				id->t_table = 2;
257				return (0);
258			}
259		}
260	}
261
262	/* keep falling back until we hit a table that looks usable. */
263	for (; table >= 1; table--) {
264		u_char cmd[2];
265#ifdef DEBUG
266		printf("pckbd: trying table %d\n", table);
267#endif
268		cmd[0] = KBC_SETTABLE;
269		cmd[1] = table;
270		if (pckbc_poll_cmd(kbctag, kbcslot, cmd, 2, 0, NULL, 0)) {
271#ifdef DEBUG
272			printf("pckbd: table set of %d failed\n", table);
273#endif
274			if (table > 1) {
275				cmd[0] = KBC_RESET;
276				(void)pckbc_poll_cmd(kbctag, kbcslot, cmd,
277				    1, 1, NULL, 1);
278				pckbc_flush(kbctag, kbcslot);
279
280				continue;
281			}
282		}
283
284		/*
285		 * the 8042 took the table set request, however, not all that
286		 * report they can work with table 3 actually work, so ask what
287		 * table it reports it's in.
288		 */
289		if (table == 3) {
290			u_char resp[1];
291
292			cmd[0] = KBC_SETTABLE;
293			cmd[1] = 0;
294			if (pckbc_poll_cmd(kbctag, kbcslot, cmd, 2, 1, resp, 0)) {
295				/*
296				 * query failed, step down to table 2 to be
297				 * safe.
298				 */
299#ifdef DEBUG
300				printf("pckbd: table 3 verification failed\n");
301#endif
302				continue;
303			} else if (resp[0] == 3) {
304#ifdef DEBUG
305				printf("pckbd: settling on table 3\n");
306#endif
307				break;
308			}
309#ifdef DEBUG
310			else
311				printf("pckbd: table \"%x\" != 3, trying 2\n",
312					resp[0]);
313#endif
314		} else {
315#ifdef DEBUG
316			printf("pckbd: settling on table %d\n", table);
317#endif
318			break;
319		}
320	}
321
322	if (table == 0)
323		return (1);
324
325	if (id != NULL)
326		id->t_table = table;
327
328	return (0);
329}
330
331static int
332pckbd_is_console(pckbc_tag_t tag, pckbc_slot_t slot)
333{
334	return (pckbd_consdata.t_isconsole &&
335		(tag == pckbd_consdata.t_kbctag) &&
336		(slot == pckbd_consdata.t_kbcslot));
337}
338
339/*
340 * these are both bad jokes
341 */
342int
343pckbdprobe(struct device *parent, void *match, void *aux)
344{
345	struct cfdata *cf = match;
346	struct pckbc_attach_args *pa = aux;
347	u_char cmd[1], resp[2];
348	int res;
349
350	/*
351	 * XXX There are rumours that a keyboard can be connected
352	 * to the aux port as well. For me, this didn't work.
353	 * For further experiments, allow it if explicitly
354	 * wired in the config file.
355	 */
356	if ((pa->pa_slot != PCKBC_KBD_SLOT) &&
357	    (cf->cf_loc[PCKBCCF_SLOT] == PCKBCCF_SLOT_DEFAULT))
358		return (0);
359
360	/* Flush any garbage. */
361	pckbc_flush(pa->pa_tag, pa->pa_slot);
362
363	/* Reset the keyboard. */
364	cmd[0] = KBC_RESET;
365	res = pckbc_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 1, resp, 1);
366	if (res != 0) {
367#ifdef DEBUG
368		printf("pckbdprobe: reset error %d\n", res);
369#endif
370	} else if (resp[0] != KBR_RSTDONE) {
371#ifdef DEBUG
372		printf("pckbdprobe: reset response 0x%x\n", resp[0]);
373#endif
374		res = EINVAL;
375	}
376#if defined(__i386__) || defined(__amd64__)
377	if (res) {
378		/*
379		 * The 8042 emulation on Chromebooks fails the reset
380		 * command but otherwise appears to work correctly.
381		 * Try a "get ID" command to give it a second chance.
382		 */
383		cmd[0] = KBC_GETID;
384		res = pckbc_poll_cmd(pa->pa_tag, pa->pa_slot,
385		    cmd, 1, 2, resp, 0);
386		if (res != 0) {
387#ifdef DEBUG
388			printf("pckbdprobe: getid error %d\n", res);
389#endif
390		} else if (resp[0] != 0xab || resp[1] != 0x83) {
391#ifdef DEBUG
392			printf("pckbdprobe: unexpected id 0x%x/0x%x\n",
393			    resp[0], resp[1]);
394#endif
395			res = EINVAL;
396		}
397	}
398#endif
399	if (res) {
400		/*
401		 * There is probably no keyboard connected.
402		 * Let the probe succeed if the keyboard is used
403		 * as console input - it can be connected later.
404		 */
405#if defined(__i386__) || defined(__amd64__)
406		/*
407		 * However, on legacy-free PCs, there might really
408		 * be no PS/2 connector at all; in that case, do not
409		 * even try to attach; ukbd will take over as console.
410		 */
411		if (res == ENXIO) {
412			/* check cf_flags from parent */
413			struct cfdata *cf = parent->dv_cfdata;
414			if (!ISSET(cf->cf_flags, PCKBCF_FORCE_KEYBOARD_PRESENT))
415				return 0;
416		}
417#endif
418		return (pckbd_is_console(pa->pa_tag, pa->pa_slot) ? 1 : 0);
419	}
420
421	/*
422	 * Some keyboards seem to leave a second ack byte after the reset.
423	 * This is kind of stupid, but we account for them anyway by just
424	 * flushing the buffer.
425	 */
426	pckbc_flush(pa->pa_tag, pa->pa_slot);
427
428	return (2);
429}
430
431void
432pckbdattach(struct device *parent, struct device *self, void *aux)
433{
434	struct pckbd_softc *sc = (void *)self;
435	struct pckbc_attach_args *pa = aux;
436	int isconsole;
437	struct wskbddev_attach_args a;
438	u_char cmd[1];
439
440	isconsole = pckbd_is_console(pa->pa_tag, pa->pa_slot);
441
442	if (isconsole) {
443		sc->id = &pckbd_consdata;
444		if (sc->id->t_table == 0)
445			pckbd_set_xtscancode(pa->pa_tag, pa->pa_slot, sc->id);
446
447		/*
448		 * Some keyboards are not enabled after a reset,
449		 * so make sure it is enabled now.
450		 */
451		cmd[0] = KBC_ENABLE;
452		(void) pckbc_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
453		    cmd, 1, 0, NULL, 0);
454		sc->sc_enabled = 1;
455	} else {
456		sc->id = malloc(sizeof(struct pckbd_internal),
457				M_DEVBUF, M_WAITOK);
458		pckbd_init(sc->id, pa->pa_tag, pa->pa_slot, 0);
459		pckbd_set_xtscancode(pa->pa_tag, pa->pa_slot, sc->id);
460
461		/* no interrupts until enabled */
462		cmd[0] = KBC_DISABLE;
463		(void) pckbc_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
464				      cmd, 1, 0, NULL, 0);
465		sc->sc_enabled = 0;
466	}
467
468	sc->id->t_sc = sc;
469
470	pckbc_set_inputhandler(sc->id->t_kbctag, sc->id->t_kbcslot,
471			       pckbd_input, sc, sc->sc_dev.dv_xname);
472
473	a.console = isconsole;
474
475	a.keymap = &pckbd_keymapdata;
476
477	a.accessops = &pckbd_accessops;
478	a.accesscookie = sc;
479
480	printf("\n");
481
482	/*
483	 * Attach the wskbd, saving a handle to it.
484	 */
485	sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
486}
487
488int
489pckbd_enable(void *v, int on)
490{
491	struct pckbd_softc *sc = v;
492	u_char cmd[1];
493	int res;
494
495	if (on) {
496		if (sc->sc_enabled)
497			return (EBUSY);
498
499		pckbc_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 1);
500
501		cmd[0] = KBC_ENABLE;
502		res = pckbc_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
503					cmd, 1, 0, NULL, 0);
504		if (res) {
505			printf("pckbd_enable: command error\n");
506			return (res);
507		}
508
509		res = pckbd_set_xtscancode(sc->id->t_kbctag,
510					   sc->id->t_kbcslot, sc->id);
511		if (res)
512			return (res);
513
514		sc->sc_enabled = 1;
515	} else {
516		if (sc->id->t_isconsole)
517			return (EBUSY);
518
519		cmd[0] = KBC_DISABLE;
520		res = pckbc_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
521					cmd, 1, 0, 1, 0);
522		if (res) {
523			printf("pckbd_disable: command error\n");
524			return (res);
525		}
526
527		pckbc_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 0);
528
529		sc->sc_enabled = 0;
530	}
531
532	return (0);
533}
534
535/*
536 * Scan code set #2 translation tables
537 */
538
539const u_int8_t pckbd_xtbl2[] = {
540/* 0x00 */
541	0,
542	RAWKEY_f9,
543	0,
544	RAWKEY_f5,
545	RAWKEY_f3,
546	RAWKEY_f1,
547	RAWKEY_f2,
548	RAWKEY_f12,
549	RAWKEY_f6,	/* F6 according to documentation */
550	RAWKEY_f10,
551	RAWKEY_f8,
552	RAWKEY_f6,	/* F6 according to experimentation */
553	RAWKEY_f4,
554	RAWKEY_Tab,
555	RAWKEY_grave,
556	0,
557/* 0x10 */
558	0,
559	RAWKEY_Alt_L,
560	RAWKEY_Shift_L,
561	0,
562	RAWKEY_Control_L,
563	RAWKEY_q,
564	RAWKEY_1,
565	0,
566	0,
567	0,
568	RAWKEY_z,
569	RAWKEY_s,
570	RAWKEY_a,
571	RAWKEY_w,
572	RAWKEY_2,
573	RAWKEY_Meta_L,
574/* 0x20 */
575	0,
576	RAWKEY_c,
577	RAWKEY_x,
578	RAWKEY_d,
579	RAWKEY_e,
580	RAWKEY_4,
581	RAWKEY_3,
582	0,
583	RAWKEY_Meta_R,
584	RAWKEY_space,
585	RAWKEY_v,
586	RAWKEY_f,
587	RAWKEY_t,
588	RAWKEY_r,
589	RAWKEY_5,
590	0,
591/* 0x30 */
592	0,
593	RAWKEY_n,
594	RAWKEY_b,
595	RAWKEY_h,
596	RAWKEY_g,
597	RAWKEY_y,
598	RAWKEY_6,
599	0,
600	0,
601	0,
602	RAWKEY_m,
603	RAWKEY_j,
604	RAWKEY_u,
605	RAWKEY_7,
606	RAWKEY_8,
607	0,
608/* 0x40 */
609	0,
610	RAWKEY_comma,
611	RAWKEY_k,
612	RAWKEY_i,
613	RAWKEY_o,
614	RAWKEY_0,
615	RAWKEY_9,
616	0,
617	0,
618	RAWKEY_period,
619	RAWKEY_slash,
620	RAWKEY_l,
621	RAWKEY_semicolon,
622	RAWKEY_p,
623	RAWKEY_minus,
624	0,
625/* 0x50 */
626	0,
627	0,
628	RAWKEY_apostrophe,
629	0,
630	RAWKEY_bracketleft,
631	RAWKEY_equal,
632	0,
633	0,
634	RAWKEY_Caps_Lock,
635	RAWKEY_Shift_R,
636	RAWKEY_Return,
637	RAWKEY_bracketright,
638	0,
639	RAWKEY_backslash,
640	0,
641	0,
642/* 0x60 */
643	0,
644	0,
645	0,
646	0,
647	0,
648	0,
649	RAWKEY_BackSpace,
650	0,
651	0,
652	RAWKEY_KP_End,
653	0,
654	RAWKEY_KP_Left,
655	RAWKEY_KP_Home,
656	0,
657	0,
658	0,
659/* 0x70 */
660	RAWKEY_KP_Insert,
661	RAWKEY_KP_Delete,
662	RAWKEY_KP_Down,
663	RAWKEY_KP_Begin,
664	RAWKEY_KP_Right,
665	RAWKEY_KP_Up,
666	RAWKEY_Escape,
667	RAWKEY_Num_Lock,
668	RAWKEY_f11,
669	RAWKEY_KP_Add,
670	RAWKEY_KP_Next,
671	RAWKEY_KP_Subtract,
672	RAWKEY_KP_Multiply,
673	RAWKEY_KP_Prior,
674	RAWKEY_Hold_Screen,
675	0,
676/* 0x80 */
677	0,
678	0,
679	0,
680	RAWKEY_f7,
681	0		/* Alt-Print Screen */
682};
683
684const u_int8_t pckbd_xtbl2_ext[] = {
685/* 0x00 */
686	0,
687	0,
688	0,
689	0,
690	0,
691	0,
692	0,
693	0,
694	0,
695	0,
696	0,
697	0,
698	0,
699	0,
700	0,
701/* 0x10 */
702	0,
703	RAWKEY_Alt_R,
704	0,		/* E0 12, to be ignored */
705	0,
706	RAWKEY_Control_R,
707	0,
708	0,
709	0,
710	0,
711	0,
712	0,
713	0,
714	0,
715	0,
716	0,
717	0,
718/* 0x20 */
719	0,
720	0,
721	0,
722	0,
723	0,
724	0,
725	0,
726	0,
727	0,
728	0,
729	0,
730	0,
731	0,
732	0,
733	0,
734	0,
735/* 0x30 */
736	0,
737	0,
738	0,
739	0,
740	0,
741	0,
742	0,
743	0,
744	0,
745	0,
746	0,
747	0,
748	0,
749	0,
750	0,
751	0,
752/* 0x40 */
753	0,
754	0,
755	0,
756	0,
757	0,
758	0,
759	0,
760	0,
761	0,
762	0,
763	RAWKEY_KP_Divide,
764	0,
765	0,
766	0,
767	0,
768	0,
769/* 0x50 */
770	0,
771	0,
772	0,
773	0,
774	0,
775	0,
776	0,
777	0,
778	0,
779	0,
780	RAWKEY_KP_Enter,
781	0,
782	0,
783	0,
784	0,
785	0,
786/* 0x60 */
787	0,
788	0,
789	0,
790	0,
791	0,
792	0,
793	0,
794	0,
795	0,
796	RAWKEY_End,
797	0,
798	RAWKEY_Left,
799	RAWKEY_Home,
800	0,
801	0,
802	0,
803/* 0x70 */
804	RAWKEY_Insert,
805	RAWKEY_Delete,
806	RAWKEY_Down,
807	0,
808	RAWKEY_Right,
809	RAWKEY_Up,
810	0,
811	0,
812	0,
813	0,
814	RAWKEY_Next,
815	0,
816	RAWKEY_Print_Screen,
817	RAWKEY_Prior,
818	0xc6,		/* Ctrl-Break */
819	0
820};
821
822#ifdef __sparc64__ /* only pckbc@ebus on sparc64 uses this */
823
824/*
825 * Scan code set #3 translation table
826 */
827
828const u_int8_t pckbd_xtbl3[] = {
829/* 0x00 */
830	0,
831	RAWKEY_L5,	/* Front */
832	RAWKEY_L1,	/* Stop */
833	RAWKEY_L3,	/* Props */
834	0,
835	RAWKEY_L7,	/* Open */
836	RAWKEY_L9,	/* Find */
837	RAWKEY_f1,
838	RAWKEY_Escape,
839	RAWKEY_L10,	/* Cut */
840	0,
841	0,
842	0,
843	RAWKEY_Tab,
844	RAWKEY_grave,
845	RAWKEY_f2,
846/* 0x10 */
847	RAWKEY_Help,
848	RAWKEY_Control_L,
849	RAWKEY_Shift_L,
850	0,
851	RAWKEY_Caps_Lock,
852	RAWKEY_q,
853	RAWKEY_1,
854	RAWKEY_f3,
855	0,
856	RAWKEY_Alt_L,
857	RAWKEY_z,
858	RAWKEY_s,
859	RAWKEY_a,
860	RAWKEY_w,
861	RAWKEY_2,
862	RAWKEY_f4,
863/* 0x20 */
864	0,
865	RAWKEY_c,
866	RAWKEY_x,
867	RAWKEY_d,
868	RAWKEY_e,
869	RAWKEY_4,
870	RAWKEY_3,
871	RAWKEY_f5,
872	RAWKEY_L4,	/* Undo */
873	RAWKEY_space,
874	RAWKEY_v,
875	RAWKEY_f,
876	RAWKEY_t,
877	RAWKEY_r,
878	RAWKEY_5,
879	RAWKEY_f6,
880/* 0x30 */
881	RAWKEY_L2,	/* Again */
882	RAWKEY_n,
883	RAWKEY_b,
884	RAWKEY_h,
885	RAWKEY_g,
886	RAWKEY_y,
887	RAWKEY_6,
888	RAWKEY_f7,
889	0,
890	RAWKEY_Alt_R,
891	RAWKEY_m,
892	RAWKEY_j,
893	RAWKEY_u,
894	RAWKEY_7,
895	RAWKEY_8,
896	RAWKEY_f8,
897/* 0x40 */
898	0,
899	RAWKEY_comma,
900	RAWKEY_k,
901	RAWKEY_i,
902	RAWKEY_o,
903	RAWKEY_0,
904	RAWKEY_9,
905	RAWKEY_f9,
906	RAWKEY_L6,	/* Copy */
907	RAWKEY_period,
908	RAWKEY_slash,
909	RAWKEY_l,
910	RAWKEY_semicolon,
911	RAWKEY_p,
912	RAWKEY_minus,
913	RAWKEY_f10,
914/* 0x50 */
915	0,
916	0,
917	RAWKEY_apostrophe,
918	0,
919	RAWKEY_bracketleft,
920	RAWKEY_equal,
921	RAWKEY_f11,
922	RAWKEY_Print_Screen,
923	RAWKEY_Control_R,
924	RAWKEY_Shift_R,
925	RAWKEY_Return,
926	RAWKEY_bracketright,
927	RAWKEY_backslash,
928	0,
929	RAWKEY_f12,
930	RAWKEY_Hold_Screen,
931/* 0x60 */
932	RAWKEY_Down,
933	RAWKEY_Left,
934	RAWKEY_Pause,
935	RAWKEY_Up,
936	RAWKEY_Delete,
937	RAWKEY_End,
938	RAWKEY_BackSpace,
939	RAWKEY_Insert,
940	RAWKEY_L8,	/* Paste */
941	RAWKEY_KP_End,
942	RAWKEY_Right,
943	RAWKEY_KP_Left,
944	RAWKEY_KP_Home,
945	RAWKEY_Next,
946	RAWKEY_Home,
947	RAWKEY_Prior,
948/* 0x70 */
949	RAWKEY_KP_Insert,
950	RAWKEY_KP_Delete,
951	RAWKEY_KP_Down,
952	RAWKEY_KP_Begin,
953	RAWKEY_KP_Right,
954	RAWKEY_KP_Up,
955	RAWKEY_Num_Lock,
956	RAWKEY_KP_Divide,
957	0,
958	RAWKEY_KP_Enter,
959	RAWKEY_KP_Next,
960	0,
961	RAWKEY_KP_Add,
962	RAWKEY_KP_Prior,
963	RAWKEY_KP_Multiply,
964	0,
965/* 0x80 */
966	0,
967	0,
968	0,
969	0,
970	RAWKEY_KP_Subtract,
971	0,
972	0,
973	0,
974	0,
975	0,
976	0,
977	RAWKEY_Meta_L,
978	RAWKEY_Meta_R
979};
980
981#endif
982
983/*
984 * Translate scan codes from set 2 or 3 to set 1
985 */
986int
987pckbd_scancode_translate(struct pckbd_internal *id, int datain)
988{
989	if (id->t_translating != 0 || id->t_table == 1)
990		return datain;
991
992	if (datain == KBR_BREAK) {
993		id->t_releasing = 0x80;	/* next keycode is a release */
994		return 0;	/* consume scancode */
995	}
996
997	switch (id->t_table) {
998	case 2:
999		/*
1000	 	* Convert BREAK sequence (14 77 -> 1D 45)
1001	 	*/
1002		if (id->t_extended1 == 2 && datain == 0x14)
1003			return 0x1d | id->t_releasing;
1004		else if (id->t_extended1 == 1 && datain == 0x77)
1005			return 0x45 | id->t_releasing;
1006
1007		if (id->t_extended != 0) {
1008			if (datain >= sizeof pckbd_xtbl2_ext)
1009				datain = 0;
1010			else
1011				datain = pckbd_xtbl2_ext[datain];
1012			/* xtbl2_ext already has the upper bit set */
1013			id->t_extended = 0;
1014		} else {
1015			if (datain >= sizeof pckbd_xtbl2)
1016				datain = 0;
1017			else
1018				datain = pckbd_xtbl2[datain] & ~0x80;
1019		}
1020		break;
1021#ifdef __sparc64__ /* only pckbc@ebus on sparc64 uses this */
1022	case 3:
1023		if (datain >= sizeof pckbd_xtbl3)
1024			datain = 0;
1025		else
1026			datain = pckbd_xtbl3[datain] & ~0x80;
1027		break;
1028#endif
1029	}
1030
1031	if (datain == 0) {
1032		/*
1033		 * We don't know how to translate this scan code, but
1034		 * we can't silently eat it either (because there might
1035		 * have been an extended byte transmitted already).
1036		 * Hopefully this value will be harmless to the upper
1037		 * layers.
1038		 */
1039		return 0xff;
1040	}
1041
1042	return datain | id->t_releasing;
1043}
1044
1045static int
1046pckbd_decode(struct pckbd_internal *id, int datain, u_int *type, int *dataout)
1047{
1048	int key;
1049	int releasing;
1050
1051	if (datain == KBR_EXTENDED0) {
1052		id->t_extended = 0x80;
1053		return 0;
1054	} else if (datain == KBR_EXTENDED1) {
1055		id->t_extended1 = 2;
1056		return 0;
1057	}
1058
1059	releasing = datain & 0x80;
1060	datain &= 0x7f;
1061
1062	/*
1063	 * process BREAK key sequence (EXT1 1D 45 / EXT1 9D C5):
1064	 * map to (unused) code 7F
1065	 */
1066	if (id->t_extended1 == 2 && datain == 0x1d) {
1067		id->t_extended1 = 1;
1068		return 0;
1069	} else if (id->t_extended1 == 1 && datain == 0x45) {
1070		id->t_extended1 = 0;
1071		datain = 0x7f;
1072	} else
1073		id->t_extended1 = 0;
1074
1075	if (id->t_translating != 0 || id->t_table == 1) {
1076		id->t_releasing = releasing;
1077	} else {
1078		/* id->t_releasing computed in pckbd_scancode_translate() */
1079	}
1080
1081	/* map extended keys to (unused) codes 128-254 */
1082	key = datain | id->t_extended;
1083	id->t_extended = 0;
1084
1085	if (id->t_releasing) {
1086		id->t_releasing = 0;
1087		id->t_lastchar = 0;
1088		*type = WSCONS_EVENT_KEY_UP;
1089	} else {
1090		/* Always ignore typematic keys */
1091		if (key == id->t_lastchar)
1092			return 0;
1093		id->t_lastchar = key;
1094		*type = WSCONS_EVENT_KEY_DOWN;
1095	}
1096
1097	*dataout = key;
1098	return 1;
1099}
1100
1101void
1102pckbd_init(struct pckbd_internal *t, pckbc_tag_t kbctag, pckbc_slot_t kbcslot,
1103    int console)
1104{
1105	bzero(t, sizeof(struct pckbd_internal));
1106
1107	t->t_isconsole = console;
1108	t->t_kbctag = kbctag;
1109	t->t_kbcslot = kbcslot;
1110}
1111
1112static int
1113pckbd_led_encode(int led)
1114{
1115	int res;
1116
1117	res = 0;
1118
1119	if (led & WSKBD_LED_SCROLL)
1120		res |= 0x01;
1121	if (led & WSKBD_LED_NUM)
1122		res |= 0x02;
1123	if (led & WSKBD_LED_CAPS)
1124		res |= 0x04;
1125	return(res);
1126}
1127
1128void
1129pckbd_set_leds(void *v, int leds)
1130{
1131	struct pckbd_softc *sc = v;
1132	u_char cmd[2];
1133
1134	cmd[0] = KBC_MODEIND;
1135	cmd[1] = pckbd_led_encode(leds);
1136	sc->sc_ledstate = leds;
1137
1138	(void) pckbc_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
1139				 cmd, 2, 0, 0, 0);
1140}
1141
1142/*
1143 * Got a console receive interrupt -
1144 * the console processor wants to give us a character.
1145 */
1146void
1147pckbd_input(void *vsc, int data)
1148{
1149	struct pckbd_softc *sc = vsc;
1150	int rc, type, key;
1151
1152	data = pckbd_scancode_translate(sc->id, data);
1153	if (data == 0)
1154		return;
1155
1156	rc = pckbd_decode(sc->id, data, &type, &key);
1157
1158#ifdef WSDISPLAY_COMPAT_RAWKBD
1159	if (sc->rawkbd) {
1160		sc->sc_rawbuf[sc->sc_rawcnt++] = (char)data;
1161
1162		if (rc != 0 || sc->sc_rawcnt == sizeof(sc->sc_rawbuf)) {
1163			wskbd_rawinput(sc->sc_wskbddev, sc->sc_rawbuf,
1164			    sc->sc_rawcnt);
1165			sc->sc_rawcnt = 0;
1166		}
1167
1168		/*
1169		 * Pass audio keys to wskbd_input anyway.
1170		 */
1171		if (rc == 0 || (key != 160 && key != 174 && key != 176))
1172			return;
1173	}
1174#endif
1175	if (rc != 0)
1176		wskbd_input(sc->sc_wskbddev, type, key);
1177}
1178
1179int
1180pckbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
1181{
1182	struct pckbd_softc *sc = v;
1183
1184	switch (cmd) {
1185	    case WSKBDIO_GTYPE:
1186		*(int *)data = WSKBD_TYPE_PC_XT;
1187		return 0;
1188	    case WSKBDIO_SETLEDS: {
1189		char cmd[2];
1190		int res;
1191		cmd[0] = KBC_MODEIND;
1192		cmd[1] = pckbd_led_encode(*(int *)data);
1193		sc->sc_ledstate = *(int *)data & (WSKBD_LED_SCROLL |
1194		    WSKBD_LED_NUM | WSKBD_LED_CAPS);
1195		res = pckbc_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
1196					cmd, 2, 0, 1, 0);
1197		return (res);
1198		}
1199	    case WSKBDIO_GETLEDS:
1200		*(int *)data = sc->sc_ledstate;
1201		return (0);
1202	    case WSKBDIO_COMPLEXBELL:
1203#define d ((struct wskbd_bell_data *)data)
1204		/*
1205		 * Keyboard can't beep directly; we have an
1206		 * externally-provided global hook to do this.
1207		 */
1208		pckbd_bell(d->pitch, d->period, d->volume, 0);
1209#undef d
1210		return (0);
1211#ifdef WSDISPLAY_COMPAT_RAWKBD
1212	    case WSKBDIO_SETMODE:
1213		sc->rawkbd = (*(int *)data == WSKBD_RAW);
1214		return (0);
1215#endif
1216	}
1217	return -1;
1218}
1219
1220void
1221pckbd_bell(u_int pitch, u_int period, u_int volume, int poll)
1222{
1223
1224	if (pckbd_bell_fn != NULL)
1225		(*pckbd_bell_fn)(pckbd_bell_fn_arg, pitch, period,
1226		    volume, poll);
1227}
1228
1229void
1230pckbd_hookup_bell(void (*fn)(void *, u_int, u_int, u_int, int), void *arg)
1231{
1232
1233	if (pckbd_bell_fn == NULL) {
1234		pckbd_bell_fn = fn;
1235		pckbd_bell_fn_arg = arg;
1236	}
1237}
1238
1239int
1240pckbd_cnattach(pckbc_tag_t kbctag)
1241{
1242	pckbd_init(&pckbd_consdata, kbctag, PCKBC_KBD_SLOT, 1);
1243	wskbd_cnattach(&pckbd_consops, &pckbd_consdata, &pckbd_keymapdata);
1244	return (0);
1245}
1246
1247void
1248pckbd_cngetc(void *v, u_int *type, int *data)
1249{
1250        struct pckbd_internal *t = v;
1251	int val;
1252
1253	for (;;) {
1254		val = pckbc_poll_data(t->t_kbctag, t->t_kbcslot);
1255		if (val == -1)
1256			continue;
1257
1258		val = pckbd_scancode_translate(t, val);
1259		if (val == 0)
1260			continue;
1261
1262		if (pckbd_decode(t, val, type, data))
1263			return;
1264	}
1265}
1266
1267void
1268pckbd_cnpollc(void *v, int on)
1269{
1270	struct pckbd_internal *t = v;
1271
1272	pckbc_set_poll(t->t_kbctag, t->t_kbcslot, on);
1273
1274	/*
1275	 * If we enter ukc or ddb before having attached the console
1276	 * keyboard we need to probe its scan code set.
1277	 */
1278	if (t->t_table == 0) {
1279		char cmd[1];
1280
1281		pckbc_flush(t->t_kbctag, t->t_kbcslot);
1282		pckbd_set_xtscancode(t->t_kbctag, t->t_kbcslot, t);
1283
1284		/* Just to be sure. */
1285		cmd[0] = KBC_ENABLE;
1286		pckbc_poll_cmd(t->t_kbctag, PCKBC_KBD_SLOT, cmd, 1, 0, NULL, 0);
1287	}
1288}
1289
1290void
1291pckbd_cnbell(void *v, u_int pitch, u_int period, u_int volume)
1292{
1293
1294	pckbd_bell(pitch, period, volume, 1);
1295}
1296
1297struct cfdriver pckbd_cd = {
1298	NULL, "pckbd", DV_DULL
1299};
1300