summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/dev/usb/usb_device.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/dev/usb/usb_device.c')
-rw-r--r--freebsd/sys/dev/usb/usb_device.c117
1 files changed, 55 insertions, 62 deletions
diff --git a/freebsd/sys/dev/usb/usb_device.c b/freebsd/sys/dev/usb/usb_device.c
index e18c32df..8e0144cc 100644
--- a/freebsd/sys/dev/usb/usb_device.c
+++ b/freebsd/sys/dev/usb/usb_device.c
@@ -437,60 +437,28 @@ usb_endpoint_foreach(struct usb_device *udev, struct usb_endpoint *ep)
}
/*------------------------------------------------------------------------*
- * usb_wait_pending_ref_locked
+ * usb_wait_pending_refs
*
* This function will wait for any USB references to go away before
- * returning and disable further USB device refcounting on the
- * specified USB device. This function is used when detaching a USB
- * device.
+ * returning. This function is used before freeing a USB device.
*------------------------------------------------------------------------*/
static void
-usb_wait_pending_ref_locked(struct usb_device *udev)
+usb_wait_pending_refs(struct usb_device *udev)
{
#if USB_HAVE_UGEN
- const uint16_t refcount =
- usb_proc_is_called_from(
- &udev->bus->explore_proc) ? 1 : 2;
-
- DPRINTF("Refcount = %d\n", (int)refcount);
+ DPRINTF("Refcount = %d\n", (int)udev->refcount);
+ mtx_lock(&usb_ref_lock);
+ udev->refcount--;
while (1) {
/* wait for any pending references to go away */
- mtx_lock(&usb_ref_lock);
- if (udev->refcount == refcount) {
- /* prevent further refs being taken */
+ if (udev->refcount == 0) {
+ /* prevent further refs being taken, if any */
udev->refcount = USB_DEV_REF_MAX;
- mtx_unlock(&usb_ref_lock);
break;
}
- usbd_enum_unlock(udev);
cv_wait(&udev->ref_cv, &usb_ref_lock);
- mtx_unlock(&usb_ref_lock);
- (void) usbd_enum_lock(udev);
}
-#endif
-}
-
-/*------------------------------------------------------------------------*
- * usb_ref_restore_locked
- *
- * This function will restore the reference count value after a call
- * to "usb_wait_pending_ref_locked()".
- *------------------------------------------------------------------------*/
-static void
-usb_ref_restore_locked(struct usb_device *udev)
-{
-#if USB_HAVE_UGEN
- const uint16_t refcount =
- usb_proc_is_called_from(
- &udev->bus->explore_proc) ? 1 : 2;
-
- DPRINTF("Refcount = %d\n", (int)refcount);
-
- /* restore reference count and wakeup waiters, if any */
- mtx_lock(&usb_ref_lock);
- udev->refcount = refcount;
- cv_broadcast(&udev->ref_cv);
mtx_unlock(&usb_ref_lock);
#endif
}
@@ -844,9 +812,6 @@ usb_config_parse(struct usb_device *udev, uint8_t iface_index, uint8_t cmd)
/* find maximum number of endpoints */
if (ep_max < temp)
ep_max = temp;
-
- /* optimalisation */
- id = (struct usb_interface_descriptor *)ed;
}
}
@@ -1100,10 +1065,12 @@ usb_detach_device_sub(struct usb_device *udev, device_t *ppdev,
*/
*ppdev = NULL;
- device_printf(dev, "at %s, port %d, addr %d "
- "(disconnected)\n",
- device_get_nameunit(udev->parent_dev),
- udev->port_no, udev->address);
+ if (!rebooting) {
+ device_printf(dev, "at %s, port %d, addr %d "
+ "(disconnected)\n",
+ device_get_nameunit(udev->parent_dev),
+ udev->port_no, udev->address);
+ }
if (device_is_attached(dev)) {
if (udev->flags.peer_suspended) {
@@ -1156,9 +1123,6 @@ usb_detach_device(struct usb_device *udev, uint8_t iface_index,
sx_assert(&udev->enum_sx, SA_LOCKED);
- /* wait for pending refs to go away */
- usb_wait_pending_ref_locked(udev);
-
/*
* First detach the child to give the child's detach routine a
* chance to detach the sub-devices in the correct order.
@@ -1185,8 +1149,6 @@ usb_detach_device(struct usb_device *udev, uint8_t iface_index,
usb_detach_device_sub(udev, &iface->subdev,
&iface->pnpinfo, flag);
}
-
- usb_ref_restore_locked(udev);
}
/*------------------------------------------------------------------------*
@@ -1999,14 +1961,46 @@ usb_make_dev(struct usb_device *udev, const char *devname, int ep,
}
void
+usb_destroy_dev_sync(struct usb_fs_privdata *pd)
+{
+ DPRINTFN(1, "Destroying device at ugen%d.%d\n",
+ pd->bus_index, pd->dev_index);
+
+ /*
+ * Destroy character device synchronously. After this
+ * all system calls are returned. Can block.
+ */
+ destroy_dev(pd->cdev);
+
+ free(pd, M_USBDEV);
+}
+
+void
usb_destroy_dev(struct usb_fs_privdata *pd)
{
+ struct usb_bus *bus;
+
if (pd == NULL)
return;
- destroy_dev(pd->cdev);
+ mtx_lock(&usb_ref_lock);
+ bus = devclass_get_softc(usb_devclass_ptr, pd->bus_index);
+ mtx_unlock(&usb_ref_lock);
- free(pd, M_USBDEV);
+ if (bus == NULL) {
+ usb_destroy_dev_sync(pd);
+ return;
+ }
+
+ /* make sure we can re-use the device name */
+ delist_dev(pd->cdev);
+
+ USB_BUS_LOCK(bus);
+ LIST_INSERT_HEAD(&bus->pd_cleanup_list, pd, pd_next);
+ /* get cleanup going */
+ usb_proc_msignal(&bus->explore_proc,
+ &bus->cleanup_msg[0], &bus->cleanup_msg[1]);
+ USB_BUS_UNLOCK(bus);
}
static void
@@ -2115,8 +2109,10 @@ usb_free_device(struct usb_device *udev, uint8_t flag)
#endif
#if USB_HAVE_UGEN
- printf("%s: <%s> at %s (disconnected)\n", udev->ugen_name,
- usb_get_manufacturer(udev), device_get_nameunit(bus->bdev));
+ if (!rebooting) {
+ printf("%s: <%s> at %s (disconnected)\n", udev->ugen_name,
+ usb_get_manufacturer(udev), device_get_nameunit(bus->bdev));
+ }
/* Destroy UGEN symlink, if any */
if (udev->ugen_symlink) {
@@ -2155,6 +2151,9 @@ usb_free_device(struct usb_device *udev, uint8_t flag)
&udev->cs_msg[0], &udev->cs_msg[1]);
USB_BUS_UNLOCK(udev->bus);
+ /* wait for all references to go away */
+ usb_wait_pending_refs(udev);
+
sx_destroy(&udev->enum_sx);
sx_destroy(&udev->sr_sx);
@@ -2640,14 +2639,8 @@ usb_fifo_free_wrap(struct usb_device *udev,
/* no need to free this FIFO */
continue;
}
- /* wait for pending refs to go away */
- usb_wait_pending_ref_locked(udev);
-
/* free this FIFO */
usb_fifo_free(f);
-
- /* restore refcount */
- usb_ref_restore_locked(udev);
}
}
#endif