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