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