diff options
Diffstat (limited to 'sys/dev/usb')
-rw-r--r-- | sys/dev/usb/template/usb_template.c | 4 | ||||
-rw-r--r-- | sys/dev/usb/usb_device.c | 44 | ||||
-rw-r--r-- | sys/dev/usb/usb_device.h | 5 | ||||
-rw-r--r-- | sys/dev/usb/usb_generic.c | 11 | ||||
-rw-r--r-- | sys/dev/usb/usb_request.c | 15 | ||||
-rw-r--r-- | sys/dev/usb/usb_transfer.c | 4 | ||||
-rw-r--r-- | sys/dev/usb/usb_util.c | 4 |
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, |