diff options
Diffstat (limited to 'drivers/usb/common')
-rw-r--r-- | drivers/usb/common/Makefile | 12 | ||||
-rw-r--r-- | drivers/usb/common/common.c | 119 | ||||
-rw-r--r-- | drivers/usb/common/fsl-dt-fixup.c | 224 | ||||
-rw-r--r-- | drivers/usb/common/fsl-errata.c | 255 | ||||
-rw-r--r-- | drivers/usb/common/usb_urb.c | 160 |
5 files changed, 770 insertions, 0 deletions
diff --git a/drivers/usb/common/Makefile b/drivers/usb/common/Makefile new file mode 100644 index 00000000000..11cc4657a0f --- /dev/null +++ b/drivers/usb/common/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2016 Freescale Semiconductor, Inc. +# + +obj-$(CONFIG_$(XPL_)DM_USB) += common.o +obj-$(CONFIG_USB_ISP1760) += usb_urb.o +obj-$(CONFIG_USB_MUSB_HOST) += usb_urb.o +obj-$(CONFIG_USB_MUSB_GADGET) += usb_urb.o +obj-$(CONFIG_USB_R8A66597_HCD) += usb_urb.o +obj-$(CONFIG_USB_EHCI_FSL) += fsl-dt-fixup.o fsl-errata.o +obj-$(CONFIG_USB_XHCI_FSL) += fsl-dt-fixup.o fsl-errata.o diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c new file mode 100644 index 00000000000..13e9a61072a --- /dev/null +++ b/drivers/usb/common/common.c @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Provides code common for host and device side USB. + * + * (C) Copyright 2016 + * Texas Instruments Incorporated, <www.ti.com> + */ + +#include <dm.h> +#include <asm/global_data.h> +#include <linux/printk.h> +#include <linux/usb/otg.h> +#include <linux/usb/ch9.h> +#include <linux/usb/phy.h> + +DECLARE_GLOBAL_DATA_PTR; + +static const char *const usb_dr_modes[] = { + [USB_DR_MODE_UNKNOWN] = "", + [USB_DR_MODE_HOST] = "host", + [USB_DR_MODE_PERIPHERAL] = "peripheral", + [USB_DR_MODE_OTG] = "otg", +}; + +enum usb_dr_mode usb_get_dr_mode(ofnode node) +{ + const char *dr_mode; + int i; + + dr_mode = ofnode_read_string(node, "dr_mode"); + if (!dr_mode) { + pr_debug("usb dr_mode not found\n"); + return USB_DR_MODE_UNKNOWN; + } + + for (i = 0; i < ARRAY_SIZE(usb_dr_modes); i++) + if (!strcmp(dr_mode, usb_dr_modes[i])) + return i; + + return USB_DR_MODE_UNKNOWN; +} + +enum usb_dr_mode usb_get_role_switch_default_mode(ofnode node) +{ + const char *dr_mode; + int i; + + dr_mode = ofnode_read_string(node, "role-switch-default-mode"); + if (!dr_mode) + return USB_DR_MODE_UNKNOWN; + + for (i = 0; i < ARRAY_SIZE(usb_dr_modes); i++) + if (!strcmp(dr_mode, usb_dr_modes[i])) + return i; + + return USB_DR_MODE_UNKNOWN; +} + +static const char *const speed_names[] = { + [USB_SPEED_UNKNOWN] = "UNKNOWN", + [USB_SPEED_LOW] = "low-speed", + [USB_SPEED_FULL] = "full-speed", + [USB_SPEED_HIGH] = "high-speed", + [USB_SPEED_WIRELESS] = "wireless", + [USB_SPEED_SUPER] = "super-speed", + [USB_SPEED_SUPER_PLUS] = "super-speed-plus", +}; + +const char *usb_speed_string(enum usb_device_speed speed) +{ + if (speed < 0 || speed >= ARRAY_SIZE(speed_names)) + speed = USB_SPEED_UNKNOWN; + return speed_names[speed]; +} + +enum usb_device_speed usb_get_maximum_speed(ofnode node) +{ + const char *max_speed; + int i; + + max_speed = ofnode_read_string(node, "maximum-speed"); + if (!max_speed) { + pr_debug("usb maximum-speed not found\n"); + return USB_SPEED_UNKNOWN; + } + + for (i = 0; i < ARRAY_SIZE(speed_names); i++) + if (!strcmp(max_speed, speed_names[i])) + return i; + + return USB_SPEED_UNKNOWN; +} + +#if CONFIG_IS_ENABLED(DM_USB) +static const char *const usbphy_modes[] = { + [USBPHY_INTERFACE_MODE_UNKNOWN] = "", + [USBPHY_INTERFACE_MODE_UTMI] = "utmi", + [USBPHY_INTERFACE_MODE_UTMIW] = "utmi_wide", + [USBPHY_INTERFACE_MODE_ULPI] = "ulpi", + [USBPHY_INTERFACE_MODE_SERIAL] = "serial", + [USBPHY_INTERFACE_MODE_HSIC] = "hsic", +}; + +enum usb_phy_interface usb_get_phy_mode(ofnode node) +{ + const char *phy_type; + int i; + + phy_type = ofnode_get_property(node, "phy_type", NULL); + if (!phy_type) + return USBPHY_INTERFACE_MODE_UNKNOWN; + + for (i = 0; i < ARRAY_SIZE(usbphy_modes); i++) + if (!strcmp(phy_type, usbphy_modes[i])) + return i; + + return USBPHY_INTERFACE_MODE_UNKNOWN; +} +#endif diff --git a/drivers/usb/common/fsl-dt-fixup.c b/drivers/usb/common/fsl-dt-fixup.c new file mode 100644 index 00000000000..6a68bd76c27 --- /dev/null +++ b/drivers/usb/common/fsl-dt-fixup.c @@ -0,0 +1,224 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2009, 2011 Freescale Semiconductor, Inc. + * + * (C) Copyright 2008, Excito Elektronik i Sk=E5ne AB + * + * Author: Tor Krill tor@excito.com + */ + +#include <log.h> +#include <usb.h> +#include <asm/io.h> +#include <hwconfig.h> +#include <fsl_errata.h> +#include <fsl_usb.h> +#include <fdt_support.h> + +/* USB Controllers */ +#define FSL_USB2_MPH "fsl-usb2-mph" +#define FSL_USB2_DR "fsl-usb2-dr" +#define CHIPIDEA_USB2 "chipidea,usb2" +#define SNPS_DWC3 "snps,dwc3" + +static const char * const compat_usb_fsl[] = { + FSL_USB2_MPH, + FSL_USB2_DR, + SNPS_DWC3, + NULL +}; + +static int fdt_usb_get_node_type(void *blob, int start_offset, + int *node_offset, const char **node_type) +{ + int i; + int ret = -ENOENT; + + for (i = 0; compat_usb_fsl[i]; i++) { + *node_offset = fdt_node_offset_by_compatible + (blob, start_offset, + compat_usb_fsl[i]); + if (*node_offset >= 0) { + *node_type = compat_usb_fsl[i]; + ret = 0; + break; + } + } + + return ret; +} + +static int fdt_fixup_usb_mode_phy_type(void *blob, const char *mode, + const char *phy_type, int start_offset) +{ + const char *prop_mode = "dr_mode"; + const char *prop_type = "phy_type"; + const char *node_type = NULL; + int node_offset; + int err; + + err = fdt_usb_get_node_type(blob, start_offset, + &node_offset, &node_type); + if (err < 0) + return err; + + if (mode) { + err = fdt_setprop(blob, node_offset, prop_mode, mode, + strlen(mode) + 1); + if (err < 0) + printf("WARNING: could not set %s for %s: %s.\n", + prop_mode, node_type, fdt_strerror(err)); + } + + if (phy_type) { + err = fdt_setprop(blob, node_offset, prop_type, phy_type, + strlen(phy_type) + 1); + if (err < 0) + printf("WARNING: could not set %s for %s: %s.\n", + prop_type, node_type, fdt_strerror(err)); + } + + return node_offset; +} + +static int fsl_fdt_fixup_usb_erratum(void *blob, const char *prop_erratum, + const char *controller_type, + int start_offset) +{ + int node_offset, err; + const char *node_type = NULL; + const char *node_name = NULL; + + err = fdt_usb_get_node_type(blob, start_offset, + &node_offset, &node_type); + if (err < 0) + return err; + + if (!strcmp(node_type, FSL_USB2_MPH) || !strcmp(node_type, FSL_USB2_DR)) + node_name = CHIPIDEA_USB2; + else + node_name = node_type; + if (strcmp(node_name, controller_type)) + return err; + + err = fdt_setprop(blob, node_offset, prop_erratum, NULL, 0); + if (err < 0) { + printf("ERROR: could not set %s for %s: %s.\n", + prop_erratum, node_type, fdt_strerror(err)); + } + + return node_offset; +} + +static int fsl_fdt_fixup_erratum(int *usb_erratum_off, void *blob, + const char *controller_type, char *str, + bool (*has_erratum)(void)) +{ + char buf[32] = {0}; + + snprintf(buf, sizeof(buf), "fsl,usb-erratum-%s", str); + if (!has_erratum()) + return -EINVAL; + *usb_erratum_off = fsl_fdt_fixup_usb_erratum(blob, buf, controller_type, + *usb_erratum_off); + if (*usb_erratum_off < 0) + return -ENOSPC; + debug("Adding USB erratum %s\n", str); + return 0; +} + +void fsl_fdt_fixup_dr_usb(void *blob, struct bd_info *bd) +{ + static const char * const modes[] = { "host", "peripheral", "otg" }; + static const char * const phys[] = { "ulpi", "utmi", "utmi_dual" }; + int usb_erratum_a006261_off = -1; + int usb_erratum_a007075_off = -1; + int usb_erratum_a007792_off = -1; + int usb_erratum_a005697_off = -1; + int usb_erratum_a008751_off = -1; + int usb_mode_off = -1; + int usb_phy_off = -1; + char str[5]; + int i, j; + int ret; + + for (i = 1; i <= CONFIG_USB_MAX_CONTROLLER_COUNT; i++) { + const char *dr_mode_type = NULL; + const char *dr_phy_type = NULL; + int mode_idx = -1, phy_idx = -1; + + snprintf(str, 5, "%s%d", "usb", i); + if (hwconfig(str)) { + for (j = 0; j < ARRAY_SIZE(modes); j++) { + if (hwconfig_subarg_cmp(str, "dr_mode", + modes[j])) { + mode_idx = j; + break; + } + } + + for (j = 0; j < ARRAY_SIZE(phys); j++) { + if (hwconfig_subarg_cmp(str, "phy_type", + phys[j])) { + phy_idx = j; + break; + } + } + + if (mode_idx < 0 && phy_idx < 0) { + printf("WARNING: invalid phy or mode\n"); + return; + } + + if (mode_idx > -1) + dr_mode_type = modes[mode_idx]; + + if (phy_idx > -1) + dr_phy_type = phys[phy_idx]; + } + + if (has_dual_phy()) + dr_phy_type = phys[2]; + + usb_mode_off = fdt_fixup_usb_mode_phy_type(blob, + dr_mode_type, NULL, + usb_mode_off); + + if (usb_mode_off < 0) + return; + + usb_phy_off = fdt_fixup_usb_mode_phy_type(blob, + NULL, dr_phy_type, + usb_phy_off); + + if (usb_phy_off < 0) + return; + + ret = fsl_fdt_fixup_erratum(&usb_erratum_a006261_off, blob, + CHIPIDEA_USB2, "a006261", + has_erratum_a006261); + if (ret == -ENOSPC) + return; + ret = fsl_fdt_fixup_erratum(&usb_erratum_a007075_off, blob, + CHIPIDEA_USB2, "a007075", + has_erratum_a007075); + if (ret == -ENOSPC) + return; + ret = fsl_fdt_fixup_erratum(&usb_erratum_a007792_off, blob, + CHIPIDEA_USB2, "a007792", + has_erratum_a007792); + if (ret == -ENOSPC) + return; + ret = fsl_fdt_fixup_erratum(&usb_erratum_a005697_off, blob, + CHIPIDEA_USB2, "a005697", + has_erratum_a005697); + if (ret == -ENOSPC) + return; + ret = fsl_fdt_fixup_erratum(&usb_erratum_a008751_off, blob, + SNPS_DWC3, "a008751", + has_erratum_a008751); + if (ret == -ENOSPC) + return; + + } +} diff --git a/drivers/usb/common/fsl-errata.c b/drivers/usb/common/fsl-errata.c new file mode 100644 index 00000000000..89ae73f2ba4 --- /dev/null +++ b/drivers/usb/common/fsl-errata.c @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Freescale USB Controller + * + * Copyright 2013 Freescale Semiconductor, Inc. + */ + +#include <hwconfig.h> +#include <fsl_errata.h> +#include<fsl_usb.h> +#if defined(CONFIG_FSL_LSCH2) || defined(CONFIG_FSL_LSCH3) || \ + defined(CONFIG_ARM) +#include <asm/arch/clock.h> +#endif + +/* USB Erratum Checking code */ +#if defined(CONFIG_PPC) || defined(CONFIG_ARM) +bool has_dual_phy(void) +{ + u32 svr = get_svr(); + u32 soc = SVR_SOC_VER(svr); + + switch (soc) { +#ifdef CONFIG_PPC + case SVR_T1023: + case SVR_T1024: + case SVR_T1013: + case SVR_T1014: + return IS_SVR_REV(svr, 1, 0); + case SVR_T1040: + case SVR_T1042: + case SVR_T1020: + case SVR_T1022: + case SVR_T2080: + case SVR_T2081: + return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 1, 1); + case SVR_T4240: + case SVR_T4160: + case SVR_T4080: + return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 2, 0); +#endif + } + + return false; +} + +bool has_erratum_a005275(void) +{ + u32 svr = get_svr(); + u32 soc = SVR_SOC_VER(svr); + + if (hwconfig("no_erratum_a005275")) + return false; + + switch (soc) { +#ifdef CONFIG_PPC + case SVR_P3041: + case SVR_P2041: + case SVR_P2040: + return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 1, 1); + case SVR_P5010: + case SVR_P5020: + case SVR_P5021: + return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 2, 0); + case SVR_P5040: + case SVR_P1010: + return IS_SVR_REV(svr, 1, 0); +#endif + } + + return false; +} + +bool has_erratum_a006261(void) +{ + u32 svr = get_svr(); + u32 soc = SVR_SOC_VER(svr); + + switch (soc) { +#ifdef CONFIG_PPC + case SVR_P1010: + return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 2, 0); + case SVR_P2041: + case SVR_P2040: + return IS_SVR_REV(svr, 1, 0) || + IS_SVR_REV(svr, 1, 1) || + IS_SVR_REV(svr, 2, 0) || IS_SVR_REV(svr, 2, 1); + case SVR_P3041: + return IS_SVR_REV(svr, 1, 0) || + IS_SVR_REV(svr, 1, 1) || + IS_SVR_REV(svr, 2, 0) || IS_SVR_REV(svr, 2, 1); + case SVR_P5010: + case SVR_P5020: + case SVR_P5021: + return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 2, 0); + case SVR_T4240: + return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 2, 0); + case SVR_P5040: + return IS_SVR_REV(svr, 1, 0) || + IS_SVR_REV(svr, 2, 0) || IS_SVR_REV(svr, 2, 1); +#endif + } + + return false; +} + +bool has_erratum_a007075(void) +{ + u32 svr = get_svr(); + u32 soc = SVR_SOC_VER(svr); + + switch (soc) { +#ifdef CONFIG_PPC + case SVR_B4860: + case SVR_B4420: + return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 2, 0); + case SVR_P1010: + return IS_SVR_REV(svr, 1, 0); + case SVR_P4080: + return IS_SVR_REV(svr, 2, 0) || IS_SVR_REV(svr, 3, 0); +#endif + } + return false; +} + +bool has_erratum_a007798(void) +{ +#ifdef CONFIG_PPC + return SVR_SOC_VER(get_svr()) == SVR_T4240 && + IS_SVR_REV(get_svr(), 2, 0); +#endif + return false; +} + +bool has_erratum_a007792(void) +{ + u32 svr = get_svr(); + u32 soc = SVR_SOC_VER(svr); + + switch (soc) { +#ifdef CONFIG_PPC + case SVR_T4240: + case SVR_T4160: + case SVR_T4080: + return IS_SVR_REV(svr, 2, 0); + case SVR_T1024: + case SVR_T1023: + return IS_SVR_REV(svr, 1, 0); + case SVR_T1040: + case SVR_T1042: + case SVR_T1020: + case SVR_T1022: + case SVR_T2080: + case SVR_T2081: + return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 1, 1); +#endif + } + return false; +} + +bool has_erratum_a005697(void) +{ + u32 svr = get_svr(); + u32 soc = SVR_SOC_VER(svr); + + switch (soc) { +#ifdef CONFIG_PPC + case SVR_9131: + case SVR_9132: + return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 1, 1); +#endif +#ifdef ONFIG_ARM64 + case SVR_LS1012A: + return IS_SVR_REV(svr, 1, 0); +#endif + } + return false; +} + +bool has_erratum_a004477(void) +{ + u32 svr = get_svr(); + u32 soc = SVR_SOC_VER(svr); + + switch (soc) { +#ifdef CONFIG_PPC + case SVR_P1010: + return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 2, 0); + case SVR_P1022: + case SVR_9131: + case SVR_9132: + return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 1, 1); + case SVR_P2020: + return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 2, 0) || + IS_SVR_REV(svr, 2, 1); + case SVR_B4860: + case SVR_B4420: + return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 2, 0); + case SVR_P4080: + return IS_SVR_REV(svr, 2, 0) || IS_SVR_REV(svr, 3, 0); +#endif + } + + return false; +} + +bool has_erratum_a008751(void) +{ + u32 svr = get_svr(); + u32 soc = SVR_SOC_VER(svr); + + switch (soc) { +#ifdef CONFIG_ARM64 + case SVR_LS2080A: + case SVR_LS2085A: + return IS_SVR_REV(svr, 1, 0); +#endif + } + return false; +} + +bool has_erratum_a010151(void) +{ + u32 svr = get_svr(); + u32 soc = SVR_SOC_VER(svr); + +#ifdef CONFIG_ARM64 + if (IS_SVR_DEV(svr, SVR_DEV(SVR_LS1043A))) + return IS_SVR_REV(svr, 1, 0) || IS_SVR_REV(svr, 1, 1); +#endif + + switch (soc) { +#ifdef CONFIG_ARM64 + case SVR_LS2080A: + case SVR_LS2085A: + /* fallthrough */ + case SVR_LS2088A: + /* fallthrough */ + case SVR_LS2081A: + case SVR_LS1046A: + case SVR_LS1012A: + return IS_SVR_REV(svr, 1, 0); +#endif +#ifdef CONFIG_ARCH_LS1021A + case SOC_VER_LS1020: + case SOC_VER_LS1021: + case SOC_VER_LS1022: + case SOC_VER_SLS1020: + return IS_SVR_REV(svr, 2, 0); +#endif + } + return false; +} + +#endif diff --git a/drivers/usb/common/usb_urb.c b/drivers/usb/common/usb_urb.c new file mode 100644 index 00000000000..be3b6b9f32e --- /dev/null +++ b/drivers/usb/common/usb_urb.c @@ -0,0 +1,160 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Common code for usb urb handling, based on the musb-new code + * + * Copyright 2021 Linaro, Rui Miguel Silva <rui.silva@linaro.org> + * + */ + +#include <dm/device.h> +#include <dm/device_compat.h> +#include <linux/usb/usb_urb_compat.h> + +#include <time.h> +#include <usb.h> + +#if CONFIG_IS_ENABLED(DM_USB) +struct usb_device *usb_dev_get_parent(struct usb_device *udev) +{ + struct udevice *parent = udev->dev->parent; + + /* + * When called from usb-uclass.c: usb_scan_device() udev->dev points + * to the parent udevice, not the actual udevice belonging to the + * udev as the device is not instantiated yet. + * + * If dev is an usb-bus, then we are called from usb_scan_device() for + * an usb-device plugged directly into the root port, return NULL. + */ + if (device_get_uclass_id(udev->dev) == UCLASS_USB) + return NULL; + + /* + * If these 2 are not the same we are being called from + * usb_scan_device() and udev itself is the parent. + */ + if (dev_get_parent_priv(udev->dev) != udev) + return udev; + + /* We are being called normally, use the parent pointer */ + if (device_get_uclass_id(parent) == UCLASS_USB_HUB) + return dev_get_parent_priv(parent); + + return NULL; +} +#else +struct usb_device *usb_dev_get_parent(struct usb_device *udev) +{ + return udev->parent; +} +#endif + +static void usb_urb_complete(struct urb *urb) +{ + urb->dev->status &= ~USB_ST_NOT_PROC; + urb->dev->act_len = urb->actual_length; + + if (urb->status == -EINPROGRESS) + urb->status = 0; +} + +void usb_urb_fill(struct urb *urb, struct usb_host_endpoint *hep, + struct usb_device *dev, int endpoint_type, + unsigned long pipe, void *buffer, int len, + struct devrequest *setup, int interval) +{ + int epnum = usb_pipeendpoint(pipe); + int is_in = usb_pipein(pipe); + u16 maxpacketsize = is_in ? dev->epmaxpacketin[epnum] : + dev->epmaxpacketout[epnum]; + + memset(urb, 0, sizeof(struct urb)); + memset(hep, 0, sizeof(struct usb_host_endpoint)); + INIT_LIST_HEAD(&hep->urb_list); + INIT_LIST_HEAD(&urb->urb_list); + urb->ep = hep; + urb->complete = usb_urb_complete; + urb->status = -EINPROGRESS; + urb->dev = dev; + urb->pipe = pipe; + urb->transfer_buffer = buffer; + urb->transfer_dma = (unsigned long)buffer; + urb->transfer_buffer_length = len; + urb->setup_packet = (unsigned char *)setup; + + urb->ep->desc.wMaxPacketSize = __cpu_to_le16(maxpacketsize); + urb->ep->desc.bmAttributes = endpoint_type; + urb->ep->desc.bEndpointAddress = ((is_in ? USB_DIR_IN : USB_DIR_OUT) | + epnum); + urb->ep->desc.bInterval = interval; +} + +int usb_urb_submit(struct usb_hcd *hcd, struct urb *urb) +{ + const struct usb_urb_ops *ops = hcd->urb_ops; + unsigned long timeout; + int ret; + + if (!ops) + return -EINVAL; + + ret = ops->urb_enqueue(hcd, urb, 0); + if (ret < 0) { + printf("Failed to enqueue URB to controller\n"); + return ret; + } + + timeout = get_timer(0) + USB_TIMEOUT_MS(urb->pipe); + do { + if (ctrlc()) + return -EIO; + ops->isr(0, hcd); + } while (urb->status == -EINPROGRESS && get_timer(0) < timeout); + + if (urb->status == -EINPROGRESS) + ops->urb_dequeue(hcd, urb, -ETIME); + + return urb->status; +} + +int usb_urb_submit_control(struct usb_hcd *hcd, struct urb *urb, + struct usb_host_endpoint *hep, + struct usb_device *dev, unsigned long pipe, + void *buffer, int len, struct devrequest *setup, + int interval, enum usb_device_speed speed) +{ + const struct usb_urb_ops *ops = hcd->urb_ops; + + usb_urb_fill(urb, hep, dev, USB_ENDPOINT_XFER_CONTROL, pipe, buffer, + len, setup, 0); + + /* Fix speed for non hub-attached devices */ + if (!usb_dev_get_parent(dev)) { + dev->speed = speed; + if (ops->hub_control) + return ops->hub_control(hcd, dev, pipe, buffer, len, + setup); + } + + return usb_urb_submit(hcd, urb); +} + +int usb_urb_submit_bulk(struct usb_hcd *hcd, struct urb *urb, + struct usb_host_endpoint *hep, struct usb_device *dev, + unsigned long pipe, void *buffer, int len) +{ + usb_urb_fill(urb, hep, dev, USB_ENDPOINT_XFER_BULK, pipe, buffer, len, + NULL, 0); + + return usb_urb_submit(hcd, urb); +} + +int usb_urb_submit_irq(struct usb_hcd *hcd, struct urb *urb, + struct usb_host_endpoint *hep, struct usb_device *dev, + unsigned long pipe, void *buffer, int len, int interval) +{ + usb_urb_fill(urb, hep, dev, USB_ENDPOINT_XFER_INT, pipe, buffer, len, + NULL, interval); + + return usb_urb_submit(hcd, urb); +} |