ukbd.c revision 1.115 1 1.115 jakllsch /* $NetBSD: ukbd.c,v 1.115 2011/12/23 00:51:47 jakllsch 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.115 jakllsch __KERNEL_RCSID(0, "$NetBSD: ukbd.c,v 1.115 2011/12/23 00:51:47 jakllsch 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.106 pooka #ifdef _KERNEL_OPT
69 1.113 macallan #include "opt_ukbd.h"
70 1.89 cube #include "opt_ukbd_layout.h"
71 1.2 augustss #include "opt_wsdisplay_compat.h"
72 1.69 augustss #include "opt_ddb.h"
73 1.106 pooka #endif /* _KERNEL_OPT */
74 1.21 augustss
75 1.62 augustss #ifdef UKBD_DEBUG
76 1.108 dyoung #define DPRINTF(x) if (ukbddebug) printf x
77 1.108 dyoung #define DPRINTFN(n,x) if (ukbddebug>(n)) printf x
78 1.1 augustss int ukbddebug = 0;
79 1.1 augustss #else
80 1.1 augustss #define DPRINTF(x)
81 1.1 augustss #define DPRINTFN(n,x)
82 1.1 augustss #endif
83 1.1 augustss
84 1.75 augustss #define MAXKEYCODE 6
85 1.75 augustss #define MAXMOD 8 /* max 32 */
86 1.2 augustss
87 1.1 augustss struct ukbd_data {
88 1.75 augustss u_int32_t modifiers;
89 1.75 augustss u_int8_t keycode[MAXKEYCODE];
90 1.1 augustss };
91 1.1 augustss
92 1.23 augustss #define PRESS 0x000
93 1.23 augustss #define RELEASE 0x100
94 1.23 augustss #define CODEMASK 0x0ff
95 1.1 augustss
96 1.109 phx struct ukbd_keycodetrans {
97 1.112 macallan u_int16_t from;
98 1.112 macallan u_int16_t to;
99 1.109 phx };
100 1.109 phx
101 1.112 macallan #define IS_PMF 0x8000
102 1.112 macallan
103 1.109 phx Static const struct ukbd_keycodetrans trtab_apple_fn[] = {
104 1.109 phx { 0x0c, 0x5d }, /* i -> KP 5 */
105 1.109 phx { 0x0d, 0x59 }, /* j -> KP 1 */
106 1.109 phx { 0x0e, 0x5a }, /* k -> KP 2 */
107 1.109 phx { 0x0f, 0x5b }, /* l -> KP 3 */
108 1.109 phx { 0x10, 0x62 }, /* m -> KP 0 */
109 1.109 phx { 0x12, 0x5e }, /* o -> KP 6 */
110 1.109 phx { 0x13, 0x55 }, /* o -> KP * */
111 1.109 phx { 0x18, 0x5c }, /* u -> KP 4 */
112 1.109 phx { 0x0c, 0x5d }, /* i -> KP 5 */
113 1.109 phx { 0x2a, 0x4c }, /* Backspace -> Delete */
114 1.109 phx { 0x28, 0x49 }, /* Return -> Insert */
115 1.109 phx { 0x24, 0x5f }, /* 7 -> KP 7 */
116 1.109 phx { 0x25, 0x60 }, /* 8 -> KP 8 */
117 1.109 phx { 0x26, 0x61 }, /* 9 -> KP 9 */
118 1.109 phx { 0x27, 0x54 }, /* 0 -> KP / */
119 1.109 phx { 0x2d, 0x67 }, /* - -> KP = */
120 1.109 phx { 0x33, 0x56 }, /* ; -> KP - */
121 1.109 phx { 0x37, 0x63 }, /* . -> KP . */
122 1.109 phx { 0x38, 0x57 }, /* / -> KP + */
123 1.109 phx { 0x3a, 0xd1 }, /* F1..F12 mapped to reserved codes 0xd1..0xdc */
124 1.109 phx { 0x3b, 0xd2 },
125 1.109 phx { 0x3c, 0xd3 },
126 1.109 phx { 0x3d, 0xd4 },
127 1.109 phx { 0x3e, 0xd5 },
128 1.109 phx { 0x3f, 0xd6 },
129 1.109 phx { 0x40, 0xd7 },
130 1.109 phx { 0x41, 0xd8 },
131 1.109 phx { 0x42, 0xd9 },
132 1.109 phx { 0x43, 0xda },
133 1.109 phx { 0x44, 0xdb },
134 1.109 phx { 0x45, 0xdc },
135 1.109 phx { 0x4f, 0x4d }, /* Right -> End */
136 1.109 phx { 0x50, 0x4a }, /* Left -> Home */
137 1.109 phx { 0x51, 0x4e }, /* Down -> PageDown */
138 1.109 phx { 0x52, 0x4b }, /* Up -> PageUp */
139 1.109 phx { 0x00, 0x00 }
140 1.109 phx };
141 1.109 phx
142 1.109 phx Static const struct ukbd_keycodetrans trtab_apple_iso[] = {
143 1.109 phx { 0x35, 0x64 }, /* swap the key above tab with key right of shift */
144 1.109 phx { 0x64, 0x35 },
145 1.109 phx { 0x31, 0x32 }, /* key left of return is Europe1, not "\|" */
146 1.109 phx { 0x00, 0x00 }
147 1.109 phx };
148 1.109 phx
149 1.113 macallan #ifdef GDIUM_KEYBOARD_HACK
150 1.115 jakllsch Static const struct ukbd_keycodetrans trtab_gdium_fn[] = {
151 1.111 macallan #ifdef notyet
152 1.111 macallan { 58, 0 }, /* F1 -> toggle camera */
153 1.111 macallan { 59, 0 }, /* F2 -> toggle wireless */
154 1.111 macallan #endif
155 1.112 macallan { 60, IS_PMF | PMFE_AUDIO_VOLUME_TOGGLE },
156 1.112 macallan { 61, IS_PMF | PMFE_AUDIO_VOLUME_UP },
157 1.112 macallan { 62, IS_PMF | PMFE_AUDIO_VOLUME_DOWN },
158 1.111 macallan #ifdef notyet
159 1.111 macallan { 63, 0 }, /* F6 -> toggle ext. video */
160 1.111 macallan { 64, 0 }, /* F7 -> toggle mouse */
161 1.112 macallan #endif
162 1.112 macallan { 65, IS_PMF | PMFE_DISPLAY_BRIGHTNESS_UP },
163 1.112 macallan { 66, IS_PMF | PMFE_DISPLAY_BRIGHTNESS_DOWN },
164 1.112 macallan #ifdef notyet
165 1.111 macallan { 67, 0 }, /* F10 -> suspend */
166 1.111 macallan { 68, 0 }, /* F11 -> user1 */
167 1.111 macallan { 69, 0 }, /* F12 -> user2 */
168 1.111 macallan { 70, 0 }, /* print screen -> sysrq */
169 1.111 macallan #endif
170 1.111 macallan { 76, 71 }, /* delete -> scroll lock */
171 1.111 macallan { 81, 78 }, /* down -> page down */
172 1.111 macallan { 82, 75 } /* up -> page up */
173 1.111 macallan };
174 1.113 macallan #endif
175 1.111 macallan
176 1.23 augustss #if defined(__NetBSD__) && defined(WSDISPLAY_COMPAT_RAWKBD)
177 1.5 augustss #define NN 0 /* no translation */
178 1.82 augustss /*
179 1.23 augustss * Translate USB keycodes to US keyboard XT scancodes.
180 1.76 augustss * Scancodes >= 0x80 represent EXTENDED keycodes.
181 1.76 augustss *
182 1.104 jakllsch * See http://www.microsoft.com/whdc/archive/scancode.mspx
183 1.104 jakllsch *
184 1.107 sborrill * Note: a real pckbd(4) has more complexity in its
185 1.104 jakllsch * protocol for some keys than this translation implements.
186 1.107 sborrill * For example, some keys generate Fake ShiftL events (e0 2a)
187 1.107 sborrill * before the actual key sequence.
188 1.19 augustss */
189 1.65 jdolecek Static const u_int8_t ukbd_trtab[256] = {
190 1.76 augustss NN, NN, NN, NN, 0x1e, 0x30, 0x2e, 0x20, /* 00 - 07 */
191 1.76 augustss 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, /* 08 - 0f */
192 1.76 augustss 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, /* 10 - 17 */
193 1.76 augustss 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, 0x02, 0x03, /* 18 - 1f */
194 1.76 augustss 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, /* 20 - 27 */
195 1.76 augustss 0x1c, 0x01, 0x0e, 0x0f, 0x39, 0x0c, 0x0d, 0x1a, /* 28 - 2f */
196 1.76 augustss 0x1b, 0x2b, 0x2b, 0x27, 0x28, 0x29, 0x33, 0x34, /* 30 - 37 */
197 1.76 augustss 0x35, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, /* 38 - 3f */
198 1.104 jakllsch 0x41, 0x42, 0x43, 0x44, 0x57, 0x58, 0xb7, 0x46, /* 40 - 47 */
199 1.76 augustss 0x7f, 0xd2, 0xc7, 0xc9, 0xd3, 0xcf, 0xd1, 0xcd, /* 48 - 4f */
200 1.76 augustss 0xcb, 0xd0, 0xc8, 0x45, 0xb5, 0x37, 0x4a, 0x4e, /* 50 - 57 */
201 1.76 augustss 0x9c, 0x4f, 0x50, 0x51, 0x4b, 0x4c, 0x4d, 0x47, /* 58 - 5f */
202 1.76 augustss 0x48, 0x49, 0x52, 0x53, 0x56, 0xdd, NN, 0x59, /* 60 - 67 */
203 1.96 tron 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, NN, /* 68 - 6f */
204 1.76 augustss NN, NN, NN, NN, NN, NN, NN, NN, /* 70 - 77 */
205 1.76 augustss NN, NN, NN, NN, NN, NN, NN, NN, /* 78 - 7f */
206 1.76 augustss NN, NN, NN, NN, NN, 0x7e, NN, 0x73, /* 80 - 87 */
207 1.76 augustss 0x70, 0x7d, 0x79, 0x7b, 0x5c, NN, NN, NN, /* 88 - 8f */
208 1.76 augustss NN, NN, 0x78, 0x77, 0x76, NN, NN, NN, /* 90 - 97 */
209 1.76 augustss NN, NN, NN, NN, NN, NN, NN, NN, /* 98 - 9f */
210 1.76 augustss NN, NN, NN, NN, NN, NN, NN, NN, /* a0 - a7 */
211 1.76 augustss NN, NN, NN, NN, NN, NN, NN, NN, /* a8 - af */
212 1.76 augustss NN, NN, NN, NN, NN, NN, NN, NN, /* b0 - b7 */
213 1.76 augustss NN, NN, NN, NN, NN, NN, NN, NN, /* b8 - bf */
214 1.76 augustss NN, NN, NN, NN, NN, NN, NN, NN, /* c0 - c7 */
215 1.76 augustss NN, NN, NN, NN, NN, NN, NN, NN, /* c8 - cf */
216 1.76 augustss NN, NN, NN, NN, NN, NN, NN, NN, /* d0 - d7 */
217 1.76 augustss NN, NN, NN, NN, NN, NN, NN, NN, /* d8 - df */
218 1.76 augustss 0x1d, 0x2a, 0x38, 0xdb, 0x9d, 0x36, 0xb8, 0xdc, /* e0 - e7 */
219 1.76 augustss NN, NN, NN, NN, NN, NN, NN, NN, /* e8 - ef */
220 1.76 augustss NN, NN, NN, NN, NN, NN, NN, NN, /* f0 - f7 */
221 1.76 augustss NN, NN, NN, NN, NN, NN, NN, NN, /* f8 - ff */
222 1.1 augustss };
223 1.23 augustss #endif /* defined(__NetBSD__) && defined(WSDISPLAY_COMPAT_RAWKBD) */
224 1.1 augustss
225 1.1 augustss #define KEY_ERROR 0x01
226 1.1 augustss
227 1.75 augustss #define MAXKEYS (MAXMOD+2*MAXKEYCODE)
228 1.20 augustss
229 1.1 augustss struct ukbd_softc {
230 1.75 augustss struct uhidev sc_hdev;
231 1.1 augustss
232 1.1 augustss struct ukbd_data sc_ndata;
233 1.1 augustss struct ukbd_data sc_odata;
234 1.75 augustss struct hid_location sc_modloc[MAXMOD];
235 1.75 augustss u_int sc_nmod;
236 1.75 augustss struct {
237 1.75 augustss u_int32_t mask;
238 1.75 augustss u_int8_t key;
239 1.75 augustss } sc_mods[MAXMOD];
240 1.75 augustss
241 1.75 augustss struct hid_location sc_keycodeloc;
242 1.75 augustss u_int sc_nkeycode;
243 1.1 augustss
244 1.109 phx u_int sc_flags; /* flags */
245 1.109 phx #define FLAG_ENABLED 0x0001
246 1.109 phx #define FLAG_POLLING 0x0002
247 1.109 phx #define FLAG_DEBOUNCE 0x0004 /* for quirk handling */
248 1.109 phx #define FLAG_APPLE_FIX_ISO 0x0008
249 1.109 phx #define FLAG_APPLE_FN 0x0010
250 1.111 macallan #define FLAG_GDIUM_FN 0x0020
251 1.109 phx #define FLAG_FN_PRESSED 0x0100 /* FN key is held down */
252 1.109 phx #define FLAG_FN_ALT 0x0200 /* Last Alt key was FN-Alt = AltGr */
253 1.1 augustss
254 1.29 thorpej int sc_console_keyboard; /* we are the console keyboard */
255 1.29 thorpej
256 1.109 phx struct callout sc_delay; /* for quirk handling */
257 1.62 augustss struct ukbd_data sc_data; /* for quirk handling */
258 1.62 augustss
259 1.109 phx struct hid_location sc_apple_fn;
260 1.75 augustss struct hid_location sc_numloc;
261 1.75 augustss struct hid_location sc_capsloc;
262 1.75 augustss struct hid_location sc_scroloc;
263 1.2 augustss int sc_leds;
264 1.16 augustss #if defined(__NetBSD__)
265 1.97 dyoung device_t sc_wskbddev;
266 1.57 thorpej
267 1.23 augustss #if defined(WSDISPLAY_COMPAT_RAWKBD)
268 1.87 augustss int sc_rawkbd;
269 1.87 augustss #if defined(UKBD_REPEAT)
270 1.108 dyoung struct callout sc_rawrepeat_ch;
271 1.20 augustss #define REP_DELAY1 400
272 1.20 augustss #define REP_DELAYN 100
273 1.20 augustss int sc_nrep;
274 1.20 augustss char sc_rep[MAXKEYS];
275 1.87 augustss #endif /* defined(UKBD_REPEAT) */
276 1.23 augustss #endif /* defined(WSDISPLAY_COMPAT_RAWKBD) */
277 1.3 augustss
278 1.84 augustss int sc_spl;
279 1.23 augustss int sc_npollchar;
280 1.23 augustss u_int16_t sc_pollchars[MAXKEYS];
281 1.23 augustss #endif /* defined(__NetBSD__) */
282 1.40 augustss
283 1.40 augustss u_char sc_dying;
284 1.1 augustss };
285 1.1 augustss
286 1.62 augustss #ifdef UKBD_DEBUG
287 1.62 augustss #define UKBDTRACESIZE 64
288 1.62 augustss struct ukbdtraceinfo {
289 1.62 augustss int unit;
290 1.62 augustss struct timeval tv;
291 1.62 augustss struct ukbd_data ud;
292 1.62 augustss };
293 1.62 augustss struct ukbdtraceinfo ukbdtracedata[UKBDTRACESIZE];
294 1.62 augustss int ukbdtraceindex = 0;
295 1.62 augustss int ukbdtrace = 0;
296 1.62 augustss void ukbdtracedump(void);
297 1.62 augustss void
298 1.62 augustss ukbdtracedump(void)
299 1.62 augustss {
300 1.62 augustss int i;
301 1.62 augustss for (i = 0; i < UKBDTRACESIZE; i++) {
302 1.82 augustss struct ukbdtraceinfo *p =
303 1.62 augustss &ukbdtracedata[(i+ukbdtraceindex)%UKBDTRACESIZE];
304 1.102 cegger printf("%"PRIu64".%06"PRIu64": mod=0x%02x key0=0x%02x key1=0x%02x "
305 1.62 augustss "key2=0x%02x key3=0x%02x\n",
306 1.102 cegger p->tv.tv_sec, (uint64_t)p->tv.tv_usec,
307 1.62 augustss p->ud.modifiers, p->ud.keycode[0], p->ud.keycode[1],
308 1.62 augustss p->ud.keycode[2], p->ud.keycode[3]);
309 1.62 augustss }
310 1.62 augustss }
311 1.62 augustss #endif
312 1.62 augustss
313 1.1 augustss #define UKBDUNIT(dev) (minor(dev))
314 1.1 augustss #define UKBD_CHUNK 128 /* chunk size for read */
315 1.1 augustss #define UKBD_BSIZE 1020 /* buffer size */
316 1.1 augustss
317 1.58 augustss Static int ukbd_is_console;
318 1.31 thorpej
319 1.60 augustss Static void ukbd_cngetc(void *, u_int *, int *);
320 1.60 augustss Static void ukbd_cnpollc(void *, int);
321 1.3 augustss
322 1.16 augustss #if defined(__NetBSD__)
323 1.8 drochner const struct wskbd_consops ukbd_consops = {
324 1.8 drochner ukbd_cngetc,
325 1.8 drochner ukbd_cnpollc,
326 1.92 christos NULL, /* bell */
327 1.8 drochner };
328 1.16 augustss #endif
329 1.8 drochner
330 1.75 augustss Static const char *ukbd_parse_desc(struct ukbd_softc *sc);
331 1.75 augustss
332 1.75 augustss Static void ukbd_intr(struct uhidev *addr, void *ibuf, u_int len);
333 1.62 augustss Static void ukbd_decode(struct ukbd_softc *sc, struct ukbd_data *ud);
334 1.62 augustss Static void ukbd_delayed_decode(void *addr);
335 1.2 augustss
336 1.60 augustss Static int ukbd_enable(void *, int);
337 1.60 augustss Static void ukbd_set_leds(void *, int);
338 1.23 augustss
339 1.16 augustss #if defined(__NetBSD__)
340 1.95 christos Static int ukbd_ioctl(void *, u_long, void *, int, struct lwp *);
341 1.88 jonathan #if defined(WSDISPLAY_COMPAT_RAWKBD) && defined(UKBD_REPEAT)
342 1.60 augustss Static void ukbd_rawrepeat(void *v);
343 1.48 mjacob #endif
344 1.1 augustss
345 1.8 drochner const struct wskbd_accessops ukbd_accessops = {
346 1.8 drochner ukbd_enable,
347 1.8 drochner ukbd_set_leds,
348 1.8 drochner ukbd_ioctl,
349 1.8 drochner };
350 1.8 drochner
351 1.23 augustss extern const struct wscons_keydesc ukbd_keydesctab[];
352 1.23 augustss
353 1.8 drochner const struct wskbd_mapdata ukbd_keymapdata = {
354 1.23 augustss ukbd_keydesctab,
355 1.86 augustss #if defined(UKBD_LAYOUT)
356 1.66 augustss UKBD_LAYOUT,
357 1.86 augustss #elif defined(PCKBD_LAYOUT)
358 1.86 augustss PCKBD_LAYOUT,
359 1.66 augustss #else
360 1.8 drochner KB_US,
361 1.66 augustss #endif
362 1.8 drochner };
363 1.16 augustss #endif
364 1.8 drochner
365 1.100 cube static int ukbd_match(device_t, cfdata_t, void *);
366 1.97 dyoung static void ukbd_attach(device_t, device_t, void *);
367 1.97 dyoung static int ukbd_detach(device_t, int);
368 1.97 dyoung static int ukbd_activate(device_t, enum devact);
369 1.97 dyoung static void ukbd_childdet(device_t, device_t);
370 1.97 dyoung
371 1.97 dyoung extern struct cfdriver ukbd_cd;
372 1.97 dyoung
373 1.100 cube CFATTACH_DECL2_NEW(ukbd, sizeof(struct ukbd_softc), ukbd_match, ukbd_attach,
374 1.97 dyoung ukbd_detach, ukbd_activate, NULL, ukbd_childdet);
375 1.1 augustss
376 1.75 augustss int
377 1.100 cube ukbd_match(device_t parent, cfdata_t match, void *aux)
378 1.1 augustss {
379 1.75 augustss struct uhidev_attach_arg *uha = aux;
380 1.75 augustss int size;
381 1.75 augustss void *desc;
382 1.82 augustss
383 1.75 augustss uhidev_get_report_desc(uha->parent, &desc, &size);
384 1.75 augustss if (!hid_is_collection(desc, size, uha->reportid,
385 1.75 augustss HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD)))
386 1.1 augustss return (UMATCH_NONE);
387 1.75 augustss
388 1.75 augustss return (UMATCH_IFACECLASS);
389 1.1 augustss }
390 1.1 augustss
391 1.75 augustss void
392 1.97 dyoung ukbd_attach(device_t parent, device_t self, void *aux)
393 1.1 augustss {
394 1.97 dyoung struct ukbd_softc *sc = device_private(self);
395 1.75 augustss struct uhidev_attach_arg *uha = aux;
396 1.62 augustss u_int32_t qflags;
397 1.75 augustss const char *parseerr;
398 1.16 augustss #if defined(__NetBSD__)
399 1.2 augustss struct wskbddev_attach_args a;
400 1.16 augustss #else
401 1.16 augustss int i;
402 1.16 augustss #endif
403 1.82 augustss
404 1.100 cube sc->sc_hdev.sc_dev = self;
405 1.75 augustss sc->sc_hdev.sc_intr = ukbd_intr;
406 1.75 augustss sc->sc_hdev.sc_parent = uha->parent;
407 1.75 augustss sc->sc_hdev.sc_report_id = uha->reportid;
408 1.109 phx sc->sc_flags = 0;
409 1.75 augustss
410 1.101 jmcneill if (!pmf_device_register(self, NULL, NULL)) {
411 1.101 jmcneill aprint_normal("\n");
412 1.101 jmcneill aprint_error_dev(self, "couldn't establish power handler\n");
413 1.101 jmcneill }
414 1.101 jmcneill
415 1.75 augustss parseerr = ukbd_parse_desc(sc);
416 1.75 augustss if (parseerr != NULL) {
417 1.98 cegger aprint_normal("\n");
418 1.100 cube aprint_error_dev(self, "attach failed, %s\n", parseerr);
419 1.108 dyoung return;
420 1.1 augustss }
421 1.82 augustss
422 1.109 phx /* Quirks */
423 1.109 phx qflags = usbd_get_quirks(uha->parent->sc_udev)->uq_flags;
424 1.109 phx if (qflags & UQ_SPUR_BUT_UP)
425 1.109 phx sc->sc_flags |= FLAG_DEBOUNCE;
426 1.109 phx if (qflags & UQ_APPLE_ISO)
427 1.109 phx sc->sc_flags |= FLAG_APPLE_FIX_ISO;
428 1.109 phx
429 1.113 macallan #ifdef GDIUM_KEYBOARD_HACK
430 1.111 macallan if (uha->uaa->vendor == USB_VENDOR_CYPRESS &&
431 1.111 macallan uha->uaa->product == USB_PRODUCT_CYPRESS_LPRDK)
432 1.111 macallan sc->sc_flags = FLAG_GDIUM_FN;
433 1.113 macallan #endif
434 1.111 macallan
435 1.75 augustss #ifdef DIAGNOSTIC
436 1.100 cube aprint_normal(": %d modifier keys, %d key codes", sc->sc_nmod,
437 1.75 augustss sc->sc_nkeycode);
438 1.109 phx if (sc->sc_flags & FLAG_APPLE_FN)
439 1.109 phx aprint_normal(", apple fn key");
440 1.109 phx if (sc->sc_flags & FLAG_APPLE_FIX_ISO)
441 1.109 phx aprint_normal(", fix apple iso");
442 1.111 macallan if (sc->sc_flags & FLAG_GDIUM_FN)
443 1.111 macallan aprint_normal(", Gdium fn key");
444 1.75 augustss #endif
445 1.100 cube aprint_normal("\n");
446 1.1 augustss
447 1.29 thorpej /*
448 1.29 thorpej * Remember if we're the console keyboard.
449 1.29 thorpej *
450 1.31 thorpej * XXX This always picks the first keyboard on the
451 1.31 thorpej * first USB bus, but what else can we really do?
452 1.29 thorpej */
453 1.31 thorpej if ((sc->sc_console_keyboard = ukbd_is_console) != 0) {
454 1.29 thorpej /* Don't let any other keyboard have it. */
455 1.31 thorpej ukbd_is_console = 0;
456 1.29 thorpej }
457 1.29 thorpej
458 1.31 thorpej if (sc->sc_console_keyboard) {
459 1.32 augustss DPRINTF(("ukbd_attach: console keyboard sc=%p\n", sc));
460 1.31 thorpej wskbd_cnattach(&ukbd_consops, sc, &ukbd_keymapdata);
461 1.34 wrstuden ukbd_enable(sc, 1);
462 1.31 thorpej }
463 1.29 thorpej
464 1.29 thorpej a.console = sc->sc_console_keyboard;
465 1.8 drochner
466 1.8 drochner a.keymap = &ukbd_keymapdata;
467 1.8 drochner
468 1.8 drochner a.accessops = &ukbd_accessops;
469 1.2 augustss a.accesscookie = sc;
470 1.8 drochner
471 1.87 augustss #ifdef UKBD_REPEAT
472 1.108 dyoung callout_init(&sc->sc_rawrepeat_ch, 0);
473 1.87 augustss #endif
474 1.57 thorpej
475 1.108 dyoung callout_init(&sc->sc_delay, 0);
476 1.62 augustss
477 1.19 augustss /* Flash the leds; no real purpose, just shows we're alive. */
478 1.19 augustss ukbd_set_leds(sc, WSKBD_LED_SCROLL | WSKBD_LED_NUM | WSKBD_LED_CAPS);
479 1.75 augustss usbd_delay_ms(uha->parent->sc_udev, 400);
480 1.19 augustss ukbd_set_leds(sc, 0);
481 1.19 augustss
482 1.64 augustss sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
483 1.55 augustss
484 1.108 dyoung return;
485 1.1 augustss }
486 1.1 augustss
487 1.8 drochner int
488 1.60 augustss ukbd_enable(void *v, int on)
489 1.8 drochner {
490 1.9 augustss struct ukbd_softc *sc = v;
491 1.9 augustss
492 1.40 augustss if (on && sc->sc_dying)
493 1.40 augustss return (EIO);
494 1.40 augustss
495 1.38 augustss /* Should only be called to change state */
496 1.109 phx if ((sc->sc_flags & FLAG_ENABLED) != 0 && on != 0) {
497 1.38 augustss #ifdef DIAGNOSTIC
498 1.82 augustss printf("ukbd_enable: %s: bad call on=%d\n",
499 1.108 dyoung device_xname(sc->sc_hdev.sc_dev), on);
500 1.38 augustss #endif
501 1.38 augustss return (EBUSY);
502 1.38 augustss }
503 1.38 augustss
504 1.33 augustss DPRINTF(("ukbd_enable: sc=%p on=%d\n", sc, on));
505 1.9 augustss if (on) {
506 1.109 phx sc->sc_flags |= FLAG_ENABLED;
507 1.75 augustss return (uhidev_open(&sc->sc_hdev));
508 1.9 augustss } else {
509 1.109 phx sc->sc_flags &= ~FLAG_ENABLED;
510 1.75 augustss uhidev_close(&sc->sc_hdev);
511 1.75 augustss return (0);
512 1.9 augustss }
513 1.37 augustss }
514 1.37 augustss
515 1.97 dyoung
516 1.97 dyoung static void
517 1.97 dyoung ukbd_childdet(device_t self, device_t child)
518 1.97 dyoung {
519 1.97 dyoung struct ukbd_softc *sc = device_private(self);
520 1.97 dyoung
521 1.97 dyoung KASSERT(sc->sc_wskbddev == child);
522 1.97 dyoung sc->sc_wskbddev = NULL;
523 1.97 dyoung }
524 1.97 dyoung
525 1.37 augustss int
526 1.97 dyoung ukbd_activate(device_t self, enum devact act)
527 1.37 augustss {
528 1.97 dyoung struct ukbd_softc *sc = device_private(self);
529 1.40 augustss
530 1.40 augustss switch (act) {
531 1.40 augustss case DVACT_DEACTIVATE:
532 1.40 augustss sc->sc_dying = 1;
533 1.105 dyoung return 0;
534 1.105 dyoung default:
535 1.105 dyoung return EOPNOTSUPP;
536 1.40 augustss }
537 1.37 augustss }
538 1.37 augustss
539 1.75 augustss int
540 1.97 dyoung ukbd_detach(device_t self, int flags)
541 1.37 augustss {
542 1.97 dyoung struct ukbd_softc *sc = device_private(self);
543 1.37 augustss int rv = 0;
544 1.37 augustss
545 1.37 augustss DPRINTF(("ukbd_detach: sc=%p flags=%d\n", sc, flags));
546 1.46 augustss
547 1.101 jmcneill pmf_device_deregister(self);
548 1.101 jmcneill
549 1.37 augustss if (sc->sc_console_keyboard) {
550 1.50 augustss #if 0
551 1.37 augustss /*
552 1.37 augustss * XXX Should probably disconnect our consops,
553 1.37 augustss * XXX and either notify some other keyboard that
554 1.37 augustss * XXX it can now be the console, or if there aren't
555 1.37 augustss * XXX any more USB keyboards, set ukbd_is_console
556 1.37 augustss * XXX back to 1 so that the next USB keyboard attached
557 1.37 augustss * XXX to the system will get it.
558 1.37 augustss */
559 1.37 augustss panic("ukbd_detach: console keyboard");
560 1.50 augustss #else
561 1.51 augustss /*
562 1.51 augustss * Disconnect our consops and set ukbd_is_console
563 1.51 augustss * back to 1 so that the next USB keyboard attached
564 1.51 augustss * to the system will get it.
565 1.51 augustss * XXX Should notify some other keyboard that it can be
566 1.51 augustss * XXX console, if there are any other keyboards.
567 1.51 augustss */
568 1.75 augustss printf("%s: was console keyboard\n",
569 1.108 dyoung device_xname(sc->sc_hdev.sc_dev));
570 1.50 augustss wskbd_cndetach();
571 1.50 augustss ukbd_is_console = 1;
572 1.50 augustss #endif
573 1.37 augustss }
574 1.45 augustss /* No need to do reference counting of ukbd, wskbd has all the goo. */
575 1.47 augustss if (sc->sc_wskbddev != NULL)
576 1.37 augustss rv = config_detach(sc->sc_wskbddev, flags);
577 1.68 augustss
578 1.68 augustss /* The console keyboard does not get a disable call, so check pipe. */
579 1.75 augustss if (sc->sc_hdev.sc_state & UHIDEV_OPEN)
580 1.75 augustss uhidev_close(&sc->sc_hdev);
581 1.55 augustss
582 1.37 augustss return (rv);
583 1.1 augustss }
584 1.1 augustss
585 1.109 phx static void
586 1.109 phx ukbd_translate_keycodes(struct ukbd_softc *sc, struct ukbd_data *ud,
587 1.109 phx const struct ukbd_keycodetrans *tab)
588 1.109 phx {
589 1.109 phx const struct ukbd_keycodetrans *tp;
590 1.109 phx int i;
591 1.109 phx u_int8_t key;
592 1.109 phx
593 1.109 phx for (i = 0; i < sc->sc_nkeycode; i++) {
594 1.109 phx key = ud->keycode[i];
595 1.109 phx if (key)
596 1.109 phx for (tp = tab; tp->from; tp++)
597 1.109 phx if (tp->from == key) {
598 1.112 macallan if (tp->to & IS_PMF) {
599 1.112 macallan pmf_event_inject(
600 1.112 macallan sc->sc_hdev.sc_dev,
601 1.112 macallan tp->to & 0xff);
602 1.112 macallan ud->keycode[i] = 0;
603 1.112 macallan } else
604 1.112 macallan ud->keycode[i] = tp->to;
605 1.109 phx break;
606 1.109 phx }
607 1.109 phx }
608 1.109 phx }
609 1.109 phx
610 1.109 phx static u_int16_t
611 1.109 phx ukbd_translate_modifier(struct ukbd_softc *sc, u_int16_t key)
612 1.109 phx {
613 1.109 phx if ((sc->sc_flags & FLAG_APPLE_FN) && (key & CODEMASK) == 0x00e2) {
614 1.109 phx if ((key & ~CODEMASK) == PRESS) {
615 1.109 phx if (sc->sc_flags & FLAG_FN_PRESSED) {
616 1.109 phx /* pressed FN-Alt, translate to AltGr */
617 1.109 phx key = 0x00e6 | PRESS;
618 1.109 phx sc->sc_flags |= FLAG_FN_ALT;
619 1.109 phx }
620 1.109 phx } else {
621 1.109 phx if (sc->sc_flags & FLAG_FN_ALT) {
622 1.109 phx /* released Alt, which was treated as FN-Alt */
623 1.109 phx key = 0x00e6 | RELEASE;
624 1.109 phx sc->sc_flags &= ~FLAG_FN_ALT;
625 1.109 phx }
626 1.109 phx }
627 1.109 phx }
628 1.109 phx return key;
629 1.109 phx }
630 1.109 phx
631 1.1 augustss void
632 1.94 christos ukbd_intr(struct uhidev *addr, void *ibuf, u_int len)
633 1.1 augustss {
634 1.75 augustss struct ukbd_softc *sc = (struct ukbd_softc *)addr;
635 1.1 augustss struct ukbd_data *ud = &sc->sc_ndata;
636 1.75 augustss int i;
637 1.76 augustss
638 1.76 augustss #ifdef UKBD_DEBUG
639 1.76 augustss if (ukbddebug > 5) {
640 1.76 augustss printf("ukbd_intr: data");
641 1.76 augustss for (i = 0; i < len; i++)
642 1.78 augustss printf(" 0x%02x", ((u_char *)ibuf)[i]);
643 1.76 augustss printf("\n");
644 1.76 augustss }
645 1.76 augustss #endif
646 1.76 augustss
647 1.75 augustss ud->modifiers = 0;
648 1.75 augustss for (i = 0; i < sc->sc_nmod; i++)
649 1.75 augustss if (hid_get_data(ibuf, &sc->sc_modloc[i]))
650 1.80 augustss ud->modifiers |= sc->sc_mods[i].mask;
651 1.75 augustss memcpy(ud->keycode, (char *)ibuf + sc->sc_keycodeloc.pos / 8,
652 1.75 augustss sc->sc_nkeycode);
653 1.1 augustss
654 1.109 phx if (sc->sc_flags & FLAG_APPLE_FN) {
655 1.109 phx if (hid_get_data(ibuf, &sc->sc_apple_fn)) {
656 1.109 phx sc->sc_flags |= FLAG_FN_PRESSED;
657 1.109 phx ukbd_translate_keycodes(sc, ud, trtab_apple_fn);
658 1.109 phx }
659 1.109 phx else
660 1.109 phx sc->sc_flags &= ~FLAG_FN_PRESSED;
661 1.109 phx }
662 1.113 macallan
663 1.113 macallan #ifdef GDIUM_KEYBOARD_HACK
664 1.111 macallan if (sc->sc_flags & FLAG_GDIUM_FN) {
665 1.111 macallan if (sc->sc_flags & FLAG_FN_PRESSED) {
666 1.111 macallan ukbd_translate_keycodes(sc, ud, trtab_gdium_fn);
667 1.111 macallan }
668 1.111 macallan }
669 1.113 macallan #endif
670 1.109 phx
671 1.109 phx if ((sc->sc_flags & FLAG_DEBOUNCE) && !(sc->sc_flags & FLAG_POLLING)) {
672 1.62 augustss /*
673 1.62 augustss * Some keyboards have a peculiar quirk. They sometimes
674 1.62 augustss * generate a key up followed by a key down for the same
675 1.62 augustss * key after about 10 ms.
676 1.62 augustss * We avoid this bug by holding off decoding for 20 ms.
677 1.62 augustss */
678 1.62 augustss sc->sc_data = *ud;
679 1.108 dyoung callout_reset(&sc->sc_delay, hz / 50, ukbd_delayed_decode, sc);
680 1.74 lukem #ifdef DDB
681 1.109 phx } else if (sc->sc_console_keyboard && !(sc->sc_flags & FLAG_POLLING)) {
682 1.69 augustss /*
683 1.69 augustss * For the console keyboard we can't deliver CTL-ALT-ESC
684 1.69 augustss * from the interrupt routine. Doing so would start
685 1.69 augustss * polling from inside the interrupt routine and that
686 1.69 augustss * loses bigtime.
687 1.69 augustss */
688 1.69 augustss sc->sc_data = *ud;
689 1.108 dyoung callout_reset(&sc->sc_delay, 1, ukbd_delayed_decode, sc);
690 1.69 augustss #endif
691 1.62 augustss } else {
692 1.62 augustss ukbd_decode(sc, ud);
693 1.62 augustss }
694 1.62 augustss }
695 1.62 augustss
696 1.62 augustss void
697 1.62 augustss ukbd_delayed_decode(void *addr)
698 1.62 augustss {
699 1.62 augustss struct ukbd_softc *sc = addr;
700 1.62 augustss
701 1.62 augustss ukbd_decode(sc, &sc->sc_data);
702 1.62 augustss }
703 1.62 augustss
704 1.62 augustss void
705 1.62 augustss ukbd_decode(struct ukbd_softc *sc, struct ukbd_data *ud)
706 1.62 augustss {
707 1.62 augustss int mod, omod;
708 1.62 augustss u_int16_t ibuf[MAXKEYS]; /* chars events */
709 1.62 augustss int s;
710 1.62 augustss int nkeys, i, j;
711 1.62 augustss int key;
712 1.62 augustss #define ADDKEY(c) ibuf[nkeys++] = (c)
713 1.62 augustss
714 1.62 augustss #ifdef UKBD_DEBUG
715 1.82 augustss /*
716 1.62 augustss * Keep a trace of the last events. Using printf changes the
717 1.62 augustss * timing, so this can be useful sometimes.
718 1.62 augustss */
719 1.62 augustss if (ukbdtrace) {
720 1.62 augustss struct ukbdtraceinfo *p = &ukbdtracedata[ukbdtraceindex];
721 1.100 cube p->unit = device_unit(sc->sc_hdev.sc_dev);
722 1.62 augustss microtime(&p->tv);
723 1.62 augustss p->ud = *ud;
724 1.62 augustss if (++ukbdtraceindex >= UKBDTRACESIZE)
725 1.62 augustss ukbdtraceindex = 0;
726 1.62 augustss }
727 1.62 augustss if (ukbddebug > 5) {
728 1.62 augustss struct timeval tv;
729 1.62 augustss microtime(&tv);
730 1.102 cegger DPRINTF((" at %"PRIu64".%06"PRIu64" mod=0x%02x key0=0x%02x key1=0x%02x "
731 1.62 augustss "key2=0x%02x key3=0x%02x\n",
732 1.102 cegger tv.tv_sec, (uint64_t)tv.tv_usec,
733 1.62 augustss ud->modifiers, ud->keycode[0], ud->keycode[1],
734 1.62 augustss ud->keycode[2], ud->keycode[3]));
735 1.62 augustss }
736 1.62 augustss #endif
737 1.1 augustss
738 1.53 augustss if (ud->keycode[0] == KEY_ERROR) {
739 1.53 augustss DPRINTF(("ukbd_intr: KEY_ERROR\n"));
740 1.1 augustss return; /* ignore */
741 1.53 augustss }
742 1.109 phx
743 1.109 phx if (sc->sc_flags & FLAG_APPLE_FIX_ISO)
744 1.109 phx ukbd_translate_keycodes(sc, ud, trtab_apple_iso);
745 1.109 phx
746 1.1 augustss nkeys = 0;
747 1.1 augustss mod = ud->modifiers;
748 1.1 augustss omod = sc->sc_odata.modifiers;
749 1.1 augustss if (mod != omod)
750 1.75 augustss for (i = 0; i < sc->sc_nmod; i++)
751 1.82 augustss if (( mod & sc->sc_mods[i].mask) !=
752 1.109 phx (omod & sc->sc_mods[i].mask)) {
753 1.109 phx key = sc->sc_mods[i].key |
754 1.109 phx ((mod & sc->sc_mods[i].mask) ?
755 1.109 phx PRESS : RELEASE);
756 1.109 phx ADDKEY(ukbd_translate_modifier(sc, key));
757 1.109 phx }
758 1.75 augustss if (memcmp(ud->keycode, sc->sc_odata.keycode, sc->sc_nkeycode) != 0) {
759 1.1 augustss /* Check for released keys. */
760 1.75 augustss for (i = 0; i < sc->sc_nkeycode; i++) {
761 1.1 augustss key = sc->sc_odata.keycode[i];
762 1.1 augustss if (key == 0)
763 1.1 augustss continue;
764 1.75 augustss for (j = 0; j < sc->sc_nkeycode; j++)
765 1.1 augustss if (key == ud->keycode[j])
766 1.1 augustss goto rfound;
767 1.62 augustss DPRINTFN(3,("ukbd_intr: relse key=0x%02x\n", key));
768 1.113 macallan #ifdef GDIUM_KEYBOARD_HACK
769 1.111 macallan if (sc->sc_flags & FLAG_GDIUM_FN) {
770 1.111 macallan if (key == 0x82) {
771 1.111 macallan sc->sc_flags &= ~FLAG_FN_PRESSED;
772 1.111 macallan goto rfound;
773 1.111 macallan }
774 1.111 macallan }
775 1.113 macallan #endif
776 1.23 augustss ADDKEY(key | RELEASE);
777 1.1 augustss rfound:
778 1.1 augustss ;
779 1.1 augustss }
780 1.82 augustss
781 1.1 augustss /* Check for pressed keys. */
782 1.75 augustss for (i = 0; i < sc->sc_nkeycode; i++) {
783 1.1 augustss key = ud->keycode[i];
784 1.1 augustss if (key == 0)
785 1.1 augustss continue;
786 1.75 augustss for (j = 0; j < sc->sc_nkeycode; j++)
787 1.1 augustss if (key == sc->sc_odata.keycode[j])
788 1.1 augustss goto pfound;
789 1.23 augustss DPRINTFN(2,("ukbd_intr: press key=0x%02x\n", key));
790 1.113 macallan #ifdef GDIUM_KEYBOARD_HACK
791 1.111 macallan if (sc->sc_flags & FLAG_GDIUM_FN) {
792 1.111 macallan if (key == 0x82) {
793 1.111 macallan sc->sc_flags |= FLAG_FN_PRESSED;
794 1.111 macallan goto pfound;
795 1.111 macallan }
796 1.111 macallan }
797 1.113 macallan #endif
798 1.23 augustss ADDKEY(key | PRESS);
799 1.1 augustss pfound:
800 1.1 augustss ;
801 1.1 augustss }
802 1.1 augustss }
803 1.1 augustss sc->sc_odata = *ud;
804 1.1 augustss
805 1.20 augustss if (nkeys == 0)
806 1.20 augustss return;
807 1.20 augustss
808 1.109 phx if (sc->sc_flags & FLAG_POLLING) {
809 1.23 augustss DPRINTFN(1,("ukbd_intr: pollchar = 0x%03x\n", ibuf[0]));
810 1.23 augustss memcpy(sc->sc_pollchars, ibuf, nkeys * sizeof(u_int16_t));
811 1.23 augustss sc->sc_npollchar = nkeys;
812 1.3 augustss return;
813 1.3 augustss }
814 1.20 augustss #ifdef WSDISPLAY_COMPAT_RAWKBD
815 1.19 augustss if (sc->sc_rawkbd) {
816 1.79 augustss u_char cbuf[MAXKEYS * 2];
817 1.24 augustss int c;
818 1.20 augustss int npress;
819 1.20 augustss
820 1.23 augustss for (npress = i = j = 0; i < nkeys; i++) {
821 1.23 augustss key = ibuf[i];
822 1.23 augustss c = ukbd_trtab[key & CODEMASK];
823 1.23 augustss if (c == NN)
824 1.23 augustss continue;
825 1.104 jakllsch if (c == 0x7f) {
826 1.104 jakllsch /* pause key */
827 1.104 jakllsch cbuf[j++] = 0xe1;
828 1.104 jakllsch cbuf[j++] = 0x1d;
829 1.104 jakllsch cbuf[j-1] |= (key & RELEASE) ? 0x80 : 0;
830 1.104 jakllsch cbuf[j] = 0x45;
831 1.104 jakllsch } else {
832 1.104 jakllsch if (c & 0x80)
833 1.104 jakllsch cbuf[j++] = 0xe0;
834 1.104 jakllsch cbuf[j] = c & 0x7f;
835 1.104 jakllsch }
836 1.23 augustss if (key & RELEASE)
837 1.19 augustss cbuf[j] |= 0x80;
838 1.87 augustss #if defined(UKBD_REPEAT)
839 1.20 augustss else {
840 1.23 augustss /* remember pressed keys for autorepeat */
841 1.20 augustss if (c & 0x80)
842 1.20 augustss sc->sc_rep[npress++] = 0xe0;
843 1.20 augustss sc->sc_rep[npress++] = c & 0x7f;
844 1.20 augustss }
845 1.87 augustss #endif
846 1.82 augustss DPRINTFN(1,("ukbd_intr: raw = %s0x%02x\n",
847 1.27 augustss c & 0x80 ? "0xe0 " : "",
848 1.27 augustss cbuf[j]));
849 1.23 augustss j++;
850 1.19 augustss }
851 1.30 augustss s = spltty();
852 1.19 augustss wskbd_rawinput(sc->sc_wskbddev, cbuf, j);
853 1.30 augustss splx(s);
854 1.87 augustss #ifdef UKBD_REPEAT
855 1.108 dyoung callout_stop(&sc->sc_rawrepeat_ch);
856 1.20 augustss if (npress != 0) {
857 1.20 augustss sc->sc_nrep = npress;
858 1.108 dyoung callout_reset(&sc->sc_rawrepeat_ch,
859 1.57 thorpej hz * REP_DELAY1 / 1000, ukbd_rawrepeat, sc);
860 1.20 augustss }
861 1.87 augustss #endif
862 1.19 augustss return;
863 1.19 augustss }
864 1.19 augustss #endif
865 1.19 augustss
866 1.30 augustss s = spltty();
867 1.2 augustss for (i = 0; i < nkeys; i++) {
868 1.23 augustss key = ibuf[i];
869 1.82 augustss wskbd_input(sc->sc_wskbddev,
870 1.23 augustss key&RELEASE ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN,
871 1.23 augustss key&CODEMASK);
872 1.20 augustss }
873 1.30 augustss splx(s);
874 1.1 augustss }
875 1.1 augustss
876 1.2 augustss void
877 1.60 augustss ukbd_set_leds(void *v, int leds)
878 1.1 augustss {
879 1.2 augustss struct ukbd_softc *sc = v;
880 1.2 augustss u_int8_t res;
881 1.1 augustss
882 1.71 augustss DPRINTF(("ukbd_set_leds: sc=%p leds=%d, sc_leds=%d\n",
883 1.71 augustss sc, leds, sc->sc_leds));
884 1.40 augustss
885 1.40 augustss if (sc->sc_dying)
886 1.40 augustss return;
887 1.1 augustss
888 1.71 augustss if (sc->sc_leds == leds)
889 1.71 augustss return;
890 1.2 augustss sc->sc_leds = leds;
891 1.2 augustss res = 0;
892 1.75 augustss /* XXX not really right */
893 1.75 augustss if ((leds & WSKBD_LED_SCROLL) && sc->sc_scroloc.size == 1)
894 1.75 augustss res |= 1 << sc->sc_scroloc.pos;
895 1.75 augustss if ((leds & WSKBD_LED_NUM) && sc->sc_numloc.size == 1)
896 1.75 augustss res |= 1 << sc->sc_numloc.pos;
897 1.75 augustss if ((leds & WSKBD_LED_CAPS) && sc->sc_capsloc.size == 1)
898 1.75 augustss res |= 1 << sc->sc_capsloc.pos;
899 1.75 augustss uhidev_set_report_async(&sc->sc_hdev, UHID_OUTPUT_REPORT, &res, 1);
900 1.1 augustss }
901 1.1 augustss
902 1.87 augustss #if defined(WSDISPLAY_COMPAT_RAWKBD) && defined(UKBD_REPEAT)
903 1.20 augustss void
904 1.60 augustss ukbd_rawrepeat(void *v)
905 1.20 augustss {
906 1.20 augustss struct ukbd_softc *sc = v;
907 1.30 augustss int s;
908 1.20 augustss
909 1.30 augustss s = spltty();
910 1.20 augustss wskbd_rawinput(sc->sc_wskbddev, sc->sc_rep, sc->sc_nrep);
911 1.30 augustss splx(s);
912 1.108 dyoung callout_reset(&sc->sc_rawrepeat_ch, hz * REP_DELAYN / 1000,
913 1.57 thorpej ukbd_rawrepeat, sc);
914 1.20 augustss }
915 1.87 augustss #endif /* defined(WSDISPLAY_COMPAT_RAWKBD) && defined(UKBD_REPEAT) */
916 1.20 augustss
917 1.1 augustss int
918 1.95 christos ukbd_ioctl(void *v, u_long cmd, void *data, int flag,
919 1.94 christos struct lwp *l)
920 1.1 augustss {
921 1.2 augustss struct ukbd_softc *sc = v;
922 1.1 augustss
923 1.2 augustss switch (cmd) {
924 1.2 augustss case WSKBDIO_GTYPE:
925 1.20 augustss *(int *)data = WSKBD_TYPE_USB;
926 1.17 augustss return (0);
927 1.2 augustss case WSKBDIO_SETLEDS:
928 1.2 augustss ukbd_set_leds(v, *(int *)data);
929 1.17 augustss return (0);
930 1.2 augustss case WSKBDIO_GETLEDS:
931 1.2 augustss *(int *)data = sc->sc_leds;
932 1.2 augustss return (0);
933 1.87 augustss #if defined(WSDISPLAY_COMPAT_RAWKBD)
934 1.2 augustss case WSKBDIO_SETMODE:
935 1.19 augustss DPRINTF(("ukbd_ioctl: set raw = %d\n", *(int *)data));
936 1.2 augustss sc->sc_rawkbd = *(int *)data == WSKBD_RAW;
937 1.87 augustss #if defined(UKBD_REPEAT)
938 1.108 dyoung callout_stop(&sc->sc_rawrepeat_ch);
939 1.87 augustss #endif
940 1.2 augustss return (0);
941 1.2 augustss #endif
942 1.2 augustss }
943 1.81 atatat return (EPASSTHROUGH);
944 1.1 augustss }
945 1.7 augustss
946 1.71 augustss /*
947 1.71 augustss * This is a hack to work around some broken ports that don't call
948 1.71 augustss * cnpollc() before cngetc().
949 1.71 augustss */
950 1.71 augustss static int pollenter, warned;
951 1.71 augustss
952 1.7 augustss /* Console interface. */
953 1.3 augustss void
954 1.60 augustss ukbd_cngetc(void *v, u_int *type, int *data)
955 1.3 augustss {
956 1.3 augustss struct ukbd_softc *sc = v;
957 1.4 augustss int c;
958 1.71 augustss int broken;
959 1.71 augustss
960 1.71 augustss if (pollenter == 0) {
961 1.71 augustss if (!warned) {
962 1.71 augustss printf("\n"
963 1.71 augustss "This port is broken, it does not call cnpollc() before calling cngetc().\n"
964 1.71 augustss "This should be fixed, but it will work anyway (for now).\n");
965 1.71 augustss warned = 1;
966 1.71 augustss }
967 1.71 augustss broken = 1;
968 1.71 augustss ukbd_cnpollc(v, 1);
969 1.71 augustss } else
970 1.71 augustss broken = 0;
971 1.3 augustss
972 1.50 augustss DPRINTFN(0,("ukbd_cngetc: enter\n"));
973 1.109 phx sc->sc_flags |= FLAG_POLLING;
974 1.23 augustss while(sc->sc_npollchar <= 0)
975 1.75 augustss usbd_dopoll(sc->sc_hdev.sc_parent->sc_iface);
976 1.109 phx sc->sc_flags &= ~FLAG_POLLING;
977 1.23 augustss c = sc->sc_pollchars[0];
978 1.23 augustss sc->sc_npollchar--;
979 1.82 augustss memcpy(sc->sc_pollchars, sc->sc_pollchars+1,
980 1.23 augustss sc->sc_npollchar * sizeof(u_int16_t));
981 1.6 augustss *type = c & RELEASE ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN;
982 1.23 augustss *data = c & CODEMASK;
983 1.50 augustss DPRINTFN(0,("ukbd_cngetc: return 0x%02x\n", c));
984 1.71 augustss if (broken)
985 1.71 augustss ukbd_cnpollc(v, 0);
986 1.3 augustss }
987 1.3 augustss
988 1.3 augustss void
989 1.60 augustss ukbd_cnpollc(void *v, int on)
990 1.3 augustss {
991 1.6 augustss struct ukbd_softc *sc = v;
992 1.52 augustss usbd_device_handle dev;
993 1.6 augustss
994 1.19 augustss DPRINTFN(2,("ukbd_cnpollc: sc=%p on=%d\n", v, on));
995 1.6 augustss
996 1.75 augustss usbd_interface2device_handle(sc->sc_hdev.sc_parent->sc_iface, &dev);
997 1.84 augustss if (on) {
998 1.84 augustss sc->sc_spl = splusb();
999 1.84 augustss pollenter++;
1000 1.84 augustss } else {
1001 1.84 augustss splx(sc->sc_spl);
1002 1.84 augustss pollenter--;
1003 1.84 augustss }
1004 1.52 augustss usbd_set_polling(dev, on);
1005 1.3 augustss }
1006 1.18 augustss
1007 1.18 augustss int
1008 1.60 augustss ukbd_cnattach(void)
1009 1.18 augustss {
1010 1.18 augustss
1011 1.31 thorpej /*
1012 1.31 thorpej * XXX USB requires too many parts of the kernel to be running
1013 1.31 thorpej * XXX in order to work, so we can't do much for the console
1014 1.31 thorpej * XXX keyboard until autconfiguration has run its course.
1015 1.31 thorpej */
1016 1.31 thorpej ukbd_is_console = 1;
1017 1.18 augustss return (0);
1018 1.75 augustss }
1019 1.75 augustss
1020 1.75 augustss const char *
1021 1.75 augustss ukbd_parse_desc(struct ukbd_softc *sc)
1022 1.75 augustss {
1023 1.75 augustss struct hid_data *d;
1024 1.75 augustss struct hid_item h;
1025 1.75 augustss int size;
1026 1.75 augustss void *desc;
1027 1.75 augustss int imod;
1028 1.75 augustss
1029 1.75 augustss uhidev_get_report_desc(sc->sc_hdev.sc_parent, &desc, &size);
1030 1.75 augustss imod = 0;
1031 1.75 augustss sc->sc_nkeycode = 0;
1032 1.75 augustss d = hid_start_parse(desc, size, hid_input);
1033 1.75 augustss while (hid_get_item(d, &h)) {
1034 1.75 augustss /*printf("ukbd: id=%d kind=%d usage=0x%x flags=0x%x pos=%d size=%d cnt=%d\n",
1035 1.75 augustss h.report_ID, h.kind, h.usage, h.flags, h.loc.pos, h.loc.size, h.loc.count);*/
1036 1.109 phx
1037 1.109 phx /* Check for special Apple notebook FN key */
1038 1.109 phx if (HID_GET_USAGE_PAGE(h.usage) == 0x00ff &&
1039 1.109 phx HID_GET_USAGE(h.usage) == 0x0003 &&
1040 1.109 phx h.kind == hid_input && (h.flags & HIO_VARIABLE)) {
1041 1.109 phx sc->sc_flags |= FLAG_APPLE_FN;
1042 1.109 phx sc->sc_apple_fn = h.loc;
1043 1.109 phx }
1044 1.109 phx
1045 1.75 augustss if (h.kind != hid_input || (h.flags & HIO_CONST) ||
1046 1.75 augustss HID_GET_USAGE_PAGE(h.usage) != HUP_KEYBOARD ||
1047 1.75 augustss h.report_ID != sc->sc_hdev.sc_report_id)
1048 1.75 augustss continue;
1049 1.79 augustss DPRINTF(("ukbd: imod=%d usage=0x%x flags=0x%x pos=%d size=%d "
1050 1.79 augustss "cnt=%d\n", imod,
1051 1.79 augustss h.usage, h.flags, h.loc.pos, h.loc.size, h.loc.count));
1052 1.75 augustss if (h.flags & HIO_VARIABLE) {
1053 1.80 augustss if (h.loc.size != 1)
1054 1.80 augustss return ("bad modifier size");
1055 1.75 augustss /* Single item */
1056 1.75 augustss if (imod < MAXMOD) {
1057 1.75 augustss sc->sc_modloc[imod] = h.loc;
1058 1.75 augustss sc->sc_mods[imod].mask = 1 << imod;
1059 1.75 augustss sc->sc_mods[imod].key = HID_GET_USAGE(h.usage);
1060 1.75 augustss imod++;
1061 1.75 augustss } else
1062 1.75 augustss return ("too many modifier keys");
1063 1.75 augustss } else {
1064 1.75 augustss /* Array */
1065 1.75 augustss if (h.loc.size != 8)
1066 1.75 augustss return ("key code size != 8");
1067 1.75 augustss if (h.loc.count > MAXKEYCODE)
1068 1.110 mbalmer h.loc.count = MAXKEYCODE;
1069 1.75 augustss if (h.loc.pos % 8 != 0)
1070 1.75 augustss return ("key codes not on byte boundary");
1071 1.75 augustss if (sc->sc_nkeycode != 0)
1072 1.75 augustss return ("multiple key code arrays\n");
1073 1.75 augustss sc->sc_keycodeloc = h.loc;
1074 1.75 augustss sc->sc_nkeycode = h.loc.count;
1075 1.75 augustss }
1076 1.75 augustss }
1077 1.75 augustss sc->sc_nmod = imod;
1078 1.75 augustss hid_end_parse(d);
1079 1.75 augustss
1080 1.75 augustss hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_NUM_LOCK),
1081 1.75 augustss sc->sc_hdev.sc_report_id, hid_output, &sc->sc_numloc, NULL);
1082 1.75 augustss hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_CAPS_LOCK),
1083 1.75 augustss sc->sc_hdev.sc_report_id, hid_output, &sc->sc_capsloc, NULL);
1084 1.75 augustss hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_SCROLL_LOCK),
1085 1.75 augustss sc->sc_hdev.sc_report_id, hid_output, &sc->sc_scroloc, NULL);
1086 1.75 augustss
1087 1.75 augustss return (NULL);
1088 1.18 augustss }
1089