diff options
Diffstat (limited to 'freebsd/sys/dev/usb/usb_dev.c')
-rw-r--r-- | freebsd/sys/dev/usb/usb_dev.c | 33 |
1 files changed, 18 insertions, 15 deletions
diff --git a/freebsd/sys/dev/usb/usb_dev.c b/freebsd/sys/dev/usb/usb_dev.c index 3ff064ee..ce107cf3 100644 --- a/freebsd/sys/dev/usb/usb_dev.c +++ b/freebsd/sys/dev/usb/usb_dev.c @@ -292,11 +292,15 @@ error: usbd_enum_unlock(cpd->udev); if (crd->is_uref) { - cpd->udev->refcount--; - cv_broadcast(&cpd->udev->ref_cv); + if (--(cpd->udev->refcount) == 0) + cv_broadcast(&cpd->udev->ref_cv); } mtx_unlock(&usb_ref_lock); DPRINTFN(2, "fail\n"); + + /* clear all refs */ + memset(crd, 0, sizeof(*crd)); + return (USB_ERR_INVAL); } @@ -360,8 +364,8 @@ usb_unref_device(struct usb_cdev_privdata *cpd, } if (crd->is_uref) { crd->is_uref = 0; - cpd->udev->refcount--; - cv_broadcast(&cpd->udev->ref_cv); + if (--(cpd->udev->refcount) == 0) + cv_broadcast(&cpd->udev->ref_cv); } mtx_unlock(&usb_ref_lock); } @@ -587,12 +591,12 @@ usb_fifo_free(struct usb_fifo *f) /* decrease refcount */ f->refcount--; - /* prevent any write flush */ - f->flag_iserror = 1; /* need to wait until all callers have exited */ while (f->refcount != 0) { mtx_unlock(&usb_ref_lock); /* avoid LOR */ mtx_lock(f->priv_mtx); + /* prevent write flush, if any */ + f->flag_iserror = 1; /* get I/O thread out of any sleep state */ if (f->flag_sleeping) { f->flag_sleeping = 0; @@ -1092,8 +1096,8 @@ usb_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int fflag, struct thread* goto done; if (usb_usb_ref_device(cpd, &refs)) { - err = ENXIO; - goto done; + /* we lost the reference */ + return (ENXIO); } err = (f->methods->f_ioctl_post) (f, cmd, addr, fflags); @@ -1116,9 +1120,8 @@ usb_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int fflag, struct thread* while (usb_ref_device(cpd, &refs, 1 /* need uref */)) { if (usb_ref_device(cpd, &refs, 0)) { - /* device no longer exits */ - err = ENXIO; - goto done; + /* device no longer exists */ + return (ENXIO); } usb_unref_device(cpd, &refs); usb_pause_mtx(NULL, hz / 128); @@ -1410,9 +1413,9 @@ usb_read(struct cdev *dev, struct uio *uio, int ioflag) return (err); err = usb_ref_device(cpd, &refs, 0 /* no uref */ ); - if (err) { + if (err) return (ENXIO); - } + fflags = cpd->fflags; f = refs.rxfifo; @@ -1536,9 +1539,9 @@ usb_write(struct cdev *dev, struct uio *uio, int ioflag) return (err); err = usb_ref_device(cpd, &refs, 0 /* no uref */ ); - if (err) { + if (err) return (ENXIO); - } + fflags = cpd->fflags; f = refs.txfifo; |