summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb
diff options
context:
space:
mode:
authorhselasky <hselasky@FreeBSD.org>2013-02-10 10:56:13 +0000
committerhselasky <hselasky@FreeBSD.org>2013-02-10 10:56:13 +0000
commit07c18e4e92170f42c04651098b0a5e506e8f1efe (patch)
tree98239bf65cd74264d2ba911ccbce4a4b729fa56b /sys/dev/usb
parent34ac6c9a18f820e4a7bbf72e956f09cf5c153a8b (diff)
downloadFreeBSD-src-07c18e4e92170f42c04651098b0a5e506e8f1efe.zip
FreeBSD-src-07c18e4e92170f42c04651098b0a5e506e8f1efe.tar.gz
- Move scratch data from the USB bus structure to the USB device structure
so that simultaneous access cannot happen. Protect scratch area using the enumeration lock. Also reduce stack usage in usbd_transfer_setup() by moving some big stack members to the scratch area. This saves around 200 bytes of stack. - Fix a whitespace. MFC after: 1 week
Diffstat (limited to 'sys/dev/usb')
-rw-r--r--sys/dev/usb/template/usb_template.c65
-rw-r--r--sys/dev/usb/usb_bus.h10
-rw-r--r--sys/dev/usb/usb_controller.h45
-rw-r--r--sys/dev/usb/usb_device.c85
-rw-r--r--sys/dev/usb/usb_device.h73
-rw-r--r--sys/dev/usb/usb_generic.c11
-rw-r--r--sys/dev/usb/usb_handle_request.c9
-rw-r--r--sys/dev/usb/usb_msctest.c9
-rw-r--r--sys/dev/usb/usb_transfer.c167
-rw-r--r--sys/dev/usb/usb_util.c22
10 files changed, 268 insertions, 228 deletions
diff --git a/sys/dev/usb/template/usb_template.c b/sys/dev/usb/template/usb_template.c
index 36c11d9..b815161 100644
--- a/sys/dev/usb/template/usb_template.c
+++ b/sys/dev/usb/template/usb_template.c
@@ -849,20 +849,20 @@ usb_hw_ep_resolve(struct usb_device *udev,
struct usb_device_descriptor *dd;
uint16_t mps;
- if (desc == NULL) {
+ if (desc == NULL)
return (USB_ERR_INVAL);
- }
+
/* get bus methods */
methods = udev->bus->methods;
- if (methods->get_hw_ep_profile == NULL) {
+ if (methods->get_hw_ep_profile == NULL)
return (USB_ERR_INVAL);
- }
+
if (desc->bDescriptorType == UDESC_DEVICE) {
- if (desc->bLength < sizeof(*dd)) {
+ if (desc->bLength < sizeof(*dd))
return (USB_ERR_INVAL);
- }
+
dd = (void *)desc;
/* get HW control endpoint 0 profile */
@@ -909,13 +909,12 @@ usb_hw_ep_resolve(struct usb_device *udev,
}
return (0); /* success */
}
- if (desc->bDescriptorType != UDESC_CONFIG) {
+ if (desc->bDescriptorType != UDESC_CONFIG)
return (USB_ERR_INVAL);
- }
- if (desc->bLength < sizeof(*(ues->cd))) {
+ if (desc->bLength < sizeof(*(ues->cd)))
return (USB_ERR_INVAL);
- }
- ues = udev->bus->scratch[0].hw_ep_scratch;
+
+ ues = udev->scratch.hw_ep_scratch;
memset(ues, 0, sizeof(*ues));
@@ -1236,13 +1235,18 @@ usb_temp_setup(struct usb_device *udev,
{
struct usb_temp_setup *uts;
void *buf;
+ usb_error_t error;
uint8_t n;
+ uint8_t do_unlock;
- if (tdd == NULL) {
- /* be NULL safe */
+ /* be NULL safe */
+ if (tdd == NULL)
return (0);
- }
- uts = udev->bus->scratch[0].temp_setup;
+
+ /* Protect scratch area */
+ do_unlock = usbd_enum_lock(udev);
+
+ uts = udev->scratch.temp_setup;
memset(uts, 0, sizeof(*uts));
@@ -1255,17 +1259,24 @@ usb_temp_setup(struct usb_device *udev,
if (uts->err) {
/* some error happened */
- return (uts->err);
+ goto done;
}
/* sanity check */
if (uts->size == 0) {
- return (USB_ERR_INVAL);
+ uts->err = USB_ERR_INVAL;
+ goto done;
}
/* allocate zeroed memory */
uts->buf = malloc(uts->size, M_USB, M_WAITOK | M_ZERO);
+ /*
+ * Allow malloc() to return NULL regardless of M_WAITOK flag.
+ * This helps when porting the software to non-FreeBSD
+ * systems.
+ */
if (uts->buf == NULL) {
/* could not allocate memory */
- return (USB_ERR_NOMEM);
+ uts->err = USB_ERR_NOMEM;
+ goto done;
}
/* second pass */
@@ -1280,7 +1291,7 @@ usb_temp_setup(struct usb_device *udev,
if (uts->err) {
/* some error happened during second pass */
- goto error;
+ goto done;
}
/*
* Resolve all endpoint addresses !
@@ -1291,7 +1302,7 @@ usb_temp_setup(struct usb_device *udev,
DPRINTFN(0, "Could not resolve endpoints for "
"Device Descriptor, error = %s\n",
usbd_errstr(uts->err));
- goto error;
+ goto done;
}
for (n = 0;; n++) {
@@ -1304,14 +1315,16 @@ usb_temp_setup(struct usb_device *udev,
DPRINTFN(0, "Could not resolve endpoints for "
"Config Descriptor %u, error = %s\n", n,
usbd_errstr(uts->err));
- goto error;
+ goto done;
}
}
- return (uts->err);
-
-error:
- usb_temp_unsetup(udev);
- return (uts->err);
+done:
+ error = uts->err;
+ if (error)
+ usb_temp_unsetup(udev);
+ if (do_unlock)
+ usbd_enum_unlock(udev);
+ return (error);
}
/*------------------------------------------------------------------------*
diff --git a/sys/dev/usb/usb_bus.h b/sys/dev/usb/usb_bus.h
index dea15f8..2898eee 100644
--- a/sys/dev/usb/usb_bus.h
+++ b/sys/dev/usb/usb_bus.h
@@ -113,16 +113,6 @@ struct usb_bus {
uint8_t devices_max; /* maximum number of USB devices */
uint8_t do_probe; /* set if USB should be re-probed */
uint8_t no_explore; /* don't explore USB ports */
-
- /*
- * The scratch area can only be used inside the explore thread
- * belonging to the give serial bus.
- */
- union {
- struct usb_hw_ep_scratch hw_ep_scratch[1];
- struct usb_temp_setup temp_setup[1];
- uint8_t data[255];
- } scratch[1];
};
#endif /* _USB_BUS_H_ */
diff --git a/sys/dev/usb/usb_controller.h b/sys/dev/usb/usb_controller.h
index 6c14454..3ee6f04 100644
--- a/sys/dev/usb/usb_controller.h
+++ b/sys/dev/usb/usb_controller.h
@@ -40,7 +40,6 @@ struct usb_page_cache;
struct usb_setup_params;
struct usb_hw_ep_profile;
struct usb_fs_isoc_schedule;
-struct usb_config_descriptor;
struct usb_endpoint_descriptor;
/* typedefs */
@@ -186,50 +185,6 @@ struct usb_hw_ep_profile {
uint8_t support_out:1; /* OUT-token is supported */
};
-/*
- * The following structure is used when trying to allocate hardware
- * endpoints for an USB configuration in USB device side mode.
- */
-struct usb_hw_ep_scratch_sub {
- const struct usb_hw_ep_profile *pf;
- uint16_t max_frame_size;
- uint8_t hw_endpoint_out;
- uint8_t hw_endpoint_in;
- uint8_t needs_ep_type;
- uint8_t needs_in:1;
- uint8_t needs_out:1;
-};
-
-/*
- * The following structure is used when trying to allocate hardware
- * endpoints for an USB configuration in USB device side mode.
- */
-struct usb_hw_ep_scratch {
- struct usb_hw_ep_scratch_sub ep[USB_EP_MAX];
- struct usb_hw_ep_scratch_sub *ep_max;
- struct usb_config_descriptor *cd;
- struct usb_device *udev;
- struct usb_bus_methods *methods;
- uint8_t bmOutAlloc[(USB_EP_MAX + 15) / 16];
- uint8_t bmInAlloc[(USB_EP_MAX + 15) / 16];
-};
-
-/*
- * The following structure is used when generating USB descriptors
- * from USB templates.
- */
-struct usb_temp_setup {
- void *buf;
- usb_size_t size;
- enum usb_dev_speed usb_speed;
- uint8_t self_powered;
- uint8_t bNumEndpoints;
- uint8_t bInterfaceNumber;
- uint8_t bAlternateSetting;
- uint8_t bConfigurationValue;
- usb_error_t err;
-};
-
/* prototypes */
void usb_bus_mem_flush_all(struct usb_bus *bus, usb_bus_mem_cb_t *cb);
diff --git a/sys/dev/usb/usb_device.c b/sys/dev/usb/usb_device.c
index a9aab53..fdc734c 100644
--- a/sys/dev/usb/usb_device.c
+++ b/sys/dev/usb/usb_device.c
@@ -460,13 +460,8 @@ usb_unconfigure(struct usb_device *udev, uint8_t flag)
{
uint8_t do_unlock;
- /* automatic locking */
- if (usbd_enum_is_locked(udev)) {
- do_unlock = 0;
- } else {
- do_unlock = 1;
- usbd_enum_lock(udev);
- }
+ /* Prevent re-enumeration */
+ do_unlock = usbd_enum_lock(udev);
/* detach all interface drivers */
usb_detach_device(udev, USB_IFACE_INDEX_ANY, flag);
@@ -529,13 +524,8 @@ usbd_set_config_index(struct usb_device *udev, uint8_t index)
DPRINTFN(6, "udev=%p index=%d\n", udev, index);
- /* automatic locking */
- if (usbd_enum_is_locked(udev)) {
- do_unlock = 0;
- } else {
- do_unlock = 1;
- usbd_enum_lock(udev);
- }
+ /* Prevent re-enumeration */
+ do_unlock = usbd_enum_lock(udev);
usb_unconfigure(udev, 0);
@@ -888,13 +878,9 @@ usbd_set_alt_interface_index(struct usb_device *udev,
usb_error_t err;
uint8_t do_unlock;
- /* automatic locking */
- if (usbd_enum_is_locked(udev)) {
- do_unlock = 0;
- } else {
- do_unlock = 1;
- usbd_enum_lock(udev);
- }
+ /* Prevent re-enumeration */
+ do_unlock = usbd_enum_lock(udev);
+
if (iface == NULL) {
err = USB_ERR_INVAL;
goto done;
@@ -931,7 +917,6 @@ usbd_set_alt_interface_index(struct usb_device *udev,
done:
if (do_unlock)
usbd_enum_unlock(udev);
-
return (err);
}
@@ -1310,13 +1295,8 @@ usb_probe_and_attach(struct usb_device *udev, uint8_t iface_index)
DPRINTF("udev == NULL\n");
return (USB_ERR_INVAL);
}
- /* automatic locking */
- if (usbd_enum_is_locked(udev)) {
- do_unlock = 0;
- } else {
- do_unlock = 1;
- usbd_enum_lock(udev);
- }
+ /* Prevent re-enumeration */
+ do_unlock = usbd_enum_lock(udev);
if (udev->curr_config_index == USB_UNCONFIG_INDEX) {
/* do nothing - no configuration has been set */
@@ -1403,7 +1383,6 @@ usb_probe_and_attach(struct usb_device *udev, uint8_t iface_index)
done:
if (do_unlock)
usbd_enum_unlock(udev);
-
return (0);
}
@@ -1532,6 +1511,7 @@ usb_alloc_device(device_t parent_dev, struct usb_bus *bus,
uint8_t config_index;
uint8_t config_quirk;
uint8_t set_config_failed;
+ uint8_t do_unlock;
DPRINTF("parent_dev=%p, bus=%p, parent_hub=%p, depth=%u, "
"port_index=%u, port_no=%u, speed=%u, usb_mode=%u\n",
@@ -1750,7 +1730,11 @@ usb_alloc_device(device_t parent_dev, struct usb_bus *bus,
* device descriptor. If no strings are present there we
* simply disable all USB strings.
*/
- scratch_ptr = udev->bus->scratch[0].data;
+
+ /* Protect scratch area */
+ do_unlock = usbd_enum_lock(udev);
+
+ scratch_ptr = udev->scratch.data;
if (udev->ddesc.iManufacturer ||
udev->ddesc.iProduct ||
@@ -1775,7 +1759,7 @@ usb_alloc_device(device_t parent_dev, struct usb_bus *bus,
mask = usb_lang_mask;
/* align length correctly */
- scratch_ptr[0] &= ~1;
+ scratch_ptr[0] &= ~1U;
/* fix compiler warning */
langid = 0;
@@ -1796,6 +1780,9 @@ usb_alloc_device(device_t parent_dev, struct usb_bus *bus,
udev->langid = langid;
}
+ if (do_unlock)
+ usbd_enum_unlock(udev);
+
/* assume 100mA bus powered for now. Changed when configured. */
udev->power = USB_MIN_POWER;
/* fetch the vendor and product strings from the device */
@@ -2295,9 +2282,13 @@ usbd_set_device_strings(struct usb_device *udev)
size_t temp_size;
uint16_t vendor_id;
uint16_t product_id;
+ uint8_t do_unlock;
- temp_ptr = (char *)udev->bus->scratch[0].data;
- temp_size = sizeof(udev->bus->scratch[0].data);
+ /* Protect scratch area */
+ do_unlock = usbd_enum_lock(udev);
+
+ temp_ptr = (char *)udev->scratch.data;
+ temp_size = sizeof(udev->scratch.data);
vendor_id = UGETW(udd->idVendor);
product_id = UGETW(udd->idProduct);
@@ -2352,6 +2343,9 @@ usbd_set_device_strings(struct usb_device *udev)
snprintf(temp_ptr, temp_size, "product 0x%04x", product_id);
udev->product = strdup(temp_ptr, M_USB);
}
+
+ if (do_unlock)
+ usbd_enum_unlock(udev);
}
/*
@@ -2664,11 +2658,17 @@ usbd_device_attached(struct usb_device *udev)
return (udev->state > USB_STATE_DETACHED);
}
-/* The following function locks enumerating the given USB device. */
-
-void
+/*
+ * The following function locks enumerating the given USB device. If
+ * the lock is already grabbed this function returns zero. Else a
+ * non-zero value is returned.
+ */
+uint8_t
usbd_enum_lock(struct usb_device *udev)
{
+ if (sx_xlocked(&udev->enum_sx))
+ return (0);
+
sx_xlock(&udev->enum_sx);
sx_xlock(&udev->sr_sx);
/*
@@ -2677,6 +2677,7 @@ usbd_enum_lock(struct usb_device *udev)
* locked multiple times.
*/
mtx_lock(&Giant);
+ return (1);
}
/* The following function unlocks enumerating the given USB device. */
@@ -2783,13 +2784,8 @@ usbd_set_endpoint_mode(struct usb_device *udev, struct usb_endpoint *ep,
usb_error_t error;
uint8_t do_unlock;
- /* automatic locking */
- if (usbd_enum_is_locked(udev)) {
- do_unlock = 0;
- } else {
- do_unlock = 1;
- usbd_enum_lock(udev);
- }
+ /* Prevent re-enumeration */
+ do_unlock = usbd_enum_lock(udev);
if (udev->bus->methods->set_endpoint_mode != NULL) {
error = (udev->bus->methods->set_endpoint_mode) (
@@ -2805,7 +2801,6 @@ usbd_set_endpoint_mode(struct usb_device *udev, struct usb_endpoint *ep,
if (do_unlock)
usbd_enum_unlock(udev);
-
return (error);
}
diff --git a/sys/dev/usb/usb_device.h b/sys/dev/usb/usb_device.h
index 4eaadc7..22a4652 100644
--- a/sys/dev/usb/usb_device.h
+++ b/sys/dev/usb/usb_device.h
@@ -27,9 +27,18 @@
#ifndef _USB_DEVICE_H_
#define _USB_DEVICE_H_
-struct usb_symlink; /* UGEN */
+#ifndef USB_GLOBAL_INCLUDE_FILE
+#include <dev/usb/usb_core.h>
+#include <dev/usb/usb_busdma.h>
+#include <dev/usb/usb_transfer.h>
+#endif
+
+struct usb_bus_methods;
+struct usb_config_descriptor;
struct usb_device; /* linux compat */
struct usb_fs_privdata;
+struct usb_hw_ep_profile;
+struct usb_symlink; /* UGEN */
#define USB_CTRL_XFER_MAX 2
@@ -108,6 +117,64 @@ struct usb_power_save {
};
/*
+ * The following structure is used when trying to allocate hardware
+ * endpoints for an USB configuration in USB device side mode.
+ */
+struct usb_hw_ep_scratch_sub {
+ const struct usb_hw_ep_profile *pf;
+ uint16_t max_frame_size;
+ uint8_t hw_endpoint_out;
+ uint8_t hw_endpoint_in;
+ uint8_t needs_ep_type;
+ uint8_t needs_in:1;
+ uint8_t needs_out:1;
+};
+
+/*
+ * The following structure is used when trying to allocate hardware
+ * endpoints for an USB configuration in USB device side mode.
+ */
+struct usb_hw_ep_scratch {
+ struct usb_hw_ep_scratch_sub ep[USB_EP_MAX];
+ struct usb_hw_ep_scratch_sub *ep_max;
+ struct usb_config_descriptor *cd;
+ struct usb_device *udev;
+ struct usb_bus_methods *methods;
+ uint8_t bmOutAlloc[(USB_EP_MAX + 15) / 16];
+ uint8_t bmInAlloc[(USB_EP_MAX + 15) / 16];
+};
+
+/*
+ * The following structure is used when generating USB descriptors
+ * from USB templates.
+ */
+struct usb_temp_setup {
+ void *buf;
+ usb_size_t size;
+ enum usb_dev_speed usb_speed;
+ uint8_t self_powered;
+ uint8_t bNumEndpoints;
+ uint8_t bInterfaceNumber;
+ uint8_t bAlternateSetting;
+ uint8_t bConfigurationValue;
+ usb_error_t err;
+};
+
+/*
+ * The scratch area for USB devices. Access to this structure is
+ * protected by the enumeration SX lock.
+ */
+union usb_device_scratch {
+ struct usb_hw_ep_scratch hw_ep_scratch[1];
+ struct usb_temp_setup temp_setup[1];
+ struct {
+ struct usb_xfer dummy;
+ struct usb_setup_params parm;
+ } xfer_setup[1];
+ uint8_t data[255];
+};
+
+/*
* The following structure defines an USB device. There exists one of
* these structures for every USB device.
*/
@@ -191,6 +258,8 @@ struct usb_device {
#endif
uint32_t clear_stall_errors; /* number of clear-stall failures */
+
+ union usb_device_scratch scratch;
};
/* globals */
@@ -227,7 +296,7 @@ struct usb_endpoint *usb_endpoint_foreach(struct usb_device *udev, struct usb_en
void usb_set_device_state(struct usb_device *, enum usb_dev_state);
enum usb_dev_state usb_get_device_state(struct usb_device *);
-void usbd_enum_lock(struct usb_device *);
+uint8_t usbd_enum_lock(struct usb_device *);
void usbd_enum_unlock(struct usb_device *);
void usbd_sr_lock(struct usb_device *);
void usbd_sr_unlock(struct usb_device *);
diff --git a/sys/dev/usb/usb_generic.c b/sys/dev/usb/usb_generic.c
index 13f5bd6..34b7778 100644
--- a/sys/dev/usb/usb_generic.c
+++ b/sys/dev/usb/usb_generic.c
@@ -719,13 +719,20 @@ 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 = f->udev->bus->scratch[0].data;
- uint16_t size = sizeof(f->udev->bus->scratch[0].data);
+ void *ptr;
+ uint16_t size;
int error;
+ ptr = f->udev->scratch.data;
+ size = sizeof(f->udev->scratch.data);
+
if (usbd_req_get_string_desc(f->udev, NULL, ptr,
size, ugd->ugd_lang_id, ugd->ugd_string_index)) {
error = EINVAL;
diff --git a/sys/dev/usb/usb_handle_request.c b/sys/dev/usb/usb_handle_request.c
index 13fff91..a775d67 100644
--- a/sys/dev/usb/usb_handle_request.c
+++ b/sys/dev/usb/usb_handle_request.c
@@ -191,13 +191,8 @@ usb_check_alt_setting(struct usb_device *udev,
uint8_t do_unlock;
usb_error_t err = 0;
- /* automatic locking */
- if (usbd_enum_is_locked(udev)) {
- do_unlock = 0;
- } else {
- do_unlock = 1;
- usbd_enum_lock(udev);
- }
+ /* Prevent re-enumeration */
+ do_unlock = usbd_enum_lock(udev);
if (alt_index >= usbd_get_no_alts(udev->cdesc, iface->idesc))
err = USB_ERR_INVAL;
diff --git a/sys/dev/usb/usb_msctest.c b/sys/dev/usb/usb_msctest.c
index a1bc5fc..1f0598a 100644
--- a/sys/dev/usb/usb_msctest.c
+++ b/sys/dev/usb/usb_msctest.c
@@ -505,13 +505,8 @@ bbb_attach(struct usb_device *udev, uint8_t iface_index)
usb_error_t err;
uint8_t do_unlock;
- /* automatic locking */
- if (usbd_enum_is_locked(udev)) {
- do_unlock = 0;
- } else {
- do_unlock = 1;
- usbd_enum_lock(udev);
- }
+ /* Prevent re-enumeration */
+ do_unlock = usbd_enum_lock(udev);
/*
* Make sure any driver which is hooked up to this interface,
diff --git a/sys/dev/usb/usb_transfer.c b/sys/dev/usb/usb_transfer.c
index edcc596..f2acf70 100644
--- a/sys/dev/usb/usb_transfer.c
+++ b/sys/dev/usb/usb_transfer.c
@@ -22,7 +22,7 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- */
+ */
#ifdef USB_GLOBAL_INCLUDE_FILE
#include USB_GLOBAL_INCLUDE_FILE
@@ -855,20 +855,17 @@ usbd_transfer_setup(struct usb_device *udev,
const struct usb_config *setup_start, uint16_t n_setup,
void *priv_sc, struct mtx *xfer_mtx)
{
- struct usb_xfer dummy;
- struct usb_setup_params parm;
const struct usb_config *setup_end = setup_start + n_setup;
const struct usb_config *setup;
+ struct usb_setup_params *parm;
struct usb_endpoint *ep;
struct usb_xfer_root *info;
struct usb_xfer *xfer;
void *buf = NULL;
+ usb_error_t error = 0;
uint16_t n;
uint16_t refcount;
-
- parm.err = 0;
- refcount = 0;
- info = NULL;
+ uint8_t do_unlock;
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
"usbd_transfer_setup can sleep!");
@@ -887,31 +884,40 @@ usbd_transfer_setup(struct usb_device *udev,
DPRINTFN(6, "using global lock\n");
xfer_mtx = &Giant;
}
- /* sanity checks */
+
+ /* more sanity checks */
+
for (setup = setup_start, n = 0;
setup != setup_end; setup++, n++) {
if (setup->bufsize == (usb_frlength_t)-1) {
- parm.err = USB_ERR_BAD_BUFSIZE;
+ error = USB_ERR_BAD_BUFSIZE;
DPRINTF("invalid bufsize\n");
}
if (setup->callback == NULL) {
- parm.err = USB_ERR_NO_CALLBACK;
+ error = USB_ERR_NO_CALLBACK;
DPRINTF("no callback\n");
}
ppxfer[n] = NULL;
}
- if (parm.err) {
- goto done;
- }
- memset(&parm, 0, sizeof(parm));
+ if (error)
+ return (error);
- parm.udev = udev;
- parm.speed = usbd_get_speed(udev);
- parm.hc_max_packet_count = 1;
+ /* Protect scratch area */
+ do_unlock = usbd_enum_lock(udev);
- if (parm.speed >= USB_SPEED_MAX) {
- parm.err = USB_ERR_INVAL;
+ refcount = 0;
+ info = NULL;
+
+ parm = &udev->scratch.xfer_setup[0].parm;
+ memset(parm, 0, sizeof(*parm));
+
+ parm->udev = udev;
+ parm->speed = usbd_get_speed(udev);
+ parm->hc_max_packet_count = 1;
+
+ if (parm->speed >= USB_SPEED_MAX) {
+ parm->err = USB_ERR_INVAL;
goto done;
}
/* setup all transfers */
@@ -926,22 +932,22 @@ usbd_transfer_setup(struct usb_device *udev,
info = USB_ADD_BYTES(buf, 0);
info->memory_base = buf;
- info->memory_size = parm.size[0];
+ info->memory_size = parm->size[0];
#if USB_HAVE_BUSDMA
- info->dma_page_cache_start = USB_ADD_BYTES(buf, parm.size[4]);
- info->dma_page_cache_end = USB_ADD_BYTES(buf, parm.size[5]);
+ info->dma_page_cache_start = USB_ADD_BYTES(buf, parm->size[4]);
+ info->dma_page_cache_end = USB_ADD_BYTES(buf, parm->size[5]);
#endif
- info->xfer_page_cache_start = USB_ADD_BYTES(buf, parm.size[5]);
- info->xfer_page_cache_end = USB_ADD_BYTES(buf, parm.size[2]);
+ info->xfer_page_cache_start = USB_ADD_BYTES(buf, parm->size[5]);
+ info->xfer_page_cache_end = USB_ADD_BYTES(buf, parm->size[2]);
cv_init(&info->cv_drain, "WDRAIN");
info->xfer_mtx = xfer_mtx;
#if USB_HAVE_BUSDMA
usb_dma_tag_setup(&info->dma_parent_tag,
- parm.dma_tag_p, udev->bus->dma_parent_tag[0].tag,
- xfer_mtx, &usb_bdma_done_event, 32, parm.dma_tag_max);
+ parm->dma_tag_p, udev->bus->dma_parent_tag[0].tag,
+ xfer_mtx, &usb_bdma_done_event, 32, parm->dma_tag_max);
#endif
info->bus = udev->bus;
@@ -976,9 +982,9 @@ usbd_transfer_setup(struct usb_device *udev,
}
/* reset sizes */
- parm.size[0] = 0;
- parm.buf = buf;
- parm.size[0] += sizeof(info[0]);
+ parm->size[0] = 0;
+ parm->buf = buf;
+ parm->size[0] += sizeof(info[0]);
for (setup = setup_start, n = 0;
setup != setup_end; setup++, n++) {
@@ -1010,22 +1016,22 @@ usbd_transfer_setup(struct usb_device *udev,
if ((setup->usb_mode != USB_MODE_DUAL) &&
(setup->usb_mode != udev->flags.usb_mode))
continue;
- parm.err = USB_ERR_NO_PIPE;
+ parm->err = USB_ERR_NO_PIPE;
goto done;
}
/* align data properly */
- parm.size[0] += ((-parm.size[0]) & (USB_HOST_ALIGN - 1));
+ parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
/* store current setup pointer */
- parm.curr_setup = setup;
+ parm->curr_setup = setup;
if (buf) {
/*
* Common initialization of the
* "usb_xfer" structure.
*/
- xfer = USB_ADD_BYTES(buf, parm.size[0]);
+ xfer = USB_ADD_BYTES(buf, parm->size[0]);
xfer->address = udev->address;
xfer->priv_sc = priv_sc;
xfer->xroot = info;
@@ -1040,8 +1046,8 @@ usbd_transfer_setup(struct usb_device *udev,
* before we have allocated any
* memory:
*/
- xfer = &dummy;
- memset(&dummy, 0, sizeof(dummy));
+ xfer = &udev->scratch.xfer_setup[0].dummy;
+ memset(xfer, 0, sizeof(*xfer));
refcount++;
}
@@ -1051,18 +1057,18 @@ usbd_transfer_setup(struct usb_device *udev,
/* set transfer stream ID */
xfer->stream_id = setup->stream_id;
- parm.size[0] += sizeof(xfer[0]);
- parm.methods = xfer->endpoint->methods;
- parm.curr_xfer = xfer;
+ parm->size[0] += sizeof(xfer[0]);
+ parm->methods = xfer->endpoint->methods;
+ parm->curr_xfer = xfer;
/*
* Call the Host or Device controller transfer
* setup routine:
*/
- (udev->bus->methods->xfer_setup) (&parm);
+ (udev->bus->methods->xfer_setup) (parm);
/* check for error */
- if (parm.err)
+ if (parm->err)
goto done;
if (buf) {
@@ -1077,7 +1083,7 @@ usbd_transfer_setup(struct usb_device *udev,
*/
USB_BUS_LOCK(info->bus);
if (xfer->endpoint->refcount_alloc >= USB_EP_REF_MAX)
- parm.err = USB_ERR_INVAL;
+ parm->err = USB_ERR_INVAL;
xfer->endpoint->refcount_alloc++;
@@ -1100,22 +1106,22 @@ usbd_transfer_setup(struct usb_device *udev,
}
/* check for error */
- if (parm.err)
+ if (parm->err)
goto done;
}
- if (buf || parm.err) {
+ if (buf != NULL || parm->err != 0)
goto done;
- }
- if (refcount == 0) {
- /* no transfers - nothing to do ! */
+
+ /* if no transfers, nothing to do */
+ if (refcount == 0)
goto done;
- }
+
/* align data properly */
- parm.size[0] += ((-parm.size[0]) & (USB_HOST_ALIGN - 1));
+ parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
/* store offset temporarily */
- parm.size[1] = parm.size[0];
+ parm->size[1] = parm->size[0];
/*
* The number of DMA tags required depends on
@@ -1126,72 +1132,72 @@ usbd_transfer_setup(struct usb_device *udev,
* 2) for allocating memory
* 3) for fixing memory [UHCI]
*/
- parm.dma_tag_max += 3 * MIN(n_setup, USB_EP_MAX);
+ parm->dma_tag_max += 3 * MIN(n_setup, USB_EP_MAX);
/*
* DMA tags for QH, TD, Data and more.
*/
- parm.dma_tag_max += 8;
+ parm->dma_tag_max += 8;
- parm.dma_tag_p += parm.dma_tag_max;
+ parm->dma_tag_p += parm->dma_tag_max;
- parm.size[0] += ((uint8_t *)parm.dma_tag_p) -
+ parm->size[0] += ((uint8_t *)parm->dma_tag_p) -
((uint8_t *)0);
/* align data properly */
- parm.size[0] += ((-parm.size[0]) & (USB_HOST_ALIGN - 1));
+ parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
/* store offset temporarily */
- parm.size[3] = parm.size[0];
+ parm->size[3] = parm->size[0];
- parm.size[0] += ((uint8_t *)parm.dma_page_ptr) -
+ parm->size[0] += ((uint8_t *)parm->dma_page_ptr) -
((uint8_t *)0);
/* align data properly */
- parm.size[0] += ((-parm.size[0]) & (USB_HOST_ALIGN - 1));
+ parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
/* store offset temporarily */
- parm.size[4] = parm.size[0];
+ parm->size[4] = parm->size[0];
- parm.size[0] += ((uint8_t *)parm.dma_page_cache_ptr) -
+ parm->size[0] += ((uint8_t *)parm->dma_page_cache_ptr) -
((uint8_t *)0);
/* store end offset temporarily */
- parm.size[5] = parm.size[0];
+ parm->size[5] = parm->size[0];
- parm.size[0] += ((uint8_t *)parm.xfer_page_cache_ptr) -
+ parm->size[0] += ((uint8_t *)parm->xfer_page_cache_ptr) -
((uint8_t *)0);
/* store end offset temporarily */
- parm.size[2] = parm.size[0];
+ parm->size[2] = parm->size[0];
/* align data properly */
- parm.size[0] += ((-parm.size[0]) & (USB_HOST_ALIGN - 1));
+ parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
- parm.size[6] = parm.size[0];
+ parm->size[6] = parm->size[0];
- parm.size[0] += ((uint8_t *)parm.xfer_length_ptr) -
+ parm->size[0] += ((uint8_t *)parm->xfer_length_ptr) -
((uint8_t *)0);
/* align data properly */
- parm.size[0] += ((-parm.size[0]) & (USB_HOST_ALIGN - 1));
+ parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
/* allocate zeroed memory */
- buf = malloc(parm.size[0], M_USB, M_WAITOK | M_ZERO);
+ buf = malloc(parm->size[0], M_USB, M_WAITOK | M_ZERO);
if (buf == NULL) {
- parm.err = USB_ERR_NOMEM;
+ parm->err = USB_ERR_NOMEM;
DPRINTFN(0, "cannot allocate memory block for "
"configuration (%d bytes)\n",
- parm.size[0]);
+ parm->size[0]);
goto done;
}
- parm.dma_tag_p = USB_ADD_BYTES(buf, parm.size[1]);
- parm.dma_page_ptr = USB_ADD_BYTES(buf, parm.size[3]);
- parm.dma_page_cache_ptr = USB_ADD_BYTES(buf, parm.size[4]);
- parm.xfer_page_cache_ptr = USB_ADD_BYTES(buf, parm.size[5]);
- parm.xfer_length_ptr = USB_ADD_BYTES(buf, parm.size[6]);
+ parm->dma_tag_p = USB_ADD_BYTES(buf, parm->size[1]);
+ parm->dma_page_ptr = USB_ADD_BYTES(buf, parm->size[3]);
+ parm->dma_page_cache_ptr = USB_ADD_BYTES(buf, parm->size[4]);
+ parm->xfer_page_cache_ptr = USB_ADD_BYTES(buf, parm->size[5]);
+ parm->xfer_length_ptr = USB_ADD_BYTES(buf, parm->size[6]);
}
done:
@@ -1207,10 +1213,17 @@ done:
usbd_transfer_unsetup_sub(info, 0);
}
}
- if (parm.err) {
+
+ /* check if any errors happened */
+ if (parm->err)
usbd_transfer_unsetup(ppxfer, n_setup);
- }
- return (parm.err);
+
+ error = parm->err;
+
+ if (do_unlock)
+ usbd_enum_unlock(udev);
+
+ return (error);
}
/*------------------------------------------------------------------------*
diff --git a/sys/dev/usb/usb_util.c b/sys/dev/usb/usb_util.c
index f9fec76..ffd005b 100644
--- a/sys/dev/usb/usb_util.c
+++ b/sys/dev/usb/usb_util.c
@@ -75,6 +75,7 @@ device_set_usb_desc(device_t dev)
struct usb_interface *iface;
char *temp_p;
usb_error_t err;
+ uint8_t do_unlock;
if (dev == NULL) {
/* should not happen */
@@ -96,19 +97,26 @@ device_set_usb_desc(device_t dev)
err = 0;
}
- temp_p = (char *)udev->bus->scratch[0].data;
+ /* Protect scratch area */
+ do_unlock = usbd_enum_lock(udev);
- if (!err) {
+ temp_p = (char *)udev->scratch.data;
+
+ if (err == 0) {
/* try to get the interface string ! */
- err = usbd_req_get_string_any
- (udev, NULL, temp_p,
- sizeof(udev->bus->scratch), iface->idesc->iInterface);
+ err = usbd_req_get_string_any(udev, NULL, temp_p,
+ sizeof(udev->scratch.data),
+ iface->idesc->iInterface);
}
- if (err) {
+ if (err != 0) {
/* use default description */
usb_devinfo(udev, temp_p,
- sizeof(udev->bus->scratch));
+ sizeof(udev->scratch.data));
}
+
+ if (do_unlock)
+ usbd_enum_unlock(udev);
+
device_set_desc_copy(dev, temp_p);
device_printf(dev, "<%s> on %s\n", temp_p,
device_get_nameunit(udev->bus->bdev));
OpenPOWER on IntegriCloud