From mboxrd@z Thu Jan 1 00:00:00 1970 From: Lukasz Majewski Date: Tue, 19 Aug 2014 10:52:29 +0200 Subject: [U-Boot] [UBOOT RFC PATCH 02/13] usb: gadget: udc-core: Add minimal udc-core from linux kernel In-Reply-To: <1408372115-4570-3-git-send-email-kishon@ti.com> References: <1408372115-4570-1-git-send-email-kishon@ti.com> <1408372115-4570-3-git-send-email-kishon@ti.com> Message-ID: <20140819105229.0559147a@amdc2363> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de Hi Kishon, > In order to support multiple USB device controllers in uboot, > udc-core is needed. Is it? In u-boot at best only one UDC is operational at a time. > udc-core also helps to cleanly link the USB > peripheral driver with the gadget driver. Hence Ported minimal > udc-core from linux kernel. I'd appreciate the exact SHA for this udc-core.c code. And the SHA should be from some already released mainline code (like final 3.16), not any private branch nor linux-next. > > Signed-off-by: Kishon Vijay Abraham I > --- > drivers/usb/gadget/Makefile | 1 + > drivers/usb/gadget/udc-core.c | 229 > ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 230 > insertions(+) create mode 100644 drivers/usb/gadget/udc-core.c > > diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile > index 66becdc..74875a2 100644 > --- a/drivers/usb/gadget/Makefile > +++ b/drivers/usb/gadget/Makefile > @@ -19,6 +19,7 @@ obj-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o > obj-$(CONFIG_DFU_FUNCTION) += f_dfu.o > obj-$(CONFIG_USB_GADGET_MASS_STORAGE) += f_mass_storage.o > obj-$(CONFIG_CMD_FASTBOOT) += f_fastboot.o > +obj-y += udc-core.o > endif > ifdef CONFIG_USB_ETHER > obj-y += ether.o > diff --git a/drivers/usb/gadget/udc-core.c > b/drivers/usb/gadget/udc-core.c new file mode 100644 > index 0000000..bbe919c > --- /dev/null > +++ b/drivers/usb/gadget/udc-core.c > @@ -0,0 +1,229 @@ > +/** > + * udc-core.c - Core UDC Framework > + * > + * Copyright (C) 2014 Texas Instruments Incorporated - > http://www.ti.com > + * > + * Author: Felipe Balbi > + * > + * Taken from Linux Kernel v3.16 (drivers/usb/gadget/udc-core.c) and > ported > + * to uboot. > + * > + * SPDX-License-Identifier: GPL-2.0+ It seems like the author is the same, but the GPL license is different: Original file ./drivers/usb/gadget/udc/udc-core.c /** * udc.c - Core UDCFramework * * Copyright (C) 2010 TexasInstruments * Author: Felipe Balbi * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 of * the License as published by the Free Software Foundation. If Felipe don't mind then he should give you the permission to add + to the GPL2. > + */ > + > +#include > +#include > +#include > +#include > + > +#include > +#include > + > +/** > + * struct usb_udc - describes one usb device controller > + * @driver - the gadget driver pointer. For use by the class code > + * @dev - the child device to the actual controller > + * @gadget - the gadget. For use by the class code > + * @list - for use by the udc class driver > + * > + * This represents the internal data structure which is used by the > UDC-class > + * to hold information about udc driver and gadget together. > + */ > +struct usb_udc { > + struct usb_gadget_driver *driver; > + struct usb_gadget *gadget; > + struct list_head list; > +}; > + > +static LIST_HEAD(udc_list); > + > +void usb_gadget_set_state(struct usb_gadget *gadget, > + enum usb_device_state state) > +{ > + gadget->state = state; > +} > + > +/** > + * usb_gadget_udc_start - tells usb device controller to start up > + * @gadget: The gadget we want to get started > + * @driver: The driver we want to bind to @gadget > + * > + * This call is issued by the UDC Class driver when it's about > + * to register a gadget driver to the device controller, before > + * calling gadget driver's bind() method. > + * > + * It allows the controller to be powered off until strictly > + * necessary to have it powered on. > + * > + * Returns zero on success, else negative errno. > + */ > +static inline int usb_gadget_udc_start(struct usb_gadget *gadget, > + struct usb_gadget_driver *driver) > +{ > + return gadget->ops->udc_start(gadget, driver); > +} > + > +/** > + * usb_gadget_udc_stop - tells usb device controller we don't need > it anymore > + * @gadget: The device we want to stop activity > + * @driver: The driver to unbind from @gadget > + * > + * This call is issued by the UDC Class driver after calling > + * gadget driver's unbind() method. > + * > + * The details are implementation specific, but it can go as > + * far as powering off UDC completely and disable its data > + * line pullups. > + */ > +static inline void usb_gadget_udc_stop(struct usb_gadget *gadget, > + struct usb_gadget_driver *driver) > +{ > + gadget->ops->udc_stop(gadget, driver); > +} > + > +/** > + * usb_add_gadget_udc_release - adds a new gadget to the udc class > driver list > + * @parent: the parent device to this udc. Usually the controller > driver's > + * device. > + * @gadget: the gadget to be added to the list. > + * @release: a gadget release function. > + * > + * Returns zero on success, negative errno otherwise. > + */ > +int usb_add_gadget_udc_release(struct usb_gadget *gadget) > +{ > + struct usb_udc *udc; > + int ret = -ENOMEM; > + > + udc = kzalloc(sizeof(*udc), GFP_KERNEL); > + if (!udc) > + return ret; > + > + udc->gadget = gadget; > + list_add_tail(&udc->list, &udc_list); > + usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED); > + return 0; > +} > + > +/** > + * usb_add_gadget_udc - adds a new gadget to the udc class driver > list > + * @parent: the parent device to this udc. Usually the controller > + * driver's device. > + * @gadget: the gadget to be added to the list > + * > + * Returns zero on success, negative errno otherwise. > + */ > +int usb_add_gadget_udc(struct usb_gadget *gadget) > +{ > + return usb_add_gadget_udc_release(gadget); > +} > + > +static void usb_gadget_remove_driver(struct usb_udc *udc) > +{ > + dev_dbg(&udc->dev, "unregistering UDC driver [%s]\n", > + udc->gadget->name); > + usb_gadget_disconnect(udc->gadget); > + udc->driver->disconnect(udc->gadget); > + udc->driver->unbind(udc->gadget); > + usb_gadget_udc_stop(udc->gadget, NULL); > + > + udc->driver = NULL; > +} > + > +/** > + * usb_del_gadget_udc - deletes @udc from udc_list > + * @gadget: the gadget to be removed. > + * > + * This, will call usb_gadget_unregister_driver() if > + * the @udc is still busy. > + */ > +void usb_del_gadget_udc(struct usb_gadget *gadget) > +{ > + struct usb_udc *udc = NULL; > + list_for_each_entry(udc, &udc_list, list) > + if (udc->gadget == gadget) > + goto found; > + > + dev_err(gadget->dev.parent, "gadget not registered.\n"); > + return; > + > +found: > + dev_vdbg(gadget->dev.parent, "unregistering gadget\n"); > + > + list_del(&udc->list); > + > + if (udc->driver) > + usb_gadget_remove_driver(udc); > + > + kfree(udc); > +} > + > +static int udc_bind_to_driver(struct usb_udc *udc, struct > usb_gadget_driver *driver) +{ > + int ret; > + > + dev_dbg(&udc->dev, "registering UDC driver [%s]\n", > + driver->function); > + > + udc->driver = driver; > + > + ret = driver->bind(udc->gadget); > + if (ret) > + goto err1; > + > + ret = usb_gadget_udc_start(udc->gadget, driver); > + if (ret) { > + driver->unbind(udc->gadget); > + goto err1; > + } > + usb_gadget_connect(udc->gadget); > + > + return 0; > +err1: > + if (ret != -EISNAM) > + dev_err(&udc->dev, "failed to start %s: %d\n", > + udc->driver->function, ret); > + udc->driver = NULL; > + return ret; > +} > + > +int usb_gadget_register_driver(struct usb_gadget_driver *driver) > +{ > + struct usb_udc *udc = NULL; > + int ret; > + > + if (!driver || !driver->bind || !driver->setup) > + return -EINVAL; > + > + list_for_each_entry(udc, &udc_list, list) { > + /* For now we take the first one */ > + if (!udc->driver) > + goto found; > + } > + > + debug("couldn't find an available UDC\n"); > + return -ENODEV; > +found: > + ret = udc_bind_to_driver(udc, driver); > + return ret; > +} > + > +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) > +{ > + struct usb_udc *udc = NULL; > + int ret = -ENODEV; > + > + if (!driver || !driver->unbind) > + return -EINVAL; > + > + list_for_each_entry(udc, &udc_list, list) > + if (udc->driver == driver) { > + usb_gadget_remove_driver(udc); > + usb_gadget_set_state(udc->gadget, > + USB_STATE_NOTATTACHED); > + ret = 0; > + break; > + } > + > + return ret; > +} -- Best regards, Lukasz Majewski Samsung R&D Institute Poland (SRPOL) | Linux Platform Group