2 * $NetBSD: uhid.c,v 1.46 2001/11/13 06:24:55 lukem Exp $
3 * $FreeBSD: src/sys/dev/usb/uhid.c,v 1.65 2003/11/09 09:17:22 tanimura Exp $
4 * $DragonFly: src/sys/dev/usbmisc/uhid/uhid.c,v 1.24 2007/06/28 13:55:13 hasso Exp $
7 /* Also already merged from NetBSD:
8 * $NetBSD: uhid.c,v 1.54 2002/09/23 05:51:21 simonb Exp $
12 * Copyright (c) 1998 The NetBSD Foundation, Inc.
13 * All rights reserved.
15 * This code is derived from software contributed to The NetBSD Foundation
16 * by Lennart Augustsson (lennart@augustsson.net) at
17 * Carlstedt Research & Technology.
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions
22 * 1. Redistributions of source code must retain the above copyright
23 * notice, this list of conditions and the following disclaimer.
24 * 2. Redistributions in binary form must reproduce the above copyright
25 * notice, this list of conditions and the following disclaimer in the
26 * documentation and/or other materials provided with the distribution.
27 * 3. All advertising materials mentioning features or use of this software
28 * must display the following acknowledgement:
29 * This product includes software developed by the NetBSD
30 * Foundation, Inc. and its contributors.
31 * 4. Neither the name of The NetBSD Foundation nor the names of its
32 * contributors may be used to endorse or promote products derived
33 * from this software without specific prior written permission.
35 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
36 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
37 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
38 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
39 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
40 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
41 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
42 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
43 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
44 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
45 * POSSIBILITY OF SUCH DAMAGE.
49 * HID spec: http://www.usb.org/developers/data/usbhid10.pdf
52 #include <sys/param.h>
53 #include <sys/systm.h>
54 #include <sys/kernel.h>
56 #include <sys/malloc.h>
57 #include <sys/signalvar.h>
58 #include <sys/ioccom.h>
59 #include <sys/filio.h>
60 #include <sys/module.h>
62 #include <sys/ioccom.h>
65 #include <sys/select.h>
67 #include <sys/vnode.h>
69 #include <sys/sysctl.h>
70 #include <sys/thread2.h>
72 #include <bus/usb/usb.h>
73 #include <bus/usb/usbhid.h>
75 #include <bus/usb/usbdevs.h>
76 #include <bus/usb/usbdi.h>
77 #include <bus/usb/usbdi_util.h>
78 #include <bus/usb/hid.h>
80 /* Report descriptor for broken Wacom Graphire */
81 #include <bus/usb/ugraphire_rdesc.h>
84 #define DPRINTF(x) if (uhiddebug) kprintf x
85 #define DPRINTFN(n,x) if (uhiddebug>(n)) kprintf x
87 SYSCTL_NODE(_hw_usb
, OID_AUTO
, uhid
, CTLFLAG_RW
, 0, "USB uhid");
88 SYSCTL_INT(_hw_usb_uhid
, OID_AUTO
, debug
, CTLFLAG_RW
,
89 &uhiddebug
, 0, "uhid debug level");
96 device_t sc_dev
; /* base device */
97 usbd_device_handle sc_udev
;
98 usbd_interface_handle sc_iface
; /* interface */
99 usbd_pipe_handle sc_intrpipe
; /* interrupt pipe */
116 struct selinfo sc_rsel
;
117 struct proc
*sc_async
; /* process that wants SIGIO */
118 u_char sc_state
; /* driver state */
119 #define UHID_OPEN 0x01 /* device is open */
120 #define UHID_ASLP 0x02 /* waiting for device data */
121 #define UHID_NEEDCLEAR 0x04 /* needs clearing endpoint stall */
122 #define UHID_IMMED 0x08 /* return read data immediately */
128 #define UHIDUNIT(dev) (minor(dev))
129 #define UHID_CHUNK 128 /* chunk size for read */
130 #define UHID_BSIZE 1020 /* buffer size */
139 #define UHID_CDEV_MAJOR 122
141 static struct dev_ops uhid_ops
= {
142 { "uhid", UHID_CDEV_MAJOR
, 0 },
144 .d_close
= uhidclose
,
146 .d_write
= uhidwrite
,
147 .d_ioctl
= uhidioctl
,
151 static void uhid_intr(usbd_xfer_handle
, usbd_private_handle
,
154 static int uhid_do_read(struct uhid_softc
*, struct uio
*uio
, int);
155 static int uhid_do_write(struct uhid_softc
*, struct uio
*uio
, int);
156 static int uhid_do_ioctl(struct uhid_softc
*, u_long
, caddr_t
, int);
158 USB_DECLARE_DRIVER(uhid
);
162 USB_MATCH_START(uhid
, uaa
);
163 usb_interface_descriptor_t
*id
;
165 if (uaa
->iface
== NULL
)
166 return (UMATCH_NONE
);
167 id
= usbd_get_interface_descriptor(uaa
->iface
);
168 if (id
== NULL
|| id
->bInterfaceClass
!= UICLASS_HID
)
169 return (UMATCH_NONE
);
171 return (uaa
->matchlvl
);
172 return (UMATCH_IFACECLASS_GENERIC
);
177 USB_ATTACH_START(uhid
, sc
, uaa
);
178 usbd_interface_handle iface
= uaa
->iface
;
179 usb_interface_descriptor_t
*id
;
180 usb_endpoint_descriptor_t
*ed
;
186 sc
->sc_udev
= uaa
->device
;
187 sc
->sc_iface
= iface
;
188 id
= usbd_get_interface_descriptor(iface
);
189 usbd_devinfo(uaa
->device
, 0, devinfo
);
191 kprintf("%s: %s, iclass %d/%d\n", device_get_nameunit(sc
->sc_dev
),
192 devinfo
, id
->bInterfaceClass
, id
->bInterfaceSubClass
);
194 ed
= usbd_interface2endpoint_descriptor(iface
, 0);
196 kprintf("%s: could not read endpoint descriptor\n",
197 device_get_nameunit(sc
->sc_dev
));
199 USB_ATTACH_ERROR_RETURN
;
202 DPRINTFN(10,("uhid_attach: bLength=%d bDescriptorType=%d "
203 "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d"
205 ed
->bLength
, ed
->bDescriptorType
,
206 ed
->bEndpointAddress
& UE_ADDR
,
207 UE_GET_DIR(ed
->bEndpointAddress
)==UE_DIR_IN
? "in" : "out",
208 ed
->bmAttributes
& UE_XFERTYPE
,
209 UGETW(ed
->wMaxPacketSize
), ed
->bInterval
));
211 if (UE_GET_DIR(ed
->bEndpointAddress
) != UE_DIR_IN
||
212 (ed
->bmAttributes
& UE_XFERTYPE
) != UE_INTERRUPT
) {
213 kprintf("%s: unexpected endpoint\n", device_get_nameunit(sc
->sc_dev
));
215 USB_ATTACH_ERROR_RETURN
;
218 sc
->sc_ep_addr
= ed
->bEndpointAddress
;
220 if (uaa
->vendor
== USB_VENDOR_WACOM
&&
221 uaa
->product
== USB_PRODUCT_WACOM_GRAPHIRE
/* &&
222 uaa->revision == 0x???? */) { /* XXX should use revision */
223 /* The report descriptor for the Wacom Graphire is broken. */
224 size
= sizeof uhid_graphire_report_descr
;
225 desc
= kmalloc(size
, M_USBDEV
, M_INTWAIT
);
226 err
= USBD_NORMAL_COMPLETION
;
227 memcpy(desc
, uhid_graphire_report_descr
, size
);
230 err
= usbd_read_report_desc(uaa
->iface
, &desc
, &size
,M_USBDEV
);
234 kprintf("%s: no report descriptor\n", device_get_nameunit(sc
->sc_dev
));
236 USB_ATTACH_ERROR_RETURN
;
239 (void)usbd_set_idle(iface
, 0, 0);
241 sc
->sc_isize
= hid_report_size(desc
, size
, hid_input
, &sc
->sc_iid
);
242 sc
->sc_osize
= hid_report_size(desc
, size
, hid_output
, &sc
->sc_oid
);
243 sc
->sc_fsize
= hid_report_size(desc
, size
, hid_feature
, &sc
->sc_fid
);
245 sc
->sc_repdesc
= desc
;
246 sc
->sc_repdesc_size
= size
;
248 dev_ops_add(&uhid_ops
, -1, device_get_unit(self
));
249 make_dev(&uhid_ops
, device_get_unit(self
),
250 UID_ROOT
, GID_OPERATOR
,
251 0644, "uhid%d", device_get_unit(self
));
253 USB_ATTACH_SUCCESS_RETURN
;
258 USB_DETACH_START(uhid
, sc
);
260 DPRINTF(("uhid_detach: sc=%p\n", sc
));
263 if (sc
->sc_intrpipe
!= NULL
)
264 usbd_abort_pipe(sc
->sc_intrpipe
);
266 if (sc
->sc_state
& UHID_OPEN
) {
268 if (--sc
->sc_refcnt
>= 0) {
271 /* Wait for processes to go away. */
272 usb_detach_wait(sc
->sc_dev
);
277 dev_ops_remove(&uhid_ops
, -1, device_get_unit(self
));
280 kfree(sc
->sc_repdesc
, M_USBDEV
);
286 uhid_intr(usbd_xfer_handle xfer
, usbd_private_handle addr
, usbd_status status
)
288 struct uhid_softc
*sc
= addr
;
294 usbd_get_xfer_status(xfer
, NULL
, NULL
, &cc
, NULL
);
295 DPRINTF(("uhid_intr: status=%d cc=%d\n", status
, cc
));
296 DPRINTF(("uhid_intr: data ="));
297 for (i
= 0; i
< cc
; i
++)
298 DPRINTF((" %02x", sc
->sc_ibuf
[i
]));
303 if (status
== USBD_CANCELLED
)
306 if (status
!= USBD_NORMAL_COMPLETION
) {
307 DPRINTF(("uhid_intr: status=%d\n", status
));
308 if (status
== USBD_STALLED
)
309 sc
->sc_state
|= UHID_NEEDCLEAR
;
313 (void) b_to_q(sc
->sc_ibuf
, sc
->sc_isize
, &sc
->sc_q
);
315 if (sc
->sc_state
& UHID_ASLP
) {
316 sc
->sc_state
&= ~UHID_ASLP
;
317 DPRINTFN(5, ("uhid_intr: waking %p\n", &sc
->sc_q
));
320 selwakeuppri(&sc
->sc_rsel
, 0);
321 if (sc
->sc_async
!= NULL
) {
322 DPRINTFN(3, ("uhid_intr: sending SIGIO %p\n", sc
->sc_async
));
323 PROC_LOCK(sc
->sc_async
);
324 ksignal(sc
->sc_async
, SIGIO
);
325 PROC_UNLOCK(sc
->sc_async
);
330 uhidopen(struct dev_open_args
*ap
)
332 cdev_t dev
= ap
->a_head
.a_dev
;
333 struct uhid_softc
*sc
;
336 USB_GET_SC_OPEN(uhid
, UHIDUNIT(dev
), sc
);
338 DPRINTF(("uhidopen: sc=%p\n", sc
));
343 if (sc
->sc_state
& UHID_OPEN
)
345 sc
->sc_state
|= UHID_OPEN
;
347 if (clalloc(&sc
->sc_q
, UHID_BSIZE
, 0) == -1) {
348 sc
->sc_state
&= ~UHID_OPEN
;
352 sc
->sc_ibuf
= kmalloc(sc
->sc_isize
, M_USBDEV
, M_WAITOK
);
353 sc
->sc_obuf
= kmalloc(sc
->sc_osize
, M_USBDEV
, M_WAITOK
);
355 /* Set up interrupt pipe. */
356 err
= usbd_open_pipe_intr(sc
->sc_iface
, sc
->sc_ep_addr
,
357 USBD_SHORT_XFER_OK
, &sc
->sc_intrpipe
, sc
, sc
->sc_ibuf
,
358 sc
->sc_isize
, uhid_intr
, USBD_DEFAULT_INTERVAL
);
360 DPRINTF(("uhidopen: usbd_open_pipe_intr failed, "
362 kfree(sc
->sc_ibuf
, M_USBDEV
);
363 kfree(sc
->sc_obuf
, M_USBDEV
);
364 sc
->sc_ibuf
= sc
->sc_obuf
= NULL
;
366 sc
->sc_state
&= ~UHID_OPEN
;
370 sc
->sc_state
&= ~UHID_IMMED
;
378 uhidclose(struct dev_close_args
*ap
)
380 cdev_t dev
= ap
->a_head
.a_dev
;
381 struct uhid_softc
*sc
;
383 USB_GET_SC(uhid
, UHIDUNIT(dev
), sc
);
385 DPRINTF(("uhidclose: sc=%p\n", sc
));
387 /* Disable interrupts. */
388 usbd_abort_pipe(sc
->sc_intrpipe
);
389 usbd_close_pipe(sc
->sc_intrpipe
);
392 ndflush(&sc
->sc_q
, sc
->sc_q
.c_cc
);
395 kfree(sc
->sc_ibuf
, M_USBDEV
);
396 kfree(sc
->sc_obuf
, M_USBDEV
);
397 sc
->sc_ibuf
= sc
->sc_obuf
= NULL
;
399 sc
->sc_state
&= ~UHID_OPEN
;
407 uhid_do_read(struct uhid_softc
*sc
, struct uio
*uio
, int flag
)
411 u_char buffer
[UHID_CHUNK
];
414 DPRINTFN(1, ("uhidread\n"));
415 if (sc
->sc_state
& UHID_IMMED
) {
416 DPRINTFN(1, ("uhidread immed\n"));
418 err
= usbd_get_report(sc
->sc_iface
, UHID_INPUT_REPORT
,
419 sc
->sc_iid
, buffer
, sc
->sc_isize
);
422 return (uiomove(buffer
, sc
->sc_isize
, uio
));
426 while (sc
->sc_q
.c_cc
== 0) {
427 if (flag
& IO_NDELAY
) {
429 return (EWOULDBLOCK
);
431 sc
->sc_state
|= UHID_ASLP
;
432 DPRINTFN(5, ("uhidread: sleep on %p\n", &sc
->sc_q
));
433 error
= tsleep(&sc
->sc_q
, PCATCH
, "uhidrea", 0);
434 DPRINTFN(5, ("uhidread: woke, error=%d\n", error
));
438 sc
->sc_state
&= ~UHID_ASLP
;
441 if (sc
->sc_state
& UHID_NEEDCLEAR
) {
442 DPRINTFN(-1,("uhidread: clearing stall\n"));
443 sc
->sc_state
&= ~UHID_NEEDCLEAR
;
444 usbd_clear_endpoint_stall(sc
->sc_intrpipe
);
449 /* Transfer as many chunks as possible. */
450 while (sc
->sc_q
.c_cc
> 0 && uio
->uio_resid
> 0 && !error
) {
451 length
= min(sc
->sc_q
.c_cc
, uio
->uio_resid
);
452 if (length
> sizeof(buffer
))
453 length
= sizeof(buffer
);
455 /* Remove a small chunk from the input queue. */
456 (void) q_to_b(&sc
->sc_q
, buffer
, length
);
457 DPRINTFN(5, ("uhidread: got %lu chars\n", (u_long
)length
));
459 /* Copy the data to the user process. */
460 if ((error
= uiomove(buffer
, length
, uio
)) != 0)
468 uhidread(struct dev_read_args
*ap
)
470 cdev_t dev
= ap
->a_head
.a_dev
;
471 struct uhid_softc
*sc
;
474 USB_GET_SC(uhid
, UHIDUNIT(dev
), sc
);
477 error
= uhid_do_read(sc
, ap
->a_uio
, ap
->a_ioflag
);
478 if (--sc
->sc_refcnt
< 0)
479 usb_detach_wakeup(sc
->sc_dev
);
484 uhid_do_write(struct uhid_softc
*sc
, struct uio
*uio
, int flag
)
490 DPRINTFN(1, ("uhidwrite\n"));
497 if (uio
->uio_resid
!= size
)
499 error
= uiomove(sc
->sc_obuf
, size
, uio
);
502 err
= usbd_set_report(sc
->sc_iface
, UHID_OUTPUT_REPORT
,
503 sc
->sc_obuf
[0], sc
->sc_obuf
+1, size
-1);
505 err
= usbd_set_report(sc
->sc_iface
, UHID_OUTPUT_REPORT
,
506 0, sc
->sc_obuf
, size
);
515 uhidwrite(struct dev_write_args
*ap
)
517 cdev_t dev
= ap
->a_head
.a_dev
;
518 struct uhid_softc
*sc
;
521 USB_GET_SC(uhid
, UHIDUNIT(dev
), sc
);
524 error
= uhid_do_write(sc
, ap
->a_uio
, ap
->a_ioflag
);
525 if (--sc
->sc_refcnt
< 0)
526 usb_detach_wakeup(sc
->sc_dev
);
531 uhid_do_ioctl(struct uhid_softc
*sc
, u_long cmd
, caddr_t addr
, int flag
)
533 struct usb_ctl_report_desc
*rd
;
534 struct usb_ctl_report
*re
;
538 DPRINTFN(2, ("uhidioctl: cmd=%lx\n", cmd
));
546 if (sc
->sc_async
!= NULL
)
548 sc
->sc_async
= curproc
;
549 DPRINTF(("uhid_do_ioctl: FIOASYNC %p\n", sc
->sc_async
));
554 /* XXX this is not the most general solution. */
556 if (sc
->sc_async
== NULL
)
558 if (*(int *)addr
!= sc
->sc_async
->p_pgid
)
562 case USB_GET_REPORT_DESC
:
563 rd
= (struct usb_ctl_report_desc
*)addr
;
564 size
= min(sc
->sc_repdesc_size
, sizeof rd
->ucrd_data
);
565 rd
->ucrd_size
= size
;
566 memcpy(rd
->ucrd_data
, sc
->sc_repdesc
, size
);
571 /* XXX should read into ibuf, but does it matter? */
572 err
= usbd_get_report(sc
->sc_iface
, UHID_INPUT_REPORT
,
573 sc
->sc_iid
, sc
->sc_ibuf
, sc
->sc_isize
);
577 sc
->sc_state
|= UHID_IMMED
;
579 sc
->sc_state
&= ~UHID_IMMED
;
583 re
= (struct usb_ctl_report
*)addr
;
584 switch (re
->ucr_report
) {
585 case UHID_INPUT_REPORT
:
589 case UHID_OUTPUT_REPORT
:
593 case UHID_FEATURE_REPORT
:
600 err
= usbd_get_report(sc
->sc_iface
, re
->ucr_report
, id
, re
->ucr_data
,
607 re
= (struct usb_ctl_report
*)addr
;
608 switch (re
->ucr_report
) {
609 case UHID_INPUT_REPORT
:
613 case UHID_OUTPUT_REPORT
:
617 case UHID_FEATURE_REPORT
:
624 err
= usbd_set_report(sc
->sc_iface
, re
->ucr_report
, id
, re
->ucr_data
,
630 case USB_GET_REPORT_ID
:
631 *(int *)addr
= 0; /* XXX: we only support reportid 0? */
641 uhidioctl(struct dev_ioctl_args
*ap
)
643 cdev_t dev
= ap
->a_head
.a_dev
;
644 struct uhid_softc
*sc
;
647 USB_GET_SC(uhid
, UHIDUNIT(dev
), sc
);
650 error
= uhid_do_ioctl(sc
, ap
->a_cmd
, ap
->a_data
, ap
->a_fflag
);
651 if (--sc
->sc_refcnt
< 0)
652 usb_detach_wakeup(sc
->sc_dev
);
657 uhidpoll(struct dev_poll_args
*ap
)
659 cdev_t dev
= ap
->a_head
.a_dev
;
660 struct uhid_softc
*sc
;
663 USB_GET_SC(uhid
, UHIDUNIT(dev
), sc
);
669 if (ap
->a_events
& (POLLOUT
| POLLWRNORM
))
670 revents
|= ap
->a_events
& (POLLOUT
| POLLWRNORM
);
671 if (ap
->a_events
& (POLLIN
| POLLRDNORM
)) {
672 if (sc
->sc_q
.c_cc
> 0)
673 revents
|= ap
->a_events
& (POLLIN
| POLLRDNORM
);
675 selrecord(curthread
, &sc
->sc_rsel
);
678 ap
->a_events
= revents
;
682 DRIVER_MODULE(uhid
, uhub
, uhid_driver
, uhid_devclass
, usbd_driver_load
, 0);