aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/gadget
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r--drivers/usb/gadget/composite.c39
-rw-r--r--drivers/usb/gadget/configfs.c39
-rw-r--r--drivers/usb/gadget/function/f_fs.c4
-rw-r--r--drivers/usb/gadget/function/f_midi.c48
-rw-r--r--drivers/usb/gadget/udc/at91_udc.c67
-rw-r--r--drivers/usb/gadget/udc/at91_udc.h8
-rw-r--r--drivers/usb/gadget/udc/bdc/bdc_core.c1
-rw-r--r--drivers/usb/gadget/udc/mv_udc_core.c4
-rw-r--r--drivers/usb/gadget/udc/udc-xilinx.c56
9 files changed, 168 insertions, 98 deletions
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 284eea9f6e4d..7dce462172cb 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -159,6 +159,8 @@ int config_ep_by_speed_and_alt(struct usb_gadget *g,
int want_comp_desc = 0;
struct usb_descriptor_header **d_spd; /* cursor for speed desc */
+ struct usb_composite_dev *cdev;
+ bool incomplete_desc = false;
if (!g || !f || !_ep)
return -EIO;
@@ -167,28 +169,43 @@ int config_ep_by_speed_and_alt(struct usb_gadget *g,
switch (g->speed) {
case USB_SPEED_SUPER_PLUS:
if (gadget_is_superspeed_plus(g)) {
- speed_desc = f->ssp_descriptors;
- want_comp_desc = 1;
- break;
+ if (f->ssp_descriptors) {
+ speed_desc = f->ssp_descriptors;
+ want_comp_desc = 1;
+ break;
+ }
+ incomplete_desc = true;
}
fallthrough;
case USB_SPEED_SUPER:
if (gadget_is_superspeed(g)) {
- speed_desc = f->ss_descriptors;
- want_comp_desc = 1;
- break;
+ if (f->ss_descriptors) {
+ speed_desc = f->ss_descriptors;
+ want_comp_desc = 1;
+ break;
+ }
+ incomplete_desc = true;
}
fallthrough;
case USB_SPEED_HIGH:
if (gadget_is_dualspeed(g)) {
- speed_desc = f->hs_descriptors;
- break;
+ if (f->hs_descriptors) {
+ speed_desc = f->hs_descriptors;
+ break;
+ }
+ incomplete_desc = true;
}
fallthrough;
default:
speed_desc = f->fs_descriptors;
}
+ cdev = get_gadget_data(g);
+ if (incomplete_desc)
+ WARNING(cdev,
+ "%s doesn't hold the descriptors for current speed\n",
+ f->name);
+
/* find correct alternate setting descriptor */
for_each_desc(speed_desc, d_spd, USB_DT_INTERFACE) {
int_desc = (struct usb_interface_descriptor *)*d_spd;
@@ -244,12 +261,8 @@ ep_found:
_ep->maxburst = comp_desc->bMaxBurst + 1;
break;
default:
- if (comp_desc->bMaxBurst != 0) {
- struct usb_composite_dev *cdev;
-
- cdev = get_gadget_data(g);
+ if (comp_desc->bMaxBurst != 0)
ERROR(cdev, "ep0 bMaxBurst must be 0\n");
- }
_ep->maxburst = 1;
break;
}
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
index 36c611d1d8d0..d4a678c0806e 100644
--- a/drivers/usb/gadget/configfs.c
+++ b/drivers/usb/gadget/configfs.c
@@ -89,10 +89,6 @@ struct gadget_strings {
struct list_head list;
};
-struct os_desc {
- struct config_group group;
-};
-
struct gadget_config_name {
struct usb_gadget_strings stringtab_dev;
struct usb_string strings;
@@ -420,9 +416,8 @@ static int config_usb_cfg_link(
struct config_usb_cfg *cfg = to_config_usb_cfg(usb_cfg_ci);
struct gadget_info *gi = cfg_to_gadget_info(cfg);
- struct config_group *group = to_config_group(usb_func_ci);
- struct usb_function_instance *fi = container_of(group,
- struct usb_function_instance, group);
+ struct usb_function_instance *fi =
+ to_usb_function_instance(usb_func_ci);
struct usb_function_instance *a_fi;
struct usb_function *f;
int ret;
@@ -470,9 +465,8 @@ static void config_usb_cfg_unlink(
struct config_usb_cfg *cfg = to_config_usb_cfg(usb_cfg_ci);
struct gadget_info *gi = cfg_to_gadget_info(cfg);
- struct config_group *group = to_config_group(usb_func_ci);
- struct usb_function_instance *fi = container_of(group,
- struct usb_function_instance, group);
+ struct usb_function_instance *fi =
+ to_usb_function_instance(usb_func_ci);
struct usb_function *f;
/*
@@ -783,15 +777,11 @@ static void gadget_strings_attr_release(struct config_item *item)
USB_CONFIG_STRING_RW_OPS(gadget_strings);
USB_CONFIG_STRINGS_LANG(gadget_strings, gadget_info);
-static inline struct os_desc *to_os_desc(struct config_item *item)
-{
- return container_of(to_config_group(item), struct os_desc, group);
-}
-
static inline struct gadget_info *os_desc_item_to_gadget_info(
struct config_item *item)
{
- return to_gadget_info(to_os_desc(item)->group.cg_item.ci_parent);
+ return container_of(to_config_group(item),
+ struct gadget_info, os_desc_group);
}
static ssize_t os_desc_use_show(struct config_item *item, char *page)
@@ -886,21 +876,12 @@ static struct configfs_attribute *os_desc_attrs[] = {
NULL,
};
-static void os_desc_attr_release(struct config_item *item)
-{
- struct os_desc *os_desc = to_os_desc(item);
- kfree(os_desc);
-}
-
static int os_desc_link(struct config_item *os_desc_ci,
struct config_item *usb_cfg_ci)
{
- struct gadget_info *gi = container_of(to_config_group(os_desc_ci),
- struct gadget_info, os_desc_group);
+ struct gadget_info *gi = os_desc_item_to_gadget_info(os_desc_ci);
struct usb_composite_dev *cdev = &gi->cdev;
- struct config_usb_cfg *c_target =
- container_of(to_config_group(usb_cfg_ci),
- struct config_usb_cfg, group);
+ struct config_usb_cfg *c_target = to_config_usb_cfg(usb_cfg_ci);
struct usb_configuration *c;
int ret;
@@ -930,8 +911,7 @@ out:
static void os_desc_unlink(struct config_item *os_desc_ci,
struct config_item *usb_cfg_ci)
{
- struct gadget_info *gi = container_of(to_config_group(os_desc_ci),
- struct gadget_info, os_desc_group);
+ struct gadget_info *gi = os_desc_item_to_gadget_info(os_desc_ci);
struct usb_composite_dev *cdev = &gi->cdev;
mutex_lock(&gi->lock);
@@ -943,7 +923,6 @@ static void os_desc_unlink(struct config_item *os_desc_ci,
}
static struct configfs_item_operations os_desc_ops = {
- .release = os_desc_attr_release,
.allow_link = os_desc_link,
.drop_link = os_desc_unlink,
};
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index e20c19a0f106..3c584da9118c 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -614,7 +614,7 @@ static int ffs_ep0_open(struct inode *inode, struct file *file)
file->private_data = ffs;
ffs_data_opened(ffs);
- return 0;
+ return stream_open(inode, file);
}
static int ffs_ep0_release(struct inode *inode, struct file *file)
@@ -1154,7 +1154,7 @@ ffs_epfile_open(struct inode *inode, struct file *file)
file->private_data = epfile;
ffs_data_opened(epfile->ffs);
- return 0;
+ return stream_open(inode, file);
}
static int ffs_aio_cancel(struct kiocb *kiocb)
diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c
index 71a1a26e85c7..fddf539008a9 100644
--- a/drivers/usb/gadget/function/f_midi.c
+++ b/drivers/usb/gadget/function/f_midi.c
@@ -1097,7 +1097,7 @@ static ssize_t f_midi_opts_##name##_show(struct config_item *item, char *page) \
int result; \
\
mutex_lock(&opts->lock); \
- result = sprintf(page, "%d\n", opts->name); \
+ result = sprintf(page, "%u\n", opts->name); \
mutex_unlock(&opts->lock); \
\
return result; \
@@ -1134,7 +1134,51 @@ end: \
\
CONFIGFS_ATTR(f_midi_opts_, name);
-F_MIDI_OPT(index, true, SNDRV_CARDS);
+#define F_MIDI_OPT_SIGNED(name, test_limit, limit) \
+static ssize_t f_midi_opts_##name##_show(struct config_item *item, char *page) \
+{ \
+ struct f_midi_opts *opts = to_f_midi_opts(item); \
+ int result; \
+ \
+ mutex_lock(&opts->lock); \
+ result = sprintf(page, "%d\n", opts->name); \
+ mutex_unlock(&opts->lock); \
+ \
+ return result; \
+} \
+ \
+static ssize_t f_midi_opts_##name##_store(struct config_item *item, \
+ const char *page, size_t len) \
+{ \
+ struct f_midi_opts *opts = to_f_midi_opts(item); \
+ int ret; \
+ s32 num; \
+ \
+ mutex_lock(&opts->lock); \
+ if (opts->refcnt > 1) { \
+ ret = -EBUSY; \
+ goto end; \
+ } \
+ \
+ ret = kstrtos32(page, 0, &num); \
+ if (ret) \
+ goto end; \
+ \
+ if (test_limit && num > limit) { \
+ ret = -EINVAL; \
+ goto end; \
+ } \
+ opts->name = num; \
+ ret = len; \
+ \
+end: \
+ mutex_unlock(&opts->lock); \
+ return ret; \
+} \
+ \
+CONFIGFS_ATTR(f_midi_opts_, name);
+
+F_MIDI_OPT_SIGNED(index, true, SNDRV_CARDS);
F_MIDI_OPT(buflen, false, 0);
F_MIDI_OPT(qlen, false, 0);
F_MIDI_OPT(in_ports, true, MAX_PORTS);
diff --git a/drivers/usb/gadget/udc/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c
index d9ad9adf7348..dd0819df096e 100644
--- a/drivers/usb/gadget/udc/at91_udc.c
+++ b/drivers/usb/gadget/udc/at91_udc.c
@@ -25,7 +25,7 @@
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/platform_data/atmel.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
@@ -1510,7 +1510,6 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc)
static void at91_vbus_update(struct at91_udc *udc, unsigned value)
{
- value ^= udc->board.vbus_active_low;
if (value != udc->vbus)
at91_vbus_session(&udc->gadget, value);
}
@@ -1521,7 +1520,7 @@ static irqreturn_t at91_vbus_irq(int irq, void *_udc)
/* vbus needs at least brief debouncing */
udelay(10);
- at91_vbus_update(udc, gpio_get_value(udc->board.vbus_pin));
+ at91_vbus_update(udc, gpiod_get_value(udc->board.vbus_pin));
return IRQ_HANDLED;
}
@@ -1531,7 +1530,7 @@ static void at91_vbus_timer_work(struct work_struct *work)
struct at91_udc *udc = container_of(work, struct at91_udc,
vbus_timer_work);
- at91_vbus_update(udc, gpio_get_value_cansleep(udc->board.vbus_pin));
+ at91_vbus_update(udc, gpiod_get_value_cansleep(udc->board.vbus_pin));
if (!timer_pending(&udc->vbus_timer))
mod_timer(&udc->vbus_timer, jiffies + VBUS_POLL_TIMEOUT);
@@ -1595,7 +1594,6 @@ static void at91udc_shutdown(struct platform_device *dev)
static int at91rm9200_udc_init(struct at91_udc *udc)
{
struct at91_ep *ep;
- int ret;
int i;
for (i = 0; i < NUM_ENDPOINTS; i++) {
@@ -1615,32 +1613,23 @@ static int at91rm9200_udc_init(struct at91_udc *udc)
}
}
- if (!gpio_is_valid(udc->board.pullup_pin)) {
+ if (!udc->board.pullup_pin) {
DBG("no D+ pullup?\n");
return -ENODEV;
}
- ret = devm_gpio_request(&udc->pdev->dev, udc->board.pullup_pin,
- "udc_pullup");
- if (ret) {
- DBG("D+ pullup is busy\n");
- return ret;
- }
-
- gpio_direction_output(udc->board.pullup_pin,
- udc->board.pullup_active_low);
+ gpiod_direction_output(udc->board.pullup_pin,
+ gpiod_is_active_low(udc->board.pullup_pin));
return 0;
}
static void at91rm9200_udc_pullup(struct at91_udc *udc, int is_on)
{
- int active = !udc->board.pullup_active_low;
-
if (is_on)
- gpio_set_value(udc->board.pullup_pin, active);
+ gpiod_set_value(udc->board.pullup_pin, 1);
else
- gpio_set_value(udc->board.pullup_pin, !active);
+ gpiod_set_value(udc->board.pullup_pin, 0);
}
static const struct at91_udc_caps at91rm9200_udc_caps = {
@@ -1783,20 +1772,20 @@ static void at91udc_of_init(struct at91_udc *udc, struct device_node *np)
{
struct at91_udc_data *board = &udc->board;
const struct of_device_id *match;
- enum of_gpio_flags flags;
u32 val;
if (of_property_read_u32(np, "atmel,vbus-polled", &val) == 0)
board->vbus_polled = 1;
- board->vbus_pin = of_get_named_gpio_flags(np, "atmel,vbus-gpio", 0,
- &flags);
- board->vbus_active_low = (flags & OF_GPIO_ACTIVE_LOW) ? 1 : 0;
+ board->vbus_pin = gpiod_get_from_of_node(np, "atmel,vbus-gpio", 0,
+ GPIOD_IN, "udc_vbus");
+ if (IS_ERR(board->vbus_pin))
+ board->vbus_pin = NULL;
- board->pullup_pin = of_get_named_gpio_flags(np, "atmel,pullup-gpio", 0,
- &flags);
-
- board->pullup_active_low = (flags & OF_GPIO_ACTIVE_LOW) ? 1 : 0;
+ board->pullup_pin = gpiod_get_from_of_node(np, "atmel,pullup-gpio", 0,
+ GPIOD_ASIS, "udc_pullup");
+ if (IS_ERR(board->pullup_pin))
+ board->pullup_pin = NULL;
match = of_match_node(at91_udc_dt_ids, np);
if (match)
@@ -1886,22 +1875,14 @@ static int at91udc_probe(struct platform_device *pdev)
goto err_unprepare_iclk;
}
- if (gpio_is_valid(udc->board.vbus_pin)) {
- retval = devm_gpio_request(dev, udc->board.vbus_pin,
- "udc_vbus");
- if (retval) {
- DBG("request vbus pin failed\n");
- goto err_unprepare_iclk;
- }
-
- gpio_direction_input(udc->board.vbus_pin);
+ if (udc->board.vbus_pin) {
+ gpiod_direction_input(udc->board.vbus_pin);
/*
* Get the initial state of VBUS - we cannot expect
* a pending interrupt.
*/
- udc->vbus = gpio_get_value_cansleep(udc->board.vbus_pin) ^
- udc->board.vbus_active_low;
+ udc->vbus = gpiod_get_value_cansleep(udc->board.vbus_pin);
if (udc->board.vbus_polled) {
INIT_WORK(&udc->vbus_timer_work, at91_vbus_timer_work);
@@ -1910,7 +1891,7 @@ static int at91udc_probe(struct platform_device *pdev)
jiffies + VBUS_POLL_TIMEOUT);
} else {
retval = devm_request_irq(dev,
- gpio_to_irq(udc->board.vbus_pin),
+ gpiod_to_irq(udc->board.vbus_pin),
at91_vbus_irq, 0, driver_name, udc);
if (retval) {
DBG("request vbus irq %d failed\n",
@@ -1988,8 +1969,8 @@ static int at91udc_suspend(struct platform_device *pdev, pm_message_t mesg)
enable_irq_wake(udc->udp_irq);
udc->active_suspend = wake;
- if (gpio_is_valid(udc->board.vbus_pin) && !udc->board.vbus_polled && wake)
- enable_irq_wake(udc->board.vbus_pin);
+ if (udc->board.vbus_pin && !udc->board.vbus_polled && wake)
+ enable_irq_wake(gpiod_to_irq(udc->board.vbus_pin));
return 0;
}
@@ -1998,9 +1979,9 @@ static int at91udc_resume(struct platform_device *pdev)
struct at91_udc *udc = platform_get_drvdata(pdev);
unsigned long flags;
- if (gpio_is_valid(udc->board.vbus_pin) && !udc->board.vbus_polled &&
+ if (udc->board.vbus_pin && !udc->board.vbus_polled &&
udc->active_suspend)
- disable_irq_wake(udc->board.vbus_pin);
+ disable_irq_wake(gpiod_to_irq(udc->board.vbus_pin));
/* maybe reconnect to host; if so, clocks on */
if (udc->active_suspend)
diff --git a/drivers/usb/gadget/udc/at91_udc.h b/drivers/usb/gadget/udc/at91_udc.h
index fd58c5b81826..28c1042f8623 100644
--- a/drivers/usb/gadget/udc/at91_udc.h
+++ b/drivers/usb/gadget/udc/at91_udc.h
@@ -109,11 +109,9 @@ struct at91_udc_caps {
};
struct at91_udc_data {
- int vbus_pin; /* high == host powering us */
- u8 vbus_active_low; /* vbus polarity */
- u8 vbus_polled; /* Use polling, not interrupt */
- int pullup_pin; /* active == D+ pulled up */
- u8 pullup_active_low; /* true == pullup_pin is active low */
+ struct gpio_desc *vbus_pin; /* high == host powering us */
+ u8 vbus_polled; /* Use polling, not interrupt */
+ struct gpio_desc *pullup_pin; /* active == D+ pulled up */
};
/*
diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c
index fa1a3908ec3b..9849e0c86e23 100644
--- a/drivers/usb/gadget/udc/bdc/bdc_core.c
+++ b/drivers/usb/gadget/udc/bdc/bdc_core.c
@@ -623,6 +623,7 @@ static int bdc_resume(struct device *dev)
ret = bdc_reinit(bdc);
if (ret) {
dev_err(bdc->dev, "err in bdc reinit\n");
+ clk_disable_unprepare(bdc->clk);
return ret;
}
diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c
index 7f24ce400b59..b6d34dda028b 100644
--- a/drivers/usb/gadget/udc/mv_udc_core.c
+++ b/drivers/usb/gadget/udc/mv_udc_core.c
@@ -2084,10 +2084,8 @@ static int mv_udc_remove(struct platform_device *pdev)
usb_del_gadget_udc(&udc->gadget);
- if (udc->qwork) {
- flush_workqueue(udc->qwork);
+ if (udc->qwork)
destroy_workqueue(udc->qwork);
- }
/* free memory allocated in probe */
dma_pool_destroy(udc->dtd_pool);
diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c
index 857159dd5ae0..6ce886fb7bfe 100644
--- a/drivers/usb/gadget/udc/udc-xilinx.c
+++ b/drivers/usb/gadget/udc/udc-xilinx.c
@@ -2179,6 +2179,61 @@ static int xudc_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int xudc_suspend(struct device *dev)
+{
+ struct xusb_udc *udc;
+ u32 crtlreg;
+ unsigned long flags;
+
+ udc = dev_get_drvdata(dev);
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ crtlreg = udc->read_fn(udc->addr + XUSB_CONTROL_OFFSET);
+ crtlreg &= ~XUSB_CONTROL_USB_READY_MASK;
+
+ udc->write_fn(udc->addr, XUSB_CONTROL_OFFSET, crtlreg);
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+ if (udc->driver && udc->driver->suspend)
+ udc->driver->suspend(&udc->gadget);
+
+ clk_disable(udc->clk);
+
+ return 0;
+}
+
+static int xudc_resume(struct device *dev)
+{
+ struct xusb_udc *udc;
+ u32 crtlreg;
+ unsigned long flags;
+ int ret;
+
+ udc = dev_get_drvdata(dev);
+
+ ret = clk_enable(udc->clk);
+ if (ret < 0)
+ return ret;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ crtlreg = udc->read_fn(udc->addr + XUSB_CONTROL_OFFSET);
+ crtlreg |= XUSB_CONTROL_USB_READY_MASK;
+
+ udc->write_fn(udc->addr, XUSB_CONTROL_OFFSET, crtlreg);
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops xudc_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(xudc_suspend, xudc_resume)
+};
+
/* Match table for of_platform binding */
static const struct of_device_id usb_of_match[] = {
{ .compatible = "xlnx,usb2-device-4.00.a", },
@@ -2190,6 +2245,7 @@ static struct platform_driver xudc_driver = {
.driver = {
.name = driver_name,
.of_match_table = usb_of_match,
+ .pm = &xudc_pm_ops,
},
.probe = xudc_probe,
.remove = xudc_remove,