summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/usb_dev.c
diff options
context:
space:
mode:
authorhselasky <hselasky@FreeBSD.org>2010-10-04 22:21:30 +0000
committerhselasky <hselasky@FreeBSD.org>2010-10-04 22:21:30 +0000
commit97650b7539017733bdc3cd4318ccd7ab926a730b (patch)
tree7df636a0fa2dd65329e74c93f332faf12841b517 /sys/dev/usb/usb_dev.c
parentc4bf79bca3ee37849267066f0dd5c166ffdac8e2 (diff)
downloadFreeBSD-src-97650b7539017733bdc3cd4318ccd7ab926a730b.zip
FreeBSD-src-97650b7539017733bdc3cd4318ccd7ab926a730b.tar.gz
Serialise USB re-enumeration with the USB explore thread.
This patch can solve problems when multiple USB devices are re-enumerated at the same time on the same bus. Approved by: thompsa (mentor)
Diffstat (limited to 'sys/dev/usb/usb_dev.c')
-rw-r--r--sys/dev/usb/usb_dev.c49
1 files changed, 36 insertions, 13 deletions
diff --git a/sys/dev/usb/usb_dev.c b/sys/dev/usb/usb_dev.c
index cb23fcd..5ccbae6 100644
--- a/sys/dev/usb/usb_dev.c
+++ b/sys/dev/usb/usb_dev.c
@@ -964,7 +964,6 @@ usb_dev_uninit(void *arg)
if (usb_dev != NULL) {
destroy_dev(usb_dev);
usb_dev = NULL;
-
}
mtx_destroy(&usb_ref_lock);
sx_destroy(&usb_sym_lock);
@@ -1058,21 +1057,45 @@ usb_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int fflag, struct thread*
err = usb_ioctl_f_sub(f, cmd, addr, td);
}
KASSERT(f != NULL, ("fifo not found"));
- if (err == ENOIOCTL) {
- err = (f->methods->f_ioctl) (f, cmd, addr, fflags);
- DPRINTFN(2, "f_ioctl cmd 0x%lx = %d\n", cmd, err);
- if (err == ENOIOCTL) {
- if (usb_usb_ref_device(cpd, &refs)) {
- err = ENXIO;
- goto done;
- }
- err = (f->methods->f_ioctl_post) (f, cmd, addr, fflags);
- DPRINTFN(2, "f_ioctl_post cmd 0x%lx = %d\n", cmd, err);
- }
+ if (err != ENOIOCTL)
+ goto done;
+
+ err = (f->methods->f_ioctl) (f, cmd, addr, fflags);
+
+ DPRINTFN(2, "f_ioctl cmd 0x%lx = %d\n", cmd, err);
+
+ if (err != ENOIOCTL)
+ goto done;
+
+ if (usb_usb_ref_device(cpd, &refs)) {
+ err = ENXIO;
+ goto done;
}
- if (err == ENOIOCTL) {
+
+ err = (f->methods->f_ioctl_post) (f, cmd, addr, fflags);
+
+ DPRINTFN(2, "f_ioctl_post cmd 0x%lx = %d\n", cmd, err);
+
+ if (err == ENOIOCTL)
err = ENOTTY;
+
+ if (err)
+ goto done;
+
+ /* Wait for re-enumeration, if any */
+
+ while (f->udev->re_enumerate_wait != 0) {
+
+ usb_unref_device(cpd, &refs);
+
+ usb_pause_mtx(NULL, hz / 128);
+
+ if (usb_ref_device(cpd, &refs, 1 /* need uref */)) {
+ err = ENXIO;
+ goto done;
+ }
}
+
done:
usb_unref_device(cpd, &refs);
return (err);
OpenPOWER on IntegriCloud