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