1 /* $NetBSD: uhid.c,v 1.82 2008/05/24 16:40:58 cube Exp $ */
4 * Copyright (c) 1998, 2004, 2008 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Lennart Augustsson (lennart@augustsson.net) at
9 * Carlstedt Research & Technology.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
34 * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: uhid.c,v 1.82 2008/05/24 16:40:58 cube Exp $");
40 #include "opt_compat_netbsd.h"
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/malloc.h>
46 #include <sys/signalvar.h>
47 #include <sys/device.h>
48 #include <sys/ioctl.h>
52 #include <sys/select.h>
54 #include <sys/vnode.h>
58 #include <dev/usb/usb.h>
59 #include <dev/usb/usbhid.h>
61 #include <dev/usb/usbdevs.h>
62 #include <dev/usb/usbdi.h>
63 #include <dev/usb/usbdi_util.h>
64 #include <dev/usb/hid.h>
65 #include <dev/usb/usb_quirks.h>
67 #include <dev/usb/uhidev.h>
70 #define DPRINTF(x) if (uhiddebug) logprintf x
71 #define DPRINTFN(n,x) if (uhiddebug>(n)) logprintf x
79 struct uhidev sc_hdev
;
88 struct selinfo sc_rsel
;
89 usb_proc_ptr sc_async
; /* process that wants SIGIO */
91 u_char sc_state
; /* driver state */
92 #define UHID_ASLP 0x01 /* waiting for device data */
93 #define UHID_IMMED 0x02 /* return read data immediately */
99 #define UHIDUNIT(dev) (minor(dev))
100 #define UHID_CHUNK 128 /* chunk size for read */
101 #define UHID_BSIZE 1020 /* buffer size */
103 dev_type_open(uhidopen
);
104 dev_type_close(uhidclose
);
105 dev_type_read(uhidread
);
106 dev_type_write(uhidwrite
);
107 dev_type_ioctl(uhidioctl
);
108 dev_type_poll(uhidpoll
);
109 dev_type_kqfilter(uhidkqfilter
);
111 const struct cdevsw uhid_cdevsw
= {
112 uhidopen
, uhidclose
, uhidread
, uhidwrite
, uhidioctl
,
113 nostop
, notty
, uhidpoll
, nommap
, uhidkqfilter
, D_OTHER
,
116 Static
void uhid_intr(struct uhidev
*, void *, u_int len
);
117 Static
void uhid_softintr(void *);
119 Static
int uhid_do_read(struct uhid_softc
*, struct uio
*uio
, int);
120 Static
int uhid_do_write(struct uhid_softc
*, struct uio
*uio
, int);
121 Static
int uhid_do_ioctl(struct uhid_softc
*, u_long
, void *, int, struct lwp
*);
123 USB_DECLARE_DRIVER(uhid
);
126 uhid_match(device_t parent
, cfdata_t match
, void *aux
)
129 struct uhidev_attach_arg
*uha
= aux
;
132 DPRINTF(("uhid_match: report=%d\n", uha
->reportid
));
134 if (match
->cf_flags
& 1)
135 return (UMATCH_HIGHEST
);
137 return (UMATCH_IFACECLASS_GENERIC
);
141 uhid_attach(device_t parent
, device_t self
, void *aux
)
143 struct uhid_softc
*sc
= device_private(self
);
144 struct uhidev_attach_arg
*uha
= aux
;
148 sc
->sc_hdev
.sc_dev
= self
;
149 selinit(&sc
->sc_rsel
);
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 sc
->sc_sih
= softint_establish(SOFTINT_MPSAFE
| SOFTINT_CLOCK
,
156 uhidev_get_report_desc(uha
->parent
, &desc
, &size
);
157 repid
= uha
->reportid
;
158 sc
->sc_isize
= hid_report_size(desc
, size
, hid_input
, repid
);
159 sc
->sc_osize
= hid_report_size(desc
, size
, hid_output
, repid
);
160 sc
->sc_fsize
= hid_report_size(desc
, size
, hid_feature
, repid
);
163 aprint_normal(": input=%d, output=%d, feature=%d\n",
164 sc
->sc_isize
, sc
->sc_osize
, sc
->sc_fsize
);
166 if (!pmf_device_register(self
, NULL
, NULL
))
167 aprint_error_dev(self
, "couldn't establish power handler\n");
169 USB_ATTACH_SUCCESS_RETURN
;
173 uhid_activate(device_ptr_t self
, enum devact act
)
175 struct uhid_softc
*sc
= device_private(self
);
178 case DVACT_DEACTIVATE
:
187 uhid_detach(device_t self
, int flags
)
189 struct uhid_softc
*sc
= device_private(self
);
193 DPRINTF(("uhid_detach: sc=%p flags=%d\n", sc
, flags
));
197 if (sc
->sc_hdev
.sc_state
& UHIDEV_OPEN
) {
199 if (--sc
->sc_refcnt
>= 0) {
202 /* Wait for processes to go away. */
203 usb_detach_wait(USBDEV(sc
->sc_hdev
.sc_dev
));
208 /* locate the major number */
209 #if defined(__NetBSD__)
210 maj
= cdevsw_lookup_major(&uhid_cdevsw
);
211 #elif defined(__OpenBSD__)
212 for (maj
= 0; maj
< nchrdev
; maj
++)
213 if (cdevsw
[maj
].d_open
== uhidopen
)
217 /* Nuke the vnodes for any open instances (calls close). */
218 mn
= device_unit(self
);
219 vdevgone(maj
, mn
, mn
, VCHR
);
222 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH
,
223 sc
->sc_hdev
.sc_parent
->sc_udev
,
224 USBDEV(sc
->sc_hdev
.sc_dev
));
226 seldestroy(&sc
->sc_rsel
);
227 softint_disestablish(sc
->sc_sih
);
233 uhid_intr(struct uhidev
*addr
, void *data
, u_int len
)
235 struct uhid_softc
*sc
= (struct uhid_softc
*)addr
;
241 DPRINTF(("uhid_intr: data ="));
242 for (i
= 0; i
< len
; i
++)
243 DPRINTF((" %02x", ((u_char
*)data
)[i
]));
248 (void)b_to_q(data
, len
, &sc
->sc_q
);
250 if (sc
->sc_state
& UHID_ASLP
) {
251 sc
->sc_state
&= ~UHID_ASLP
;
252 DPRINTFN(5, ("uhid_intr: waking %p\n", &sc
->sc_q
));
255 selnotify(&sc
->sc_rsel
, 0, 0);
256 if (sc
->sc_async
!= NULL
) {
257 DPRINTFN(3, ("uhid_intr: sending SIGIO %p\n", sc
->sc_async
));
258 softint_schedule(sc
->sc_sih
);
263 uhid_softintr(void *cookie
)
265 struct uhid_softc
*sc
;
269 mutex_enter(proc_lock
);
270 if (sc
->sc_async
!= NULL
)
271 psignal(sc
->sc_async
, SIGIO
);
272 mutex_exit(proc_lock
);
276 uhidopen(dev_t dev
, int flag
, int mode
,
279 struct uhid_softc
*sc
;
282 USB_GET_SC_OPEN(uhid
, UHIDUNIT(dev
), sc
);
284 DPRINTF(("uhidopen: sc=%p\n", sc
));
289 error
= uhidev_open(&sc
->sc_hdev
);
293 if (clalloc(&sc
->sc_q
, UHID_BSIZE
, 0) == -1) {
294 uhidev_close(&sc
->sc_hdev
);
297 sc
->sc_obuf
= malloc(sc
->sc_osize
, M_USBDEV
, M_WAITOK
);
298 sc
->sc_state
&= ~UHID_IMMED
;
299 mutex_enter(proc_lock
);
301 mutex_exit(proc_lock
);
307 uhidclose(dev_t dev
, int flag
, int mode
,
310 struct uhid_softc
*sc
;
312 USB_GET_SC(uhid
, UHIDUNIT(dev
), sc
);
314 DPRINTF(("uhidclose: sc=%p\n", sc
));
317 free(sc
->sc_obuf
, M_USBDEV
);
318 mutex_enter(proc_lock
);
320 mutex_exit(proc_lock
);
321 uhidev_close(&sc
->sc_hdev
);
327 uhid_do_read(struct uhid_softc
*sc
, struct uio
*uio
, int flag
)
333 u_char buffer
[UHID_CHUNK
];
336 DPRINTFN(1, ("uhidread\n"));
337 if (sc
->sc_state
& UHID_IMMED
) {
338 DPRINTFN(1, ("uhidread immed\n"));
339 extra
= sc
->sc_hdev
.sc_report_id
!= 0;
340 err
= uhidev_get_report(&sc
->sc_hdev
, UHID_INPUT_REPORT
,
341 buffer
, sc
->sc_isize
+ extra
);
344 return (uiomove(buffer
+extra
, sc
->sc_isize
, uio
));
348 while (sc
->sc_q
.c_cc
== 0) {
349 if (flag
& IO_NDELAY
) {
351 return (EWOULDBLOCK
);
353 sc
->sc_state
|= UHID_ASLP
;
354 DPRINTFN(5, ("uhidread: sleep on %p\n", &sc
->sc_q
));
355 error
= tsleep(&sc
->sc_q
, PZERO
| PCATCH
, "uhidrea", 0);
356 DPRINTFN(5, ("uhidread: woke, error=%d\n", error
));
360 sc
->sc_state
&= ~UHID_ASLP
;
366 /* Transfer as many chunks as possible. */
367 while (sc
->sc_q
.c_cc
> 0 && uio
->uio_resid
> 0 && !error
) {
368 length
= min(sc
->sc_q
.c_cc
, uio
->uio_resid
);
369 if (length
> sizeof(buffer
))
370 length
= sizeof(buffer
);
372 /* Remove a small chunk from the input queue. */
373 (void) q_to_b(&sc
->sc_q
, buffer
, length
);
374 DPRINTFN(5, ("uhidread: got %lu chars\n", (u_long
)length
));
376 /* Copy the data to the user process. */
377 if ((error
= uiomove(buffer
, length
, uio
)) != 0)
385 uhidread(dev_t dev
, struct uio
*uio
, int flag
)
387 struct uhid_softc
*sc
;
390 USB_GET_SC(uhid
, UHIDUNIT(dev
), sc
);
393 error
= uhid_do_read(sc
, uio
, flag
);
394 if (--sc
->sc_refcnt
< 0)
395 usb_detach_wakeup(USBDEV(sc
->sc_hdev
.sc_dev
));
400 uhid_do_write(struct uhid_softc
*sc
, struct uio
*uio
, int flag
)
406 DPRINTFN(1, ("uhidwrite\n"));
413 if (uio
->uio_resid
!= size
)
415 error
= uiomove(sc
->sc_obuf
, size
, uio
);
417 err
= uhidev_set_report(&sc
->sc_hdev
, UHID_OUTPUT_REPORT
,
427 uhidwrite(dev_t dev
, struct uio
*uio
, int flag
)
429 struct uhid_softc
*sc
;
432 USB_GET_SC(uhid
, UHIDUNIT(dev
), sc
);
435 error
= uhid_do_write(sc
, uio
, flag
);
436 if (--sc
->sc_refcnt
< 0)
437 usb_detach_wakeup(USBDEV(sc
->sc_hdev
.sc_dev
));
442 uhid_do_ioctl(struct uhid_softc
*sc
, u_long cmd
, void *addr
,
443 int flag
, struct lwp
*l
)
445 struct usb_ctl_report_desc
*rd
;
446 struct usb_ctl_report
*re
;
447 u_char buffer
[UHID_CHUNK
];
452 DPRINTFN(2, ("uhidioctl: cmd=%lx\n", cmd
));
459 /* All handled in the upper FS layer. */
463 mutex_enter(proc_lock
);
465 if (sc
->sc_async
!= NULL
)
467 sc
->sc_async
= l
->l_proc
;
468 DPRINTF(("uhid_do_ioctl: FIOASYNC %p\n", l
->l_proc
));
471 mutex_exit(proc_lock
);
474 /* XXX this is not the most general solution. */
476 mutex_enter(proc_lock
);
477 if (sc
->sc_async
== NULL
) {
478 mutex_exit(proc_lock
);
481 if (*(int *)addr
!= sc
->sc_async
->p_pgid
) {
482 mutex_exit(proc_lock
);
485 mutex_exit(proc_lock
);
489 mutex_enter(proc_lock
);
490 if (sc
->sc_async
== NULL
) {
491 mutex_exit(proc_lock
);
494 if (-*(int *)addr
!= sc
->sc_async
->p_pgid
495 && *(int *)addr
!= sc
->sc_async
->p_pid
) {
496 mutex_exit(proc_lock
);
499 mutex_exit(proc_lock
);
502 case USB_GET_REPORT_DESC
:
503 uhidev_get_report_desc(sc
->sc_hdev
.sc_parent
, &desc
, &size
);
504 rd
= (struct usb_ctl_report_desc
*)addr
;
505 size
= min(size
, sizeof rd
->ucrd_data
);
506 rd
->ucrd_size
= size
;
507 memcpy(rd
->ucrd_data
, desc
, size
);
512 extra
= sc
->sc_hdev
.sc_report_id
!= 0;
513 err
= uhidev_get_report(&sc
->sc_hdev
, UHID_INPUT_REPORT
,
514 buffer
, sc
->sc_isize
+ extra
);
518 sc
->sc_state
|= UHID_IMMED
;
520 sc
->sc_state
&= ~UHID_IMMED
;
524 re
= (struct usb_ctl_report
*)addr
;
525 switch (re
->ucr_report
) {
526 case UHID_INPUT_REPORT
:
529 case UHID_OUTPUT_REPORT
:
532 case UHID_FEATURE_REPORT
:
538 extra
= sc
->sc_hdev
.sc_report_id
!= 0;
539 err
= uhidev_get_report(&sc
->sc_hdev
, re
->ucr_report
,
540 re
->ucr_data
, size
+ extra
);
542 memcpy(re
->ucr_data
, re
->ucr_data
+1, size
);
548 re
= (struct usb_ctl_report
*)addr
;
549 switch (re
->ucr_report
) {
550 case UHID_INPUT_REPORT
:
553 case UHID_OUTPUT_REPORT
:
556 case UHID_FEATURE_REPORT
:
562 err
= uhidev_set_report(&sc
->sc_hdev
, re
->ucr_report
,
568 case USB_GET_REPORT_ID
:
569 *(int *)addr
= sc
->sc_hdev
.sc_report_id
;
572 case USB_GET_DEVICEINFO
:
573 usbd_fill_deviceinfo(sc
->sc_hdev
.sc_parent
->sc_udev
,
574 (struct usb_device_info
*)addr
, 0);
577 case USB_GET_DEVICEINFO_OLD
:
578 usbd_fill_deviceinfo_old(sc
->sc_hdev
.sc_parent
->sc_udev
,
579 (struct usb_device_info_old
*)addr
, 0);
583 case USB_GET_STRING_DESC
:
585 struct usb_string_desc
*si
= (struct usb_string_desc
*)addr
;
586 err
= usbd_get_string_desc(sc
->sc_hdev
.sc_parent
->sc_udev
,
587 si
->usd_string_index
,
588 si
->usd_language_id
, &si
->usd_desc
, &size
);
601 uhidioctl(dev_t dev
, u_long cmd
, void *addr
, int flag
, struct lwp
*l
)
603 struct uhid_softc
*sc
;
606 USB_GET_SC(uhid
, UHIDUNIT(dev
), sc
);
609 error
= uhid_do_ioctl(sc
, cmd
, addr
, flag
, l
);
610 if (--sc
->sc_refcnt
< 0)
611 usb_detach_wakeup(USBDEV(sc
->sc_hdev
.sc_dev
));
616 uhidpoll(dev_t dev
, int events
, struct lwp
*l
)
618 struct uhid_softc
*sc
;
622 USB_GET_SC(uhid
, UHIDUNIT(dev
), sc
);
628 if (events
& (POLLOUT
| POLLWRNORM
))
629 revents
|= events
& (POLLOUT
| POLLWRNORM
);
630 if (events
& (POLLIN
| POLLRDNORM
)) {
631 if (sc
->sc_q
.c_cc
> 0)
632 revents
|= events
& (POLLIN
| POLLRDNORM
);
634 selrecord(l
, &sc
->sc_rsel
);
642 filt_uhidrdetach(struct knote
*kn
)
644 struct uhid_softc
*sc
= kn
->kn_hook
;
648 SLIST_REMOVE(&sc
->sc_rsel
.sel_klist
, kn
, knote
, kn_selnext
);
653 filt_uhidread(struct knote
*kn
, long hint
)
655 struct uhid_softc
*sc
= kn
->kn_hook
;
657 kn
->kn_data
= sc
->sc_q
.c_cc
;
658 return (kn
->kn_data
> 0);
661 static const struct filterops uhidread_filtops
=
662 { 1, NULL
, filt_uhidrdetach
, filt_uhidread
};
664 static const struct filterops uhid_seltrue_filtops
=
665 { 1, NULL
, filt_uhidrdetach
, filt_seltrue
};
668 uhidkqfilter(dev_t dev
, struct knote
*kn
)
670 struct uhid_softc
*sc
;
674 USB_GET_SC(uhid
, UHIDUNIT(dev
), sc
);
679 switch (kn
->kn_filter
) {
681 klist
= &sc
->sc_rsel
.sel_klist
;
682 kn
->kn_fop
= &uhidread_filtops
;
686 klist
= &sc
->sc_rsel
.sel_klist
;
687 kn
->kn_fop
= &uhid_seltrue_filtops
;
697 SLIST_INSERT_HEAD(klist
, kn
, kn_selnext
);