diff options
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r-- | drivers/usb/gadget/composite.c | 53 | ||||
-rw-r--r-- | drivers/usb/gadget/configfs.c | 39 | ||||
-rw-r--r-- | drivers/usb/gadget/function/f_fs.c | 13 | ||||
-rw-r--r-- | drivers/usb/gadget/function/f_midi.c | 48 | ||||
-rw-r--r-- | drivers/usb/gadget/function/u_audio.c | 28 | ||||
-rw-r--r-- | drivers/usb/gadget/function/u_ether.c | 16 | ||||
-rw-r--r-- | drivers/usb/gadget/legacy/dbgp.c | 15 | ||||
-rw-r--r-- | drivers/usb/gadget/legacy/inode.c | 34 | ||||
-rw-r--r-- | drivers/usb/gadget/udc/aspeed-vhub/dev.c | 19 | ||||
-rw-r--r-- | drivers/usb/gadget/udc/aspeed-vhub/ep0.c | 7 | ||||
-rw-r--r-- | drivers/usb/gadget/udc/aspeed-vhub/hub.c | 47 | ||||
-rw-r--r-- | drivers/usb/gadget/udc/aspeed-vhub/vhub.h | 1 | ||||
-rw-r--r-- | drivers/usb/gadget/udc/at91_udc.c | 67 | ||||
-rw-r--r-- | drivers/usb/gadget/udc/at91_udc.h | 8 | ||||
-rw-r--r-- | drivers/usb/gadget/udc/bcm63xx_udc.c | 8 | ||||
-rw-r--r-- | drivers/usb/gadget/udc/bdc/bdc_core.c | 1 | ||||
-rw-r--r-- | drivers/usb/gadget/udc/mv_udc_core.c | 4 | ||||
-rw-r--r-- | drivers/usb/gadget/udc/pxa25x_udc.c | 2 | ||||
-rw-r--r-- | drivers/usb/gadget/udc/udc-xilinx.c | 61 |
19 files changed, 323 insertions, 148 deletions
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 504c1cbc255d..16f9e3423c9f 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; } @@ -1679,6 +1692,18 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) struct usb_function *f = NULL; u8 endp; + if (w_length > USB_COMP_EP0_BUFSIZ) { + if (ctrl->bRequestType & USB_DIR_IN) { + /* Cast away the const, we are going to overwrite on purpose. */ + __le16 *temp = (__le16 *)&ctrl->wLength; + + *temp = cpu_to_le16(USB_COMP_EP0_BUFSIZ); + w_length = USB_COMP_EP0_BUFSIZ; + } else { + goto done; + } + } + /* partial re-init of the response message; the function or the * gadget might need to intercept e.g. a control-OUT completion * when we delegate to it. @@ -2209,7 +2234,7 @@ int composite_dev_prepare(struct usb_composite_driver *composite, if (!cdev->req) return -ENOMEM; - cdev->req->buf = kmalloc(USB_COMP_EP0_BUFSIZ, GFP_KERNEL); + cdev->req->buf = kzalloc(USB_COMP_EP0_BUFSIZ, GFP_KERNEL); if (!cdev->req->buf) goto fail; 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..25ad1e97a458 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) @@ -1773,11 +1773,15 @@ static void ffs_data_clear(struct ffs_data *ffs) BUG_ON(ffs->gadget); - if (ffs->epfiles) + if (ffs->epfiles) { ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count); + ffs->epfiles = NULL; + } - if (ffs->ffs_eventfd) + if (ffs->ffs_eventfd) { eventfd_ctx_put(ffs->ffs_eventfd); + ffs->ffs_eventfd = NULL; + } kfree(ffs->raw_descs_data); kfree(ffs->raw_strings); @@ -1790,7 +1794,6 @@ static void ffs_data_reset(struct ffs_data *ffs) ffs_data_clear(ffs); - ffs->epfiles = NULL; ffs->raw_descs_data = NULL; ffs->raw_descs = NULL; ffs->raw_strings = NULL; 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/function/u_audio.c b/drivers/usb/gadget/function/u_audio.c index c46400be5464..4561d7a183ff 100644 --- a/drivers/usb/gadget/function/u_audio.c +++ b/drivers/usb/gadget/function/u_audio.c @@ -76,8 +76,8 @@ struct snd_uac_chip { struct snd_pcm *pcm; /* pre-calculated values for playback iso completion */ - unsigned long long p_interval_mil; unsigned long long p_residue_mil; + unsigned int p_interval; unsigned int p_framesize; }; @@ -194,21 +194,24 @@ static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req) * If there is a residue from this division, add it to the * residue accumulator. */ + unsigned long long p_interval_mil = uac->p_interval * 1000000ULL; + pitched_rate_mil = (unsigned long long) params->p_srate * prm->pitch; div_result = pitched_rate_mil; - do_div(div_result, uac->p_interval_mil); + do_div(div_result, uac->p_interval); + do_div(div_result, 1000000); frames = (unsigned int) div_result; pr_debug("p_srate %d, pitch %d, interval_mil %llu, frames %d\n", - params->p_srate, prm->pitch, uac->p_interval_mil, frames); + params->p_srate, prm->pitch, p_interval_mil, frames); p_pktsize = min_t(unsigned int, uac->p_framesize * frames, ep->maxpacket); if (p_pktsize < ep->maxpacket) { - residue_frames_mil = pitched_rate_mil - frames * uac->p_interval_mil; + residue_frames_mil = pitched_rate_mil - frames * p_interval_mil; p_pktsize_residue_mil = uac->p_framesize * residue_frames_mil; } else p_pktsize_residue_mil = 0; @@ -222,11 +225,11 @@ static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req) * size and decrease the accumulator. */ div_result = uac->p_residue_mil; - do_div(div_result, uac->p_interval_mil); + do_div(div_result, uac->p_interval); + do_div(div_result, 1000000); if ((unsigned int) div_result >= uac->p_framesize) { req->length += uac->p_framesize; - uac->p_residue_mil -= uac->p_framesize * - uac->p_interval_mil; + uac->p_residue_mil -= uac->p_framesize * p_interval_mil; pr_debug("increased req length to %d\n", req->length); } pr_debug("remains uac->p_residue_mil %llu\n", uac->p_residue_mil); @@ -591,7 +594,7 @@ int u_audio_start_playback(struct g_audio *audio_dev) unsigned int factor; const struct usb_endpoint_descriptor *ep_desc; int req_len, i; - unsigned int p_interval, p_pktsize; + unsigned int p_pktsize; ep = audio_dev->in_ep; prm = &uac->p_prm; @@ -612,11 +615,10 @@ int u_audio_start_playback(struct g_audio *audio_dev) /* pre-compute some values for iso_complete() */ uac->p_framesize = params->p_ssize * num_channels(params->p_chmask); - p_interval = factor / (1 << (ep_desc->bInterval - 1)); - uac->p_interval_mil = (unsigned long long) p_interval * 1000000; + uac->p_interval = factor / (1 << (ep_desc->bInterval - 1)); p_pktsize = min_t(unsigned int, uac->p_framesize * - (params->p_srate / p_interval), + (params->p_srate / uac->p_interval), ep->maxpacket); req_len = p_pktsize; @@ -1145,7 +1147,7 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name, } kctl->id.device = pcm->device; - kctl->id.subdevice = i; + kctl->id.subdevice = 0; err = snd_ctl_add(card, kctl); if (err < 0) @@ -1168,7 +1170,7 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name, } kctl->id.device = pcm->device; - kctl->id.subdevice = i; + kctl->id.subdevice = 0; kctl->tlv.c = u_audio_volume_tlv; diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index e0ad5aed6ac9..6f5d45ef2e39 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -17,6 +17,7 @@ #include <linux/etherdevice.h> #include <linux/ethtool.h> #include <linux/if_vlan.h> +#include <linux/etherdevice.h> #include "u_ether.h" @@ -863,19 +864,23 @@ int gether_register_netdev(struct net_device *net) { struct eth_dev *dev; struct usb_gadget *g; - struct sockaddr sa; int status; if (!net->dev.parent) return -EINVAL; dev = netdev_priv(net); g = dev->gadget; + + net->addr_assign_type = NET_ADDR_RANDOM; + eth_hw_addr_set(net, dev->dev_mac); + status = register_netdev(net); if (status < 0) { dev_dbg(&g->dev, "register_netdev failed, %d\n", status); return status; } else { INFO(dev, "HOST MAC %pM\n", dev->host_mac); + INFO(dev, "MAC %pM\n", dev->dev_mac); /* two kinds of host-initiated state changes: * - iff DATA transfer is active, carrier is "on" @@ -883,15 +888,6 @@ int gether_register_netdev(struct net_device *net) */ netif_carrier_off(net); } - sa.sa_family = net->type; - memcpy(sa.sa_data, dev->dev_mac, ETH_ALEN); - rtnl_lock(); - status = dev_set_mac_address(net, &sa, NULL); - rtnl_unlock(); - if (status) - pr_warn("cannot set self ethernet address: %d\n", status); - else - INFO(dev, "MAC %pM\n", dev->dev_mac); return status; } diff --git a/drivers/usb/gadget/legacy/dbgp.c b/drivers/usb/gadget/legacy/dbgp.c index e1d566c9918a..6bcbad382580 100644 --- a/drivers/usb/gadget/legacy/dbgp.c +++ b/drivers/usb/gadget/legacy/dbgp.c @@ -137,7 +137,7 @@ static int dbgp_enable_ep_req(struct usb_ep *ep) goto fail_1; } - req->buf = kmalloc(DBGP_REQ_LEN, GFP_KERNEL); + req->buf = kzalloc(DBGP_REQ_LEN, GFP_KERNEL); if (!req->buf) { err = -ENOMEM; stp = 2; @@ -345,6 +345,19 @@ static int dbgp_setup(struct usb_gadget *gadget, void *data = NULL; u16 len = 0; + if (length > DBGP_REQ_LEN) { + if (ctrl->bRequestType & USB_DIR_IN) { + /* Cast away the const, we are going to overwrite on purpose. */ + __le16 *temp = (__le16 *)&ctrl->wLength; + + *temp = cpu_to_le16(DBGP_REQ_LEN); + length = DBGP_REQ_LEN; + } else { + return err; + } + } + + if (request == USB_REQ_GET_DESCRIPTOR) { switch (value>>8) { case USB_DT_DEVICE: diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c index 78be94750232..51f9d96827b1 100644 --- a/drivers/usb/gadget/legacy/inode.c +++ b/drivers/usb/gadget/legacy/inode.c @@ -110,6 +110,8 @@ enum ep0_state { /* enough for the whole queue: most events invalidate others */ #define N_EVENT 5 +#define RBUF_SIZE 256 + struct dev_data { spinlock_t lock; refcount_t count; @@ -144,7 +146,7 @@ struct dev_data { struct dentry *dentry; /* except this scratch i/o buffer for ep0 */ - u8 rbuf [256]; + u8 rbuf[RBUF_SIZE]; }; static inline void get_dev (struct dev_data *data) @@ -1240,7 +1242,7 @@ out: return mask; } -static long dev_ioctl (struct file *fd, unsigned code, unsigned long value) +static long gadget_dev_ioctl (struct file *fd, unsigned code, unsigned long value) { struct dev_data *dev = fd->private_data; struct usb_gadget *gadget = dev->gadget; @@ -1331,6 +1333,18 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) u16 w_value = le16_to_cpu(ctrl->wValue); u16 w_length = le16_to_cpu(ctrl->wLength); + if (w_length > RBUF_SIZE) { + if (ctrl->bRequestType & USB_DIR_IN) { + /* Cast away the const, we are going to overwrite on purpose. */ + __le16 *temp = (__le16 *)&ctrl->wLength; + + *temp = cpu_to_le16(RBUF_SIZE); + w_length = RBUF_SIZE; + } else { + return value; + } + } + spin_lock (&dev->lock); dev->setup_abort = 0; if (dev->state == STATE_DEV_UNCONNECTED) { @@ -1812,8 +1826,9 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) spin_lock_irq (&dev->lock); value = -EINVAL; if (dev->buf) { + spin_unlock_irq(&dev->lock); kfree(kbuf); - goto fail; + return value; } dev->buf = kbuf; @@ -1860,8 +1875,8 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) value = usb_gadget_probe_driver(&gadgetfs_driver); if (value != 0) { - kfree (dev->buf); - dev->buf = NULL; + spin_lock_irq(&dev->lock); + goto fail; } else { /* at this point "good" hardware has for the first time * let the USB the host see us. alternatively, if users @@ -1878,6 +1893,9 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) return value; fail: + dev->config = NULL; + dev->hs_config = NULL; + dev->dev = NULL; spin_unlock_irq (&dev->lock); pr_debug ("%s: %s fail %zd, %p\n", shortname, __func__, value, dev); kfree (dev->buf); @@ -1886,7 +1904,7 @@ fail: } static int -dev_open (struct inode *inode, struct file *fd) +gadget_dev_open (struct inode *inode, struct file *fd) { struct dev_data *dev = inode->i_private; int value = -EBUSY; @@ -1906,12 +1924,12 @@ dev_open (struct inode *inode, struct file *fd) static const struct file_operations ep0_operations = { .llseek = no_llseek, - .open = dev_open, + .open = gadget_dev_open, .read = ep0_read, .write = dev_config, .fasync = ep0_fasync, .poll = ep0_poll, - .unlocked_ioctl = dev_ioctl, + .unlocked_ioctl = gadget_dev_ioctl, .release = dev_release, }; diff --git a/drivers/usb/gadget/udc/aspeed-vhub/dev.c b/drivers/usb/gadget/udc/aspeed-vhub/dev.c index d918e8b2af3c..b0dfca43fbdc 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/dev.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/dev.c @@ -110,15 +110,26 @@ static int ast_vhub_dev_feature(struct ast_vhub_dev *d, u16 wIndex, u16 wValue, bool is_set) { + u32 val; + DDBG(d, "%s_FEATURE(dev val=%02x)\n", is_set ? "SET" : "CLEAR", wValue); - if (wValue != USB_DEVICE_REMOTE_WAKEUP) - return std_req_driver; + if (wValue == USB_DEVICE_REMOTE_WAKEUP) { + d->wakeup_en = is_set; + return std_req_complete; + } - d->wakeup_en = is_set; + if (wValue == USB_DEVICE_TEST_MODE) { + val = readl(d->vhub->regs + AST_VHUB_CTRL); + val &= ~GENMASK(10, 8); + val |= VHUB_CTRL_SET_TEST_MODE((wIndex >> 8) & 0x7); + writel(val, d->vhub->regs + AST_VHUB_CTRL); - return std_req_complete; + return std_req_complete; + } + + return std_req_driver; } static int ast_vhub_ep_feature(struct ast_vhub_dev *d, diff --git a/drivers/usb/gadget/udc/aspeed-vhub/ep0.c b/drivers/usb/gadget/udc/aspeed-vhub/ep0.c index 74ea36c19b1e..b4cf46249fea 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/ep0.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/ep0.c @@ -251,6 +251,13 @@ static void ast_vhub_ep0_do_receive(struct ast_vhub_ep *ep, struct ast_vhub_req len = remain; rc = -EOVERFLOW; } + + /* Hardware return wrong data len */ + if (len < ep->ep.maxpacket && len != remain) { + EPDBG(ep, "using expected data len instead\n"); + len = remain; + } + if (len && req->req.buf) memcpy(req->req.buf + req->req.actual, ep->buf, len); req->req.actual += len; diff --git a/drivers/usb/gadget/udc/aspeed-vhub/hub.c b/drivers/usb/gadget/udc/aspeed-vhub/hub.c index b9960fdd8a51..65cd4e46f031 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/hub.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/hub.c @@ -68,6 +68,18 @@ static const struct usb_device_descriptor ast_vhub_dev_desc = { .bNumConfigurations = 1, }; +static const struct usb_qualifier_descriptor ast_vhub_qual_desc = { + .bLength = 0xA, + .bDescriptorType = USB_DT_DEVICE_QUALIFIER, + .bcdUSB = cpu_to_le16(0x0200), + .bDeviceClass = USB_CLASS_HUB, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = 64, + .bNumConfigurations = 1, + .bRESERVED = 0, +}; + /* * Configuration descriptor: same comments as above * regarding handling USB1 mode. @@ -200,17 +212,28 @@ static int ast_vhub_hub_dev_feature(struct ast_vhub_ep *ep, u16 wIndex, u16 wValue, bool is_set) { + u32 val; + EPDBG(ep, "%s_FEATURE(dev val=%02x)\n", is_set ? "SET" : "CLEAR", wValue); - if (wValue != USB_DEVICE_REMOTE_WAKEUP) - return std_req_stall; + if (wValue == USB_DEVICE_REMOTE_WAKEUP) { + ep->vhub->wakeup_en = is_set; + EPDBG(ep, "Hub remote wakeup %s\n", + is_set ? "enabled" : "disabled"); + return std_req_complete; + } - ep->vhub->wakeup_en = is_set; - EPDBG(ep, "Hub remote wakeup %s\n", - is_set ? "enabled" : "disabled"); + if (wValue == USB_DEVICE_TEST_MODE) { + val = readl(ep->vhub->regs + AST_VHUB_CTRL); + val &= ~GENMASK(10, 8); + val |= VHUB_CTRL_SET_TEST_MODE((wIndex >> 8) & 0x7); + writel(val, ep->vhub->regs + AST_VHUB_CTRL); - return std_req_complete; + return std_req_complete; + } + + return std_req_stall; } static int ast_vhub_hub_ep_feature(struct ast_vhub_ep *ep, @@ -271,9 +294,11 @@ static int ast_vhub_rep_desc(struct ast_vhub_ep *ep, BUILD_BUG_ON(dsize > sizeof(vhub->vhub_dev_desc)); BUILD_BUG_ON(USB_DT_DEVICE_SIZE >= AST_VHUB_EP0_MAX_PACKET); break; + case USB_DT_OTHER_SPEED_CONFIG: case USB_DT_CONFIG: dsize = AST_VHUB_CONF_DESC_SIZE; memcpy(ep->buf, &vhub->vhub_conf_desc, dsize); + ((u8 *)ep->buf)[1] = desc_type; BUILD_BUG_ON(dsize > sizeof(vhub->vhub_conf_desc)); BUILD_BUG_ON(AST_VHUB_CONF_DESC_SIZE >= AST_VHUB_EP0_MAX_PACKET); break; @@ -283,6 +308,10 @@ static int ast_vhub_rep_desc(struct ast_vhub_ep *ep, BUILD_BUG_ON(dsize > sizeof(vhub->vhub_hub_desc)); BUILD_BUG_ON(AST_VHUB_HUB_DESC_SIZE >= AST_VHUB_EP0_MAX_PACKET); break; + case USB_DT_DEVICE_QUALIFIER: + dsize = sizeof(vhub->vhub_qual_desc); + memcpy(ep->buf, &vhub->vhub_qual_desc, dsize); + break; default: return std_req_stall; } @@ -428,6 +457,8 @@ enum std_req_rc ast_vhub_std_hub_request(struct ast_vhub_ep *ep, switch (wValue >> 8) { case USB_DT_DEVICE: case USB_DT_CONFIG: + case USB_DT_DEVICE_QUALIFIER: + case USB_DT_OTHER_SPEED_CONFIG: return ast_vhub_rep_desc(ep, wValue >> 8, wLength); case USB_DT_STRING: @@ -1033,6 +1064,10 @@ static int ast_vhub_init_desc(struct ast_vhub *vhub) else ret = ast_vhub_str_alloc_add(vhub, &ast_vhub_strings); + /* Initialize vhub Qualifier Descriptor. */ + memcpy(&vhub->vhub_qual_desc, &ast_vhub_qual_desc, + sizeof(vhub->vhub_qual_desc)); + return ret; } diff --git a/drivers/usb/gadget/udc/aspeed-vhub/vhub.h b/drivers/usb/gadget/udc/aspeed-vhub/vhub.h index 87a5dea12d3c..6b9dfa6e10eb 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/vhub.h +++ b/drivers/usb/gadget/udc/aspeed-vhub/vhub.h @@ -425,6 +425,7 @@ struct ast_vhub { struct ast_vhub_full_cdesc vhub_conf_desc; struct usb_hub_descriptor vhub_hub_desc; struct list_head vhub_str_desc; + struct usb_qualifier_descriptor vhub_qual_desc; }; /* Standard request handlers result codes */ 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/bcm63xx_udc.c b/drivers/usb/gadget/udc/bcm63xx_udc.c index a9f07c59fc37..2cdb07905bde 100644 --- a/drivers/usb/gadget/udc/bcm63xx_udc.c +++ b/drivers/usb/gadget/udc/bcm63xx_udc.c @@ -2321,8 +2321,10 @@ static int bcm63xx_udc_probe(struct platform_device *pdev) /* IRQ resource #0: control interrupt (VBUS, speed, etc.) */ irq = platform_get_irq(pdev, 0); - if (irq < 0) + if (irq < 0) { + rc = irq; goto out_uninit; + } if (devm_request_irq(dev, irq, &bcm63xx_udc_ctrl_isr, 0, dev_name(dev), udc) < 0) goto report_request_failure; @@ -2330,8 +2332,10 @@ static int bcm63xx_udc_probe(struct platform_device *pdev) /* IRQ resources #1-6: data interrupts for IUDMA channels 0-5 */ for (i = 0; i < BCM63XX_NUM_IUDMA; i++) { irq = platform_get_irq(pdev, i + 1); - if (irq < 0) + if (irq < 0) { + rc = irq; goto out_uninit; + } if (devm_request_irq(dev, irq, &bcm63xx_udc_data_isr, 0, dev_name(dev), &udc->iudma[i]) < 0) goto report_request_failure; 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/pxa25x_udc.c b/drivers/usb/gadget/udc/pxa25x_udc.c index 52cdfd8212d6..b38747fd3bb0 100644 --- a/drivers/usb/gadget/udc/pxa25x_udc.c +++ b/drivers/usb/gadget/udc/pxa25x_udc.c @@ -2364,7 +2364,7 @@ static int pxa25x_udc_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) - return -ENODEV; + return irq; dev->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(dev->regs)) diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c index f5ca670776a3..6ce886fb7bfe 100644 --- a/drivers/usb/gadget/udc/udc-xilinx.c +++ b/drivers/usb/gadget/udc/udc-xilinx.c @@ -2136,7 +2136,7 @@ static int xudc_probe(struct platform_device *pdev) ret = usb_add_gadget_udc(&pdev->dev, &udc->gadget); if (ret) - goto fail; + goto err_disable_unprepare_clk; udc->dev = &udc->gadget.dev; @@ -2155,6 +2155,9 @@ static int xudc_probe(struct platform_device *pdev) udc->dma_enabled ? "with DMA" : "without DMA"); return 0; + +err_disable_unprepare_clk: + clk_disable_unprepare(udc->clk); fail: dev_err(&pdev->dev, "probe failed, %d\n", ret); return ret; @@ -2176,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", }, @@ -2187,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, |