diff options
author | hselasky <hselasky@FreeBSD.org> | 2010-10-04 22:21:30 +0000 |
---|---|---|
committer | hselasky <hselasky@FreeBSD.org> | 2010-10-04 22:21:30 +0000 |
commit | 97650b7539017733bdc3cd4318ccd7ab926a730b (patch) | |
tree | 7df636a0fa2dd65329e74c93f332faf12841b517 /sys/dev/usb/usb_dev.c | |
parent | c4bf79bca3ee37849267066f0dd5c166ffdac8e2 (diff) | |
download | FreeBSD-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.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 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); |