summaryrefslogtreecommitdiff
path: root/drivers/usb/gadget/udc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget/udc')
-rw-r--r--drivers/usb/gadget/udc/core.c289
-rw-r--r--drivers/usb/gadget/udc/net2272.c6
-rw-r--r--drivers/usb/gadget/udc/net2280.c14
-rw-r--r--drivers/usb/gadget/udc/omap_udc.c16
-rw-r--r--drivers/usb/gadget/udc/pxa27x_udc.h2
-rw-r--r--drivers/usb/gadget/udc/s3c-hsudc.c4
-rw-r--r--drivers/usb/gadget/udc/tegra-xudc.c4
-rw-r--r--drivers/usb/gadget/udc/udc-xilinx.c2
8 files changed, 164 insertions, 173 deletions
diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index 85b194011a16..7886497253cc 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/device.h>
#include <linux/list.h>
+#include <linux/idr.h>
#include <linux/err.h>
#include <linux/dma-mapping.h>
#include <linux/sched/task_stack.h>
@@ -23,6 +24,10 @@
#include "trace.h"
+static DEFINE_IDA(gadget_id_numbers);
+
+static struct bus_type gadget_bus_type;
+
/**
* struct usb_udc - describes one usb device controller
* @driver: the gadget driver pointer. For use by the class code
@@ -47,11 +52,9 @@ struct usb_udc {
static struct class *udc_class;
static LIST_HEAD(udc_list);
-static LIST_HEAD(gadget_driver_pending_list);
-static DEFINE_MUTEX(udc_lock);
-static int udc_bind_to_driver(struct usb_udc *udc,
- struct usb_gadget_driver *driver);
+/* Protects udc_list, udc->driver, driver->is_bound, and related calls */
+static DEFINE_MUTEX(udc_lock);
/* ------------------------------------------------------------------------- */
@@ -1238,38 +1241,16 @@ static void usb_udc_nop_release(struct device *dev)
dev_vdbg(dev, "%s\n", __func__);
}
-/* should be called with udc_lock held */
-static int check_pending_gadget_drivers(struct usb_udc *udc)
-{
- struct usb_gadget_driver *driver;
- int ret = 0;
-
- list_for_each_entry(driver, &gadget_driver_pending_list, pending)
- if (!driver->udc_name || strcmp(driver->udc_name,
- dev_name(&udc->dev)) == 0) {
- ret = udc_bind_to_driver(udc, driver);
- if (ret != -EPROBE_DEFER)
- list_del_init(&driver->pending);
- break;
- }
-
- return ret;
-}
-
/**
* usb_initialize_gadget - initialize a gadget and its embedded struct device
* @parent: the parent device to this udc. Usually the controller driver's
* device.
* @gadget: the gadget to be initialized.
* @release: a gadget release function.
- *
- * Returns zero on success, negative errno otherwise.
- * Calls the gadget release function in the latter case.
*/
void usb_initialize_gadget(struct device *parent, struct usb_gadget *gadget,
void (*release)(struct device *dev))
{
- dev_set_name(&gadget->dev, "gadget");
INIT_WORK(&gadget->work, usb_gadget_state_work);
gadget->dev.parent = parent;
@@ -1279,6 +1260,7 @@ void usb_initialize_gadget(struct device *parent, struct usb_gadget *gadget,
gadget->dev.release = usb_udc_nop_release;
device_initialize(&gadget->dev);
+ gadget->dev.bus = &gadget_bus_type;
}
EXPORT_SYMBOL_GPL(usb_initialize_gadget);
@@ -1308,10 +1290,6 @@ int usb_add_gadget(struct usb_gadget *gadget)
if (ret)
goto err_put_udc;
- ret = device_add(&gadget->dev);
- if (ret)
- goto err_put_udc;
-
udc->gadget = gadget;
gadget->udc = udc;
@@ -1319,6 +1297,7 @@ int usb_add_gadget(struct usb_gadget *gadget)
mutex_lock(&udc_lock);
list_add_tail(&udc->list, &udc_list);
+ mutex_unlock(&udc_lock);
ret = device_add(&udc->dev);
if (ret)
@@ -1327,25 +1306,30 @@ int usb_add_gadget(struct usb_gadget *gadget)
usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
udc->vbus = true;
- /* pick up one of pending gadget drivers */
- ret = check_pending_gadget_drivers(udc);
- if (ret)
+ ret = ida_alloc(&gadget_id_numbers, GFP_KERNEL);
+ if (ret < 0)
goto err_del_udc;
+ gadget->id_number = ret;
+ dev_set_name(&gadget->dev, "gadget.%d", ret);
- mutex_unlock(&udc_lock);
+ ret = device_add(&gadget->dev);
+ if (ret)
+ goto err_free_id;
return 0;
+ err_free_id:
+ ida_free(&gadget_id_numbers, gadget->id_number);
+
err_del_udc:
flush_work(&gadget->work);
device_del(&udc->dev);
err_unlist_udc:
+ mutex_lock(&udc_lock);
list_del(&udc->list);
mutex_unlock(&udc_lock);
- device_del(&gadget->dev);
-
err_put_udc:
put_device(&udc->dev);
@@ -1421,30 +1405,11 @@ int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
}
EXPORT_SYMBOL_GPL(usb_add_gadget_udc);
-static void usb_gadget_remove_driver(struct usb_udc *udc)
-{
- dev_dbg(&udc->dev, "unregistering UDC driver [%s]\n",
- udc->driver->function);
-
- kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
-
- usb_gadget_disconnect(udc->gadget);
- usb_gadget_disable_async_callbacks(udc);
- if (udc->gadget->irq)
- synchronize_irq(udc->gadget->irq);
- udc->driver->unbind(udc->gadget);
- usb_gadget_udc_stop(udc);
-
- udc->driver = NULL;
- udc->gadget->dev.driver = NULL;
-}
-
/**
- * usb_del_gadget - deletes @udc from udc_list
- * @gadget: the gadget to be removed.
+ * usb_del_gadget - deletes a gadget and unregisters its udc
+ * @gadget: the gadget to be deleted.
*
- * This will call usb_gadget_unregister_driver() if
- * the @udc is still busy.
+ * This will unbind @gadget, if it is bound.
* It will not do a final usb_put_gadget().
*/
void usb_del_gadget(struct usb_gadget *gadget)
@@ -1458,25 +1423,19 @@ void usb_del_gadget(struct usb_gadget *gadget)
mutex_lock(&udc_lock);
list_del(&udc->list);
-
- if (udc->driver) {
- struct usb_gadget_driver *driver = udc->driver;
-
- usb_gadget_remove_driver(udc);
- list_add(&driver->pending, &gadget_driver_pending_list);
- }
mutex_unlock(&udc_lock);
kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
flush_work(&gadget->work);
- device_unregister(&udc->dev);
device_del(&gadget->dev);
+ ida_free(&gadget_id_numbers, gadget->id_number);
+ device_unregister(&udc->dev);
}
EXPORT_SYMBOL_GPL(usb_del_gadget);
/**
- * usb_del_gadget_udc - deletes @udc from udc_list
- * @gadget: the gadget to be removed.
+ * usb_del_gadget_udc - unregisters a gadget
+ * @gadget: the gadget to be unregistered.
*
* Calls usb_del_gadget() and does a final usb_put_gadget().
*/
@@ -1489,123 +1448,147 @@ EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
/* ------------------------------------------------------------------------- */
-static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver)
+static int gadget_match_driver(struct device *dev, struct device_driver *drv)
{
- int ret;
+ struct usb_gadget *gadget = dev_to_usb_gadget(dev);
+ struct usb_udc *udc = gadget->udc;
+ struct usb_gadget_driver *driver = container_of(drv,
+ struct usb_gadget_driver, driver);
- dev_dbg(&udc->dev, "registering UDC driver [%s]\n",
- driver->function);
+ /* If the driver specifies a udc_name, it must match the UDC's name */
+ if (driver->udc_name &&
+ strcmp(driver->udc_name, dev_name(&udc->dev)) != 0)
+ return 0;
+
+ /* If the driver is already bound to a gadget, it doesn't match */
+ if (driver->is_bound)
+ return 0;
+
+ /* Otherwise any gadget driver matches any UDC */
+ return 1;
+}
+static int gadget_bind_driver(struct device *dev)
+{
+ struct usb_gadget *gadget = dev_to_usb_gadget(dev);
+ struct usb_udc *udc = gadget->udc;
+ struct usb_gadget_driver *driver = container_of(dev->driver,
+ struct usb_gadget_driver, driver);
+ int ret = 0;
+
+ mutex_lock(&udc_lock);
+ if (driver->is_bound) {
+ mutex_unlock(&udc_lock);
+ return -ENXIO; /* Driver binds to only one gadget */
+ }
+ driver->is_bound = true;
udc->driver = driver;
- udc->gadget->dev.driver = &driver->driver;
+ mutex_unlock(&udc_lock);
+
+ dev_dbg(&udc->dev, "binding gadget driver [%s]\n", driver->function);
usb_gadget_udc_set_speed(udc, driver->max_speed);
+ mutex_lock(&udc_lock);
ret = driver->bind(udc->gadget, driver);
if (ret)
- goto err1;
+ goto err_bind;
+
ret = usb_gadget_udc_start(udc);
- if (ret) {
- driver->unbind(udc->gadget);
- goto err1;
- }
+ if (ret)
+ goto err_start;
usb_gadget_enable_async_callbacks(udc);
usb_udc_connect_control(udc);
+ mutex_unlock(&udc_lock);
kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
return 0;
-err1:
+
+ err_start:
+ driver->unbind(udc->gadget);
+
+ err_bind:
if (ret != -EISNAM)
dev_err(&udc->dev, "failed to start %s: %d\n",
- udc->driver->function, ret);
+ driver->function, ret);
+
udc->driver = NULL;
- udc->gadget->dev.driver = NULL;
+ driver->is_bound = false;
+ mutex_unlock(&udc_lock);
+
return ret;
}
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
+static void gadget_unbind_driver(struct device *dev)
{
- struct usb_udc *udc = NULL, *iter;
- int ret = -ENODEV;
+ struct usb_gadget *gadget = dev_to_usb_gadget(dev);
+ struct usb_udc *udc = gadget->udc;
+ struct usb_gadget_driver *driver = udc->driver;
+
+ dev_dbg(&udc->dev, "unbinding gadget driver [%s]\n", driver->function);
+
+ kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
+
+ mutex_lock(&udc_lock);
+ usb_gadget_disconnect(gadget);
+ usb_gadget_disable_async_callbacks(udc);
+ if (gadget->irq)
+ synchronize_irq(gadget->irq);
+ udc->driver->unbind(gadget);
+ usb_gadget_udc_stop(udc);
+
+ driver->is_bound = false;
+ udc->driver = NULL;
+ mutex_unlock(&udc_lock);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int usb_gadget_register_driver_owner(struct usb_gadget_driver *driver,
+ struct module *owner, const char *mod_name)
+{
+ int ret;
if (!driver || !driver->bind || !driver->setup)
return -EINVAL;
+ driver->driver.bus = &gadget_bus_type;
+ driver->driver.owner = owner;
+ driver->driver.mod_name = mod_name;
+ ret = driver_register(&driver->driver);
+ if (ret) {
+ pr_warn("%s: driver registration failed: %d\n",
+ driver->function, ret);
+ return ret;
+ }
+
mutex_lock(&udc_lock);
- if (driver->udc_name) {
- list_for_each_entry(iter, &udc_list, list) {
- ret = strcmp(driver->udc_name, dev_name(&iter->dev));
- if (ret)
- continue;
- udc = iter;
- break;
- }
- if (ret)
- ret = -ENODEV;
- else if (udc->driver)
+ if (!driver->is_bound) {
+ if (driver->match_existing_only) {
+ pr_warn("%s: couldn't find an available UDC or it's busy\n",
+ driver->function);
ret = -EBUSY;
- else
- goto found;
- } else {
- list_for_each_entry(iter, &udc_list, list) {
- /* For now we take the first one */
- if (iter->driver)
- continue;
- udc = iter;
- goto found;
+ } else {
+ pr_info("%s: couldn't find an available UDC\n",
+ driver->function);
+ ret = 0;
}
}
-
- if (!driver->match_existing_only) {
- list_add_tail(&driver->pending, &gadget_driver_pending_list);
- pr_info("couldn't find an available UDC - added [%s] to list of pending drivers\n",
- driver->function);
- ret = 0;
- }
-
mutex_unlock(&udc_lock);
+
if (ret)
- pr_warn("couldn't find an available UDC or it's busy: %d\n", ret);
- return ret;
-found:
- ret = udc_bind_to_driver(udc, driver);
- mutex_unlock(&udc_lock);
+ driver_unregister(&driver->driver);
return ret;
}
-EXPORT_SYMBOL_GPL(usb_gadget_probe_driver);
+EXPORT_SYMBOL_GPL(usb_gadget_register_driver_owner);
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
{
- struct usb_udc *udc = NULL;
- int ret = -ENODEV;
-
if (!driver || !driver->unbind)
return -EINVAL;
- mutex_lock(&udc_lock);
- 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);
-
- /* Maybe there is someone waiting for this UDC? */
- check_pending_gadget_drivers(udc);
- /*
- * For now we ignore bind errors as probably it's
- * not a valid reason to fail other's gadget unbind
- */
- ret = 0;
- break;
- }
- }
-
- if (ret) {
- list_del(&driver->pending);
- ret = 0;
- }
- mutex_unlock(&udc_lock);
- return ret;
+ driver_unregister(&driver->driver);
+ return 0;
}
EXPORT_SYMBOL_GPL(usb_gadget_unregister_driver);
@@ -1757,8 +1740,17 @@ static int usb_udc_uevent(struct device *dev, struct kobj_uevent_env *env)
return 0;
}
+static struct bus_type gadget_bus_type = {
+ .name = "gadget",
+ .probe = gadget_bind_driver,
+ .remove = gadget_unbind_driver,
+ .match = gadget_match_driver,
+};
+
static int __init usb_udc_init(void)
{
+ int rc;
+
udc_class = class_create(THIS_MODULE, "udc");
if (IS_ERR(udc_class)) {
pr_err("failed to create udc class --> %ld\n",
@@ -1767,12 +1759,17 @@ static int __init usb_udc_init(void)
}
udc_class->dev_uevent = usb_udc_uevent;
- return 0;
+
+ rc = bus_register(&gadget_bus_type);
+ if (rc)
+ class_destroy(udc_class);
+ return rc;
}
subsys_initcall(usb_udc_init);
static void __exit usb_udc_exit(void)
{
+ bus_unregister(&gadget_bus_type);
class_destroy(udc_class);
}
module_exit(usb_udc_exit);
diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c
index 6a8884632273..c97cd4bc817c 100644
--- a/drivers/usb/gadget/udc/net2272.c
+++ b/drivers/usb/gadget/udc/net2272.c
@@ -71,7 +71,7 @@ static ushort dma_ep = 1;
module_param(dma_ep, ushort, 0644);
/*
- * dma_mode: net2272 dma mode setting (see LOCCTL1 definiton):
+ * dma_mode: net2272 dma mode setting (see LOCCTL1 definition):
* mode 0 == Slow DREQ mode
* mode 1 == Fast DREQ mode
* mode 2 == Burst mode
@@ -97,7 +97,7 @@ module_param(fifo_mode, ushort, 0644);
/*
* enable_suspend: When enabled, the driver will respond to
* USB suspend requests by powering down the NET2272. Otherwise,
- * USB suspend requests will be ignored. This is acceptible for
+ * USB suspend requests will be ignored. This is acceptable for
* self-powered devices. For bus powered devices set this to 1.
*/
static ushort enable_suspend = 0;
@@ -288,7 +288,7 @@ static void net2272_ep_reset(struct net2272_ep *ep)
| (1 << LOCAL_OUT_ZLP)
| (1 << BUFFER_FLUSH));
- /* fifo size is handled seperately */
+ /* fifo size is handled separately */
}
static int net2272_disable(struct usb_ep *_ep)
diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c
index 051d024b369e..d6a68631354a 100644
--- a/drivers/usb/gadget/udc/net2280.c
+++ b/drivers/usb/gadget/udc/net2280.c
@@ -932,19 +932,11 @@ static void start_dma(struct net2280_ep *ep, struct net2280_request *req)
static inline void
queue_dma(struct net2280_ep *ep, struct net2280_request *req, int valid)
{
- struct net2280_dma *end;
- dma_addr_t tmp;
-
/* swap new dummy for old, link; fill and maybe activate */
- end = ep->dummy;
- ep->dummy = req->td;
- req->td = end;
-
- tmp = ep->td_dma;
- ep->td_dma = req->td_dma;
- req->td_dma = tmp;
+ swap(ep->dummy, req->td);
+ swap(ep->td_dma, req->td_dma);
- end->dmadesc = cpu_to_le32 (ep->td_dma);
+ req->td->dmadesc = cpu_to_le32 (ep->td_dma);
fill_dma_desc(ep, req, valid);
}
diff --git a/drivers/usb/gadget/udc/omap_udc.c b/drivers/usb/gadget/udc/omap_udc.c
index 5096d24915ce..61cabb9de6ae 100644
--- a/drivers/usb/gadget/udc/omap_udc.c
+++ b/drivers/usb/gadget/udc/omap_udc.c
@@ -1470,7 +1470,7 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
if (!udc->ep0_in) {
stat = 0;
/* read next OUT packet of request, maybe
- * reactiviting the fifo; stall on errors.
+ * reactivating the fifo; stall on errors.
*/
stat = read_fifo(ep0, req);
if (!req || stat < 0) {
@@ -2609,6 +2609,8 @@ static void omap_udc_release(struct device *dev)
if (udc->dc_clk) {
if (udc->clk_requested)
omap_udc_enable_clock(0);
+ clk_unprepare(udc->hhc_clk);
+ clk_unprepare(udc->dc_clk);
clk_put(udc->hhc_clk);
clk_put(udc->dc_clk);
}
@@ -2773,8 +2775,8 @@ static int omap_udc_probe(struct platform_device *pdev)
hhc_clk = clk_get(&pdev->dev, "usb_hhc_ck");
BUG_ON(IS_ERR(dc_clk) || IS_ERR(hhc_clk));
/* can't use omap_udc_enable_clock yet */
- clk_enable(dc_clk);
- clk_enable(hhc_clk);
+ clk_prepare_enable(dc_clk);
+ clk_prepare_enable(hhc_clk);
udelay(100);
}
@@ -2783,8 +2785,8 @@ static int omap_udc_probe(struct platform_device *pdev)
hhc_clk = clk_get(&pdev->dev, "l3_ocpi_ck");
BUG_ON(IS_ERR(dc_clk) || IS_ERR(hhc_clk));
/* can't use omap_udc_enable_clock yet */
- clk_enable(dc_clk);
- clk_enable(hhc_clk);
+ clk_prepare_enable(dc_clk);
+ clk_prepare_enable(hhc_clk);
udelay(100);
}
@@ -2932,8 +2934,8 @@ cleanup0:
usb_put_phy(xceiv);
if (cpu_is_omap16xx() || cpu_is_omap7xx()) {
- clk_disable(hhc_clk);
- clk_disable(dc_clk);
+ clk_disable_unprepare(hhc_clk);
+ clk_disable_unprepare(dc_clk);
clk_put(hhc_clk);
clk_put(dc_clk);
}
diff --git a/drivers/usb/gadget/udc/pxa27x_udc.h b/drivers/usb/gadget/udc/pxa27x_udc.h
index 0a6bc18a1264..31bf79ce931c 100644
--- a/drivers/usb/gadget/udc/pxa27x_udc.h
+++ b/drivers/usb/gadget/udc/pxa27x_udc.h
@@ -326,7 +326,7 @@ struct udc_usb_ep {
* @addr: usb endpoint number
* @config: configuration in which this endpoint is active
* @interface: interface in which this endpoint is active
- * @alternate: altsetting in which this endpoitn is active
+ * @alternate: altsetting in which this endpoint is active
* @fifo_size: max packet size in the endpoint fifo
* @type: endpoint type (bulk, iso, int, ...)
* @udccsr_value: save register of UDCCSR0 for suspend/resume
diff --git a/drivers/usb/gadget/udc/s3c-hsudc.c b/drivers/usb/gadget/udc/s3c-hsudc.c
index bf803e013458..4b7eb7701470 100644
--- a/drivers/usb/gadget/udc/s3c-hsudc.c
+++ b/drivers/usb/gadget/udc/s3c-hsudc.c
@@ -126,7 +126,7 @@ struct s3c_hsudc_req {
/**
* struct s3c_hsudc - Driver's abstraction of the device controller.
* @gadget: Instance of usb_gadget which is referenced by gadget driver.
- * @driver: Reference to currenty active gadget driver.
+ * @driver: Reference to currently active gadget driver.
* @dev: The device reference used by probe function.
* @lock: Lock to synchronize the usage of Endpoints (EP's are indexed).
* @regs: Remapped base address of controller's register space.
@@ -633,7 +633,7 @@ static void s3c_hsudc_process_setup(struct s3c_hsudc *hsudc)
}
/** s3c_hsudc_handle_ep0_intr - Handle endpoint 0 interrupt.
- * @hsudc: Device controller on which endpoint 0 interrupt has occured.
+ * @hsudc: Device controller on which endpoint 0 interrupt has occurred.
*
* Handle endpoint 0 interrupt when it occurs. EP0 interrupt could occur
* when a stall handshake is sent to host or data is sent/received on
diff --git a/drivers/usb/gadget/udc/tegra-xudc.c b/drivers/usb/gadget/udc/tegra-xudc.c
index d9c406bdb680..6d31ccf6aee5 100644
--- a/drivers/usb/gadget/udc/tegra-xudc.c
+++ b/drivers/usb/gadget/udc/tegra-xudc.c
@@ -1434,7 +1434,7 @@ __tegra_xudc_ep_dequeue(struct tegra_xudc_ep *ep,
return 0;
}
- /* Halt DMA for this endpiont. */
+ /* Halt DMA for this endpoint. */
if (ep_ctx_read_state(ep->context) == EP_STATE_RUNNING) {
ep_pause(xudc, ep->index);
ep_wait_for_inactive(xudc, ep->index);
@@ -3423,7 +3423,7 @@ static void tegra_xudc_device_params_init(struct tegra_xudc *xudc)
}
/*
- * Compliacne suite appears to be violating polling LFPS tBurst max
+ * Compliance suite appears to be violating polling LFPS tBurst max
* of 1.4us. Send 1.45us instead.
*/
val = xudc_readl(xudc, SSPX_CORE_CNT32);
diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c
index 428c755cf2e1..4827e3cd3834 100644
--- a/drivers/usb/gadget/udc/udc-xilinx.c
+++ b/drivers/usb/gadget/udc/udc-xilinx.c
@@ -632,7 +632,7 @@ top:
dev_dbg(udc->dev, "read %s, %d bytes%s req %p %d/%d\n",
ep->ep_usb.name, count, is_short ? "/S" : "", req,
req->usb_req.actual, req->usb_req.length);
- bufferspace -= count;
+
/* Completion */
if ((req->usb_req.actual == req->usb_req.length) || is_short) {
if (udc->dma_enabled && req->usb_req.length)