| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: uhidev.c,v 1.90 2022/03/28 12:44:17 riastradh Exp $ */ | | 1 | /* $NetBSD: uhidev.c,v 1.91 2022/03/28 12:44:28 riastradh Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2001, 2012 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2001, 2012 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Lennart Augustsson (lennart@augustsson.net) at | | 8 | * by Lennart Augustsson (lennart@augustsson.net) at |
9 | * Carlstedt Research & Technology and Matthew R. Green (mrg@eterna.com.au). | | 9 | * Carlstedt Research & Technology and Matthew R. Green (mrg@eterna.com.au). |
10 | * | | 10 | * |
11 | * Redistribution and use in source and binary forms, with or without | | 11 | * Redistribution and use in source and binary forms, with or without |
12 | * modification, are permitted provided that the following conditions | | 12 | * modification, are permitted provided that the following conditions |
13 | * are met: | | 13 | * are met: |
14 | * 1. Redistributions of source code must retain the above copyright | | 14 | * 1. Redistributions of source code must retain the above copyright |
| @@ -25,27 +25,27 @@ | | | @@ -25,27 +25,27 @@ |
25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 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 | | 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 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 | | 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
30 | * POSSIBILITY OF SUCH DAMAGE. | | 30 | * POSSIBILITY OF SUCH DAMAGE. |
31 | */ | | 31 | */ |
32 | | | 32 | |
33 | /* | | 33 | /* |
34 | * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf | | 34 | * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf |
35 | */ | | 35 | */ |
36 | | | 36 | |
37 | #include <sys/cdefs.h> | | 37 | #include <sys/cdefs.h> |
38 | __KERNEL_RCSID(0, "$NetBSD: uhidev.c,v 1.90 2022/03/28 12:44:17 riastradh Exp $"); | | 38 | __KERNEL_RCSID(0, "$NetBSD: uhidev.c,v 1.91 2022/03/28 12:44:28 riastradh Exp $"); |
39 | | | 39 | |
40 | #ifdef _KERNEL_OPT | | 40 | #ifdef _KERNEL_OPT |
41 | #include "opt_usb.h" | | 41 | #include "opt_usb.h" |
42 | #endif | | 42 | #endif |
43 | | | 43 | |
44 | #include <sys/param.h> | | 44 | #include <sys/param.h> |
45 | #include <sys/types.h> | | 45 | #include <sys/types.h> |
46 | | | 46 | |
47 | #include <sys/atomic.h> | | 47 | #include <sys/atomic.h> |
48 | #include <sys/conf.h> | | 48 | #include <sys/conf.h> |
49 | #include <sys/device.h> | | 49 | #include <sys/device.h> |
50 | #include <sys/ioctl.h> | | 50 | #include <sys/ioctl.h> |
51 | #include <sys/kernel.h> | | 51 | #include <sys/kernel.h> |
| @@ -100,27 +100,26 @@ struct uhidev_softc { | | | @@ -100,27 +100,26 @@ struct uhidev_softc { |
100 | #define UHIDEV_OPEN 0x01 /* device is open */ | | 100 | #define UHIDEV_OPEN 0x01 /* device is open */ |
101 | #define UHIDEV_STOPPED 0x02 /* xfers are stopped */ | | 101 | #define UHIDEV_STOPPED 0x02 /* xfers are stopped */ |
102 | } *sc_subdevs; | | 102 | } *sc_subdevs; |
103 | | | 103 | |
104 | kmutex_t sc_lock; | | 104 | kmutex_t sc_lock; |
105 | kcondvar_t sc_cv; | | 105 | kcondvar_t sc_cv; |
106 | | | 106 | |
107 | /* Read/written under sc_lock. */ | | 107 | /* Read/written under sc_lock. */ |
108 | struct lwp *sc_writelock; | | 108 | struct lwp *sc_writelock; |
109 | struct lwp *sc_configlock; | | 109 | struct lwp *sc_configlock; |
110 | int sc_refcnt; | | 110 | int sc_refcnt; |
111 | int sc_writereportid; | | 111 | int sc_writereportid; |
112 | int sc_stopreportid; | | 112 | int sc_stopreportid; |
113 | u_char sc_dying; | | | |
114 | | | 113 | |
115 | /* | | 114 | /* |
116 | * - Read under sc_lock, provided sc_refcnt > 0. | | 115 | * - Read under sc_lock, provided sc_refcnt > 0. |
117 | * - Written under sc_configlock only when transitioning to and | | 116 | * - Written under sc_configlock only when transitioning to and |
118 | * from sc_refcnt = 0. | | 117 | * from sc_refcnt = 0. |
119 | */ | | 118 | */ |
120 | u_char *sc_ibuf; | | 119 | u_char *sc_ibuf; |
121 | struct usbd_pipe *sc_ipipe; /* input interrupt pipe */ | | 120 | struct usbd_pipe *sc_ipipe; /* input interrupt pipe */ |
122 | struct usbd_pipe *sc_opipe; /* output interrupt pipe */ | | 121 | struct usbd_pipe *sc_opipe; /* output interrupt pipe */ |
123 | struct usbd_xfer *sc_oxfer; /* write request */ | | 122 | struct usbd_xfer *sc_oxfer; /* write request */ |
124 | usbd_callback sc_writecallback; /* async write request callback */ | | 123 | usbd_callback sc_writecallback; /* async write request callback */ |
125 | void *sc_writecookie; | | 124 | void *sc_writecookie; |
126 | | | 125 | |
| @@ -136,30 +135,29 @@ int uhidevdebug = 0; | | | @@ -136,30 +135,29 @@ int uhidevdebug = 0; |
136 | #define DPRINTF(x) | | 135 | #define DPRINTF(x) |
137 | #define DPRINTFN(n,x) | | 136 | #define DPRINTFN(n,x) |
138 | #endif | | 137 | #endif |
139 | | | 138 | |
140 | static void uhidev_intr(struct usbd_xfer *, void *, usbd_status); | | 139 | static void uhidev_intr(struct usbd_xfer *, void *, usbd_status); |
141 | | | 140 | |
142 | static int uhidev_maxrepid(void *, int); | | 141 | static int uhidev_maxrepid(void *, int); |
143 | static int uhidevprint(void *, const char *); | | 142 | static int uhidevprint(void *, const char *); |
144 | | | 143 | |
145 | static int uhidev_match(device_t, cfdata_t, void *); | | 144 | static int uhidev_match(device_t, cfdata_t, void *); |
146 | static void uhidev_attach(device_t, device_t, void *); | | 145 | static void uhidev_attach(device_t, device_t, void *); |
147 | static void uhidev_childdet(device_t, device_t); | | 146 | static void uhidev_childdet(device_t, device_t); |
148 | static int uhidev_detach(device_t, int); | | 147 | static int uhidev_detach(device_t, int); |
149 | static int uhidev_activate(device_t, enum devact); | | | |
150 | | | 148 | |
151 | CFATTACH_DECL2_NEW(uhidev, sizeof(struct uhidev_softc), uhidev_match, | | 149 | CFATTACH_DECL2_NEW(uhidev, sizeof(struct uhidev_softc), uhidev_match, |
152 | uhidev_attach, uhidev_detach, uhidev_activate, NULL, uhidev_childdet); | | 150 | uhidev_attach, uhidev_detach, NULL, NULL, uhidev_childdet); |
153 | | | 151 | |
154 | static int | | 152 | static int |
155 | uhidev_match(device_t parent, cfdata_t match, void *aux) | | 153 | uhidev_match(device_t parent, cfdata_t match, void *aux) |
156 | { | | 154 | { |
157 | struct usbif_attach_arg *uiaa = aux; | | 155 | struct usbif_attach_arg *uiaa = aux; |
158 | | | 156 | |
159 | /* Game controllers in "XInput" mode */ | | 157 | /* Game controllers in "XInput" mode */ |
160 | if (USBIF_IS_XINPUT(uiaa)) | | 158 | if (USBIF_IS_XINPUT(uiaa)) |
161 | return UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO; | | 159 | return UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO; |
162 | /* Xbox One controllers */ | | 160 | /* Xbox One controllers */ |
163 | if (USBIF_IS_X1INPUT(uiaa) && uiaa->uiaa_ifaceno == 0) | | 161 | if (USBIF_IS_X1INPUT(uiaa) && uiaa->uiaa_ifaceno == 0) |
164 | return UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO; | | 162 | return UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO; |
165 | | | 163 | |
| @@ -193,27 +191,26 @@ uhidev_attach(device_t parent, device_t | | | @@ -193,27 +191,26 @@ uhidev_attach(device_t parent, device_t |
193 | sc->sc_udev = uiaa->uiaa_device; | | 191 | sc->sc_udev = uiaa->uiaa_device; |
194 | sc->sc_iface = iface; | | 192 | sc->sc_iface = iface; |
195 | | | 193 | |
196 | aprint_naive("\n"); | | 194 | aprint_naive("\n"); |
197 | aprint_normal("\n"); | | 195 | aprint_normal("\n"); |
198 | | | 196 | |
199 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); | | 197 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); |
200 | cv_init(&sc->sc_cv, "uhidev"); | | 198 | cv_init(&sc->sc_cv, "uhidev"); |
201 | sc->sc_writelock = NULL; | | 199 | sc->sc_writelock = NULL; |
202 | sc->sc_configlock = NULL; | | 200 | sc->sc_configlock = NULL; |
203 | sc->sc_refcnt = 0; | | 201 | sc->sc_refcnt = 0; |
204 | sc->sc_writereportid = -1; | | 202 | sc->sc_writereportid = -1; |
205 | sc->sc_stopreportid = -1; | | 203 | sc->sc_stopreportid = -1; |
206 | sc->sc_dying = false; | | | |
207 | | | 204 | |
208 | id = usbd_get_interface_descriptor(iface); | | 205 | id = usbd_get_interface_descriptor(iface); |
209 | | | 206 | |
210 | devinfop = usbd_devinfo_alloc(uiaa->uiaa_device, 0); | | 207 | devinfop = usbd_devinfo_alloc(uiaa->uiaa_device, 0); |
211 | aprint_normal_dev(self, "%s, iclass %d/%d\n", | | 208 | aprint_normal_dev(self, "%s, iclass %d/%d\n", |
212 | devinfop, id->bInterfaceClass, id->bInterfaceSubClass); | | 209 | devinfop, id->bInterfaceClass, id->bInterfaceSubClass); |
213 | usbd_devinfo_free(devinfop); | | 210 | usbd_devinfo_free(devinfop); |
214 | | | 211 | |
215 | if (!pmf_device_register(self, NULL, NULL)) | | 212 | if (!pmf_device_register(self, NULL, NULL)) |
216 | aprint_error_dev(self, "couldn't establish power handler\n"); | | 213 | aprint_error_dev(self, "couldn't establish power handler\n"); |
217 | | | 214 | |
218 | if (uiaa->uiaa_vendor == USB_VENDOR_WACOM) { | | 215 | if (uiaa->uiaa_vendor == USB_VENDOR_WACOM) { |
219 | if (uiaa->uiaa_product == USB_PRODUCT_WACOM_XD0912U) { | | 216 | if (uiaa->uiaa_product == USB_PRODUCT_WACOM_XD0912U) { |
| @@ -234,27 +231,26 @@ uhidev_attach(device_t parent, device_t | | | @@ -234,27 +231,26 @@ uhidev_attach(device_t parent, device_t |
234 | */ | | 231 | */ |
235 | if ((usbd_get_quirks(sc->sc_udev)->uq_flags & UQ_NO_SET_PROTO) == 0 && | | 232 | if ((usbd_get_quirks(sc->sc_udev)->uq_flags & UQ_NO_SET_PROTO) == 0 && |
236 | id->bInterfaceSubClass == UISUBCLASS_BOOT) | | 233 | id->bInterfaceSubClass == UISUBCLASS_BOOT) |
237 | (void)usbd_set_protocol(iface, 1); | | 234 | (void)usbd_set_protocol(iface, 1); |
238 | #endif | | 235 | #endif |
239 | | | 236 | |
240 | maxinpktsize = 0; | | 237 | maxinpktsize = 0; |
241 | sc->sc_iep_addr = sc->sc_oep_addr = -1; | | 238 | sc->sc_iep_addr = sc->sc_oep_addr = -1; |
242 | for (i = 0; i < id->bNumEndpoints; i++) { | | 239 | for (i = 0; i < id->bNumEndpoints; i++) { |
243 | ed = usbd_interface2endpoint_descriptor(iface, i); | | 240 | ed = usbd_interface2endpoint_descriptor(iface, i); |
244 | if (ed == NULL) { | | 241 | if (ed == NULL) { |
245 | aprint_error_dev(self, | | 242 | aprint_error_dev(self, |
246 | "could not read endpoint descriptor\n"); | | 243 | "could not read endpoint descriptor\n"); |
247 | sc->sc_dying = 1; | | | |
248 | return; | | 244 | return; |
249 | } | | 245 | } |
250 | | | 246 | |
251 | DPRINTFN(10,("uhidev_attach: bLength=%d bDescriptorType=%d " | | 247 | DPRINTFN(10,("uhidev_attach: bLength=%d bDescriptorType=%d " |
252 | "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d" | | 248 | "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d" |
253 | " bInterval=%d\n", | | 249 | " bInterval=%d\n", |
254 | ed->bLength, ed->bDescriptorType, | | 250 | ed->bLength, ed->bDescriptorType, |
255 | ed->bEndpointAddress & UE_ADDR, | | 251 | ed->bEndpointAddress & UE_ADDR, |
256 | UE_GET_DIR(ed->bEndpointAddress)==UE_DIR_IN? "in" : "out", | | 252 | UE_GET_DIR(ed->bEndpointAddress)==UE_DIR_IN? "in" : "out", |
257 | ed->bmAttributes & UE_XFERTYPE, | | 253 | ed->bmAttributes & UE_XFERTYPE, |
258 | UGETW(ed->wMaxPacketSize), ed->bInterval)); | | 254 | UGETW(ed->wMaxPacketSize), ed->bInterval)); |
259 | | | 255 | |
260 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | | 256 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && |
| @@ -265,27 +261,26 @@ uhidev_attach(device_t parent, device_t | | | @@ -265,27 +261,26 @@ uhidev_attach(device_t parent, device_t |
265 | (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) { | | 261 | (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) { |
266 | sc->sc_oep_addr = ed->bEndpointAddress; | | 262 | sc->sc_oep_addr = ed->bEndpointAddress; |
267 | } else { | | 263 | } else { |
268 | aprint_verbose_dev(self, "endpoint %d: ignored\n", i); | | 264 | aprint_verbose_dev(self, "endpoint %d: ignored\n", i); |
269 | } | | 265 | } |
270 | } | | 266 | } |
271 | | | 267 | |
272 | /* | | 268 | /* |
273 | * Check that we found an input interrupt endpoint. The output interrupt | | 269 | * Check that we found an input interrupt endpoint. The output interrupt |
274 | * endpoint is optional | | 270 | * endpoint is optional |
275 | */ | | 271 | */ |
276 | if (sc->sc_iep_addr == -1) { | | 272 | if (sc->sc_iep_addr == -1) { |
277 | aprint_error_dev(self, "no input interrupt endpoint\n"); | | 273 | aprint_error_dev(self, "no input interrupt endpoint\n"); |
278 | sc->sc_dying = 1; | | | |
279 | return; | | 274 | return; |
280 | } | | 275 | } |
281 | | | 276 | |
282 | /* XXX need to extend this */ | | 277 | /* XXX need to extend this */ |
283 | descptr = NULL; | | 278 | descptr = NULL; |
284 | if (uiaa->uiaa_vendor == USB_VENDOR_WACOM) { | | 279 | if (uiaa->uiaa_vendor == USB_VENDOR_WACOM) { |
285 | static uByte reportbuf[3]; | | 280 | static uByte reportbuf[3]; |
286 | | | 281 | |
287 | /* The report descriptor for the Wacom Graphire is broken. */ | | 282 | /* The report descriptor for the Wacom Graphire is broken. */ |
288 | switch (uiaa->uiaa_product) { | | 283 | switch (uiaa->uiaa_product) { |
289 | case USB_PRODUCT_WACOM_GRAPHIRE3_4X5: | | 284 | case USB_PRODUCT_WACOM_GRAPHIRE3_4X5: |
290 | case USB_PRODUCT_WACOM_GRAPHIRE3_6X8: | | 285 | case USB_PRODUCT_WACOM_GRAPHIRE3_6X8: |
291 | case USB_PRODUCT_WACOM_GRAPHIRE4_4X5: /* The 6x8 too? */ | | 286 | case USB_PRODUCT_WACOM_GRAPHIRE4_4X5: /* The 6x8 too? */ |
| @@ -326,27 +321,26 @@ uhidev_attach(device_t parent, device_t | | | @@ -326,27 +321,26 @@ uhidev_attach(device_t parent, device_t |
326 | descptr = uhid_x1input_report_descr; | | 321 | descptr = uhid_x1input_report_descr; |
327 | } | | 322 | } |
328 | | | 323 | |
329 | if (descptr) { | | 324 | if (descptr) { |
330 | desc = kmem_alloc(size, KM_SLEEP); | | 325 | desc = kmem_alloc(size, KM_SLEEP); |
331 | err = USBD_NORMAL_COMPLETION; | | 326 | err = USBD_NORMAL_COMPLETION; |
332 | memcpy(desc, descptr, size); | | 327 | memcpy(desc, descptr, size); |
333 | } else { | | 328 | } else { |
334 | desc = NULL; | | 329 | desc = NULL; |
335 | err = usbd_read_report_desc(uiaa->uiaa_iface, &desc, &size); | | 330 | err = usbd_read_report_desc(uiaa->uiaa_iface, &desc, &size); |
336 | } | | 331 | } |
337 | if (err) { | | 332 | if (err) { |
338 | aprint_error_dev(self, "no report descriptor\n"); | | 333 | aprint_error_dev(self, "no report descriptor\n"); |
339 | sc->sc_dying = 1; | | | |
340 | return; | | 334 | return; |
341 | } | | 335 | } |
342 | | | 336 | |
343 | if (uiaa->uiaa_vendor == USB_VENDOR_HOSIDEN && | | 337 | if (uiaa->uiaa_vendor == USB_VENDOR_HOSIDEN && |
344 | uiaa->uiaa_product == USB_PRODUCT_HOSIDEN_PPP) { | | 338 | uiaa->uiaa_product == USB_PRODUCT_HOSIDEN_PPP) { |
345 | static uByte reportbuf[] = { 1 }; | | 339 | static uByte reportbuf[] = { 1 }; |
346 | /* | | 340 | /* |
347 | * This device was sold by Konami with its ParaParaParadise | | 341 | * This device was sold by Konami with its ParaParaParadise |
348 | * game for PlayStation2. It needs to be "turned on" | | 342 | * game for PlayStation2. It needs to be "turned on" |
349 | * before it will send any reports. | | 343 | * before it will send any reports. |
350 | */ | | 344 | */ |
351 | | | 345 | |
352 | usbd_set_report(uiaa->uiaa_iface, UHID_FEATURE_REPORT, 0, | | 346 | usbd_set_report(uiaa->uiaa_iface, UHID_FEATURE_REPORT, 0, |
| @@ -469,40 +463,26 @@ uhidev_maxrepid(void *buf, int len) | | | @@ -469,40 +463,26 @@ uhidev_maxrepid(void *buf, int len) |
469 | | | 463 | |
470 | static int | | 464 | static int |
471 | uhidevprint(void *aux, const char *pnp) | | 465 | uhidevprint(void *aux, const char *pnp) |
472 | { | | 466 | { |
473 | struct uhidev_attach_arg *uha = aux; | | 467 | struct uhidev_attach_arg *uha = aux; |
474 | | | 468 | |
475 | if (pnp) | | 469 | if (pnp) |
476 | aprint_normal("uhid at %s", pnp); | | 470 | aprint_normal("uhid at %s", pnp); |
477 | if (uha->reportid != 0) | | 471 | if (uha->reportid != 0) |
478 | aprint_normal(" reportid %d", uha->reportid); | | 472 | aprint_normal(" reportid %d", uha->reportid); |
479 | return UNCONF; | | 473 | return UNCONF; |
480 | } | | 474 | } |
481 | | | 475 | |
482 | static int | | | |
483 | uhidev_activate(device_t self, enum devact act) | | | |
484 | { | | | |
485 | struct uhidev_softc *sc = device_private(self); | | | |
486 | | | | |
487 | switch (act) { | | | |
488 | case DVACT_DEACTIVATE: | | | |
489 | sc->sc_dying = 1; | | | |
490 | return 0; | | | |
491 | default: | | | |
492 | return EOPNOTSUPP; | | | |
493 | } | | | |
494 | } | | | |
495 | | | | |
496 | static void | | 476 | static void |
497 | uhidev_childdet(device_t self, device_t child) | | 477 | uhidev_childdet(device_t self, device_t child) |
498 | { | | 478 | { |
499 | int i; | | 479 | int i; |
500 | struct uhidev_softc *sc = device_private(self); | | 480 | struct uhidev_softc *sc = device_private(self); |
501 | | | 481 | |
502 | for (i = 0; i < sc->sc_nrepid; i++) { | | 482 | for (i = 0; i < sc->sc_nrepid; i++) { |
503 | if (sc->sc_subdevs[i].sc_dev == child) | | 483 | if (sc->sc_subdevs[i].sc_dev == child) |
504 | break; | | 484 | break; |
505 | } | | 485 | } |
506 | KASSERT(i < sc->sc_nrepid); | | 486 | KASSERT(i < sc->sc_nrepid); |
507 | sc->sc_subdevs[i].sc_dev = NULL; | | 487 | sc->sc_subdevs[i].sc_dev = NULL; |
508 | /* | | 488 | /* |
| @@ -513,46 +493,37 @@ uhidev_childdet(device_t self, device_t | | | @@ -513,46 +493,37 @@ uhidev_childdet(device_t self, device_t |
513 | * rescan method, but if there were, it could.) | | 493 | * rescan method, but if there were, it could.) |
514 | */ | | 494 | */ |
515 | rnd_detach_source(&sc->sc_subdevs[i].sc_rndsource); | | 495 | rnd_detach_source(&sc->sc_subdevs[i].sc_rndsource); |
516 | } | | 496 | } |
517 | | | 497 | |
518 | static int | | 498 | static int |
519 | uhidev_detach(device_t self, int flags) | | 499 | uhidev_detach(device_t self, int flags) |
520 | { | | 500 | { |
521 | struct uhidev_softc *sc = device_private(self); | | 501 | struct uhidev_softc *sc = device_private(self); |
522 | int rv; | | 502 | int rv; |
523 | | | 503 | |
524 | DPRINTF(("uhidev_detach: sc=%p flags=%d\n", sc, flags)); | | 504 | DPRINTF(("uhidev_detach: sc=%p flags=%d\n", sc, flags)); |
525 | | | 505 | |
526 | /* Notify that we are going away. */ | | | |
527 | mutex_enter(&sc->sc_lock); | | | |
528 | sc->sc_dying = 1; | | | |
529 | cv_broadcast(&sc->sc_cv); | | | |
530 | mutex_exit(&sc->sc_lock); | | | |
531 | | | | |
532 | /* | | 506 | /* |
533 | * Try to detach all our children. If anything fails, bail. | | 507 | * Try to detach all our children. If anything fails, bail. |
534 | * Failure can happen if this is from drvctl -d; of course, if | | 508 | * Failure can happen if this is from drvctl -d; of course, if |
535 | * this is a USB device being yanked, flags will have | | 509 | * this is a USB device being yanked, flags will have |
536 | * DETACH_FORCE and the children will not have the option of | | 510 | * DETACH_FORCE and the children will not have the option of |
537 | * refusing detachment. | | 511 | * refusing detachment. If they do detach, the pipes can no |
| | | 512 | * longer be in use. |
538 | */ | | 513 | */ |
539 | rv = config_detach_children(self, flags); | | 514 | rv = config_detach_children(self, flags); |
540 | if (rv) { | | 515 | if (rv) |
541 | mutex_enter(&sc->sc_lock); | | | |
542 | sc->sc_dying = 0; | | | |
543 | mutex_exit(&sc->sc_lock); | | | |
544 | return rv; | | 516 | return rv; |
545 | } | | | |
546 | | | 517 | |
547 | KASSERTMSG(sc->sc_refcnt == 0, | | 518 | KASSERTMSG(sc->sc_refcnt == 0, |
548 | "%s: %d refs remain", device_xname(sc->sc_dev), sc->sc_refcnt); | | 519 | "%s: %d refs remain", device_xname(sc->sc_dev), sc->sc_refcnt); |
549 | KASSERT(sc->sc_opipe == NULL); | | 520 | KASSERT(sc->sc_opipe == NULL); |
550 | KASSERT(sc->sc_ipipe == NULL); | | 521 | KASSERT(sc->sc_ipipe == NULL); |
551 | KASSERT(sc->sc_ibuf == NULL); | | 522 | KASSERT(sc->sc_ibuf == NULL); |
552 | | | 523 | |
553 | if (sc->sc_repdesc != NULL) { | | 524 | if (sc->sc_repdesc != NULL) { |
554 | kmem_free(sc->sc_repdesc, sc->sc_repdesc_size); | | 525 | kmem_free(sc->sc_repdesc, sc->sc_repdesc_size); |
555 | sc->sc_repdesc = NULL; | | 526 | sc->sc_repdesc = NULL; |
556 | } | | 527 | } |
557 | if (sc->sc_subdevs != NULL) { | | 528 | if (sc->sc_subdevs != NULL) { |
558 | int nrepid = sc->sc_nrepid; | | 529 | int nrepid = sc->sc_nrepid; |
| @@ -640,28 +611,26 @@ uhidev_get_report_desc(struct uhidev *sc | | | @@ -640,28 +611,26 @@ uhidev_get_report_desc(struct uhidev *sc |
640 | | | 611 | |
641 | *desc = sc->sc_repdesc; | | 612 | *desc = sc->sc_repdesc; |
642 | *size = sc->sc_repdesc_size; | | 613 | *size = sc->sc_repdesc_size; |
643 | } | | 614 | } |
644 | | | 615 | |
645 | static int | | 616 | static int |
646 | uhidev_config_enter(struct uhidev_softc *sc) | | 617 | uhidev_config_enter(struct uhidev_softc *sc) |
647 | { | | 618 | { |
648 | int error; | | 619 | int error; |
649 | | | 620 | |
650 | KASSERT(mutex_owned(&sc->sc_lock)); | | 621 | KASSERT(mutex_owned(&sc->sc_lock)); |
651 | | | 622 | |
652 | for (;;) { | | 623 | for (;;) { |
653 | if (sc->sc_dying) | | | |
654 | return ENXIO; | | | |
655 | if (sc->sc_configlock == NULL) | | 624 | if (sc->sc_configlock == NULL) |
656 | break; | | 625 | break; |
657 | error = cv_wait_sig(&sc->sc_cv, &sc->sc_lock); | | 626 | error = cv_wait_sig(&sc->sc_cv, &sc->sc_lock); |
658 | if (error) | | 627 | if (error) |
659 | return error; | | 628 | return error; |
660 | } | | 629 | } |
661 | | | 630 | |
662 | sc->sc_configlock = curlwp; | | 631 | sc->sc_configlock = curlwp; |
663 | return 0; | | 632 | return 0; |
664 | } | | 633 | } |
665 | | | 634 | |
666 | static void | | 635 | static void |
667 | uhidev_config_enter_nointr(struct uhidev_softc *sc) | | 636 | uhidev_config_enter_nointr(struct uhidev_softc *sc) |
| @@ -690,30 +659,26 @@ uhidev_config_exit(struct uhidev_softc * | | | @@ -690,30 +659,26 @@ uhidev_config_exit(struct uhidev_softc * |
690 | * uhidev_open_pipes(sc) | | 659 | * uhidev_open_pipes(sc) |
691 | * | | 660 | * |
692 | * Ensure the pipes of the softc are open. Caller must hold | | 661 | * Ensure the pipes of the softc are open. Caller must hold |
693 | * sc_lock, which may be released and reacquired. | | 662 | * sc_lock, which may be released and reacquired. |
694 | */ | | 663 | */ |
695 | static int | | 664 | static int |
696 | uhidev_open_pipes(struct uhidev_softc *sc) | | 665 | uhidev_open_pipes(struct uhidev_softc *sc) |
697 | { | | 666 | { |
698 | usbd_status err; | | 667 | usbd_status err; |
699 | int error; | | 668 | int error; |
700 | | | 669 | |
701 | KASSERT(mutex_owned(&sc->sc_lock)); | | 670 | KASSERT(mutex_owned(&sc->sc_lock)); |
702 | | | 671 | |
703 | /* If the device is dying, refuse. */ | | | |
704 | if (sc->sc_dying) | | | |
705 | return ENXIO; | | | |
706 | | | | |
707 | /* | | 672 | /* |
708 | * If the pipes are already open, just increment the reference | | 673 | * If the pipes are already open, just increment the reference |
709 | * count, or fail if it would overflow. | | 674 | * count, or fail if it would overflow. |
710 | */ | | 675 | */ |
711 | if (sc->sc_refcnt) { | | 676 | if (sc->sc_refcnt) { |
712 | if (sc->sc_refcnt == INT_MAX) | | 677 | if (sc->sc_refcnt == INT_MAX) |
713 | return EBUSY; | | 678 | return EBUSY; |
714 | sc->sc_refcnt++; | | 679 | sc->sc_refcnt++; |
715 | return 0; | | 680 | return 0; |
716 | } | | 681 | } |
717 | | | 682 | |
718 | /* | | 683 | /* |
719 | * If there's no input data to prepare, don't bother with the | | 684 | * If there's no input data to prepare, don't bother with the |
| @@ -1112,30 +1077,26 @@ usbd_status | | | @@ -1112,30 +1077,26 @@ usbd_status |
1112 | uhidev_write(struct uhidev *scd, void *data, int len) | | 1077 | uhidev_write(struct uhidev *scd, void *data, int len) |
1113 | { | | 1078 | { |
1114 | struct uhidev_softc *sc = scd->sc_parent; | | 1079 | struct uhidev_softc *sc = scd->sc_parent; |
1115 | usbd_status err; | | 1080 | usbd_status err; |
1116 | | | 1081 | |
1117 | DPRINTF(("uhidev_write: data=%p, len=%d\n", data, len)); | | 1082 | DPRINTF(("uhidev_write: data=%p, len=%d\n", data, len)); |
1118 | | | 1083 | |
1119 | if (sc->sc_opipe == NULL) | | 1084 | if (sc->sc_opipe == NULL) |
1120 | return USBD_INVAL; | | 1085 | return USBD_INVAL; |
1121 | | | 1086 | |
1122 | mutex_enter(&sc->sc_lock); | | 1087 | mutex_enter(&sc->sc_lock); |
1123 | KASSERT(sc->sc_refcnt); | | 1088 | KASSERT(sc->sc_refcnt); |
1124 | for (;;) { | | 1089 | for (;;) { |
1125 | if (sc->sc_dying) { | | | |
1126 | err = USBD_IOERROR; | | | |
1127 | goto out; | | | |
1128 | } | | | |
1129 | if (scd->sc_state & UHIDEV_STOPPED) { | | 1090 | if (scd->sc_state & UHIDEV_STOPPED) { |
1130 | err = USBD_CANCELLED; | | 1091 | err = USBD_CANCELLED; |
1131 | goto out; | | 1092 | goto out; |
1132 | } | | 1093 | } |
1133 | if (sc->sc_writelock == NULL && sc->sc_stopreportid == -1) | | 1094 | if (sc->sc_writelock == NULL && sc->sc_stopreportid == -1) |
1134 | break; | | 1095 | break; |
1135 | if (cv_wait_sig(&sc->sc_cv, &sc->sc_lock)) { | | 1096 | if (cv_wait_sig(&sc->sc_cv, &sc->sc_lock)) { |
1136 | err = USBD_INTERRUPTED; | | 1097 | err = USBD_INTERRUPTED; |
1137 | goto out; | | 1098 | goto out; |
1138 | } | | 1099 | } |
1139 | } | | 1100 | } |
1140 | sc->sc_writelock = curlwp; | | 1101 | sc->sc_writelock = curlwp; |
1141 | sc->sc_writereportid = scd->sc_report_id; | | 1102 | sc->sc_writereportid = scd->sc_report_id; |
| @@ -1200,30 +1161,26 @@ usbd_status | | | @@ -1200,30 +1161,26 @@ usbd_status |
1200 | uhidev_write_async(struct uhidev *scd, void *data, int len, int flags, | | 1161 | uhidev_write_async(struct uhidev *scd, void *data, int len, int flags, |
1201 | int timo, usbd_callback writecallback, void *writecookie) | | 1162 | int timo, usbd_callback writecallback, void *writecookie) |
1202 | { | | 1163 | { |
1203 | struct uhidev_softc *sc = scd->sc_parent; | | 1164 | struct uhidev_softc *sc = scd->sc_parent; |
1204 | usbd_status err; | | 1165 | usbd_status err; |
1205 | | | 1166 | |
1206 | DPRINTF(("%s: data=%p, len=%d\n", __func__, data, len)); | | 1167 | DPRINTF(("%s: data=%p, len=%d\n", __func__, data, len)); |
1207 | | | 1168 | |
1208 | if (sc->sc_opipe == NULL) | | 1169 | if (sc->sc_opipe == NULL) |
1209 | return USBD_INVAL; | | 1170 | return USBD_INVAL; |
1210 | | | 1171 | |
1211 | mutex_enter(&sc->sc_lock); | | 1172 | mutex_enter(&sc->sc_lock); |
1212 | KASSERT(sc->sc_refcnt); | | 1173 | KASSERT(sc->sc_refcnt); |
1213 | if (sc->sc_dying) { | | | |
1214 | err = USBD_IOERROR; | | | |
1215 | goto out; | | | |
1216 | } | | | |
1217 | if (scd->sc_state & UHIDEV_STOPPED) { | | 1174 | if (scd->sc_state & UHIDEV_STOPPED) { |
1218 | err = USBD_CANCELLED; | | 1175 | err = USBD_CANCELLED; |
1219 | goto out; | | 1176 | goto out; |
1220 | } | | 1177 | } |
1221 | if (sc->sc_writelock != NULL || sc->sc_stopreportid != -1) { | | 1178 | if (sc->sc_writelock != NULL || sc->sc_stopreportid != -1) { |
1222 | err = USBD_IN_USE; | | 1179 | err = USBD_IN_USE; |
1223 | goto out; | | 1180 | goto out; |
1224 | } | | 1181 | } |
1225 | sc->sc_writelock = (void *)1; /* XXX no lwp to attribute async xfer */ | | 1182 | sc->sc_writelock = (void *)1; /* XXX no lwp to attribute async xfer */ |
1226 | sc->sc_writereportid = scd->sc_report_id; | | 1183 | sc->sc_writereportid = scd->sc_report_id; |
1227 | sc->sc_writecallback = writecallback; | | 1184 | sc->sc_writecallback = writecallback; |
1228 | sc->sc_writecookie = writecookie; | | 1185 | sc->sc_writecookie = writecookie; |
1229 | usbd_setup_xfer(sc->sc_oxfer, sc, data, len, flags, timo, | | 1186 | usbd_setup_xfer(sc->sc_oxfer, sc, data, len, flags, timo, |