aboutsummaryrefslogtreecommitdiffstats
path: root/sys/dev/usb
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/usb')
-rw-r--r--sys/dev/usb/template/usb_template.c4
-rw-r--r--sys/dev/usb/usb_device.c44
-rw-r--r--sys/dev/usb/usb_device.h5
-rw-r--r--sys/dev/usb/usb_generic.c11
-rw-r--r--sys/dev/usb/usb_request.c15
-rw-r--r--sys/dev/usb/usb_transfer.c4
-rw-r--r--sys/dev/usb/usb_util.c4
7 files changed, 60 insertions, 27 deletions
diff --git a/sys/dev/usb/template/usb_template.c b/sys/dev/usb/template/usb_template.c
index ce48b3fe7c5c..805fb8ffe103 100644
--- a/sys/dev/usb/template/usb_template.c
+++ b/sys/dev/usb/template/usb_template.c
@@ -1240,7 +1240,7 @@ usb_temp_setup(struct usb_device *udev,
return (0);
/* Protect scratch area */
- do_unlock = usbd_enum_lock(udev);
+ do_unlock = usbd_ctrl_lock(udev);
uts = udev->scratch.temp_setup;
@@ -1319,7 +1319,7 @@ done:
if (error)
usb_temp_unsetup(udev);
if (do_unlock)
- usbd_enum_unlock(udev);
+ usbd_ctrl_unlock(udev);
return (error);
}
diff --git a/sys/dev/usb/usb_device.c b/sys/dev/usb/usb_device.c
index 638aef41c9ea..de30122b37a7 100644
--- a/sys/dev/usb/usb_device.c
+++ b/sys/dev/usb/usb_device.c
@@ -1550,6 +1550,7 @@ usb_alloc_device(device_t parent_dev, struct usb_bus *bus,
/* initialise our SX-lock */
sx_init_flags(&udev->enum_sx, "USB config SX lock", SX_DUPOK);
sx_init_flags(&udev->sr_sx, "USB suspend and resume SX lock", SX_NOWITNESS);
+ sx_init_flags(&udev->ctrl_sx, "USB control transfer SX lock", SX_DUPOK);
cv_init(&udev->ctrlreq_cv, "WCTRL");
cv_init(&udev->ref_cv, "UGONE");
@@ -1735,7 +1736,7 @@ usb_alloc_device(device_t parent_dev, struct usb_bus *bus,
*/
/* Protect scratch area */
- do_unlock = usbd_enum_lock(udev);
+ do_unlock = usbd_ctrl_lock(udev);
scratch_ptr = udev->scratch.data;
@@ -1786,7 +1787,7 @@ usb_alloc_device(device_t parent_dev, struct usb_bus *bus,
}
if (do_unlock)
- usbd_enum_unlock(udev);
+ usbd_ctrl_unlock(udev);
/* assume 100mA bus powered for now. Changed when configured. */
udev->power = USB_MIN_POWER;
@@ -2148,6 +2149,7 @@ usb_free_device(struct usb_device *udev, uint8_t flag)
sx_destroy(&udev->enum_sx);
sx_destroy(&udev->sr_sx);
+ sx_destroy(&udev->ctrl_sx);
cv_destroy(&udev->ctrlreq_cv);
cv_destroy(&udev->ref_cv);
@@ -2311,7 +2313,7 @@ usbd_set_device_strings(struct usb_device *udev)
uint8_t do_unlock;
/* Protect scratch area */
- do_unlock = usbd_enum_lock(udev);
+ do_unlock = usbd_ctrl_lock(udev);
temp_ptr = (char *)udev->scratch.data;
temp_size = sizeof(udev->scratch.data);
@@ -2371,7 +2373,7 @@ usbd_set_device_strings(struct usb_device *udev)
}
if (do_unlock)
- usbd_enum_unlock(udev);
+ usbd_ctrl_unlock(udev);
}
/*
@@ -2853,6 +2855,40 @@ usbd_enum_is_locked(struct usb_device *udev)
}
/*
+ * The following function is used to serialize access to USB control
+ * transfers and the USB scratch area. If the lock is already grabbed
+ * this function returns zero. Else a value of one is returned.
+ */
+uint8_t
+usbd_ctrl_lock(struct usb_device *udev)
+{
+ if (sx_xlocked(&udev->ctrl_sx))
+ return (0);
+ sx_xlock(&udev->ctrl_sx);
+
+ /*
+ * We need to allow suspend and resume at this point, else the
+ * control transfer will timeout if the device is suspended!
+ */
+ if (usbd_enum_is_locked(udev))
+ usbd_sr_unlock(udev);
+ return (1);
+}
+
+void
+usbd_ctrl_unlock(struct usb_device *udev)
+{
+ sx_xunlock(&udev->ctrl_sx);
+
+ /*
+ * Restore the suspend and resume lock after we have unlocked
+ * the USB control transfer lock to avoid LOR:
+ */
+ if (usbd_enum_is_locked(udev))
+ usbd_sr_lock(udev);
+}
+
+/*
* The following function is used to set the per-interface specific
* plug and play information. The string referred to by the pnpinfo
* argument can safely be freed after calling this function. The
diff --git a/sys/dev/usb/usb_device.h b/sys/dev/usb/usb_device.h
index b4ff58f225ff..063ea2dc1a35 100644
--- a/sys/dev/usb/usb_device.h
+++ b/sys/dev/usb/usb_device.h
@@ -162,7 +162,7 @@ struct usb_temp_setup {
/*
* The scratch area for USB devices. Access to this structure is
- * protected by the enumeration SX lock.
+ * protected by the control SX lock.
*/
union usb_device_scratch {
struct usb_hw_ep_scratch hw_ep_scratch[1];
@@ -183,6 +183,7 @@ struct usb_device {
struct usb_udev_msg cs_msg[2];
struct sx enum_sx;
struct sx sr_sx;
+ struct sx ctrl_sx;
struct mtx device_mtx;
struct cv ctrlreq_cv;
struct cv ref_cv;
@@ -309,6 +310,8 @@ uint8_t usbd_enum_lock_sig(struct usb_device *);
void usbd_enum_unlock(struct usb_device *);
void usbd_sr_lock(struct usb_device *);
void usbd_sr_unlock(struct usb_device *);
+uint8_t usbd_ctrl_lock(struct usb_device *);
+void usbd_ctrl_unlock(struct usb_device *);
uint8_t usbd_enum_is_locked(struct usb_device *);
#if USB_HAVE_TT_SUPPORT
diff --git a/sys/dev/usb/usb_generic.c b/sys/dev/usb/usb_generic.c
index dc796dc09a99..f5014f61b667 100644
--- a/sys/dev/usb/usb_generic.c
+++ b/sys/dev/usb/usb_generic.c
@@ -706,16 +706,16 @@ ugen_get_cdesc(struct usb_fifo *f, struct usb_gen_descriptor *ugd)
return (error);
}
-/*
- * This function is called having the enumeration SX locked which
- * protects the scratch area used.
- */
static int
ugen_get_sdesc(struct usb_fifo *f, struct usb_gen_descriptor *ugd)
{
void *ptr;
uint16_t size;
int error;
+ uint8_t do_unlock;
+
+ /* Protect scratch area */
+ do_unlock = usbd_ctrl_lock(f->udev);
ptr = f->udev->scratch.data;
size = sizeof(f->udev->scratch.data);
@@ -736,6 +736,9 @@ ugen_get_sdesc(struct usb_fifo *f, struct usb_gen_descriptor *ugd)
error = copyout(ptr, ugd->ugd_data, size);
}
+ if (do_unlock)
+ usbd_ctrl_unlock(f->udev);
+
return (error);
}
diff --git a/sys/dev/usb/usb_request.c b/sys/dev/usb/usb_request.c
index 5574795de190..982835a906b9 100644
--- a/sys/dev/usb/usb_request.c
+++ b/sys/dev/usb/usb_request.c
@@ -453,16 +453,9 @@ usbd_do_request_flags(struct usb_device *udev, struct mtx *mtx,
}
/*
- * Grab the USB device enumeration SX-lock serialization is
- * achieved when multiple threads are involved:
+ * Serialize access to this function:
*/
- do_unlock = usbd_enum_lock(udev);
-
- /*
- * We need to allow suspend and resume at this point, else the
- * control transfer will timeout if the device is suspended!
- */
- usbd_sr_unlock(udev);
+ do_unlock = usbd_ctrl_lock(udev);
hr_func = usbd_get_hr_func(udev);
@@ -706,10 +699,8 @@ usbd_do_request_flags(struct usb_device *udev, struct mtx *mtx,
USB_XFER_UNLOCK(xfer);
done:
- usbd_sr_lock(udev);
-
if (do_unlock)
- usbd_enum_unlock(udev);
+ usbd_ctrl_unlock(udev);
if ((mtx != NULL) && (mtx != &Giant))
mtx_lock(mtx);
diff --git a/sys/dev/usb/usb_transfer.c b/sys/dev/usb/usb_transfer.c
index 3fe4ff4c1c17..4ec6ecdc4ef2 100644
--- a/sys/dev/usb/usb_transfer.c
+++ b/sys/dev/usb/usb_transfer.c
@@ -872,7 +872,7 @@ usbd_transfer_setup(struct usb_device *udev,
return (error);
/* Protect scratch area */
- do_unlock = usbd_enum_lock(udev);
+ do_unlock = usbd_ctrl_lock(udev);
refcount = 0;
info = NULL;
@@ -1170,7 +1170,7 @@ done:
error = parm->err;
if (do_unlock)
- usbd_enum_unlock(udev);
+ usbd_ctrl_unlock(udev);
return (error);
}
diff --git a/sys/dev/usb/usb_util.c b/sys/dev/usb/usb_util.c
index 1aeb9461c366..7aa45b9a49b8 100644
--- a/sys/dev/usb/usb_util.c
+++ b/sys/dev/usb/usb_util.c
@@ -119,7 +119,7 @@ device_set_usb_desc(device_t dev)
}
/* Protect scratch area */
- do_unlock = usbd_enum_lock(udev);
+ do_unlock = usbd_ctrl_lock(udev);
temp_p = (char *)udev->scratch.data;
@@ -136,7 +136,7 @@ device_set_usb_desc(device_t dev)
}
if (do_unlock)
- usbd_enum_unlock(udev);
+ usbd_ctrl_unlock(udev);
device_set_desc_copy(dev, temp_p);
device_printf(dev, "<%s> on %s\n", temp_p,