aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/usb/usb_dev.c
diff options
context:
space:
mode:
authorHans Petter Selasky <hselasky@FreeBSD.org>2010-10-04 22:21:30 +0000
committerHans Petter Selasky <hselasky@FreeBSD.org>2010-10-04 22:21:30 +0000
commit8f9750b7fdf0e5bc23218c45827f56f9b2b4aa4a (patch)
tree7df636a0fa2dd65329e74c93f332faf12841b517 /sys/dev/usb/usb_dev.c
parentce4092bda42214e65486318364ed49f0de37a264 (diff)
downloadsrc-8f9750b7fdf0e5bc23218c45827f56f9b2b4aa4a.tar.gz
src-8f9750b7fdf0e5bc23218c45827f56f9b2b4aa4a.zip
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)
Notes
Notes: svn path=/head/; revision=213432
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 cb23fcd7fcab..5ccbae656b70 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);