ukbd.c revision 1.1 1 /* $NetBSD: ukbd.c,v 1.1 1998/07/12 19:52:00 augustss Exp $ */
2
3 /*
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Author: Lennart Augustsson <augustss (at) carlstedt.se>
8 * Carlstedt Research & Technology
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #include <sys/malloc.h>
44 #include <sys/device.h>
45 #include <sys/ioctl.h>
46 #include <sys/tty.h>
47 #include <sys/file.h>
48 #include <sys/select.h>
49 #include <sys/proc.h>
50 #include <sys/vnode.h>
51 #include <sys/device.h>
52 #include <sys/poll.h>
53
54 #include <dev/usb/usb.h>
55
56 #include <dev/usb/usbdi.h>
57 #include <dev/usb/usbdi_util.h>
58 #include <dev/usb/usbdevs.h>
59 #include <dev/usb/usb_quirks.h>
60 #include <dev/usb/hid.h>
61
62 #ifdef USB_DEBUG
63 #define DPRINTF(x) if (ukbddebug) printf x
64 #define DPRINTFN(n,x) if (ukbddebug>(n)) printf x
65 int ukbddebug = 0;
66 #else
67 #define DPRINTF(x)
68 #define DPRINTFN(n,x)
69 #endif
70
71 #define UPROTO_BOOT_KEYBOARD 1
72
73 #define NKEYCODE 6
74
75 struct ukbd_data {
76 u_int8_t modifiers;
77 #define MOD_CONTROL_L 0x01
78 #define MOD_CONTROL_R 0x10
79 #define MOD_SHIFT_L 0x02
80 #define MOD_SHIFT_R 0x20
81 #define MOD_ALT_L 0x04
82 #define MOD_ALT_R 0x40
83 #define MOD_WIN_L 0x08
84 #define MOD_WIN_R 0x80
85 u_int8_t reserved;
86 u_int8_t keycode[NKEYCODE];
87 };
88
89 #define PRESS 0
90 #define RELEASE 0x80
91
92 #define NMOD 6
93 static struct {
94 int mask, key;
95 } ukbd_mods[NMOD] = {
96 { MOD_CONTROL_L, 29 },
97 { MOD_CONTROL_R, 58 },
98 { MOD_SHIFT_L, 42 },
99 { MOD_SHIFT_R, 54 },
100 { MOD_ALT_L, 56 },
101 { MOD_ALT_R, 56 },
102 };
103
104 #define XX 0
105 /* Translate USB keycodes to US keyboard scancodes. */
106 /* XXX very incomplete */
107 static char ukbd_trtab[256] = {
108 0, 0, 0, 0, 30, 48, 46, 32,
109 18, 33, 34, 35, 23, 36, 37, 38,
110 50, 49, 24, 25, 16, 19, 31, 20,
111 22, 47, 17, 45, 21, 44, 2, 3,
112 4, 5, 6, 7, 8, 9, 10, 11,
113 28, 1, 14, 15, 57, 12, 13, 26,
114 27, 43, XX, 39, 40, 41, 51, 52,
115 53, 58, 59, 60, 61, 62, 63, 64,
116 65, 66, 67, 68, 87, 88, XX, 70,
117 XX, XX, XX, XX, XX,
118 };
119
120 #define KEY_ERROR 0x01
121
122 struct ukbd_softc {
123 struct device sc_dev; /* base device */
124 usbd_interface_handle sc_iface; /* interface */
125 usbd_pipe_handle sc_intrpipe; /* interrupt pipe */
126 int sc_ep_addr;
127
128 struct ukbd_data sc_ndata;
129 struct ukbd_data sc_odata;
130
131 struct clist sc_q;
132 struct selinfo sc_rsel;
133 u_char sc_state; /* keyboard driver state */
134 #define UKBD_OPEN 0x01 /* device is open */
135 #define UKBD_ASLP 0x02 /* waiting for keyboard data */
136 #define UKBD_NEEDCLEAR 0x04 /* needs clearing endpoint stall */
137
138 int sc_disconnected; /* device is gone */
139 };
140
141 #define UKBDUNIT(dev) (minor(dev))
142 #define UKBD_CHUNK 128 /* chunk size for read */
143 #define UKBD_BSIZE 1020 /* buffer size */
144
145 int ukbd_match __P((struct device *, struct cfdata *, void *));
146 void ukbd_attach __P((struct device *, struct device *, void *));
147
148 int ukbdopen __P((dev_t, int, int, struct proc *));
149 int ukbdclose __P((dev_t, int, int, struct proc *p));
150 int ukbdread __P((dev_t, struct uio *uio, int));
151 int ukbdioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
152 int ukbdpoll __P((dev_t, int, struct proc *));
153 void ukbd_intr __P((usbd_request_handle, usbd_private_handle, usbd_status));
154 void ukbd_disco __P((void *));
155
156 extern struct cfdriver ukbd_cd;
157
158 struct cfattach ukbd_ca = {
159 sizeof(struct ukbd_softc), ukbd_match, ukbd_attach
160 };
161
162 int
163 ukbd_match(parent, match, aux)
164 struct device *parent;
165 struct cfdata *match;
166 void *aux;
167 {
168 struct usb_attach_arg *uaa = (struct usb_attach_arg *)aux;
169 usb_interface_descriptor_t *id;
170
171 /* Check that this is a keyboard that speaks the boot protocol. */
172 if (!uaa->iface)
173 return (UMATCH_NONE);
174 id = usbd_get_interface_descriptor(uaa->iface);
175 if (id->bInterfaceClass != UCLASS_HID ||
176 id->bInterfaceSubClass != USUBCLASS_BOOT ||
177 id->bInterfaceProtocol != UPROTO_BOOT_KEYBOARD)
178 return (UMATCH_NONE);
179 return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO);
180 }
181
182 void
183 ukbd_attach(parent, self, aux)
184 struct device *parent;
185 struct device *self;
186 void *aux;
187 {
188 struct ukbd_softc *sc = (struct ukbd_softc *)self;
189 struct usb_attach_arg *uaa = aux;
190 usbd_interface_handle iface = uaa->iface;
191 usb_interface_descriptor_t *id;
192 usb_endpoint_descriptor_t *ed;
193 usbd_status r;
194 char devinfo[1024];
195
196 sc->sc_disconnected = 1;
197 sc->sc_iface = iface;
198 id = usbd_get_interface_descriptor(iface);
199 usbd_devinfo(uaa->device, 0, devinfo);
200 printf(": %s (interface class %d/%d)\n", devinfo,
201 id->bInterfaceClass, id->bInterfaceSubClass);
202 ed = usbd_interface2endpoint_descriptor(iface, 0);
203 if (!ed) {
204 printf("%s: could not read endpoint descriptor\n",
205 sc->sc_dev.dv_xname);
206 return;
207 }
208
209 DPRINTFN(10,("ukbd_attach: \
210 bLength=%d bDescriptorType=%d bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d bInterval=%d\n",
211 ed->bLength, ed->bDescriptorType, ed->bEndpointAddress & UE_ADDR,
212 ed->bEndpointAddress & UE_IN ? "in" : "out",
213 ed->bmAttributes & UE_XFERTYPE,
214 UGETW(ed->wMaxPacketSize), ed->bInterval));
215
216 if ((ed->bEndpointAddress & UE_IN) != UE_IN ||
217 (ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) {
218 printf("%s: unexpected endpoint\n",
219 sc->sc_dev.dv_xname);
220 return;
221 }
222
223 if ((usbd_get_quirks(uaa->device)->uq_flags & UQ_NO_SET_PROTO) == 0) {
224 r = usbd_set_protocol(iface, 0);
225 DPRINTFN(5, ("ukbd_attach: protocol set\n"));
226 if (r != USBD_NORMAL_COMPLETION) {
227 printf("%s: set protocol failed\n",
228 sc->sc_dev.dv_xname);
229 return;
230 }
231 }
232
233 sc->sc_ep_addr = ed->bEndpointAddress;
234 sc->sc_disconnected = 0;
235 }
236
237 void
238 ukbd_disco(p)
239 void *p;
240 {
241 struct ukbd_softc *sc = p;
242 sc->sc_disconnected = 1;
243 }
244
245 void
246 ukbd_intr(reqh, addr, status)
247 usbd_request_handle reqh;
248 usbd_private_handle addr;
249 usbd_status status;
250 {
251 struct ukbd_softc *sc = addr;
252 struct ukbd_data *ud = &sc->sc_ndata;
253 int mod, omod;
254 char ibuf[NMOD+2*NKEYCODE]; /* chars events */
255 int nkeys, i, j;
256 int key, ch;
257 #define ADDKEY(c) ibuf[nkeys++] = (c)
258
259 DPRINTFN(5, ("ukbd_intr: status=%d\n", status));
260 if (status == USBD_CANCELLED)
261 return;
262
263 if (status != USBD_NORMAL_COMPLETION) {
264 DPRINTF(("ukbd_intr: status=%d\n", status));
265 sc->sc_state |= UKBD_NEEDCLEAR;
266 return;
267 }
268
269 DPRINTFN(5, (" mod=0x%02x key0=0x%02x key1=0x%02x\n",
270 ud->modifiers, ud->keycode[0], ud->keycode[1]));
271
272 if (ud->keycode[0] == KEY_ERROR)
273 return; /* ignore */
274 nkeys = 0;
275 mod = ud->modifiers;
276 omod = sc->sc_odata.modifiers;
277 if (mod != omod)
278 for (i = 0; i < NMOD; i++)
279 if (( mod & ukbd_mods[i].mask) !=
280 (omod & ukbd_mods[i].mask))
281 ADDKEY(ukbd_mods[i].key |
282 (mod & ukbd_mods[i].mask
283 ? PRESS : RELEASE));
284 if (memcmp(ud->keycode, sc->sc_odata.keycode, NKEYCODE) != 0) {
285 /* Check for released keys. */
286 for (i = 0; i < NKEYCODE; i++) {
287 key = sc->sc_odata.keycode[i];
288 if (key == 0)
289 continue;
290 for (j = 0; j < NKEYCODE; j++)
291 if (key == ud->keycode[j])
292 goto rfound;
293 ch = ukbd_trtab[key];
294 if (ch)
295 ADDKEY(ch | RELEASE);
296 rfound:
297 ;
298 }
299
300 /* Check for pressed keys. */
301 for (i = 0; i < NKEYCODE; i++) {
302 key = ud->keycode[i];
303 if (key == 0)
304 continue;
305 for (j = 0; j < NKEYCODE; j++)
306 if (key == sc->sc_odata.keycode[j])
307 goto pfound;
308 ch = ukbd_trtab[key];
309 if (ch)
310 ADDKEY(ch | PRESS);
311 pfound:
312 ;
313 }
314 }
315 sc->sc_odata = *ud;
316
317 if (nkeys) {
318 b_to_q(ibuf, nkeys, &sc->sc_q);
319
320 if (sc->sc_state & UKBD_ASLP) {
321 sc->sc_state &= ~UKBD_ASLP;
322 DPRINTFN(5, ("ukbd_intr: waking %p\n", sc));
323 wakeup((caddr_t)sc);
324 }
325 selwakeup(&sc->sc_rsel);
326 }
327 }
328
329 int
330 ukbdopen(dev, flag, mode, p)
331 dev_t dev;
332 int flag;
333 int mode;
334 struct proc *p;
335 {
336 int unit = UKBDUNIT(dev);
337 struct ukbd_softc *sc;
338 usbd_status r;
339
340 if (unit >= ukbd_cd.cd_ndevs)
341 return ENXIO;
342 sc = ukbd_cd.cd_devs[unit];
343 if (!sc)
344 return ENXIO;
345
346 DPRINTF(("ukbdopen: sc=%p, disco=%d\n", sc, sc->sc_disconnected));
347
348 if (sc->sc_disconnected)
349 return (EIO);
350
351 if (sc->sc_state & UKBD_OPEN)
352 return EBUSY;
353
354 if (clalloc(&sc->sc_q, UKBD_BSIZE, 0) == -1)
355 return ENOMEM;
356
357 sc->sc_state |= UKBD_OPEN;
358
359 /* Set up interrupt pipe. */
360 r = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ep_addr,
361 USBD_SHORT_XFER_OK,
362 &sc->sc_intrpipe, sc, &sc->sc_ndata,
363 sizeof(sc->sc_ndata), ukbd_intr);
364 if (r != USBD_NORMAL_COMPLETION) {
365 DPRINTF(("ukbdopen: usbd_open_pipe_intr failed, error=%d\n",r));
366 sc->sc_state &= ~UKBD_OPEN;
367 clfree(&sc->sc_q);
368 return (EIO);
369 }
370 usbd_set_disco(sc->sc_intrpipe, ukbd_disco, sc);
371 return 0;
372 }
373
374 int
375 ukbdclose(dev, flag, mode, p)
376 dev_t dev;
377 int flag;
378 int mode;
379 struct proc *p;
380 {
381 struct ukbd_softc *sc = ukbd_cd.cd_devs[UKBDUNIT(dev)];
382
383 if (sc->sc_disconnected)
384 return (EIO);
385
386 /* Disable interrupts. */
387 usbd_abort_pipe(sc->sc_intrpipe);
388 usbd_close_pipe(sc->sc_intrpipe);
389
390 sc->sc_state &= ~UKBD_OPEN;
391
392 clfree(&sc->sc_q);
393
394 return 0;
395 }
396
397 int
398 ukbdread(dev, uio, flag)
399 dev_t dev;
400 struct uio *uio;
401 int flag;
402 {
403 struct ukbd_softc *sc = ukbd_cd.cd_devs[UKBDUNIT(dev)];
404 int s;
405 int error = 0;
406 size_t length;
407 u_char buffer[UKBD_CHUNK];
408
409 if (sc->sc_disconnected)
410 return (EIO);
411
412 /* Block until keyboard activity occured. */
413 s = spltty();
414 while (sc->sc_q.c_cc == 0) {
415 if (flag & IO_NDELAY) {
416 splx(s);
417 return EWOULDBLOCK;
418 }
419 sc->sc_state |= UKBD_ASLP;
420 DPRINTFN(5, ("ukbdread: sleep on %p\n", sc));
421 error = tsleep((caddr_t)sc, PZERO | PCATCH, "ukbdrea", 0);
422 DPRINTFN(5, ("ukbdread: woke, error=%d\n", error));
423 if (error) {
424 sc->sc_state &= ~UKBD_ASLP;
425 splx(s);
426 return error;
427 }
428 }
429 splx(s);
430
431 /* Transfer as many chunks as possible. */
432 while (sc->sc_q.c_cc > 0 && uio->uio_resid > 0) {
433 length = min(sc->sc_q.c_cc, uio->uio_resid);
434 if (length > sizeof(buffer))
435 length = sizeof(buffer);
436
437 /* Remove a small chunk from the input queue. */
438 (void) q_to_b(&sc->sc_q, buffer, length);
439 DPRINTFN(5, ("ukbdread: got %d chars\n", length));
440
441 /* Copy the data to the user process. */
442 if ((error = uiomove(buffer, length, uio)) != 0)
443 break;
444 }
445
446 return error;
447 }
448
449 int
450 ukbdioctl(dev, cmd, addr, flag, p)
451 dev_t dev;
452 u_long cmd;
453 caddr_t addr;
454 int flag;
455 struct proc *p;
456 {
457 struct ukbd_softc *sc = ukbd_cd.cd_devs[UKBDUNIT(dev)];
458
459 if (sc->sc_disconnected)
460 return (EIO);
461
462 return EINVAL;
463 }
464
465 int
466 ukbdpoll(dev, events, p)
467 dev_t dev;
468 int events;
469 struct proc *p;
470 {
471 struct ukbd_softc *sc = ukbd_cd.cd_devs[UKBDUNIT(dev)];
472 int revents = 0;
473 int s;
474
475 if (sc->sc_disconnected)
476 return (EIO);
477
478 s = spltty();
479 if (events & (POLLIN | POLLRDNORM))
480 if (sc->sc_q.c_cc > 0)
481 revents |= events & (POLLIN | POLLRDNORM);
482 else
483 selrecord(p, &sc->sc_rsel);
484
485 splx(s);
486 return (revents);
487 }
488