Annotation of sys/dev/usb/uhid.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: uhid.c,v 1.41 2007/06/14 10:11:15 mbalmer Exp $ */
2: /* $NetBSD: uhid.c,v 1.57 2003/03/11 16:44:00 augustss Exp $ */
3:
4: /*
5: * Copyright (c) 1998 The NetBSD Foundation, Inc.
6: * All rights reserved.
7: *
8: * This code is derived from software contributed to The NetBSD Foundation
9: * by Lennart Augustsson (lennart@augustsson.net) at
10: * Carlstedt Research & Technology.
11: *
12: * Redistribution and use in source and binary forms, with or without
13: * modification, are permitted provided that the following conditions
14: * are met:
15: * 1. Redistributions of source code must retain the above copyright
16: * notice, this list of conditions and the following disclaimer.
17: * 2. Redistributions in binary form must reproduce the above copyright
18: * notice, this list of conditions and the following disclaimer in the
19: * documentation and/or other materials provided with the distribution.
20: * 3. All advertising materials mentioning features or use of this software
21: * must display the following acknowledgement:
22: * This product includes software developed by the NetBSD
23: * Foundation, Inc. and its contributors.
24: * 4. Neither the name of The NetBSD Foundation nor the names of its
25: * contributors may be used to endorse or promote products derived
26: * from this software without specific prior written permission.
27: *
28: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38: * POSSIBILITY OF SUCH DAMAGE.
39: */
40:
41: /*
42: * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
43: */
44:
45: #include <sys/param.h>
46: #include <sys/systm.h>
47: #include <sys/kernel.h>
48: #include <sys/malloc.h>
49: #include <sys/signalvar.h>
50: #include <sys/device.h>
51: #include <sys/ioctl.h>
52: #include <sys/conf.h>
53: #include <sys/tty.h>
54: #include <sys/file.h>
55: #include <sys/selinfo.h>
56: #include <sys/proc.h>
57: #include <sys/vnode.h>
58: #include <sys/poll.h>
59:
60: #include <dev/usb/usb.h>
61: #include <dev/usb/usbhid.h>
62:
63: #include <dev/usb/usbdevs.h>
64: #include <dev/usb/usbdi.h>
65: #include <dev/usb/usbdi_util.h>
66: #include <dev/usb/hid.h>
67: #include <dev/usb/usb_quirks.h>
68:
69: #include <dev/usb/uhidev.h>
70:
71: #ifdef UHID_DEBUG
72: #define DPRINTF(x) do { if (uhiddebug) printf x; } while (0)
73: #define DPRINTFN(n,x) do { if (uhiddebug>(n)) printf x; } while (0)
74: int uhiddebug = 0;
75: #else
76: #define DPRINTF(x)
77: #define DPRINTFN(n,x)
78: #endif
79:
80: struct uhid_softc {
81: struct uhidev sc_hdev;
82:
83: int sc_isize;
84: int sc_osize;
85: int sc_fsize;
86:
87: u_char *sc_obuf;
88:
89: struct clist sc_q;
90: struct selinfo sc_rsel;
91: struct proc *sc_async; /* process that wants SIGIO */
92: u_char sc_state; /* driver state */
93: #define UHID_ASLP 0x01 /* waiting for device data */
94: #define UHID_IMMED 0x02 /* return read data immediately */
95:
96: int sc_refcnt;
97: u_char sc_dying;
98: };
99:
100: #define UHIDUNIT(dev) (minor(dev))
101: #define UHID_CHUNK 128 /* chunk size for read */
102: #define UHID_BSIZE 1020 /* buffer size */
103:
104: void uhid_intr(struct uhidev *, void *, u_int len);
105:
106: int uhid_do_read(struct uhid_softc *, struct uio *uio, int);
107: int uhid_do_write(struct uhid_softc *, struct uio *uio, int);
108: int uhid_do_ioctl(struct uhid_softc*, u_long, caddr_t, int,
109: struct proc *);
110:
111: int uhid_match(struct device *, void *, void *);
112: void uhid_attach(struct device *, struct device *, void *);
113: int uhid_detach(struct device *, int);
114: int uhid_activate(struct device *, enum devact);
115:
116: struct cfdriver uhid_cd = {
117: NULL, "uhid", DV_DULL
118: };
119:
120: const struct cfattach uhid_ca = {
121: sizeof(struct uhid_softc),
122: uhid_match,
123: uhid_attach,
124: uhid_detach,
125: uhid_activate,
126: };
127:
128: int
129: uhid_match(struct device *parent, void *match, void *aux)
130: {
131: struct usb_attach_arg *uaa = aux;
132: struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa;
133:
134: DPRINTF(("uhid_match: report=%d\n", uha->reportid));
135:
136: if (uha->matchlvl)
137: return (uha->matchlvl);
138: return (UMATCH_IFACECLASS_GENERIC);
139: }
140:
141: void
142: uhid_attach(struct device *parent, struct device *self, void *aux)
143: {
144: struct uhid_softc *sc = (struct uhid_softc *)self;
145: struct usb_attach_arg *uaa = aux;
146: struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa;
147: int size, repid;
148: void *desc;
149:
150: sc->sc_hdev.sc_intr = uhid_intr;
151: sc->sc_hdev.sc_parent = uha->parent;
152: sc->sc_hdev.sc_report_id = uha->reportid;
153:
154: uhidev_get_report_desc(uha->parent, &desc, &size);
155: repid = uha->reportid;
156: sc->sc_isize = hid_report_size(desc, size, hid_input, repid);
157: sc->sc_osize = hid_report_size(desc, size, hid_output, repid);
158: sc->sc_fsize = hid_report_size(desc, size, hid_feature, repid);
159:
160: printf(": input=%d, output=%d, feature=%d\n",
161: sc->sc_isize, sc->sc_osize, sc->sc_fsize);
162: }
163:
164: int
165: uhid_activate(struct device *self, enum devact act)
166: {
167: struct uhid_softc *sc = (struct uhid_softc *)self;
168:
169: switch (act) {
170: case DVACT_ACTIVATE:
171: break;
172:
173: case DVACT_DEACTIVATE:
174: sc->sc_dying = 1;
175: break;
176: }
177: return (0);
178: }
179:
180: int
181: uhid_detach(struct device *self, int flags)
182: {
183: struct uhid_softc *sc = (struct uhid_softc *)self;
184: int s;
185: int maj, mn;
186:
187: DPRINTF(("uhid_detach: sc=%p flags=%d\n", sc, flags));
188:
189: sc->sc_dying = 1;
190:
191: if (sc->sc_hdev.sc_state & UHIDEV_OPEN) {
192: s = splusb();
193: if (--sc->sc_refcnt >= 0) {
194: /* Wake everyone */
195: wakeup(&sc->sc_q);
196: /* Wait for processes to go away. */
197: usb_detach_wait(&sc->sc_hdev.sc_dev);
198: }
199: splx(s);
200: }
201:
202: /* locate the major number */
203: for (maj = 0; maj < nchrdev; maj++)
204: if (cdevsw[maj].d_open == uhidopen)
205: break;
206:
207: /* Nuke the vnodes for any open instances (calls close). */
208: mn = self->dv_unit;
209: vdevgone(maj, mn, mn, VCHR);
210:
211: #if 0
212: usbd_add_drv_event(USB_EVENT_DRIVER_DETACH,
213: sc->sc_hdev.sc_parent->sc_udev,
214: &sc->sc_hdev.sc_dev);
215: #endif
216:
217: return (0);
218: }
219:
220: void
221: uhid_intr(struct uhidev *addr, void *data, u_int len)
222: {
223: struct uhid_softc *sc = (struct uhid_softc *)addr;
224:
225: #ifdef UHID_DEBUG
226: if (uhiddebug > 5) {
227: u_int32_t i;
228:
229: DPRINTF(("uhid_intr: data ="));
230: for (i = 0; i < len; i++)
231: DPRINTF((" %02x", ((u_char *)data)[i]));
232: DPRINTF(("\n"));
233: }
234: #endif
235:
236: (void)b_to_q(data, len, &sc->sc_q);
237:
238: if (sc->sc_state & UHID_ASLP) {
239: sc->sc_state &= ~UHID_ASLP;
240: DPRINTFN(5, ("uhid_intr: waking %p\n", &sc->sc_q));
241: wakeup(&sc->sc_q);
242: }
243: selwakeup(&sc->sc_rsel);
244: if (sc->sc_async != NULL) {
245: DPRINTFN(3, ("uhid_intr: sending SIGIO %p\n", sc->sc_async));
246: psignal(sc->sc_async, SIGIO);
247: }
248: }
249:
250: int
251: uhidopen(dev_t dev, int flag, int mode, struct proc *p)
252: {
253: struct uhid_softc *sc;
254: int error;
255:
256: if (UHIDUNIT(dev) >= uhid_cd.cd_ndevs)
257: return (ENXIO);
258: sc = uhid_cd.cd_devs[UHIDUNIT(dev)];
259: if (sc == NULL)
260: return (ENXIO);
261:
262: DPRINTF(("uhidopen: sc=%p\n", sc));
263:
264: if (sc->sc_dying)
265: return (ENXIO);
266:
267: error = uhidev_open(&sc->sc_hdev);
268: if (error)
269: return (error);
270:
271: if (clalloc(&sc->sc_q, UHID_BSIZE, 0) == -1) {
272: uhidev_close(&sc->sc_hdev);
273: return (ENOMEM);
274: }
275: sc->sc_obuf = malloc(sc->sc_osize, M_USBDEV, M_WAITOK);
276: sc->sc_state &= ~UHID_IMMED;
277: sc->sc_async = NULL;
278:
279: return (0);
280: }
281:
282: int
283: uhidclose(dev_t dev, int flag, int mode, struct proc *p)
284: {
285: struct uhid_softc *sc;
286:
287: sc = uhid_cd.cd_devs[UHIDUNIT(dev)];
288:
289: DPRINTF(("uhidclose: sc=%p\n", sc));
290:
291: clfree(&sc->sc_q);
292: free(sc->sc_obuf, M_USBDEV);
293: sc->sc_async = NULL;
294: uhidev_close(&sc->sc_hdev);
295:
296: return (0);
297: }
298:
299: int
300: uhid_do_read(struct uhid_softc *sc, struct uio *uio, int flag)
301: {
302: int s;
303: int error = 0;
304: int extra;
305: size_t length;
306: u_char buffer[UHID_CHUNK];
307: usbd_status err;
308:
309: DPRINTFN(1, ("uhidread\n"));
310: if (sc->sc_state & UHID_IMMED) {
311: DPRINTFN(1, ("uhidread immed\n"));
312: extra = sc->sc_hdev.sc_report_id != 0;
313: err = uhidev_get_report(&sc->sc_hdev, UHID_INPUT_REPORT,
314: buffer, sc->sc_isize + extra);
315: if (err)
316: return (EIO);
317: return (uiomove(buffer+extra, sc->sc_isize, uio));
318: }
319:
320: s = splusb();
321: while (sc->sc_q.c_cc == 0) {
322: if (flag & IO_NDELAY) {
323: splx(s);
324: return (EWOULDBLOCK);
325: }
326: sc->sc_state |= UHID_ASLP;
327: DPRINTFN(5, ("uhidread: sleep on %p\n", &sc->sc_q));
328: error = tsleep(&sc->sc_q, PZERO | PCATCH, "uhidrea", 0);
329: DPRINTFN(5, ("uhidread: woke, error=%d\n", error));
330: if (sc->sc_dying)
331: error = EIO;
332: if (error) {
333: sc->sc_state &= ~UHID_ASLP;
334: break;
335: }
336: }
337: splx(s);
338:
339: /* Transfer as many chunks as possible. */
340: while (sc->sc_q.c_cc > 0 && uio->uio_resid > 0 && !error) {
341: length = min(sc->sc_q.c_cc, uio->uio_resid);
342: if (length > sizeof(buffer))
343: length = sizeof(buffer);
344:
345: /* Remove a small chunk from the input queue. */
346: (void) q_to_b(&sc->sc_q, buffer, length);
347: DPRINTFN(5, ("uhidread: got %lu chars\n", (u_long)length));
348:
349: /* Copy the data to the user process. */
350: if ((error = uiomove(buffer, length, uio)) != 0)
351: break;
352: }
353:
354: return (error);
355: }
356:
357: int
358: uhidread(dev_t dev, struct uio *uio, int flag)
359: {
360: struct uhid_softc *sc;
361: int error;
362:
363: sc = uhid_cd.cd_devs[UHIDUNIT(dev)];
364:
365: sc->sc_refcnt++;
366: error = uhid_do_read(sc, uio, flag);
367: if (--sc->sc_refcnt < 0)
368: usb_detach_wakeup(&sc->sc_hdev.sc_dev);
369: return (error);
370: }
371:
372: int
373: uhid_do_write(struct uhid_softc *sc, struct uio *uio, int flag)
374: {
375: int error;
376: int size;
377: usbd_status err;
378:
379: DPRINTFN(1, ("uhidwrite\n"));
380:
381: if (sc->sc_dying)
382: return (EIO);
383:
384: size = sc->sc_osize;
385: error = 0;
386: if (uio->uio_resid != size)
387: return (EINVAL);
388: error = uiomove(sc->sc_obuf, size, uio);
389: if (!error) {
390: err = uhidev_set_report(&sc->sc_hdev, UHID_OUTPUT_REPORT,
391: sc->sc_obuf, size);
392: if (err)
393: error = EIO;
394: }
395:
396: return (error);
397: }
398:
399: int
400: uhidwrite(dev_t dev, struct uio *uio, int flag)
401: {
402: struct uhid_softc *sc;
403: int error;
404:
405: sc = uhid_cd.cd_devs[UHIDUNIT(dev)];
406:
407: sc->sc_refcnt++;
408: error = uhid_do_write(sc, uio, flag);
409: if (--sc->sc_refcnt < 0)
410: usb_detach_wakeup(&sc->sc_hdev.sc_dev);
411: return (error);
412: }
413:
414: int
415: uhid_do_ioctl(struct uhid_softc *sc, u_long cmd, caddr_t addr,
416: int flag, struct proc *p)
417: {
418: struct usb_ctl_report_desc *rd;
419: struct usb_ctl_report *re;
420: u_char buffer[UHID_CHUNK];
421: int size, extra;
422: usbd_status err;
423: void *desc;
424:
425: DPRINTFN(2, ("uhidioctl: cmd=%lx\n", cmd));
426:
427: if (sc->sc_dying)
428: return (EIO);
429:
430: switch (cmd) {
431: case FIONBIO:
432: /* All handled in the upper FS layer. */
433: break;
434:
435: case FIOASYNC:
436: if (*(int *)addr) {
437: if (sc->sc_async != NULL)
438: return (EBUSY);
439: sc->sc_async = p;
440: DPRINTF(("uhid_do_ioctl: FIOASYNC %p\n", p));
441: } else
442: sc->sc_async = NULL;
443: break;
444:
445: /* XXX this is not the most general solution. */
446: case TIOCSPGRP:
447: if (sc->sc_async == NULL)
448: return (EINVAL);
449: if (*(int *)addr != sc->sc_async->p_pgid)
450: return (EPERM);
451: break;
452:
453: case USB_GET_REPORT_DESC:
454: uhidev_get_report_desc(sc->sc_hdev.sc_parent, &desc, &size);
455: rd = (struct usb_ctl_report_desc *)addr;
456: size = min(size, sizeof rd->ucrd_data);
457: rd->ucrd_size = size;
458: memcpy(rd->ucrd_data, desc, size);
459: break;
460:
461: case USB_SET_IMMED:
462: if (*(int *)addr) {
463: extra = sc->sc_hdev.sc_report_id != 0;
464: err = uhidev_get_report(&sc->sc_hdev, UHID_INPUT_REPORT,
465: buffer, sc->sc_isize + extra);
466: if (err)
467: return (EOPNOTSUPP);
468:
469: sc->sc_state |= UHID_IMMED;
470: } else
471: sc->sc_state &= ~UHID_IMMED;
472: break;
473:
474: case USB_GET_REPORT:
475: re = (struct usb_ctl_report *)addr;
476: switch (re->ucr_report) {
477: case UHID_INPUT_REPORT:
478: size = sc->sc_isize;
479: break;
480: case UHID_OUTPUT_REPORT:
481: size = sc->sc_osize;
482: break;
483: case UHID_FEATURE_REPORT:
484: size = sc->sc_fsize;
485: break;
486: default:
487: return (EINVAL);
488: }
489: extra = sc->sc_hdev.sc_report_id != 0;
490: err = uhidev_get_report(&sc->sc_hdev, re->ucr_report,
491: re->ucr_data, size + extra);
492: if (extra)
493: memcpy(re->ucr_data, re->ucr_data+1, size);
494: if (err)
495: return (EIO);
496: break;
497:
498: case USB_SET_REPORT:
499: re = (struct usb_ctl_report *)addr;
500: switch (re->ucr_report) {
501: case UHID_INPUT_REPORT:
502: size = sc->sc_isize;
503: break;
504: case UHID_OUTPUT_REPORT:
505: size = sc->sc_osize;
506: break;
507: case UHID_FEATURE_REPORT:
508: size = sc->sc_fsize;
509: break;
510: default:
511: return (EINVAL);
512: }
513: err = uhidev_set_report(&sc->sc_hdev, re->ucr_report,
514: re->ucr_data, size);
515: if (err)
516: return (EIO);
517: break;
518:
519: case USB_GET_REPORT_ID:
520: *(int *)addr = sc->sc_hdev.sc_report_id;
521: break;
522:
523: default:
524: return (EINVAL);
525: }
526: return (0);
527: }
528:
529: int
530: uhidioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
531: {
532: struct uhid_softc *sc;
533: int error;
534:
535: sc = uhid_cd.cd_devs[UHIDUNIT(dev)];
536:
537: sc->sc_refcnt++;
538: error = uhid_do_ioctl(sc, cmd, addr, flag, p);
539: if (--sc->sc_refcnt < 0)
540: usb_detach_wakeup(&sc->sc_hdev.sc_dev);
541: return (error);
542: }
543:
544: int
545: uhidpoll(dev_t dev, int events, struct proc *p)
546: {
547: struct uhid_softc *sc;
548: int revents = 0;
549: int s;
550:
551: sc = uhid_cd.cd_devs[UHIDUNIT(dev)];
552:
553: if (sc->sc_dying)
554: return (POLLERR);
555:
556: s = splusb();
557: if (events & (POLLOUT | POLLWRNORM))
558: revents |= events & (POLLOUT | POLLWRNORM);
559: if (events & (POLLIN | POLLRDNORM)) {
560: if (sc->sc_q.c_cc > 0)
561: revents |= events & (POLLIN | POLLRDNORM);
562: else
563: selrecord(p, &sc->sc_rsel);
564: }
565:
566: splx(s);
567: return (revents);
568: }
569:
570: void filt_uhidrdetach(struct knote *);
571: int filt_uhidread(struct knote *, long);
572: int uhidkqfilter(dev_t, struct knote *);
573:
574: void
575: filt_uhidrdetach(struct knote *kn)
576: {
577: struct uhid_softc *sc = (void *)kn->kn_hook;
578: int s;
579:
580: s = splusb();
581: SLIST_REMOVE(&sc->sc_rsel.si_note, kn, knote, kn_selnext);
582: splx(s);
583: }
584:
585: int
586: filt_uhidread(struct knote *kn, long hint)
587: {
588: struct uhid_softc *sc = (void *)kn->kn_hook;
589:
590: kn->kn_data = sc->sc_q.c_cc;
591: return (kn->kn_data > 0);
592: }
593:
594: struct filterops uhidread_filtops =
595: { 1, NULL, filt_uhidrdetach, filt_uhidread };
596:
597: struct filterops uhid_seltrue_filtops =
598: { 1, NULL, filt_uhidrdetach, filt_seltrue };
599:
600: int
601: uhidkqfilter(dev_t dev, struct knote *kn)
602: {
603: struct uhid_softc *sc;
604: struct klist *klist;
605: int s;
606:
607: sc = uhid_cd.cd_devs[UHIDUNIT(dev)];
608:
609: if (sc->sc_dying)
610: return (EIO);
611:
612: switch (kn->kn_filter) {
613: case EVFILT_READ:
614: klist = &sc->sc_rsel.si_note;
615: kn->kn_fop = &uhidread_filtops;
616: break;
617:
618: case EVFILT_WRITE:
619: klist = &sc->sc_rsel.si_note;
620: kn->kn_fop = &uhid_seltrue_filtops;
621: break;
622:
623: default:
624: return (1);
625: }
626:
627: kn->kn_hook = (void *)sc;
628:
629: s = splusb();
630: SLIST_INSERT_HEAD(klist, kn, kn_selnext);
631: splx(s);
632:
633: return (0);
634: }
CVSweb