diff options
author | Hans Petter Selasky <hselasky@FreeBSD.org> | 2010-10-04 22:21:30 +0000 |
---|---|---|
committer | Hans Petter Selasky <hselasky@FreeBSD.org> | 2010-10-04 22:21:30 +0000 |
commit | 8f9750b7fdf0e5bc23218c45827f56f9b2b4aa4a (patch) | |
tree | 7df636a0fa2dd65329e74c93f332faf12841b517 /sys/dev/usb/usb_dev.c | |
parent | ce4092bda42214e65486318364ed49f0de37a264 (diff) | |
download | src-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.c | 49 |
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); |