ukbd.c revision 1.105 1 1.105 dyoung /* $NetBSD: ukbd.c,v 1.105 2009/11/12 19:58:27 dyoung Exp $ */
2 1.1 augustss
3 1.1 augustss /*
4 1.1 augustss * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 1.1 augustss * All rights reserved.
6 1.1 augustss *
7 1.11 augustss * This code is derived from software contributed to The NetBSD Foundation
8 1.59 augustss * by Lennart Augustsson (lennart (at) augustsson.net) at
9 1.11 augustss * Carlstedt Research & Technology.
10 1.1 augustss *
11 1.1 augustss * Redistribution and use in source and binary forms, with or without
12 1.1 augustss * modification, are permitted provided that the following conditions
13 1.1 augustss * are met:
14 1.1 augustss * 1. Redistributions of source code must retain the above copyright
15 1.1 augustss * notice, this list of conditions and the following disclaimer.
16 1.1 augustss * 2. Redistributions in binary form must reproduce the above copyright
17 1.1 augustss * notice, this list of conditions and the following disclaimer in the
18 1.1 augustss * documentation and/or other materials provided with the distribution.
19 1.1 augustss *
20 1.1 augustss * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 1.1 augustss * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 1.1 augustss * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 1.1 augustss * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 1.1 augustss * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 1.1 augustss * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 1.1 augustss * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 1.1 augustss * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 1.1 augustss * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 1.1 augustss * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 1.1 augustss * POSSIBILITY OF SUCH DAMAGE.
31 1.1 augustss */
32 1.1 augustss
33 1.17 augustss /*
34 1.85 augustss * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
35 1.17 augustss */
36 1.72 lukem
37 1.72 lukem #include <sys/cdefs.h>
38 1.105 dyoung __KERNEL_RCSID(0, "$NetBSD: ukbd.c,v 1.105 2009/11/12 19:58:27 dyoung Exp $");
39 1.17 augustss
40 1.1 augustss #include <sys/param.h>
41 1.1 augustss #include <sys/systm.h>
42 1.57 thorpej #include <sys/callout.h>
43 1.1 augustss #include <sys/kernel.h>
44 1.1 augustss #include <sys/device.h>
45 1.1 augustss #include <sys/ioctl.h>
46 1.1 augustss #include <sys/file.h>
47 1.1 augustss #include <sys/select.h>
48 1.1 augustss #include <sys/proc.h>
49 1.1 augustss #include <sys/vnode.h>
50 1.1 augustss #include <sys/poll.h>
51 1.1 augustss
52 1.1 augustss #include <dev/usb/usb.h>
53 1.2 augustss #include <dev/usb/usbhid.h>
54 1.37 augustss
55 1.1 augustss #include <dev/usb/usbdi.h>
56 1.1 augustss #include <dev/usb/usbdi_util.h>
57 1.1 augustss #include <dev/usb/usbdevs.h>
58 1.1 augustss #include <dev/usb/usb_quirks.h>
59 1.75 augustss #include <dev/usb/uhidev.h>
60 1.1 augustss #include <dev/usb/hid.h>
61 1.31 thorpej #include <dev/usb/ukbdvar.h>
62 1.1 augustss
63 1.2 augustss #include <dev/wscons/wsconsio.h>
64 1.2 augustss #include <dev/wscons/wskbdvar.h>
65 1.2 augustss #include <dev/wscons/wsksymdef.h>
66 1.2 augustss #include <dev/wscons/wsksymvar.h>
67 1.2 augustss
68 1.89 cube #include "opt_ukbd_layout.h"
69 1.2 augustss #include "opt_wsdisplay_compat.h"
70 1.69 augustss #include "opt_ddb.h"
71 1.21 augustss
72 1.62 augustss #ifdef UKBD_DEBUG
73 1.39 augustss #define DPRINTF(x) if (ukbddebug) logprintf x
74 1.39 augustss #define DPRINTFN(n,x) if (ukbddebug>(n)) logprintf x
75 1.1 augustss int ukbddebug = 0;
76 1.1 augustss #else
77 1.1 augustss #define DPRINTF(x)
78 1.1 augustss #define DPRINTFN(n,x)
79 1.1 augustss #endif
80 1.1 augustss
81 1.75 augustss #define MAXKEYCODE 6
82 1.75 augustss #define MAXMOD 8 /* max 32 */
83 1.2 augustss
84 1.1 augustss struct ukbd_data {
85 1.75 augustss u_int32_t modifiers;
86 1.75 augustss u_int8_t keycode[MAXKEYCODE];
87 1.1 augustss };
88 1.1 augustss
89 1.23 augustss #define PRESS 0x000
90 1.23 augustss #define RELEASE 0x100
91 1.23 augustss #define CODEMASK 0x0ff
92 1.1 augustss
93 1.23 augustss #if defined(__NetBSD__) && defined(WSDISPLAY_COMPAT_RAWKBD)
94 1.5 augustss #define NN 0 /* no translation */
95 1.82 augustss /*
96 1.23 augustss * Translate USB keycodes to US keyboard XT scancodes.
97 1.76 augustss * Scancodes >= 0x80 represent EXTENDED keycodes.
98 1.76 augustss *
99 1.104 jakllsch * See http://www.microsoft.com/whdc/archive/scancode.mspx
100 1.104 jakllsch *
101 1.104 jakllsch * Note: a real pckbd(4) has more complexity in it's
102 1.104 jakllsch * protocol for some keys than this translation implements.
103 1.19 augustss */
104 1.65 jdolecek Static const u_int8_t ukbd_trtab[256] = {
105 1.76 augustss NN, NN, NN, NN, 0x1e, 0x30, 0x2e, 0x20, /* 00 - 07 */
106 1.76 augustss 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, /* 08 - 0f */
107 1.76 augustss 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, /* 10 - 17 */
108 1.76 augustss 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, 0x02, 0x03, /* 18 - 1f */
109 1.76 augustss 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, /* 20 - 27 */
110 1.76 augustss 0x1c, 0x01, 0x0e, 0x0f, 0x39, 0x0c, 0x0d, 0x1a, /* 28 - 2f */
111 1.76 augustss 0x1b, 0x2b, 0x2b, 0x27, 0x28, 0x29, 0x33, 0x34, /* 30 - 37 */
112 1.76 augustss 0x35, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, /* 38 - 3f */
113 1.104 jakllsch 0x41, 0x42, 0x43, 0x44, 0x57, 0x58, 0xb7, 0x46, /* 40 - 47 */
114 1.76 augustss 0x7f, 0xd2, 0xc7, 0xc9, 0xd3, 0xcf, 0xd1, 0xcd, /* 48 - 4f */
115 1.76 augustss 0xcb, 0xd0, 0xc8, 0x45, 0xb5, 0x37, 0x4a, 0x4e, /* 50 - 57 */
116 1.76 augustss 0x9c, 0x4f, 0x50, 0x51, 0x4b, 0x4c, 0x4d, 0x47, /* 58 - 5f */
117 1.76 augustss 0x48, 0x49, 0x52, 0x53, 0x56, 0xdd, NN, 0x59, /* 60 - 67 */
118 1.96 tron 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, NN, /* 68 - 6f */
119 1.76 augustss NN, NN, NN, NN, NN, NN, NN, NN, /* 70 - 77 */
120 1.76 augustss NN, NN, NN, NN, NN, NN, NN, NN, /* 78 - 7f */
121 1.76 augustss NN, NN, NN, NN, NN, 0x7e, NN, 0x73, /* 80 - 87 */
122 1.76 augustss 0x70, 0x7d, 0x79, 0x7b, 0x5c, NN, NN, NN, /* 88 - 8f */
123 1.76 augustss NN, NN, 0x78, 0x77, 0x76, NN, NN, NN, /* 90 - 97 */
124 1.76 augustss NN, NN, NN, NN, NN, NN, NN, NN, /* 98 - 9f */
125 1.76 augustss NN, NN, NN, NN, NN, NN, NN, NN, /* a0 - a7 */
126 1.76 augustss NN, NN, NN, NN, NN, NN, NN, NN, /* a8 - af */
127 1.76 augustss NN, NN, NN, NN, NN, NN, NN, NN, /* b0 - b7 */
128 1.76 augustss NN, NN, NN, NN, NN, NN, NN, NN, /* b8 - bf */
129 1.76 augustss NN, NN, NN, NN, NN, NN, NN, NN, /* c0 - c7 */
130 1.76 augustss NN, NN, NN, NN, NN, NN, NN, NN, /* c8 - cf */
131 1.76 augustss NN, NN, NN, NN, NN, NN, NN, NN, /* d0 - d7 */
132 1.76 augustss NN, NN, NN, NN, NN, NN, NN, NN, /* d8 - df */
133 1.76 augustss 0x1d, 0x2a, 0x38, 0xdb, 0x9d, 0x36, 0xb8, 0xdc, /* e0 - e7 */
134 1.76 augustss NN, NN, NN, NN, NN, NN, NN, NN, /* e8 - ef */
135 1.76 augustss NN, NN, NN, NN, NN, NN, NN, NN, /* f0 - f7 */
136 1.76 augustss NN, NN, NN, NN, NN, NN, NN, NN, /* f8 - ff */
137 1.1 augustss };
138 1.23 augustss #endif /* defined(__NetBSD__) && defined(WSDISPLAY_COMPAT_RAWKBD) */
139 1.1 augustss
140 1.1 augustss #define KEY_ERROR 0x01
141 1.1 augustss
142 1.75 augustss #define MAXKEYS (MAXMOD+2*MAXKEYCODE)
143 1.20 augustss
144 1.1 augustss struct ukbd_softc {
145 1.75 augustss struct uhidev sc_hdev;
146 1.1 augustss
147 1.1 augustss struct ukbd_data sc_ndata;
148 1.1 augustss struct ukbd_data sc_odata;
149 1.75 augustss struct hid_location sc_modloc[MAXMOD];
150 1.75 augustss u_int sc_nmod;
151 1.75 augustss struct {
152 1.75 augustss u_int32_t mask;
153 1.75 augustss u_int8_t key;
154 1.75 augustss } sc_mods[MAXMOD];
155 1.75 augustss
156 1.75 augustss struct hid_location sc_keycodeloc;
157 1.75 augustss u_int sc_nkeycode;
158 1.1 augustss
159 1.9 augustss char sc_enabled;
160 1.1 augustss
161 1.29 thorpej int sc_console_keyboard; /* we are the console keyboard */
162 1.29 thorpej
163 1.62 augustss char sc_debounce; /* for quirk handling */
164 1.70 augustss usb_callout_t sc_delay; /* for quirk handling */
165 1.62 augustss struct ukbd_data sc_data; /* for quirk handling */
166 1.62 augustss
167 1.75 augustss struct hid_location sc_numloc;
168 1.75 augustss struct hid_location sc_capsloc;
169 1.75 augustss struct hid_location sc_scroloc;
170 1.2 augustss int sc_leds;
171 1.16 augustss #if defined(__NetBSD__)
172 1.97 dyoung device_t sc_wskbddev;
173 1.57 thorpej
174 1.23 augustss #if defined(WSDISPLAY_COMPAT_RAWKBD)
175 1.87 augustss int sc_rawkbd;
176 1.87 augustss #if defined(UKBD_REPEAT)
177 1.87 augustss usb_callout_t sc_rawrepeat_ch;
178 1.20 augustss #define REP_DELAY1 400
179 1.20 augustss #define REP_DELAYN 100
180 1.20 augustss int sc_nrep;
181 1.20 augustss char sc_rep[MAXKEYS];
182 1.87 augustss #endif /* defined(UKBD_REPEAT) */
183 1.23 augustss #endif /* defined(WSDISPLAY_COMPAT_RAWKBD) */
184 1.3 augustss
185 1.84 augustss int sc_spl;
186 1.3 augustss int sc_polling;
187 1.23 augustss int sc_npollchar;
188 1.23 augustss u_int16_t sc_pollchars[MAXKEYS];
189 1.23 augustss #endif /* defined(__NetBSD__) */
190 1.40 augustss
191 1.40 augustss u_char sc_dying;
192 1.1 augustss };
193 1.1 augustss
194 1.62 augustss #ifdef UKBD_DEBUG
195 1.62 augustss #define UKBDTRACESIZE 64
196 1.62 augustss struct ukbdtraceinfo {
197 1.62 augustss int unit;
198 1.62 augustss struct timeval tv;
199 1.62 augustss struct ukbd_data ud;
200 1.62 augustss };
201 1.62 augustss struct ukbdtraceinfo ukbdtracedata[UKBDTRACESIZE];
202 1.62 augustss int ukbdtraceindex = 0;
203 1.62 augustss int ukbdtrace = 0;
204 1.62 augustss void ukbdtracedump(void);
205 1.62 augustss void
206 1.62 augustss ukbdtracedump(void)
207 1.62 augustss {
208 1.62 augustss int i;
209 1.62 augustss for (i = 0; i < UKBDTRACESIZE; i++) {
210 1.82 augustss struct ukbdtraceinfo *p =
211 1.62 augustss &ukbdtracedata[(i+ukbdtraceindex)%UKBDTRACESIZE];
212 1.102 cegger printf("%"PRIu64".%06"PRIu64": mod=0x%02x key0=0x%02x key1=0x%02x "
213 1.62 augustss "key2=0x%02x key3=0x%02x\n",
214 1.102 cegger p->tv.tv_sec, (uint64_t)p->tv.tv_usec,
215 1.62 augustss p->ud.modifiers, p->ud.keycode[0], p->ud.keycode[1],
216 1.62 augustss p->ud.keycode[2], p->ud.keycode[3]);
217 1.62 augustss }
218 1.62 augustss }
219 1.62 augustss #endif
220 1.62 augustss
221 1.1 augustss #define UKBDUNIT(dev) (minor(dev))
222 1.1 augustss #define UKBD_CHUNK 128 /* chunk size for read */
223 1.1 augustss #define UKBD_BSIZE 1020 /* buffer size */
224 1.1 augustss
225 1.58 augustss Static int ukbd_is_console;
226 1.31 thorpej
227 1.60 augustss Static void ukbd_cngetc(void *, u_int *, int *);
228 1.60 augustss Static void ukbd_cnpollc(void *, int);
229 1.3 augustss
230 1.16 augustss #if defined(__NetBSD__)
231 1.8 drochner const struct wskbd_consops ukbd_consops = {
232 1.8 drochner ukbd_cngetc,
233 1.8 drochner ukbd_cnpollc,
234 1.92 christos NULL, /* bell */
235 1.8 drochner };
236 1.16 augustss #endif
237 1.8 drochner
238 1.75 augustss Static const char *ukbd_parse_desc(struct ukbd_softc *sc);
239 1.75 augustss
240 1.75 augustss Static void ukbd_intr(struct uhidev *addr, void *ibuf, u_int len);
241 1.62 augustss Static void ukbd_decode(struct ukbd_softc *sc, struct ukbd_data *ud);
242 1.62 augustss Static void ukbd_delayed_decode(void *addr);
243 1.2 augustss
244 1.60 augustss Static int ukbd_enable(void *, int);
245 1.60 augustss Static void ukbd_set_leds(void *, int);
246 1.23 augustss
247 1.16 augustss #if defined(__NetBSD__)
248 1.95 christos Static int ukbd_ioctl(void *, u_long, void *, int, struct lwp *);
249 1.88 jonathan #if defined(WSDISPLAY_COMPAT_RAWKBD) && defined(UKBD_REPEAT)
250 1.60 augustss Static void ukbd_rawrepeat(void *v);
251 1.48 mjacob #endif
252 1.1 augustss
253 1.8 drochner const struct wskbd_accessops ukbd_accessops = {
254 1.8 drochner ukbd_enable,
255 1.8 drochner ukbd_set_leds,
256 1.8 drochner ukbd_ioctl,
257 1.8 drochner };
258 1.8 drochner
259 1.23 augustss extern const struct wscons_keydesc ukbd_keydesctab[];
260 1.23 augustss
261 1.8 drochner const struct wskbd_mapdata ukbd_keymapdata = {
262 1.23 augustss ukbd_keydesctab,
263 1.86 augustss #if defined(UKBD_LAYOUT)
264 1.66 augustss UKBD_LAYOUT,
265 1.86 augustss #elif defined(PCKBD_LAYOUT)
266 1.86 augustss PCKBD_LAYOUT,
267 1.66 augustss #else
268 1.8 drochner KB_US,
269 1.66 augustss #endif
270 1.8 drochner };
271 1.16 augustss #endif
272 1.8 drochner
273 1.100 cube static int ukbd_match(device_t, cfdata_t, void *);
274 1.97 dyoung static void ukbd_attach(device_t, device_t, void *);
275 1.97 dyoung static int ukbd_detach(device_t, int);
276 1.97 dyoung static int ukbd_activate(device_t, enum devact);
277 1.97 dyoung static void ukbd_childdet(device_t, device_t);
278 1.97 dyoung
279 1.97 dyoung extern struct cfdriver ukbd_cd;
280 1.97 dyoung
281 1.100 cube CFATTACH_DECL2_NEW(ukbd, sizeof(struct ukbd_softc), ukbd_match, ukbd_attach,
282 1.97 dyoung ukbd_detach, ukbd_activate, NULL, ukbd_childdet);
283 1.1 augustss
284 1.75 augustss int
285 1.100 cube ukbd_match(device_t parent, cfdata_t match, void *aux)
286 1.1 augustss {
287 1.75 augustss struct uhidev_attach_arg *uha = aux;
288 1.75 augustss int size;
289 1.75 augustss void *desc;
290 1.82 augustss
291 1.75 augustss uhidev_get_report_desc(uha->parent, &desc, &size);
292 1.75 augustss if (!hid_is_collection(desc, size, uha->reportid,
293 1.75 augustss HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD)))
294 1.1 augustss return (UMATCH_NONE);
295 1.75 augustss
296 1.75 augustss return (UMATCH_IFACECLASS);
297 1.1 augustss }
298 1.1 augustss
299 1.75 augustss void
300 1.97 dyoung ukbd_attach(device_t parent, device_t self, void *aux)
301 1.1 augustss {
302 1.97 dyoung struct ukbd_softc *sc = device_private(self);
303 1.75 augustss struct uhidev_attach_arg *uha = aux;
304 1.62 augustss u_int32_t qflags;
305 1.75 augustss const char *parseerr;
306 1.16 augustss #if defined(__NetBSD__)
307 1.2 augustss struct wskbddev_attach_args a;
308 1.16 augustss #else
309 1.16 augustss int i;
310 1.16 augustss #endif
311 1.82 augustss
312 1.100 cube sc->sc_hdev.sc_dev = self;
313 1.75 augustss sc->sc_hdev.sc_intr = ukbd_intr;
314 1.75 augustss sc->sc_hdev.sc_parent = uha->parent;
315 1.75 augustss sc->sc_hdev.sc_report_id = uha->reportid;
316 1.75 augustss
317 1.101 jmcneill if (!pmf_device_register(self, NULL, NULL)) {
318 1.101 jmcneill aprint_normal("\n");
319 1.101 jmcneill aprint_error_dev(self, "couldn't establish power handler\n");
320 1.101 jmcneill }
321 1.101 jmcneill
322 1.75 augustss parseerr = ukbd_parse_desc(sc);
323 1.75 augustss if (parseerr != NULL) {
324 1.98 cegger aprint_normal("\n");
325 1.100 cube aprint_error_dev(self, "attach failed, %s\n", parseerr);
326 1.16 augustss USB_ATTACH_ERROR_RETURN;
327 1.1 augustss }
328 1.82 augustss
329 1.75 augustss #ifdef DIAGNOSTIC
330 1.100 cube aprint_normal(": %d modifier keys, %d key codes", sc->sc_nmod,
331 1.75 augustss sc->sc_nkeycode);
332 1.75 augustss #endif
333 1.100 cube aprint_normal("\n");
334 1.1 augustss
335 1.75 augustss qflags = usbd_get_quirks(uha->parent->sc_udev)->uq_flags;
336 1.62 augustss sc->sc_debounce = (qflags & UQ_SPUR_BUT_UP) != 0;
337 1.20 augustss
338 1.29 thorpej /*
339 1.29 thorpej * Remember if we're the console keyboard.
340 1.29 thorpej *
341 1.31 thorpej * XXX This always picks the first keyboard on the
342 1.31 thorpej * first USB bus, but what else can we really do?
343 1.29 thorpej */
344 1.31 thorpej if ((sc->sc_console_keyboard = ukbd_is_console) != 0) {
345 1.29 thorpej /* Don't let any other keyboard have it. */
346 1.31 thorpej ukbd_is_console = 0;
347 1.29 thorpej }
348 1.29 thorpej
349 1.31 thorpej if (sc->sc_console_keyboard) {
350 1.32 augustss DPRINTF(("ukbd_attach: console keyboard sc=%p\n", sc));
351 1.31 thorpej wskbd_cnattach(&ukbd_consops, sc, &ukbd_keymapdata);
352 1.34 wrstuden ukbd_enable(sc, 1);
353 1.31 thorpej }
354 1.29 thorpej
355 1.29 thorpej a.console = sc->sc_console_keyboard;
356 1.8 drochner
357 1.8 drochner a.keymap = &ukbd_keymapdata;
358 1.8 drochner
359 1.8 drochner a.accessops = &ukbd_accessops;
360 1.2 augustss a.accesscookie = sc;
361 1.8 drochner
362 1.87 augustss #ifdef UKBD_REPEAT
363 1.70 augustss usb_callout_init(sc->sc_rawrepeat_ch);
364 1.87 augustss #endif
365 1.57 thorpej
366 1.70 augustss usb_callout_init(sc->sc_delay);
367 1.62 augustss
368 1.19 augustss /* Flash the leds; no real purpose, just shows we're alive. */
369 1.19 augustss ukbd_set_leds(sc, WSKBD_LED_SCROLL | WSKBD_LED_NUM | WSKBD_LED_CAPS);
370 1.75 augustss usbd_delay_ms(uha->parent->sc_udev, 400);
371 1.19 augustss ukbd_set_leds(sc, 0);
372 1.19 augustss
373 1.64 augustss sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
374 1.55 augustss
375 1.16 augustss USB_ATTACH_SUCCESS_RETURN;
376 1.1 augustss }
377 1.1 augustss
378 1.8 drochner int
379 1.60 augustss ukbd_enable(void *v, int on)
380 1.8 drochner {
381 1.9 augustss struct ukbd_softc *sc = v;
382 1.9 augustss
383 1.40 augustss if (on && sc->sc_dying)
384 1.40 augustss return (EIO);
385 1.40 augustss
386 1.38 augustss /* Should only be called to change state */
387 1.38 augustss if (sc->sc_enabled == on) {
388 1.38 augustss #ifdef DIAGNOSTIC
389 1.82 augustss printf("ukbd_enable: %s: bad call on=%d\n",
390 1.75 augustss USBDEVNAME(sc->sc_hdev.sc_dev), on);
391 1.38 augustss #endif
392 1.38 augustss return (EBUSY);
393 1.38 augustss }
394 1.38 augustss
395 1.33 augustss DPRINTF(("ukbd_enable: sc=%p on=%d\n", sc, on));
396 1.75 augustss sc->sc_enabled = on;
397 1.9 augustss if (on) {
398 1.75 augustss return (uhidev_open(&sc->sc_hdev));
399 1.9 augustss } else {
400 1.75 augustss uhidev_close(&sc->sc_hdev);
401 1.75 augustss return (0);
402 1.9 augustss }
403 1.37 augustss }
404 1.37 augustss
405 1.97 dyoung
406 1.97 dyoung static void
407 1.97 dyoung ukbd_childdet(device_t self, device_t child)
408 1.97 dyoung {
409 1.97 dyoung struct ukbd_softc *sc = device_private(self);
410 1.97 dyoung
411 1.97 dyoung KASSERT(sc->sc_wskbddev == child);
412 1.97 dyoung sc->sc_wskbddev = NULL;
413 1.97 dyoung }
414 1.97 dyoung
415 1.37 augustss int
416 1.97 dyoung ukbd_activate(device_t self, enum devact act)
417 1.37 augustss {
418 1.97 dyoung struct ukbd_softc *sc = device_private(self);
419 1.40 augustss
420 1.40 augustss switch (act) {
421 1.40 augustss case DVACT_DEACTIVATE:
422 1.40 augustss sc->sc_dying = 1;
423 1.105 dyoung return 0;
424 1.105 dyoung default:
425 1.105 dyoung return EOPNOTSUPP;
426 1.40 augustss }
427 1.37 augustss }
428 1.37 augustss
429 1.75 augustss int
430 1.97 dyoung ukbd_detach(device_t self, int flags)
431 1.37 augustss {
432 1.97 dyoung struct ukbd_softc *sc = device_private(self);
433 1.37 augustss int rv = 0;
434 1.37 augustss
435 1.37 augustss DPRINTF(("ukbd_detach: sc=%p flags=%d\n", sc, flags));
436 1.46 augustss
437 1.101 jmcneill pmf_device_deregister(self);
438 1.101 jmcneill
439 1.37 augustss if (sc->sc_console_keyboard) {
440 1.50 augustss #if 0
441 1.37 augustss /*
442 1.37 augustss * XXX Should probably disconnect our consops,
443 1.37 augustss * XXX and either notify some other keyboard that
444 1.37 augustss * XXX it can now be the console, or if there aren't
445 1.37 augustss * XXX any more USB keyboards, set ukbd_is_console
446 1.37 augustss * XXX back to 1 so that the next USB keyboard attached
447 1.37 augustss * XXX to the system will get it.
448 1.37 augustss */
449 1.37 augustss panic("ukbd_detach: console keyboard");
450 1.50 augustss #else
451 1.51 augustss /*
452 1.51 augustss * Disconnect our consops and set ukbd_is_console
453 1.51 augustss * back to 1 so that the next USB keyboard attached
454 1.51 augustss * to the system will get it.
455 1.51 augustss * XXX Should notify some other keyboard that it can be
456 1.51 augustss * XXX console, if there are any other keyboards.
457 1.51 augustss */
458 1.75 augustss printf("%s: was console keyboard\n",
459 1.75 augustss USBDEVNAME(sc->sc_hdev.sc_dev));
460 1.50 augustss wskbd_cndetach();
461 1.50 augustss ukbd_is_console = 1;
462 1.50 augustss #endif
463 1.37 augustss }
464 1.45 augustss /* No need to do reference counting of ukbd, wskbd has all the goo. */
465 1.47 augustss if (sc->sc_wskbddev != NULL)
466 1.37 augustss rv = config_detach(sc->sc_wskbddev, flags);
467 1.68 augustss
468 1.68 augustss /* The console keyboard does not get a disable call, so check pipe. */
469 1.75 augustss if (sc->sc_hdev.sc_state & UHIDEV_OPEN)
470 1.75 augustss uhidev_close(&sc->sc_hdev);
471 1.55 augustss
472 1.37 augustss return (rv);
473 1.1 augustss }
474 1.1 augustss
475 1.1 augustss void
476 1.94 christos ukbd_intr(struct uhidev *addr, void *ibuf, u_int len)
477 1.1 augustss {
478 1.75 augustss struct ukbd_softc *sc = (struct ukbd_softc *)addr;
479 1.1 augustss struct ukbd_data *ud = &sc->sc_ndata;
480 1.75 augustss int i;
481 1.76 augustss
482 1.76 augustss #ifdef UKBD_DEBUG
483 1.76 augustss if (ukbddebug > 5) {
484 1.76 augustss printf("ukbd_intr: data");
485 1.76 augustss for (i = 0; i < len; i++)
486 1.78 augustss printf(" 0x%02x", ((u_char *)ibuf)[i]);
487 1.76 augustss printf("\n");
488 1.76 augustss }
489 1.76 augustss #endif
490 1.76 augustss
491 1.75 augustss ud->modifiers = 0;
492 1.75 augustss for (i = 0; i < sc->sc_nmod; i++)
493 1.75 augustss if (hid_get_data(ibuf, &sc->sc_modloc[i]))
494 1.80 augustss ud->modifiers |= sc->sc_mods[i].mask;
495 1.75 augustss memcpy(ud->keycode, (char *)ibuf + sc->sc_keycodeloc.pos / 8,
496 1.75 augustss sc->sc_nkeycode);
497 1.1 augustss
498 1.69 augustss if (sc->sc_debounce && !sc->sc_polling) {
499 1.62 augustss /*
500 1.62 augustss * Some keyboards have a peculiar quirk. They sometimes
501 1.62 augustss * generate a key up followed by a key down for the same
502 1.62 augustss * key after about 10 ms.
503 1.62 augustss * We avoid this bug by holding off decoding for 20 ms.
504 1.62 augustss */
505 1.62 augustss sc->sc_data = *ud;
506 1.70 augustss usb_callout(sc->sc_delay, hz / 50, ukbd_delayed_decode, sc);
507 1.74 lukem #ifdef DDB
508 1.69 augustss } else if (sc->sc_console_keyboard && !sc->sc_polling) {
509 1.69 augustss /*
510 1.69 augustss * For the console keyboard we can't deliver CTL-ALT-ESC
511 1.69 augustss * from the interrupt routine. Doing so would start
512 1.69 augustss * polling from inside the interrupt routine and that
513 1.69 augustss * loses bigtime.
514 1.69 augustss */
515 1.69 augustss sc->sc_data = *ud;
516 1.70 augustss usb_callout(sc->sc_delay, 1, ukbd_delayed_decode, sc);
517 1.69 augustss #endif
518 1.62 augustss } else {
519 1.62 augustss ukbd_decode(sc, ud);
520 1.62 augustss }
521 1.62 augustss }
522 1.62 augustss
523 1.62 augustss void
524 1.62 augustss ukbd_delayed_decode(void *addr)
525 1.62 augustss {
526 1.62 augustss struct ukbd_softc *sc = addr;
527 1.62 augustss
528 1.62 augustss ukbd_decode(sc, &sc->sc_data);
529 1.62 augustss }
530 1.62 augustss
531 1.62 augustss void
532 1.62 augustss ukbd_decode(struct ukbd_softc *sc, struct ukbd_data *ud)
533 1.62 augustss {
534 1.62 augustss int mod, omod;
535 1.62 augustss u_int16_t ibuf[MAXKEYS]; /* chars events */
536 1.62 augustss int s;
537 1.62 augustss int nkeys, i, j;
538 1.62 augustss int key;
539 1.62 augustss #define ADDKEY(c) ibuf[nkeys++] = (c)
540 1.62 augustss
541 1.62 augustss #ifdef UKBD_DEBUG
542 1.82 augustss /*
543 1.62 augustss * Keep a trace of the last events. Using printf changes the
544 1.62 augustss * timing, so this can be useful sometimes.
545 1.62 augustss */
546 1.62 augustss if (ukbdtrace) {
547 1.62 augustss struct ukbdtraceinfo *p = &ukbdtracedata[ukbdtraceindex];
548 1.100 cube p->unit = device_unit(sc->sc_hdev.sc_dev);
549 1.62 augustss microtime(&p->tv);
550 1.62 augustss p->ud = *ud;
551 1.62 augustss if (++ukbdtraceindex >= UKBDTRACESIZE)
552 1.62 augustss ukbdtraceindex = 0;
553 1.62 augustss }
554 1.62 augustss if (ukbddebug > 5) {
555 1.62 augustss struct timeval tv;
556 1.62 augustss microtime(&tv);
557 1.102 cegger DPRINTF((" at %"PRIu64".%06"PRIu64" mod=0x%02x key0=0x%02x key1=0x%02x "
558 1.62 augustss "key2=0x%02x key3=0x%02x\n",
559 1.102 cegger tv.tv_sec, (uint64_t)tv.tv_usec,
560 1.62 augustss ud->modifiers, ud->keycode[0], ud->keycode[1],
561 1.62 augustss ud->keycode[2], ud->keycode[3]));
562 1.62 augustss }
563 1.62 augustss #endif
564 1.1 augustss
565 1.53 augustss if (ud->keycode[0] == KEY_ERROR) {
566 1.53 augustss DPRINTF(("ukbd_intr: KEY_ERROR\n"));
567 1.1 augustss return; /* ignore */
568 1.53 augustss }
569 1.1 augustss nkeys = 0;
570 1.1 augustss mod = ud->modifiers;
571 1.1 augustss omod = sc->sc_odata.modifiers;
572 1.1 augustss if (mod != omod)
573 1.75 augustss for (i = 0; i < sc->sc_nmod; i++)
574 1.82 augustss if (( mod & sc->sc_mods[i].mask) !=
575 1.75 augustss (omod & sc->sc_mods[i].mask))
576 1.82 augustss ADDKEY(sc->sc_mods[i].key |
577 1.82 augustss (mod & sc->sc_mods[i].mask
578 1.1 augustss ? PRESS : RELEASE));
579 1.75 augustss if (memcmp(ud->keycode, sc->sc_odata.keycode, sc->sc_nkeycode) != 0) {
580 1.1 augustss /* Check for released keys. */
581 1.75 augustss for (i = 0; i < sc->sc_nkeycode; i++) {
582 1.1 augustss key = sc->sc_odata.keycode[i];
583 1.1 augustss if (key == 0)
584 1.1 augustss continue;
585 1.75 augustss for (j = 0; j < sc->sc_nkeycode; j++)
586 1.1 augustss if (key == ud->keycode[j])
587 1.1 augustss goto rfound;
588 1.62 augustss DPRINTFN(3,("ukbd_intr: relse key=0x%02x\n", key));
589 1.23 augustss ADDKEY(key | RELEASE);
590 1.1 augustss rfound:
591 1.1 augustss ;
592 1.1 augustss }
593 1.82 augustss
594 1.1 augustss /* Check for pressed keys. */
595 1.75 augustss for (i = 0; i < sc->sc_nkeycode; i++) {
596 1.1 augustss key = ud->keycode[i];
597 1.1 augustss if (key == 0)
598 1.1 augustss continue;
599 1.75 augustss for (j = 0; j < sc->sc_nkeycode; j++)
600 1.1 augustss if (key == sc->sc_odata.keycode[j])
601 1.1 augustss goto pfound;
602 1.23 augustss DPRINTFN(2,("ukbd_intr: press key=0x%02x\n", key));
603 1.23 augustss ADDKEY(key | PRESS);
604 1.1 augustss pfound:
605 1.1 augustss ;
606 1.1 augustss }
607 1.1 augustss }
608 1.1 augustss sc->sc_odata = *ud;
609 1.1 augustss
610 1.20 augustss if (nkeys == 0)
611 1.20 augustss return;
612 1.20 augustss
613 1.3 augustss if (sc->sc_polling) {
614 1.23 augustss DPRINTFN(1,("ukbd_intr: pollchar = 0x%03x\n", ibuf[0]));
615 1.23 augustss memcpy(sc->sc_pollchars, ibuf, nkeys * sizeof(u_int16_t));
616 1.23 augustss sc->sc_npollchar = nkeys;
617 1.3 augustss return;
618 1.3 augustss }
619 1.20 augustss #ifdef WSDISPLAY_COMPAT_RAWKBD
620 1.19 augustss if (sc->sc_rawkbd) {
621 1.79 augustss u_char cbuf[MAXKEYS * 2];
622 1.24 augustss int c;
623 1.20 augustss int npress;
624 1.20 augustss
625 1.23 augustss for (npress = i = j = 0; i < nkeys; i++) {
626 1.23 augustss key = ibuf[i];
627 1.23 augustss c = ukbd_trtab[key & CODEMASK];
628 1.23 augustss if (c == NN)
629 1.23 augustss continue;
630 1.104 jakllsch if (c == 0x7f) {
631 1.104 jakllsch /* pause key */
632 1.104 jakllsch cbuf[j++] = 0xe1;
633 1.104 jakllsch cbuf[j++] = 0x1d;
634 1.104 jakllsch cbuf[j-1] |= (key & RELEASE) ? 0x80 : 0;
635 1.104 jakllsch cbuf[j] = 0x45;
636 1.104 jakllsch } else {
637 1.104 jakllsch if (c & 0x80)
638 1.104 jakllsch cbuf[j++] = 0xe0;
639 1.104 jakllsch cbuf[j] = c & 0x7f;
640 1.104 jakllsch }
641 1.23 augustss if (key & RELEASE)
642 1.19 augustss cbuf[j] |= 0x80;
643 1.87 augustss #if defined(UKBD_REPEAT)
644 1.20 augustss else {
645 1.23 augustss /* remember pressed keys for autorepeat */
646 1.20 augustss if (c & 0x80)
647 1.20 augustss sc->sc_rep[npress++] = 0xe0;
648 1.20 augustss sc->sc_rep[npress++] = c & 0x7f;
649 1.20 augustss }
650 1.87 augustss #endif
651 1.82 augustss DPRINTFN(1,("ukbd_intr: raw = %s0x%02x\n",
652 1.27 augustss c & 0x80 ? "0xe0 " : "",
653 1.27 augustss cbuf[j]));
654 1.23 augustss j++;
655 1.19 augustss }
656 1.30 augustss s = spltty();
657 1.19 augustss wskbd_rawinput(sc->sc_wskbddev, cbuf, j);
658 1.30 augustss splx(s);
659 1.87 augustss #ifdef UKBD_REPEAT
660 1.70 augustss usb_uncallout(sc->sc_rawrepeat_ch, ukbd_rawrepeat, sc);
661 1.20 augustss if (npress != 0) {
662 1.20 augustss sc->sc_nrep = npress;
663 1.70 augustss usb_callout(sc->sc_rawrepeat_ch,
664 1.57 thorpej hz * REP_DELAY1 / 1000, ukbd_rawrepeat, sc);
665 1.20 augustss }
666 1.87 augustss #endif
667 1.19 augustss return;
668 1.19 augustss }
669 1.19 augustss #endif
670 1.19 augustss
671 1.30 augustss s = spltty();
672 1.2 augustss for (i = 0; i < nkeys; i++) {
673 1.23 augustss key = ibuf[i];
674 1.82 augustss wskbd_input(sc->sc_wskbddev,
675 1.23 augustss key&RELEASE ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN,
676 1.23 augustss key&CODEMASK);
677 1.20 augustss }
678 1.30 augustss splx(s);
679 1.1 augustss }
680 1.1 augustss
681 1.2 augustss void
682 1.60 augustss ukbd_set_leds(void *v, int leds)
683 1.1 augustss {
684 1.2 augustss struct ukbd_softc *sc = v;
685 1.2 augustss u_int8_t res;
686 1.1 augustss
687 1.71 augustss DPRINTF(("ukbd_set_leds: sc=%p leds=%d, sc_leds=%d\n",
688 1.71 augustss sc, leds, sc->sc_leds));
689 1.40 augustss
690 1.40 augustss if (sc->sc_dying)
691 1.40 augustss return;
692 1.1 augustss
693 1.71 augustss if (sc->sc_leds == leds)
694 1.71 augustss return;
695 1.2 augustss sc->sc_leds = leds;
696 1.2 augustss res = 0;
697 1.75 augustss /* XXX not really right */
698 1.75 augustss if ((leds & WSKBD_LED_SCROLL) && sc->sc_scroloc.size == 1)
699 1.75 augustss res |= 1 << sc->sc_scroloc.pos;
700 1.75 augustss if ((leds & WSKBD_LED_NUM) && sc->sc_numloc.size == 1)
701 1.75 augustss res |= 1 << sc->sc_numloc.pos;
702 1.75 augustss if ((leds & WSKBD_LED_CAPS) && sc->sc_capsloc.size == 1)
703 1.75 augustss res |= 1 << sc->sc_capsloc.pos;
704 1.75 augustss uhidev_set_report_async(&sc->sc_hdev, UHID_OUTPUT_REPORT, &res, 1);
705 1.1 augustss }
706 1.1 augustss
707 1.87 augustss #if defined(WSDISPLAY_COMPAT_RAWKBD) && defined(UKBD_REPEAT)
708 1.20 augustss void
709 1.60 augustss ukbd_rawrepeat(void *v)
710 1.20 augustss {
711 1.20 augustss struct ukbd_softc *sc = v;
712 1.30 augustss int s;
713 1.20 augustss
714 1.30 augustss s = spltty();
715 1.20 augustss wskbd_rawinput(sc->sc_wskbddev, sc->sc_rep, sc->sc_nrep);
716 1.30 augustss splx(s);
717 1.70 augustss usb_callout(sc->sc_rawrepeat_ch, hz * REP_DELAYN / 1000,
718 1.57 thorpej ukbd_rawrepeat, sc);
719 1.20 augustss }
720 1.87 augustss #endif /* defined(WSDISPLAY_COMPAT_RAWKBD) && defined(UKBD_REPEAT) */
721 1.20 augustss
722 1.1 augustss int
723 1.95 christos ukbd_ioctl(void *v, u_long cmd, void *data, int flag,
724 1.94 christos struct lwp *l)
725 1.1 augustss {
726 1.2 augustss struct ukbd_softc *sc = v;
727 1.1 augustss
728 1.2 augustss switch (cmd) {
729 1.2 augustss case WSKBDIO_GTYPE:
730 1.20 augustss *(int *)data = WSKBD_TYPE_USB;
731 1.17 augustss return (0);
732 1.2 augustss case WSKBDIO_SETLEDS:
733 1.2 augustss ukbd_set_leds(v, *(int *)data);
734 1.17 augustss return (0);
735 1.2 augustss case WSKBDIO_GETLEDS:
736 1.2 augustss *(int *)data = sc->sc_leds;
737 1.2 augustss return (0);
738 1.87 augustss #if defined(WSDISPLAY_COMPAT_RAWKBD)
739 1.2 augustss case WSKBDIO_SETMODE:
740 1.19 augustss DPRINTF(("ukbd_ioctl: set raw = %d\n", *(int *)data));
741 1.2 augustss sc->sc_rawkbd = *(int *)data == WSKBD_RAW;
742 1.87 augustss #if defined(UKBD_REPEAT)
743 1.70 augustss usb_uncallout(sc->sc_rawrepeat_ch, ukbd_rawrepeat, sc);
744 1.87 augustss #endif
745 1.2 augustss return (0);
746 1.2 augustss #endif
747 1.2 augustss }
748 1.81 atatat return (EPASSTHROUGH);
749 1.1 augustss }
750 1.7 augustss
751 1.71 augustss /*
752 1.71 augustss * This is a hack to work around some broken ports that don't call
753 1.71 augustss * cnpollc() before cngetc().
754 1.71 augustss */
755 1.71 augustss static int pollenter, warned;
756 1.71 augustss
757 1.7 augustss /* Console interface. */
758 1.3 augustss void
759 1.60 augustss ukbd_cngetc(void *v, u_int *type, int *data)
760 1.3 augustss {
761 1.3 augustss struct ukbd_softc *sc = v;
762 1.4 augustss int c;
763 1.71 augustss int broken;
764 1.71 augustss
765 1.71 augustss if (pollenter == 0) {
766 1.71 augustss if (!warned) {
767 1.71 augustss printf("\n"
768 1.71 augustss "This port is broken, it does not call cnpollc() before calling cngetc().\n"
769 1.71 augustss "This should be fixed, but it will work anyway (for now).\n");
770 1.71 augustss warned = 1;
771 1.71 augustss }
772 1.71 augustss broken = 1;
773 1.71 augustss ukbd_cnpollc(v, 1);
774 1.71 augustss } else
775 1.71 augustss broken = 0;
776 1.3 augustss
777 1.50 augustss DPRINTFN(0,("ukbd_cngetc: enter\n"));
778 1.3 augustss sc->sc_polling = 1;
779 1.23 augustss while(sc->sc_npollchar <= 0)
780 1.75 augustss usbd_dopoll(sc->sc_hdev.sc_parent->sc_iface);
781 1.3 augustss sc->sc_polling = 0;
782 1.23 augustss c = sc->sc_pollchars[0];
783 1.23 augustss sc->sc_npollchar--;
784 1.82 augustss memcpy(sc->sc_pollchars, sc->sc_pollchars+1,
785 1.23 augustss sc->sc_npollchar * sizeof(u_int16_t));
786 1.6 augustss *type = c & RELEASE ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN;
787 1.23 augustss *data = c & CODEMASK;
788 1.50 augustss DPRINTFN(0,("ukbd_cngetc: return 0x%02x\n", c));
789 1.71 augustss if (broken)
790 1.71 augustss ukbd_cnpollc(v, 0);
791 1.3 augustss }
792 1.3 augustss
793 1.3 augustss void
794 1.60 augustss ukbd_cnpollc(void *v, int on)
795 1.3 augustss {
796 1.6 augustss struct ukbd_softc *sc = v;
797 1.52 augustss usbd_device_handle dev;
798 1.6 augustss
799 1.19 augustss DPRINTFN(2,("ukbd_cnpollc: sc=%p on=%d\n", v, on));
800 1.6 augustss
801 1.75 augustss usbd_interface2device_handle(sc->sc_hdev.sc_parent->sc_iface, &dev);
802 1.84 augustss if (on) {
803 1.84 augustss sc->sc_spl = splusb();
804 1.84 augustss pollenter++;
805 1.84 augustss } else {
806 1.84 augustss splx(sc->sc_spl);
807 1.84 augustss pollenter--;
808 1.84 augustss }
809 1.52 augustss usbd_set_polling(dev, on);
810 1.3 augustss }
811 1.18 augustss
812 1.18 augustss int
813 1.60 augustss ukbd_cnattach(void)
814 1.18 augustss {
815 1.18 augustss
816 1.31 thorpej /*
817 1.31 thorpej * XXX USB requires too many parts of the kernel to be running
818 1.31 thorpej * XXX in order to work, so we can't do much for the console
819 1.31 thorpej * XXX keyboard until autconfiguration has run its course.
820 1.31 thorpej */
821 1.31 thorpej ukbd_is_console = 1;
822 1.18 augustss return (0);
823 1.75 augustss }
824 1.75 augustss
825 1.75 augustss const char *
826 1.75 augustss ukbd_parse_desc(struct ukbd_softc *sc)
827 1.75 augustss {
828 1.75 augustss struct hid_data *d;
829 1.75 augustss struct hid_item h;
830 1.75 augustss int size;
831 1.75 augustss void *desc;
832 1.75 augustss int imod;
833 1.75 augustss
834 1.75 augustss uhidev_get_report_desc(sc->sc_hdev.sc_parent, &desc, &size);
835 1.75 augustss imod = 0;
836 1.75 augustss sc->sc_nkeycode = 0;
837 1.75 augustss d = hid_start_parse(desc, size, hid_input);
838 1.75 augustss while (hid_get_item(d, &h)) {
839 1.75 augustss /*printf("ukbd: id=%d kind=%d usage=0x%x flags=0x%x pos=%d size=%d cnt=%d\n",
840 1.75 augustss h.report_ID, h.kind, h.usage, h.flags, h.loc.pos, h.loc.size, h.loc.count);*/
841 1.75 augustss if (h.kind != hid_input || (h.flags & HIO_CONST) ||
842 1.75 augustss HID_GET_USAGE_PAGE(h.usage) != HUP_KEYBOARD ||
843 1.75 augustss h.report_ID != sc->sc_hdev.sc_report_id)
844 1.75 augustss continue;
845 1.79 augustss DPRINTF(("ukbd: imod=%d usage=0x%x flags=0x%x pos=%d size=%d "
846 1.79 augustss "cnt=%d\n", imod,
847 1.79 augustss h.usage, h.flags, h.loc.pos, h.loc.size, h.loc.count));
848 1.75 augustss if (h.flags & HIO_VARIABLE) {
849 1.80 augustss if (h.loc.size != 1)
850 1.80 augustss return ("bad modifier size");
851 1.75 augustss /* Single item */
852 1.75 augustss if (imod < MAXMOD) {
853 1.75 augustss sc->sc_modloc[imod] = h.loc;
854 1.75 augustss sc->sc_mods[imod].mask = 1 << imod;
855 1.75 augustss sc->sc_mods[imod].key = HID_GET_USAGE(h.usage);
856 1.75 augustss imod++;
857 1.75 augustss } else
858 1.75 augustss return ("too many modifier keys");
859 1.75 augustss } else {
860 1.75 augustss /* Array */
861 1.75 augustss if (h.loc.size != 8)
862 1.75 augustss return ("key code size != 8");
863 1.75 augustss if (h.loc.count > MAXKEYCODE)
864 1.75 augustss return ("too many key codes");
865 1.75 augustss if (h.loc.pos % 8 != 0)
866 1.75 augustss return ("key codes not on byte boundary");
867 1.75 augustss if (sc->sc_nkeycode != 0)
868 1.75 augustss return ("multiple key code arrays\n");
869 1.75 augustss sc->sc_keycodeloc = h.loc;
870 1.75 augustss sc->sc_nkeycode = h.loc.count;
871 1.75 augustss }
872 1.75 augustss }
873 1.75 augustss sc->sc_nmod = imod;
874 1.75 augustss hid_end_parse(d);
875 1.75 augustss
876 1.75 augustss hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_NUM_LOCK),
877 1.75 augustss sc->sc_hdev.sc_report_id, hid_output, &sc->sc_numloc, NULL);
878 1.75 augustss hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_CAPS_LOCK),
879 1.75 augustss sc->sc_hdev.sc_report_id, hid_output, &sc->sc_capsloc, NULL);
880 1.75 augustss hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_SCROLL_LOCK),
881 1.75 augustss sc->sc_hdev.sc_report_id, hid_output, &sc->sc_scroloc, NULL);
882 1.75 augustss
883 1.75 augustss return (NULL);
884 1.18 augustss }
885