summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/user/usb.rst4
-rw-r--r--commands/Kconfig1
-rw-r--r--commands/usbgadget.c72
-rw-r--r--common/Kconfig7
-rw-r--r--common/Makefile1
-rw-r--r--common/usbgadget.c (renamed from drivers/usb/gadget/autostart.c)85
-rw-r--r--drivers/usb/core/usb.c5
-rw-r--r--drivers/usb/gadget/Kconfig8
-rw-r--r--drivers/usb/gadget/Makefile1
-rw-r--r--drivers/usb/gadget/at91_udc.c2
-rw-r--r--drivers/usb/gadget/fsl_udc.c72
-rw-r--r--drivers/usb/gadget/pxa27x_udc.c5
-rw-r--r--drivers/usb/host/ehci-atmel.c24
-rw-r--r--drivers/usb/host/ehci-hcd.c80
-rw-r--r--drivers/usb/imx/chipidea-imx.c39
-rw-r--r--include/usb/ehci.h20
-rw-r--r--include/usb/fsl_usb2.h6
-rw-r--r--include/usb/gadget-multi.h4
-rw-r--r--include/usb/usb.h1
19 files changed, 275 insertions, 162 deletions
diff --git a/Documentation/user/usb.rst b/Documentation/user/usb.rst
index 8396f3897c..029e463540 100644
--- a/Documentation/user/usb.rst
+++ b/Documentation/user/usb.rst
@@ -264,5 +264,9 @@ USB Gadget autostart Options
``global.usbgadget.acm``
Boolean flag. If set to 1, CDC ACM function will be created.
See :ref:`command_usbgadget` -a. (Default 0).
+``global.usbgadget.dfu_function``
+ Function description for DFU. See :ref:`command_usbgadget` -D [desc].
``global.usbgadget.fastboot_function``
Function description for fastboot. See :ref:`command_usbgadget` -A [desc].
+``global.usbgadget.fastboot_bbu``
+ Export barebox update handlers. See :ref:`command_usbgadget` -b. (Default 0).
diff --git a/commands/Kconfig b/commands/Kconfig
index 675bd1ca76..1de4b9d604 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -1910,7 +1910,6 @@ config CMD_USB
config CMD_USBGADGET
bool
depends on USB_GADGET
- select FILE_LIST
prompt "usbgadget"
config CMD_WD
diff --git a/commands/usbgadget.c b/commands/usbgadget.c
index a1744cbe13..e8e1e9adac 100644
--- a/commands/usbgadget.c
+++ b/commands/usbgadget.c
@@ -32,30 +32,26 @@
static int do_usbgadget(int argc, char *argv[])
{
- int opt, ret;
- int acm = 1, create_serial = 0, fastboot_set = 0, fastboot_export_bbu = 0;
+ int opt;
+ bool acm = false, dfu = false, fastboot = false, export_bbu = false;
const char *fastboot_opts = NULL, *dfu_opts = NULL;
- struct f_multi_opts *opts;
- while ((opt = getopt(argc, argv, "asdA::D:b")) > 0) {
+ while ((opt = getopt(argc, argv, "asdA::D::b")) > 0) {
switch (opt) {
case 'a':
- acm = 1;
- create_serial = 1;
- break;
case 's':
- acm = 0;
- create_serial = 1;
+ acm = true;
break;
case 'D':
+ dfu = true;
dfu_opts = optarg;
break;
case 'A':
+ fastboot = true;
fastboot_opts = optarg;
- fastboot_set = 1;
break;
case 'b':
- fastboot_export_bbu = 1;
+ export_bbu = true;
break;
case 'd':
usb_multi_unregister();
@@ -65,54 +61,8 @@ static int do_usbgadget(int argc, char *argv[])
}
}
- if (fastboot_set && !fastboot_opts)
- fastboot_opts = getenv("global.usbgadget.fastboot_function");
-
- if (!dfu_opts && !fastboot_opts && !create_serial)
- return COMMAND_ERROR_USAGE;
-
- /*
- * Creating a gadget with both DFU and Fastboot doesn't work.
- * Both client tools seem to assume that the device only has
- * a single configuration
- */
- if (fastboot_opts && dfu_opts) {
- printf("Only one of Fastboot and DFU allowed\n");
- return -EINVAL;
- }
-
- opts = xzalloc(sizeof(*opts));
- opts->release = usb_multi_opts_release;
-
- if (fastboot_opts) {
- opts->fastboot_opts.files = file_list_parse(fastboot_opts);
- if (IS_ERR(opts->fastboot_opts.files))
- goto err_parse;
- opts->fastboot_opts.export_bbu = fastboot_export_bbu;
- }
-
- if (dfu_opts) {
- opts->dfu_opts.files = file_list_parse(dfu_opts);
- if (IS_ERR(opts->dfu_opts.files))
- goto err_parse;
- }
-
- if (create_serial) {
- opts->create_acm = acm;
- }
-
- ret = usb_multi_register(opts);
- if (ret)
- usb_multi_opts_release(opts);
-
- return ret;
-
-err_parse:
- printf("Cannot parse file list \"%s\": %s\n", fastboot_opts, strerrorp(opts->fastboot_opts.files));
-
- free(opts);
-
- return 1;
+ return usbgadget_register(dfu, dfu_opts, fastboot, fastboot_opts, acm,
+ export_bbu);
}
BAREBOX_CMD_HELP_START(usbgadget)
@@ -120,11 +70,11 @@ BAREBOX_CMD_HELP_TEXT("Enable / disable a USB composite gadget on the USB device
BAREBOX_CMD_HELP_TEXT("")
BAREBOX_CMD_HELP_TEXT("Options:")
BAREBOX_CMD_HELP_OPT ("-a\t", "Create CDC ACM function")
-BAREBOX_CMD_HELP_OPT ("-s\t", "Create Generic Serial function")
BAREBOX_CMD_HELP_OPT ("-A <desc>", "Create Android Fastboot function. If 'desc' is not provided, "
"try to use 'global.usbgadget.fastboot_function' variable.")
BAREBOX_CMD_HELP_OPT ("-b\t", "include registered barebox update handlers (fastboot specific)")
-BAREBOX_CMD_HELP_OPT ("-D <desc>", "Create DFU function")
+BAREBOX_CMD_HELP_OPT ("-D <desc>", "Create DFU function. If 'desc' is not provided, "
+ "try to use 'global.usbgadget.dfu_function' variable.")
BAREBOX_CMD_HELP_OPT ("-d\t", "Disable the currently running gadget")
BAREBOX_CMD_HELP_END
diff --git a/common/Kconfig b/common/Kconfig
index eddd99ea3b..2ad92158c1 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -115,6 +115,13 @@ config UBIFORMAT
depends on MTD_UBI
default y
+config USBGADGET_START
+ bool
+ depends on CMD_USBGADGET || USB_GADGET_AUTOSTART
+ select ENVIRONMENT_VARIABLES
+ select FILE_LIST
+ default y
+
config BOOT
bool
diff --git a/common/Makefile b/common/Makefile
index 861365bd55..b617642242 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -64,6 +64,7 @@ obj-$(CONFIG_UBIFORMAT) += ubiformat.o
obj-$(CONFIG_BAREBOX_UPDATE_IMX_NAND_FCB) += imx-bbu-nand-fcb.o
obj-$(CONFIG_BOOT) += boot.o
obj-$(CONFIG_SERIAL_DEV_BUS) += serdev.o
+obj-$(CONFIG_USBGADGET_START) += usbgadget.o
ifdef CONFIG_PASSWORD
diff --git a/drivers/usb/gadget/autostart.c b/common/usbgadget.c
index 272b0ea8fa..a8f104cf1c 100644
--- a/drivers/usb/gadget/autostart.c
+++ b/common/usbgadget.c
@@ -11,7 +11,7 @@
* GNU General Public License for more details.
*
*/
-#define pr_fmt(fmt) "usbgadget autostart: " fmt
+#define pr_fmt(fmt) "usbgadget: " fmt
#include <common.h>
#include <command.h>
@@ -29,39 +29,68 @@
static int autostart;
static int acm;
+static char *dfu_function;
static char *fastboot_function;
static int fastboot_bbu;
-static int usbgadget_autostart(void)
+static struct file_list *parse(const char *files)
+{
+ struct file_list *list = file_list_parse(files);
+ if (IS_ERR(list)) {
+ pr_err("Parsing file list \"%s\" failed: %s\n", files,
+ strerrorp(list));
+ return NULL;
+ }
+ return list;
+}
+
+int usbgadget_register(bool dfu, const char *dfu_opts,
+ bool fastboot, const char *fastboot_opts,
+ bool acm, bool export_bbu)
{
- struct f_multi_opts *opts;
- struct device_d *dev;
int ret;
+ struct device_d *dev;
+ struct f_multi_opts *opts;
- if (!autostart)
- return 0;
+ if (dfu && !dfu_opts && dfu_function && *dfu_function)
+ dfu_opts = dfu_function;
+
+ if (fastboot && !fastboot_opts &&
+ fastboot_function && *fastboot_function)
+ fastboot_opts = fastboot_function;
+
+ if (!dfu_opts && !fastboot_opts && !acm)
+ return COMMAND_ERROR_USAGE;
+
+ /*
+ * Creating a gadget with both DFU and Fastboot doesn't work.
+ * Both client tools seem to assume that the device only has
+ * a single configuration
+ */
+ if (fastboot_opts && dfu_opts) {
+ pr_err("Only one of Fastboot and DFU allowed\n");
+ return -EINVAL;
+ }
opts = xzalloc(sizeof(*opts));
opts->release = usb_multi_opts_release;
- if (fastboot_function) {
- opts->fastboot_opts.files = file_list_parse(fastboot_function);
- if (IS_ERR(opts->fastboot_opts.files)) {
- pr_err("Parsing file list \"%s\" failed: %s\n", fastboot_function,
- strerrorp(opts->fastboot_opts.files));
- opts->fastboot_opts.files = NULL;
- }
-
- opts->fastboot_opts.export_bbu = fastboot_bbu;
+ if (fastboot_opts) {
+ opts->fastboot_opts.files = parse(fastboot_opts);
+ opts->fastboot_opts.export_bbu = export_bbu;
}
- opts->create_acm = acm;
+ if (dfu_opts)
+ opts->dfu_opts.files = parse(dfu_opts);
- if (!opts->fastboot_opts.files && !opts->create_acm) {
+ if (!opts->dfu_opts.files && !opts->fastboot_opts.files && !acm) {
pr_warn("No functions to register\n");
+ free(opts);
return 0;
}
+ opts->create_acm = acm;
+
dev = get_device_by_name("otg");
if (dev)
dev_set_param(dev, "mode", "peripheral");
@@ -72,16 +101,27 @@ static int usbgadget_autostart(void)
return ret;
}
+
+static int usbgadget_autostart(void)
+{
+ if (!IS_ENABLED(CONFIG_USB_GADGET_AUTOSTART) || !autostart)
+ return 0;
+
+ return usbgadget_register(true, NULL, true, NULL, acm, fastboot_bbu);
+}
postenvironment_initcall(usbgadget_autostart);
static int usbgadget_globalvars_init(void)
{
-
- globalvar_add_simple_bool("usbgadget.autostart", &autostart);
- globalvar_add_simple_bool("usbgadget.acm", &acm);
+ if (IS_ENABLED(CONFIG_USB_GADGET_AUTOSTART)) {
+ globalvar_add_simple_bool("usbgadget.autostart", &autostart);
+ globalvar_add_simple_bool("usbgadget.acm", &acm);
+ globalvar_add_simple_bool("usbgadget.fastboot_bbu",
+ &fastboot_bbu);
+ }
+ globalvar_add_simple_string("usbgadget.dfu_function", &dfu_function);
globalvar_add_simple_string("usbgadget.fastboot_function",
&fastboot_function);
- globalvar_add_simple_bool("usbgadget.fastboot_bbu", &fastboot_bbu);
return 0;
}
@@ -93,6 +133,9 @@ BAREBOX_MAGICVAR_NAMED(global_usbgadget_autostart,
BAREBOX_MAGICVAR_NAMED(global_usbgadget_acm,
global.usbgadget.acm,
"usbgadget: Create CDC ACM function");
+BAREBOX_MAGICVAR_NAMED(global_usbgadget_dfu_function,
+ global.usbgadget.dfu_function,
+ "usbgadget: Create DFU function");
BAREBOX_MAGICVAR_NAMED(global_usbgadget_fastboot_function,
global.usbgadget.fastboot_function,
"usbgadget: Create Android Fastboot function");
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 0ee8808a6b..7b008435fd 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -102,6 +102,11 @@ int usb_register_host(struct usb_host *host)
return 0;
}
+void usb_unregister_host(struct usb_host *host)
+{
+ list_del(&host->list);
+}
+
/**
* set configuration number to configuration
*/
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index b0408e3bbe..ca1bfc1b4e 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -33,13 +33,11 @@ config USB_GADGET_DRIVER_PXA27X
config USB_GADGET_AUTOSTART
bool
default y
- select ENVIRONMENT_VARIABLES
- select FILE_LIST
prompt "Automatically start usbgadget on boot"
help
- Enabling this option allows to automatically start a fastboot
- gadget during boot. This behaviour is controlled with the
- global.usbgadget.fastboot_function variable.
+ Enabling this option allows to automatically start a dfu or
+ fastboot gadget during boot. This behaviour is controlled with
+ the global.usbgadget.{dfu,fastboot}_function variable.
comment "USB Gadget drivers"
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index e74cf02664..9ef594575b 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -1,6 +1,5 @@
obj-$(CONFIG_USB_GADGET) += composite.o config.o usbstring.o epautoconf.o udc-core.o functions.o config.o multi.o
-obj-$(CONFIG_USB_GADGET_AUTOSTART) += autostart.o
obj-$(CONFIG_USB_GADGET_SERIAL) += u_serial.o serial.o f_serial.o f_acm.o
obj-$(CONFIG_USB_GADGET_DFU) += dfu.o
obj-$(CONFIG_USB_GADGET_FASTBOOT) += f_fastboot.o
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 645275a016..729f752128 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -622,7 +622,7 @@ static void udc_reinit(struct at91_udc *udc)
ep->desc = NULL;
ep->stopped = 0;
ep->fifo_bank = 0;
- ep->ep.maxpacket = ep->maxpacket;
+ usb_ep_set_maxpacket_limit(&ep->ep, ep->maxpacket);
ep->creg = (void __iomem *) udc->udp_baseaddr + AT91_UDP_CSR(i);
/* initialize one queue per endpoint */
INIT_LIST_HEAD(&ep->queue);
diff --git a/drivers/usb/gadget/fsl_udc.c b/drivers/usb/gadget/fsl_udc.c
index 9b59669773..705f6c0ba7 100644
--- a/drivers/usb/gadget/fsl_udc.c
+++ b/drivers/usb/gadget/fsl_udc.c
@@ -450,6 +450,11 @@ struct fsl_udc {
u8 device_address; /* Device USB address */
};
+static inline struct fsl_udc *to_fsl_udc(struct usb_gadget *gadget)
+{
+ return container_of(gadget, struct fsl_udc, gadget);
+}
+
/*-------------------------------------------------------------------------*/
#ifdef DEBUG
@@ -523,7 +528,6 @@ static void dump_msg(const char *label, const u8 * buf, unsigned int length)
#define get_pipe_by_ep(EP) (ep_index(EP) * 2 + ep_is_in(EP))
static struct usb_dr_device __iomem *dr_regs;
-static struct fsl_udc *udc_controller = NULL;
static const struct usb_endpoint_descriptor
fsl_ep0_desc = {
@@ -1943,12 +1947,9 @@ static void dtd_complete_irq(struct fsl_udc *udc)
*/
static void fsl_udc_gadget_poll(struct usb_gadget *gadget)
{
- struct fsl_udc *udc = udc_controller;
+ struct fsl_udc *udc = to_fsl_udc(gadget);
u32 irq_src;
- if (!udc)
- return;
-
/* Disable ISR for OTG host mode */
if (udc->stopped)
return;
@@ -1981,7 +1982,7 @@ static void fsl_udc_gadget_poll(struct usb_gadget *gadget)
/* Sleep Enable (Suspend) */
if (irq_src & USB_STS_SUSPEND)
- udc->driver->disconnect(&udc_controller->gadget);
+ udc->driver->disconnect(gadget);
if (irq_src & (USB_STS_ERR | USB_STS_SYS_ERR))
printf("Error IRQ %x\n", irq_src);
@@ -1993,6 +1994,8 @@ static void fsl_udc_gadget_poll(struct usb_gadget *gadget)
*----------------------------------------------------------------*/
static int fsl_udc_start(struct usb_gadget *gadget, struct usb_gadget_driver *driver)
{
+ struct fsl_udc *udc = to_fsl_udc(gadget);
+
/*
* We currently have PHY no driver which could call vbus_connect,
* so when the USB gadget core calls usb_gadget_connect() the
@@ -2002,13 +2005,13 @@ static int fsl_udc_start(struct usb_gadget *gadget, struct usb_gadget_driver *dr
usb_gadget_vbus_connect(gadget);
/* hook up the driver */
- udc_controller->driver = driver;
+ udc->driver = driver;
/* Enable DR IRQ reg and Set usbcmd reg Run bit */
- dr_controller_run(udc_controller);
- udc_controller->usb_state = USB_STATE_ATTACHED;
- udc_controller->ep0_state = WAIT_FOR_SETUP;
- udc_controller->ep0_dir = 0;
+ dr_controller_run(udc);
+ udc->usb_state = USB_STATE_ATTACHED;
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = 0;
return 0;
}
@@ -2016,20 +2019,21 @@ static int fsl_udc_start(struct usb_gadget *gadget, struct usb_gadget_driver *dr
/* Disconnect from gadget driver */
static int fsl_udc_stop(struct usb_gadget *gadget, struct usb_gadget_driver *driver)
{
+ struct fsl_udc *udc = to_fsl_udc(gadget);
struct fsl_ep *loop_ep;
/* stop DR, disable intr */
- dr_controller_stop(udc_controller);
+ dr_controller_stop(udc);
/* in fact, no needed */
- udc_controller->usb_state = USB_STATE_ATTACHED;
- udc_controller->ep0_state = WAIT_FOR_SETUP;
- udc_controller->ep0_dir = 0;
+ udc->usb_state = USB_STATE_ATTACHED;
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = 0;
/* stand operation */
- udc_controller->gadget.speed = USB_SPEED_UNKNOWN;
- nuke(&udc_controller->eps[0], -ESHUTDOWN);
- list_for_each_entry(loop_ep, &udc_controller->gadget.ep_list,
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ nuke(&udc->eps[0], -ESHUTDOWN);
+ list_for_each_entry(loop_ep, &udc->gadget.ep_list,
ep.ep_list)
nuke(loop_ep, -ESHUTDOWN);
@@ -2221,8 +2225,9 @@ static int __init struct_ep_setup(struct fsl_udc *udc, unsigned char index,
return 0;
}
-int ci_udc_register(struct device_d *dev, void __iomem *regs)
+struct fsl_udc *ci_udc_register(struct device_d *dev, void __iomem *regs)
{
+ struct fsl_udc *udc_controller;
int ret, i;
u32 dccparams;
@@ -2270,7 +2275,8 @@ int ci_udc_register(struct device_d *dev, void __iomem *regs)
* for other eps, gadget layer called ep_enable with defined desc
*/
udc_controller->eps[0].desc = &fsl_ep0_desc;
- udc_controller->eps[0].ep.maxpacket = USB_MAX_CTRL_PAYLOAD;
+ usb_ep_set_maxpacket_limit(&udc_controller->eps[0].ep,
+ USB_MAX_CTRL_PAYLOAD);
/* setup the udc->eps[] for non-control endpoints and link
* to gadget.ep_list */
@@ -2288,31 +2294,41 @@ int ci_udc_register(struct device_d *dev, void __iomem *regs)
if (ret)
goto err_out;
- return 0;
+ return udc_controller;
err_out:
- return ret;
+ free(udc_controller);
+
+ return ERR_PTR(ret);
}
-void ci_udc_unregister(void)
+void ci_udc_unregister(struct fsl_udc *udc)
{
- if (udc_controller)
- usb_del_gadget_udc(&udc_controller->gadget);
-
+ usb_del_gadget_udc(&udc->gadget);
+ free(udc);
}
static int fsl_udc_probe(struct device_d *dev)
{
+ struct fsl_udc *udc;
void __iomem *regs = dev_request_mem_region(dev, 0);
if (IS_ERR(regs))
return PTR_ERR(regs);
- return ci_udc_register(dev, regs);
+ udc = ci_udc_register(dev, regs);
+ if (IS_ERR(udc))
+ return PTR_ERR(udc);
+
+ dev->priv = udc;
+
+ return 0;
}
static void fsl_udc_remove(struct device_d *dev)
{
- ci_udc_unregister();
+ struct fsl_udc *udc = dev->priv;
+
+ ci_udc_unregister(udc);
}
static struct driver_d fsl_udc_driver = {
diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c
index 4e6b858868..442c90ca05 100644
--- a/drivers/usb/gadget/pxa27x_udc.c
+++ b/drivers/usb/gadget/pxa27x_udc.c
@@ -940,9 +940,12 @@ static __init void udc_init_data(struct pxa_udc *dev)
}
/* USB endpoints init */
- for (i = 1; i < NR_USB_ENDPOINTS; i++)
+ for (i = 1; i < NR_USB_ENDPOINTS; i++) {
list_add_tail(&dev->udc_usb_ep[i].usb_ep.ep_list,
&dev->gadget.ep_list);
+ usb_ep_set_maxpacket_limit(&dev->udc_usb_ep[i].usb_ep,
+ dev->udc_usb_ep[i].usb_ep.maxpacket);
+ }
}
static void udc_enable(struct pxa_udc *udc)
diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index 1132879c9b..6c88d646c9 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -30,6 +30,7 @@
#include "ehci.h"
struct atmel_ehci_priv {
+ struct ehci_host *ehci;
struct device_d *dev;
struct clk *iclk;
struct clk *uclk;
@@ -59,6 +60,13 @@ static void atmel_stop_clock(struct atmel_ehci_priv *atehci)
clk_disable(atehci->uclk);
}
+static int atmel_ehci_detect(struct device_d *dev)
+{
+ struct atmel_ehci_priv *atehci = dev->priv;
+
+ return ehci_detect(atehci->ehci);
+}
+
static int atmel_ehci_probe(struct device_d *dev)
{
int ret;
@@ -66,12 +74,14 @@ static int atmel_ehci_probe(struct device_d *dev)
struct ehci_data data;
struct atmel_ehci_priv *atehci;
const char *uclk_name;
+ struct ehci_host *ehci;
uclk_name = (dev->device_node) ? "usb_clk" : "uhpck";
atehci = xzalloc(sizeof(*atehci));
atehci->dev = dev;
dev->priv = atehci;
+ dev->detect = atmel_ehci_detect;
atehci->iclk = clk_get(dev, "ehci_clk");
if (IS_ERR(atehci->iclk)) {
@@ -99,15 +109,25 @@ static int atmel_ehci_probe(struct device_d *dev)
return PTR_ERR(iores);
data.hccr = IOMEM(iores->start);
- return ehci_register(dev, &data);
+ ehci = ehci_register(dev, &data);
+ if (IS_ERR(ehci))
+ return PTR_ERR(ehci);
+
+ atehci->ehci = ehci;
+
+ return 0;
}
static void atmel_ehci_remove(struct device_d *dev)
{
+ struct atmel_ehci_priv *atehci = dev->priv;
+
+ ehci_unregister(atehci->ehci);
+
/*
* Stop the USB clocks.
*/
- atmel_stop_clock(dev->priv);
+ atmel_stop_clock(atehci);
}
static const struct of_device_id atmel_ehci_dt_ids[] = {
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 9bbdda365c..87af95d2ed 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -34,7 +34,7 @@
#include "ehci.h"
-struct ehci_priv {
+struct ehci_host {
int rootdev;
struct device_d *dev;
struct ehci_hccr *hccr;
@@ -63,7 +63,7 @@ struct int_queue {
struct qTD *tds;
};
-#define to_ehci(ptr) container_of(ptr, struct ehci_priv, host)
+#define to_ehci(ptr) container_of(ptr, struct ehci_host, host)
#define NUM_QH 2
#define NUM_TD 3
@@ -155,7 +155,7 @@ static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec)
}
}
-static int ehci_reset(struct ehci_priv *ehci)
+static int ehci_reset(struct ehci_host *ehci)
{
uint32_t cmd;
uint32_t tmp;
@@ -218,7 +218,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
int length, struct devrequest *req, int timeout_ms)
{
struct usb_host *host = dev->host;
- struct ehci_priv *ehci = to_ehci(host);
+ struct ehci_host *ehci = to_ehci(host);
struct QH *qh;
struct qTD *td;
volatile struct qTD *vtd;
@@ -460,7 +460,7 @@ fail:
* boards.
* See http://lists.infradead.org/pipermail/linux-arm-kernel/2011-January/037341.html
*/
-static void ehci_powerup_fixup(struct ehci_priv *ehci)
+static void ehci_powerup_fixup(struct ehci_host *ehci)
{
void *viewport = (void *)ehci->hcor + 0x30;
@@ -471,12 +471,12 @@ static void ehci_powerup_fixup(struct ehci_priv *ehci)
viewport);
}
#else
-static inline void ehci_powerup_fixup(struct ehci_priv *ehci)
+static inline void ehci_powerup_fixup(struct ehci_host *ehci)
{
}
#endif
-static void pass_to_companion(struct ehci_priv *ehci, int port)
+static void pass_to_companion(struct ehci_host *ehci, int port)
{
uint32_t *status_reg = (uint32_t *)&ehci->hcor->or_portsc[port - 1];
uint32_t reg = ehci_readl(status_reg);
@@ -493,7 +493,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
int length, struct devrequest *req)
{
struct usb_host *host = dev->host;
- struct ehci_priv *ehci = to_ehci(host);
+ struct ehci_host *ehci = to_ehci(host);
uint8_t tmpbuf[4];
u16 typeReq;
void *srcptr = NULL;
@@ -772,7 +772,7 @@ unknown:
}
/* force HC to halt state from unknown (EHCI spec section 2.3) */
-static int ehci_halt(struct ehci_priv *ehci)
+static int ehci_halt(struct ehci_host *ehci)
{
u32 temp = ehci_readl(&ehci->hcor->or_usbsts);
@@ -792,7 +792,7 @@ static int ehci_halt(struct ehci_priv *ehci)
static int ehci_init(struct usb_host *host)
{
- struct ehci_priv *ehci = to_ehci(host);
+ struct ehci_host *ehci = to_ehci(host);
uint32_t reg;
uint32_t cmd;
int ret = 0;
@@ -902,7 +902,7 @@ submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
int length, int timeout)
{
struct usb_host *host = dev->host;
- struct ehci_priv *ehci = to_ehci(host);
+ struct ehci_host *ehci = to_ehci(host);
if (usb_pipetype(pipe) != PIPE_BULK) {
dev_dbg(ehci->dev, "non-bulk pipe (type=%lu)", usb_pipetype(pipe));
@@ -916,7 +916,7 @@ submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
int length, struct devrequest *setup, int timeout)
{
struct usb_host *host = dev->host;
- struct ehci_priv *ehci = to_ehci(host);
+ struct ehci_host *ehci = to_ehci(host);
if (usb_pipetype(pipe) != PIPE_CONTROL) {
dev_dbg(ehci->dev, "non-control pipe (type=%lu)", usb_pipetype(pipe));
@@ -932,7 +932,7 @@ submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
}
static int
-disable_periodic(struct ehci_priv *ehci)
+disable_periodic(struct ehci_host *ehci)
{
uint32_t cmd;
struct ehci_hcor *hcor = ehci->hcor;
@@ -954,7 +954,7 @@ disable_periodic(struct ehci_priv *ehci)
#define NEXT_QH(qh) (struct QH *)((unsigned long)hc32_to_cpu((qh)->qh_link) & ~0x1f)
static int
-enable_periodic(struct ehci_priv *ehci)
+enable_periodic(struct ehci_host *ehci)
{
uint32_t cmd;
struct ehci_hcor *hcor = ehci->hcor;
@@ -1018,7 +1018,7 @@ static struct int_queue *ehci_create_int_queue(struct usb_device *dev,
void *buffer, int interval)
{
struct usb_host *host = dev->host;
- struct ehci_priv *ehci = to_ehci(host);
+ struct ehci_host *ehci = to_ehci(host);
struct int_queue *result = NULL;
uint32_t i;
struct QH *list = ehci->periodic_queue;
@@ -1187,7 +1187,7 @@ static int ehci_destroy_int_queue(struct usb_device *dev,
{
int result = -EINVAL;
struct usb_host *host = dev->host;
- struct ehci_priv *ehci = to_ehci(host);
+ struct ehci_host *ehci = to_ehci(host);
struct QH *cur = ehci->periodic_queue;
if (disable_periodic(ehci) < 0) {
@@ -1230,7 +1230,7 @@ submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
int length, int interval)
{
struct usb_host *host = dev->host;
- struct ehci_priv *ehci = to_ehci(host);
+ struct ehci_host *ehci = to_ehci(host);
struct int_queue *queue;
uint64_t start;
void *backbuffer;
@@ -1273,22 +1273,19 @@ submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
return result;
}
-static int ehci_detect(struct device_d *dev)
+int ehci_detect(struct ehci_host *ehci)
{
- struct ehci_priv *ehci = dev->priv;
-
return usb_host_detect(&ehci->host);
}
-int ehci_register(struct device_d *dev, struct ehci_data *data)
+struct ehci_host *ehci_register(struct device_d *dev, struct ehci_data *data)
{
struct usb_host *host;
- struct ehci_priv *ehci;
+ struct ehci_host *ehci;
uint32_t reg;
- ehci = xzalloc(sizeof(struct ehci_priv));
+ ehci = xzalloc(sizeof(struct ehci_host));
host = &ehci->host;
- dev->priv = ehci;
ehci->flags = data->flags;
ehci->hccr = data->hccr;
ehci->dev = dev;
@@ -1321,14 +1318,28 @@ int ehci_register(struct device_d *dev, struct ehci_data *data)
ehci_reset(ehci);
}
- dev->detect = ehci_detect;
-
usb_register_host(host);
reg = HC_VERSION(ehci_readl(&ehci->hccr->cr_capbase));
dev_info(dev, "USB EHCI %x.%02x\n", reg >> 8, reg & 0xff);
- return 0;
+ return ehci;
+}
+
+void ehci_unregister(struct ehci_host *ehci)
+{
+ ehci_halt(ehci);
+
+ usb_unregister_host(&ehci->host);
+
+ free(ehci);
+}
+
+static int ehci_dev_detect(struct device_d *dev)
+{
+ struct ehci_host *ehci = dev->priv;
+
+ return ehci_detect(ehci);
}
static int ehci_probe(struct device_d *dev)
@@ -1337,6 +1348,7 @@ static int ehci_probe(struct device_d *dev)
struct ehci_data data = {};
struct ehci_platform_data *pdata = dev->platform_data;
struct device_node *dn = dev->device_node;
+ struct ehci_host *ehci;
if (pdata)
data.flags = pdata->flags;
@@ -1364,13 +1376,21 @@ static int ehci_probe(struct device_d *dev)
else
data.hcor = NULL;
- return ehci_register(dev, &data);
+ ehci = ehci_register(dev, &data);
+ if (IS_ERR(ehci))
+ return PTR_ERR(ehci);
+
+ dev->priv = ehci;
+ dev->detect = ehci_dev_detect;
+
+ return 0;
}
static void ehci_remove(struct device_d *dev)
{
- struct ehci_priv *ehci = dev->priv;
- ehci_halt(ehci);
+ struct ehci_host *ehci = dev->priv;
+
+ ehci_unregister(ehci);
}
static __maybe_unused struct of_device_id ehci_platform_dt_ids[] = {
diff --git a/drivers/usb/imx/chipidea-imx.c b/drivers/usb/imx/chipidea-imx.c
index 3e3e6a365f..8792217706 100644
--- a/drivers/usb/imx/chipidea-imx.c
+++ b/drivers/usb/imx/chipidea-imx.c
@@ -46,6 +46,8 @@ struct imx_chipidea {
struct phy *phy;
struct usb_phy *usbphy;
struct clk *clk;
+ struct ehci_host *ehci;
+ struct fsl_udc *udc;
};
static int imx_chipidea_port_init(void *drvdata)
@@ -175,6 +177,13 @@ static int imx_chipidea_probe_dt(struct imx_chipidea *ci)
return 0;
}
+static int ci_ehci_detect(struct device_d *dev)
+{
+ struct imx_chipidea *ci = dev->priv;
+
+ return ehci_detect(ci->ehci);
+}
+
static int ci_register_role(struct imx_chipidea *ci)
{
int ret;
@@ -184,14 +193,20 @@ static int ci_register_role(struct imx_chipidea *ci)
if (ci->mode == IMX_USB_MODE_HOST) {
if (IS_ENABLED(CONFIG_USB_EHCI)) {
+ struct ehci_host *ehci;
+
ci->role_registered = IMX_USB_MODE_HOST;
ret = regulator_enable(ci->vbus);
if (ret)
return ret;
- ret = ehci_register(ci->dev, &ci->data);
- if (!ret)
- return 0;
+ ehci = ehci_register(ci->dev, &ci->data);
+ if (IS_ERR(ehci))
+ return PTR_ERR(ehci);
+
+ ci->ehci = ehci;
+
+ ci->dev->detect = ci_ehci_detect;
regulator_disable(ci->vbus);
} else {
@@ -202,8 +217,14 @@ static int ci_register_role(struct imx_chipidea *ci)
if (ci->mode == IMX_USB_MODE_DEVICE) {
if (IS_ENABLED(CONFIG_USB_GADGET_DRIVER_ARC)) {
+ struct fsl_udc *udc;
ci->role_registered = IMX_USB_MODE_DEVICE;
- return ci_udc_register(ci->dev, ci->base);
+
+ udc = ci_udc_register(ci->dev, ci->base);
+ if (IS_ERR(udc))
+ return PTR_ERR(udc);
+
+ ci->udc = udc;
} else {
dev_err(ci->dev, "USB device support not available\n");
return -ENODEV;
@@ -266,6 +287,7 @@ static int imx_chipidea_probe(struct device_d *dev)
ci = xzalloc(sizeof(*ci));
ci->dev = dev;
+ dev->priv = ci;
ci->role_registered = IMX_USB_MODE_OTG;
if (IS_ENABLED(CONFIG_OFDEVICE) && dev->device_node) {
@@ -349,8 +371,13 @@ static int imx_chipidea_probe(struct device_d *dev)
static void imx_chipidea_remove(struct device_d *dev)
{
- if (IS_ENABLED(CONFIG_USB_GADGET_DRIVER_ARC))
- ci_udc_unregister();
+ struct imx_chipidea *ci = dev->priv;
+
+ if (ci->ehci)
+ ehci_unregister(ci->ehci);
+
+ if (IS_ENABLED(CONFIG_USB_GADGET_DRIVER_ARC) && ci->udc)
+ ci_udc_unregister(ci->udc);
}
static __maybe_unused struct of_device_id imx_chipidea_dt_ids[] = {
diff --git a/include/usb/ehci.h b/include/usb/ehci.h
index 1008e92f02..9ca9252eb1 100644
--- a/include/usb/ehci.h
+++ b/include/usb/ehci.h
@@ -19,12 +19,26 @@ struct ehci_data {
void *drvdata;
};
+struct ehci_host;
+
#ifdef CONFIG_USB_EHCI
-int ehci_register(struct device_d *dev, struct ehci_data *data);
+struct ehci_host *ehci_register(struct device_d *dev, struct ehci_data *data);
+void ehci_unregister(struct ehci_host *);
+int ehci_detect(struct ehci_host *ehci);
#else
-static inline int ehci_register(struct device_d *dev, struct ehci_data *data)
+static inline struct ehci_host *ehci_register(struct device_d *dev,
+ struct ehci_data *data)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
+static inline void ehci_unregister(struct ehci_host *ehci)
+{
+}
+
+static inline int ehci_detect(struct ehci_host *ehci)
{
- return -ENOSYS;
+ return 0;
}
#endif
diff --git a/include/usb/fsl_usb2.h b/include/usb/fsl_usb2.h
index 881a5d4fdf..39757f71ad 100644
--- a/include/usb/fsl_usb2.h
+++ b/include/usb/fsl_usb2.h
@@ -23,7 +23,9 @@ struct fsl_usb2_platform_data {
unsigned int port_enables;
};
-int ci_udc_register(struct device_d *dev, void __iomem *regs);
-void ci_udc_unregister(void);
+struct fsl_udc;
+
+struct fsl_udc *ci_udc_register(struct device_d *dev, void __iomem *regs);
+void ci_udc_unregister(struct fsl_udc *);
#endif /* __USB_FSL_USB2_H */
diff --git a/include/usb/gadget-multi.h b/include/usb/gadget-multi.h
index 81beddc7cf..030e604fe7 100644
--- a/include/usb/gadget-multi.h
+++ b/include/usb/gadget-multi.h
@@ -16,4 +16,8 @@ int usb_multi_register(struct f_multi_opts *opts);
void usb_multi_unregister(void);
void usb_multi_opts_release(struct f_multi_opts *opts);
+int usbgadget_register(bool dfu, const char *dfu_opts,
+ bool fastboot, const char *fastboot_opts,
+ bool acm, bool export_bbu);
+
#endif /* __USB_GADGET_MULTI_H */
diff --git a/include/usb/usb.h b/include/usb/usb.h
index 9aab06c87c..eb2eeb8db3 100644
--- a/include/usb/usb.h
+++ b/include/usb/usb.h
@@ -157,6 +157,7 @@ struct usb_host {
};
int usb_register_host(struct usb_host *);
+void usb_unregister_host(struct usb_host *host);
int usb_host_detect(struct usb_host *host);