diff --git a/Documentation/user/usb.rst b/Documentation/user/usb.rst index 8396f38..029e463 100644 --- a/Documentation/user/usb.rst +++ b/Documentation/user/usb.rst @@ -264,5 +264,9 @@ ``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 675bd1c..1de4b9d 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -1910,7 +1910,6 @@ 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 a1744cb..e8e1e9a 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 @@ } } - 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("") 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 ", "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 ", "Create DFU function") +BAREBOX_CMD_HELP_OPT ("-D ", "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 eddd99e..2ad9215 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -115,6 +115,13 @@ 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 861365b..b617642 100644 --- a/common/Makefile +++ b/common/Makefile @@ -64,6 +64,7 @@ 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/common/usbgadget.c b/common/usbgadget.c new file mode 100644 index 0000000..a8f104c --- /dev/null +++ b/common/usbgadget.c @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2017 Oleksij Rempel , Pengutronix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#define pr_fmt(fmt) "usbgadget: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int autostart; +static int acm; +static char *dfu_function; +static char *fastboot_function; +static int fastboot_bbu; + +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) +{ + int ret; + struct device_d *dev; + struct f_multi_opts *opts; + + 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_opts) { + opts->fastboot_opts.files = parse(fastboot_opts); + opts->fastboot_opts.export_bbu = export_bbu; + } + + if (dfu_opts) + opts->dfu_opts.files = parse(dfu_opts); + + 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"); + + ret = usb_multi_register(opts); + if (ret) + usb_multi_opts_release(opts); + + 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) +{ + 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); + + return 0; +} +device_initcall(usbgadget_globalvars_init); + +BAREBOX_MAGICVAR_NAMED(global_usbgadget_autostart, + global.usbgadget.autostart, + "usbgadget: Automatically start usbgadget on boot"); +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"); +BAREBOX_MAGICVAR_NAMED(global_usbgadget_fastboot_bbu, + global.usbgadget.fastboot_bbu, + "usbgadget: export barebox update handlers via fastboot"); diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 0ee8808..7b00843 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -102,6 +102,11 @@ 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 b0408e3..ca1bfc1 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -33,13 +33,11 @@ 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 e74cf02..9ef5945 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 645275a..729f752 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -622,7 +622,7 @@ 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/autostart.c b/drivers/usb/gadget/autostart.c deleted file mode 100644 index 272b0ea..0000000 --- a/drivers/usb/gadget/autostart.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2017 Oleksij Rempel , Pengutronix - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#define pr_fmt(fmt) "usbgadget autostart: " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int autostart; -static int acm; -static char *fastboot_function; -static int fastboot_bbu; - -static int usbgadget_autostart(void) -{ - struct f_multi_opts *opts; - struct device_d *dev; - int ret; - - if (!autostart) - return 0; - - 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; - } - - opts->create_acm = acm; - - if (!opts->fastboot_opts.files && !opts->create_acm) { - pr_warn("No functions to register\n"); - return 0; - } - - dev = get_device_by_name("otg"); - if (dev) - dev_set_param(dev, "mode", "peripheral"); - - ret = usb_multi_register(opts); - if (ret) - usb_multi_opts_release(opts); - - return ret; -} -postenvironment_initcall(usbgadget_autostart); - -static int usbgadget_globalvars_init(void) -{ - - globalvar_add_simple_bool("usbgadget.autostart", &autostart); - globalvar_add_simple_bool("usbgadget.acm", &acm); - globalvar_add_simple_string("usbgadget.fastboot_function", - &fastboot_function); - globalvar_add_simple_bool("usbgadget.fastboot_bbu", &fastboot_bbu); - - return 0; -} -device_initcall(usbgadget_globalvars_init); - -BAREBOX_MAGICVAR_NAMED(global_usbgadget_autostart, - global.usbgadget.autostart, - "usbgadget: Automatically start usbgadget on boot"); -BAREBOX_MAGICVAR_NAMED(global_usbgadget_acm, - global.usbgadget.acm, - "usbgadget: Create CDC ACM function"); -BAREBOX_MAGICVAR_NAMED(global_usbgadget_fastboot_function, - global.usbgadget.fastboot_function, - "usbgadget: Create Android Fastboot function"); -BAREBOX_MAGICVAR_NAMED(global_usbgadget_fastboot_bbu, - global.usbgadget.fastboot_bbu, - "usbgadget: export barebox update handlers via fastboot"); diff --git a/drivers/usb/gadget/fsl_udc.c b/drivers/usb/gadget/fsl_udc.c index 9b59669..705f6c0 100644 --- a/drivers/usb/gadget/fsl_udc.c +++ b/drivers/usb/gadget/fsl_udc.c @@ -450,6 +450,11 @@ 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 @@ #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 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 @@ /* 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 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 @@ 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 @@ /* 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 @@ 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 @@ * 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 @@ 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 4e6b858..442c90c 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -940,9 +940,12 @@ } /* 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 1132879..6c88d64 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 @@ 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 @@ 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 @@ 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 9bbdda3..87af95d 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 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 ehci_reset(struct ehci_priv *ehci) +static int ehci_reset(struct ehci_host *ehci) { uint32_t cmd; uint32_t tmp; @@ -218,7 +218,7 @@ 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 @@ * 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 @@ 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 @@ 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 @@ } /* 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_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 @@ 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 @@ 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 @@ } 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 @@ #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 @@ 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 @@ { 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 3e3e6a3..8792217 100644 --- a/drivers/usb/imx/chipidea-imx.c +++ b/drivers/usb/imx/chipidea-imx.c @@ -46,6 +46,8 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 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 1008e92..9ca9252 100644 --- a/include/usb/ehci.h +++ b/include/usb/ehci.h @@ -19,12 +19,26 @@ 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 -ENOSYS; + return ERR_PTR(-ENOSYS); +} + +static inline void ehci_unregister(struct ehci_host *ehci) +{ +} + +static inline int ehci_detect(struct ehci_host *ehci) +{ + return 0; } #endif diff --git a/include/usb/fsl_usb2.h b/include/usb/fsl_usb2.h index 881a5d4..39757f7 100644 --- a/include/usb/fsl_usb2.h +++ b/include/usb/fsl_usb2.h @@ -23,7 +23,9 @@ 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 81beddc..030e604 100644 --- a/include/usb/gadget-multi.h +++ b/include/usb/gadget-multi.h @@ -16,4 +16,8 @@ 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 9aab06c..eb2eeb8 100644 --- a/include/usb/usb.h +++ b/include/usb/usb.h @@ -157,6 +157,7 @@ }; int usb_register_host(struct usb_host *); +void usb_unregister_host(struct usb_host *host); int usb_host_detect(struct usb_host *host);