diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2020-05-25 14:28:20 +0300 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2020-05-25 14:28:20 +0300 |
commit | ca681aa49200422a4144ee376a2079a9f717bf11 (patch) | |
tree | de603ed4c5463ebdccc1841685209267b7b7a046 /drivers/usb/gadget | |
parent | 14f3a5ccacdb4268764474d834ee353219dbd1a2 (diff) | |
parent | 1c11e74e9079289d8aaccc34b74cbf6463c0b791 (diff) | |
download | linux-ca681aa49200422a4144ee376a2079a9f717bf11.tar.xz |
Merge tag 'usb-for-v5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next
Felipe writes:
USB: changes for v5.8 merge window
Rather busy cycle. We have a total 99 non-merge commits going into v5.8
merge window. The majority of the changes are in dwc3 this around (31.7%
of all changes). It's composed mostly Thinh's recent updates to get dwc3
to behave correctly with stream transfers. We have also have Roger's for
Keystone platforms and Neil's updates for the meson glue layer.
Apart from those, we have the usual set of non-critical fixes, new
device IDs, spelling fixes all over the place.
Signed-off-by: Felipe Balbi <balbi@kernel.org>
* tag 'usb-for-v5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb: (99 commits)
usb: dwc3: keystone: Turn on USB3 PHY before controller
dt-bindings: usb: ti,keystone-dwc3.yaml: Add USB3.0 PHY property
dt-bindings: usb: convert keystone-usb.txt to YAML
usb: dwc3: gadget: Check for prepared TRBs
usb: gadget: Fix issue with config_ep_by_speed function
usb: cdns3: ep0: delete the redundant status stage
usb: dwc2: Update Core Reset programming flow.
usb: gadget: fsl: Fix a wrong judgment in fsl_udc_probe()
usb: gadget: fix potential double-free in m66592_probe.
usb: cdns3: Fix runtime PM imbalance on error
usb: gadget: lpc32xx_udc: don't dereference ep pointer before null check
usb: dwc3: Increase timeout for CmdAct cleared by device controller
USB: dummy-hcd: use configurable endpoint naming scheme
usb: cdns3: gadget: assign interrupt number to USB gadget structure
usb: gadget: core: sync interrupt before unbind the udc
arm64: dts: qcom: sc7180: Add interconnect properties for USB
arm64: dts: qcom: sdm845: Add interconnect properties for USB
dt-bindings: usb: qcom,dwc3: Introduce interconnect properties for Qualcomm DWC3 driver
ARM: dts: at91: Remove the USB EP child node
dt-bindings: usb: atmel: Mark EP child node as deprecated
...
Diffstat (limited to 'drivers/usb/gadget')
54 files changed, 701 insertions, 248 deletions
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index cb4950cf1cdc..5c1eb96a5c57 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -96,40 +96,43 @@ function_descriptors(struct usb_function *f, } /** - * next_ep_desc() - advance to the next EP descriptor + * next_desc() - advance to the next desc_type descriptor * @t: currect pointer within descriptor array + * @desc_type: descriptor type * - * Return: next EP descriptor or NULL + * Return: next desc_type descriptor or NULL * - * Iterate over @t until either EP descriptor found or + * Iterate over @t until either desc_type descriptor found or * NULL (that indicates end of list) encountered */ static struct usb_descriptor_header** -next_ep_desc(struct usb_descriptor_header **t) +next_desc(struct usb_descriptor_header **t, u8 desc_type) { for (; *t; t++) { - if ((*t)->bDescriptorType == USB_DT_ENDPOINT) + if ((*t)->bDescriptorType == desc_type) return t; } return NULL; } /* - * for_each_ep_desc()- iterate over endpoint descriptors in the - * descriptors list - * @start: pointer within descriptor array. - * @ep_desc: endpoint descriptor to use as the loop cursor + * for_each_desc() - iterate over desc_type descriptors in the + * descriptors list + * @start: pointer within descriptor array. + * @iter_desc: desc_type descriptor to use as the loop cursor + * @desc_type: wanted descriptr type */ -#define for_each_ep_desc(start, ep_desc) \ - for (ep_desc = next_ep_desc(start); \ - ep_desc; ep_desc = next_ep_desc(ep_desc+1)) +#define for_each_desc(start, iter_desc, desc_type) \ + for (iter_desc = next_desc(start, desc_type); \ + iter_desc; iter_desc = next_desc(iter_desc + 1, desc_type)) /** - * config_ep_by_speed() - configures the given endpoint + * config_ep_by_speed_and_alt() - configures the given endpoint * according to gadget speed. * @g: pointer to the gadget * @f: usb function * @_ep: the endpoint to configure + * @alt: alternate setting number * * Return: error code, 0 on success * @@ -142,11 +145,13 @@ next_ep_desc(struct usb_descriptor_header **t) * Note: the supplied function should hold all the descriptors * for supported speeds */ -int config_ep_by_speed(struct usb_gadget *g, - struct usb_function *f, - struct usb_ep *_ep) +int config_ep_by_speed_and_alt(struct usb_gadget *g, + struct usb_function *f, + struct usb_ep *_ep, + u8 alt) { struct usb_endpoint_descriptor *chosen_desc = NULL; + struct usb_interface_descriptor *int_desc = NULL; struct usb_descriptor_header **speed_desc = NULL; struct usb_ss_ep_comp_descriptor *comp_desc = NULL; @@ -182,8 +187,21 @@ int config_ep_by_speed(struct usb_gadget *g, default: speed_desc = f->fs_descriptors; } + + /* find correct alternate setting descriptor */ + for_each_desc(speed_desc, d_spd, USB_DT_INTERFACE) { + int_desc = (struct usb_interface_descriptor *)*d_spd; + + if (int_desc->bAlternateSetting == alt) { + speed_desc = d_spd; + goto intf_found; + } + } + return -EIO; + +intf_found: /* find descriptors */ - for_each_ep_desc(speed_desc, d_spd) { + for_each_desc(speed_desc, d_spd, USB_DT_ENDPOINT) { chosen_desc = (struct usb_endpoint_descriptor *)*d_spd; if (chosen_desc->bEndpointAddress == _ep->address) goto ep_found; @@ -237,6 +255,32 @@ ep_found: } return 0; } +EXPORT_SYMBOL_GPL(config_ep_by_speed_and_alt); + +/** + * config_ep_by_speed() - configures the given endpoint + * according to gadget speed. + * @g: pointer to the gadget + * @f: usb function + * @_ep: the endpoint to configure + * + * Return: error code, 0 on success + * + * This function chooses the right descriptors for a given + * endpoint according to gadget speed and saves it in the + * endpoint desc field. If the endpoint already has a descriptor + * assigned to it - overwrites it with currently corresponding + * descriptor. The endpoint maxpacket field is updated according + * to the chosen descriptor. + * Note: the supplied function should hold all the descriptors + * for supported speeds + */ +int config_ep_by_speed(struct usb_gadget *g, + struct usb_function *f, + struct usb_ep *_ep) +{ + return config_ep_by_speed_and_alt(g, f, _ep, 0); +} EXPORT_SYMBOL_GPL(config_ep_by_speed); /** diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 6a9aa4413d64..9dc06a4e1b30 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -13,8 +13,6 @@ int check_user_usb_string(const char *name, struct usb_gadget_strings *stringtab_dev) { - unsigned primary_lang; - unsigned sub_lang; u16 num; int ret; @@ -22,17 +20,7 @@ int check_user_usb_string(const char *name, if (ret) return ret; - primary_lang = num & 0x3ff; - sub_lang = num >> 10; - - /* simple sanity check for valid langid */ - switch (primary_lang) { - case 0: - case 0x62 ... 0xfe: - case 0x100 ... 0x3ff: - return -EINVAL; - } - if (!sub_lang) + if (!usb_validate_langid(num)) return -EINVAL; stringtab_dev->language = num; diff --git a/drivers/usb/gadget/function/f_acm.c b/drivers/usb/gadget/function/f_acm.c index 7c152c28b26c..200596ea9557 100644 --- a/drivers/usb/gadget/function/f_acm.c +++ b/drivers/usb/gadget/function/f_acm.c @@ -723,6 +723,20 @@ static void acm_free_func(struct usb_function *f) kfree(acm); } +static void acm_resume(struct usb_function *f) +{ + struct f_acm *acm = func_to_acm(f); + + gserial_resume(&acm->port); +} + +static void acm_suspend(struct usb_function *f) +{ + struct f_acm *acm = func_to_acm(f); + + gserial_suspend(&acm->port); +} + static struct usb_function *acm_alloc_func(struct usb_function_instance *fi) { struct f_serial_opts *opts; @@ -750,6 +764,8 @@ static struct usb_function *acm_alloc_func(struct usb_function_instance *fi) acm->port_num = opts->port_num; acm->port.func.unbind = acm_unbind; acm->port.func.free_func = acm_free_func; + acm->port.func.resume = acm_resume; + acm->port.func.suspend = acm_suspend; return &acm->port.func; } diff --git a/drivers/usb/gadget/function/f_eem.c b/drivers/usb/gadget/function/f_eem.c index b81a91d504bd..cfcc4e81fb77 100644 --- a/drivers/usb/gadget/function/f_eem.c +++ b/drivers/usb/gadget/function/f_eem.c @@ -291,8 +291,6 @@ static int eem_bind(struct usb_configuration *c, struct usb_function *f) goto fail; eem->port.out_ep = ep; - status = -ENOMEM; - /* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at * both speeds diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 10f01f974f67..494f853f2206 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -2508,7 +2508,7 @@ static int __ffs_data_got_descs(struct ffs_data *ffs, os_descs_count = get_unaligned_le32(data); data += 4; len -= 4; - }; + } /* Read descriptors */ raw_descs = data; diff --git a/drivers/usb/gadget/function/f_serial.c b/drivers/usb/gadget/function/f_serial.c index 1406255d0865..e62713846350 100644 --- a/drivers/usb/gadget/function/f_serial.c +++ b/drivers/usb/gadget/function/f_serial.c @@ -348,6 +348,20 @@ static void gser_unbind(struct usb_configuration *c, struct usb_function *f) usb_free_all_descriptors(f); } +static void gser_resume(struct usb_function *f) +{ + struct f_gser *gser = func_to_gser(f); + + gserial_resume(&gser->port); +} + +static void gser_suspend(struct usb_function *f) +{ + struct f_gser *gser = func_to_gser(f); + + gserial_suspend(&gser->port); +} + static struct usb_function *gser_alloc(struct usb_function_instance *fi) { struct f_gser *gser; @@ -369,6 +383,8 @@ static struct usb_function *gser_alloc(struct usb_function_instance *fi) gser->port.func.set_alt = gser_set_alt; gser->port.func.disable = gser_disable; gser->port.func.free_func = gser_free; + gser->port.func.resume = gser_resume; + gser->port.func.suspend = gser_suspend; return &gser->port.func; } diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c index 36504931b2d1..2979cbe4d95f 100644 --- a/drivers/usb/gadget/function/f_tcm.c +++ b/drivers/usb/gadget/function/f_tcm.c @@ -531,6 +531,7 @@ static int uasp_prepare_r_request(struct usbg_cmd *cmd) stream->req_in->sg = se_cmd->t_data_sg; } + stream->req_in->is_last = 1; stream->req_in->complete = uasp_status_data_cmpl; stream->req_in->length = se_cmd->data_length; stream->req_in->context = cmd; @@ -554,6 +555,7 @@ static void uasp_prepare_status(struct usbg_cmd *cmd) */ iu->len = cpu_to_be16(se_cmd->scsi_sense_length); iu->status = se_cmd->scsi_status; + stream->req_status->is_last = 1; stream->req_status->context = cmd; stream->req_status->length = se_cmd->scsi_sense_length + 16; stream->req_status->buf = iu; @@ -991,6 +993,7 @@ static int usbg_prepare_w_request(struct usbg_cmd *cmd, struct usb_request *req) req->sg = se_cmd->t_data_sg; } + req->is_last = 1; req->complete = usbg_data_write_cmpl; req->length = se_cmd->data_length; req->context = cmd; diff --git a/drivers/usb/gadget/function/f_uvc.h b/drivers/usb/gadget/function/f_uvc.h index a81a17765558..1db972d4beeb 100644 --- a/drivers/usb/gadget/function/f_uvc.h +++ b/drivers/usb/gadget/function/f_uvc.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * f_uvc.h -- USB Video Class Gadget driver * diff --git a/drivers/usb/gadget/function/rndis.h b/drivers/usb/gadget/function/rndis.h index c7e3a70ce6c1..f6167f7fea82 100644 --- a/drivers/usb/gadget/function/rndis.h +++ b/drivers/usb/gadget/function/rndis.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * RNDIS Definitions for Remote NDIS * diff --git a/drivers/usb/gadget/function/u_audio.h b/drivers/usb/gadget/function/u_audio.h index 81d3d4ed6dfb..5ea6b86f1fda 100644 --- a/drivers/usb/gadget/function/u_audio.h +++ b/drivers/usb/gadget/function/u_audio.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * u_audio.h -- interface to USB gadget "ALSA sound card" utilities * diff --git a/drivers/usb/gadget/function/u_ecm.h b/drivers/usb/gadget/function/u_ecm.h index 098ece573a5e..77cfb89932be 100644 --- a/drivers/usb/gadget/function/u_ecm.h +++ b/drivers/usb/gadget/function/u_ecm.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * u_ecm.h * diff --git a/drivers/usb/gadget/function/u_eem.h b/drivers/usb/gadget/function/u_eem.h index 921386a375cf..3bd85dfcd71c 100644 --- a/drivers/usb/gadget/function/u_eem.h +++ b/drivers/usb/gadget/function/u_eem.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * u_eem.h * diff --git a/drivers/usb/gadget/function/u_ether.h b/drivers/usb/gadget/function/u_ether.h index 332307d54292..10dd640684e2 100644 --- a/drivers/usb/gadget/function/u_ether.h +++ b/drivers/usb/gadget/function/u_ether.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * u_ether.h -- interface to USB gadget "ethernet link" utilities * diff --git a/drivers/usb/gadget/function/u_ether_configfs.h b/drivers/usb/gadget/function/u_ether_configfs.h index d8b92485b727..bd92b5703013 100644 --- a/drivers/usb/gadget/function/u_ether_configfs.h +++ b/drivers/usb/gadget/function/u_ether_configfs.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * u_ether_configfs.h * diff --git a/drivers/usb/gadget/function/u_fs.h b/drivers/usb/gadget/function/u_fs.h index f9b0cf67360d..f102ec23f3af 100644 --- a/drivers/usb/gadget/function/u_fs.h +++ b/drivers/usb/gadget/function/u_fs.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * u_fs.h * diff --git a/drivers/usb/gadget/function/u_gether.h b/drivers/usb/gadget/function/u_gether.h index ce4f07626f96..2f7a373ed449 100644 --- a/drivers/usb/gadget/function/u_gether.h +++ b/drivers/usb/gadget/function/u_gether.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * u_gether.h * diff --git a/drivers/usb/gadget/function/u_hid.h b/drivers/usb/gadget/function/u_hid.h index 1594bfa312eb..84e6da302499 100644 --- a/drivers/usb/gadget/function/u_hid.h +++ b/drivers/usb/gadget/function/u_hid.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * u_hid.h * diff --git a/drivers/usb/gadget/function/u_midi.h b/drivers/usb/gadget/function/u_midi.h index 29bf006c0a13..f6e14af7f566 100644 --- a/drivers/usb/gadget/function/u_midi.h +++ b/drivers/usb/gadget/function/u_midi.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * u_midi.h * diff --git a/drivers/usb/gadget/function/u_ncm.h b/drivers/usb/gadget/function/u_ncm.h index 70da3201a1d0..5408854d8407 100644 --- a/drivers/usb/gadget/function/u_ncm.h +++ b/drivers/usb/gadget/function/u_ncm.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * u_ncm.h * diff --git a/drivers/usb/gadget/function/u_phonet.h b/drivers/usb/gadget/function/u_phonet.h index 12fb613f85d1..c53233b37192 100644 --- a/drivers/usb/gadget/function/u_phonet.h +++ b/drivers/usb/gadget/function/u_phonet.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * u_phonet.h - interface to Phonet * diff --git a/drivers/usb/gadget/function/u_printer.h b/drivers/usb/gadget/function/u_printer.h index 78797764f478..318205fb778e 100644 --- a/drivers/usb/gadget/function/u_printer.h +++ b/drivers/usb/gadget/function/u_printer.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * u_printer.h * diff --git a/drivers/usb/gadget/function/u_rndis.h b/drivers/usb/gadget/function/u_rndis.h index 1e148b76f339..a8c409b2f52f 100644 --- a/drivers/usb/gadget/function/u_rndis.h +++ b/drivers/usb/gadget/function/u_rndis.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * u_rndis.h * diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index 8167d379e115..3cfc6e2eba71 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -120,6 +120,8 @@ struct gs_port { wait_queue_head_t drain_wait; /* wait while writes drain */ bool write_busy; wait_queue_head_t close_wait; + bool suspended; /* port suspended */ + bool start_delayed; /* delay start when suspended */ /* REVISIT this state ... */ struct usb_cdc_line_coding port_line_coding; /* 8-N-1 etc */ @@ -630,13 +632,19 @@ static int gs_open(struct tty_struct *tty, struct file *file) /* if connected, start the I/O stream */ if (port->port_usb) { - struct gserial *gser = port->port_usb; - - pr_debug("gs_open: start ttyGS%d\n", port->port_num); - gs_start_io(port); - - if (gser->connect) - gser->connect(gser); + /* if port is suspended, wait resume to start I/0 stream */ + if (!port->suspended) { + struct gserial *gser = port->port_usb; + + pr_debug("gs_open: start ttyGS%d\n", port->port_num); + gs_start_io(port); + + if (gser->connect) + gser->connect(gser); + } else { + pr_debug("delay start of ttyGS%d\n", port->port_num); + port->start_delayed = true; + } } pr_debug("gs_open: ttyGS%d (%p,%p)\n", port->port_num, tty, file); @@ -680,7 +688,7 @@ raced_with_open: pr_debug("gs_close: ttyGS%d (%p,%p) ...\n", port->port_num, tty, file); gser = port->port_usb; - if (gser && gser->disconnect) + if (gser && !port->suspended && gser->disconnect) gser->disconnect(gser); /* wait for circular write buffer to drain, disconnect, or at @@ -708,6 +716,7 @@ raced_with_open: else kfifo_reset(&port->port_write_buf); + port->start_delayed = false; port->port.count = 0; port->port.tty = NULL; @@ -1403,6 +1412,38 @@ void gserial_disconnect(struct gserial *gser) } EXPORT_SYMBOL_GPL(gserial_disconnect); +void gserial_suspend(struct gserial *gser) +{ + struct gs_port *port = gser->ioport; + unsigned long flags; + + spin_lock_irqsave(&port->port_lock, flags); + port->suspended = true; + spin_unlock_irqrestore(&port->port_lock, flags); +} +EXPORT_SYMBOL_GPL(gserial_suspend); + +void gserial_resume(struct gserial *gser) +{ + struct gs_port *port = gser->ioport; + unsigned long flags; + + spin_lock_irqsave(&port->port_lock, flags); + port->suspended = false; + if (!port->start_delayed) { + spin_unlock_irqrestore(&port->port_lock, flags); + return; + } + + pr_debug("delayed start ttyGS%d\n", port->port_num); + gs_start_io(port); + if (gser->connect) + gser->connect(gser); + port->start_delayed = false; + spin_unlock_irqrestore(&port->port_lock, flags); +} +EXPORT_SYMBOL_GPL(gserial_resume); + static int userial_init(void) { unsigned i; diff --git a/drivers/usb/gadget/function/u_serial.h b/drivers/usb/gadget/function/u_serial.h index e5b08ab8cf7a..cadb76eecbc7 100644 --- a/drivers/usb/gadget/function/u_serial.h +++ b/drivers/usb/gadget/function/u_serial.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * u_serial.h - interface to USB gadget "serial port"/TTY utilities * @@ -68,6 +68,8 @@ ssize_t gserial_get_console(unsigned char port_num, char *page); /* connect/disconnect is handled by individual functions */ int gserial_connect(struct gserial *, u8 port_num); void gserial_disconnect(struct gserial *); +void gserial_suspend(struct gserial *p); +void gserial_resume(struct gserial *p); /* functions are bound to configurations by a config or gadget driver */ int gser_bind_config(struct usb_configuration *c, u8 port_num); diff --git a/drivers/usb/gadget/function/u_tcm.h b/drivers/usb/gadget/function/u_tcm.h index 3f7ccecb0f9b..2cd15d9a1c0d 100644 --- a/drivers/usb/gadget/function/u_tcm.h +++ b/drivers/usb/gadget/function/u_tcm.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * u_tcm.h * diff --git a/drivers/usb/gadget/function/u_uac1.h b/drivers/usb/gadget/function/u_uac1.h index 6f1a9d73defe..39c0e29e1b46 100644 --- a/drivers/usb/gadget/function/u_uac1.h +++ b/drivers/usb/gadget/function/u_uac1.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * u_uac1.h - Utility definitions for UAC1 function * diff --git a/drivers/usb/gadget/function/u_uac1_legacy.h b/drivers/usb/gadget/function/u_uac1_legacy.h index 5c1bdf46fe32..b5df9bcbbeba 100644 --- a/drivers/usb/gadget/function/u_uac1_legacy.h +++ b/drivers/usb/gadget/function/u_uac1_legacy.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * u_uac1.h -- interface to USB gadget "ALSA AUDIO" utilities * diff --git a/drivers/usb/gadget/function/u_uac2.h b/drivers/usb/gadget/function/u_uac2.h index 82048791eb6e..b5035711172d 100644 --- a/drivers/usb/gadget/function/u_uac2.h +++ b/drivers/usb/gadget/function/u_uac2.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * u_uac2.h * diff --git a/drivers/usb/gadget/function/u_uvc.h b/drivers/usb/gadget/function/u_uvc.h index 16da49a2fcf2..9a01a7d4f17f 100644 --- a/drivers/usb/gadget/function/u_uvc.h +++ b/drivers/usb/gadget/function/u_uvc.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * u_uvc.h * diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h index 1473d25ff17a..23ee25383c1f 100644 --- a/drivers/usb/gadget/function/uvc.h +++ b/drivers/usb/gadget/function/uvc.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * uvc_gadget.h -- USB Video Class Gadget driver * @@ -77,6 +77,8 @@ struct uvc_video { struct uvc_device *uvc; struct usb_ep *ep; + struct work_struct pump; + /* Frame parameters */ u8 bpp; u32 fcc; diff --git a/drivers/usb/gadget/function/uvc_configfs.h b/drivers/usb/gadget/function/uvc_configfs.h index 341391dbc81f..7e1d7ca29bf2 100644 --- a/drivers/usb/gadget/function/uvc_configfs.h +++ b/drivers/usb/gadget/function/uvc_configfs.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * uvc_configfs.h * diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c index 495f0ec663ea..4ca89eab6159 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c @@ -169,7 +169,9 @@ uvc_v4l2_qbuf(struct file *file, void *fh, struct v4l2_buffer *b) if (ret < 0) return ret; - return uvcg_video_pump(video); + schedule_work(&video->pump); + + return ret; } static int diff --git a/drivers/usb/gadget/function/uvc_v4l2.h b/drivers/usb/gadget/function/uvc_v4l2.h index 452d71059b3f..1576005b61fd 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.h +++ b/drivers/usb/gadget/function/uvc_v4l2.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * uvc_v4l2.h -- USB Video Class Gadget driver * diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c index 5c042f380708..633e23d58d86 100644 --- a/drivers/usb/gadget/function/uvc_video.c +++ b/drivers/usb/gadget/function/uvc_video.c @@ -142,44 +142,12 @@ static int uvcg_video_ep_queue(struct uvc_video *video, struct usb_request *req) return ret; } -/* - * I somehow feel that synchronisation won't be easy to achieve here. We have - * three events that control USB requests submission: - * - * - USB request completion: the completion handler will resubmit the request - * if a video buffer is available. - * - * - USB interface setting selection: in response to a SET_INTERFACE request, - * the handler will start streaming if a video buffer is available and if - * video is not currently streaming. - * - * - V4L2 buffer queueing: the driver will start streaming if video is not - * currently streaming. - * - * Race conditions between those 3 events might lead to deadlocks or other - * nasty side effects. - * - * The "video currently streaming" condition can't be detected by the irqqueue - * being empty, as a request can still be in flight. A separate "queue paused" - * flag is thus needed. - * - * The paused flag will be set when we try to retrieve the irqqueue head if the - * queue is empty, and cleared when we queue a buffer. - * - * The USB request completion handler will get the buffer at the irqqueue head - * under protection of the queue spinlock. If the queue is empty, the streaming - * paused flag will be set. Right after releasing the spinlock a userspace - * application can queue a buffer. The flag will then cleared, and the ioctl - * handler will restart the video stream. - */ static void uvc_video_complete(struct usb_ep *ep, struct usb_request *req) { struct uvc_video *video = req->context; struct uvc_video_queue *queue = &video->queue; - struct uvc_buffer *buf; unsigned long flags; - int ret; switch (req->status) { case 0: @@ -188,39 +156,20 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req) case -ESHUTDOWN: /* disconnect from host. */ uvcg_dbg(&video->uvc->func, "VS request cancelled.\n"); uvcg_queue_cancel(queue, 1); - goto requeue; + break; default: uvcg_info(&video->uvc->func, "VS request completed with status %d.\n", req->status); uvcg_queue_cancel(queue, 0); - goto requeue; } - spin_lock_irqsave(&video->queue.irqlock, flags); - buf = uvcg_queue_head(&video->queue); - if (buf == NULL) { - spin_unlock_irqrestore(&video->queue.irqlock, flags); - goto requeue; - } - - video->encode(req, video, buf); - - ret = uvcg_video_ep_queue(video, req); - spin_unlock_irqrestore(&video->queue.irqlock, flags); - - if (ret < 0) { - uvcg_queue_cancel(queue, 0); - goto requeue; - } - - return; - -requeue: spin_lock_irqsave(&video->req_lock, flags); list_add_tail(&req->list, &video->req_free); spin_unlock_irqrestore(&video->req_lock, flags); + + schedule_work(&video->pump); } static int @@ -294,18 +243,15 @@ error: * This function fills the available USB requests (listed in req_free) with * video data from the queued buffers. */ -int uvcg_video_pump(struct uvc_video *video) +static void uvcg_video_pump(struct work_struct *work) { + struct uvc_video *video = container_of(work, struct uvc_video, pump); struct uvc_video_queue *queue = &video->queue; struct usb_request *req; struct uvc_buffer *buf; unsigned long flags; int ret; - /* FIXME TODO Race between uvcg_video_pump and requests completion - * handler ??? - */ - while (1) { /* Retrieve the first available USB request, protected by the * request lock. @@ -313,7 +259,7 @@ int uvcg_video_pump(struct uvc_video *video) spin_lock_irqsave(&video->req_lock, flags); if (list_empty(&video->req_free)) { spin_unlock_irqrestore(&video->req_lock, flags); - return 0; + return; } req = list_first_entry(&video->req_free, struct usb_request, list); @@ -345,7 +291,7 @@ int uvcg_video_pump(struct uvc_video *video) spin_lock_irqsave(&video->req_lock, flags); list_add_tail(&req->list, &video->req_free); spin_unlock_irqrestore(&video->req_lock, flags); - return 0; + return; } /* @@ -363,6 +309,9 @@ int uvcg_video_enable(struct uvc_video *video, int enable) } if (!enable) { + cancel_work_sync(&video->pump); + uvcg_queue_cancel(&video->queue, 0); + for (i = 0; i < UVC_NUM_REQUESTS; ++i) if (video->req[i]) usb_ep_dequeue(video->ep, video->req[i]); @@ -384,7 +333,9 @@ int uvcg_video_enable(struct uvc_video *video, int enable) } else video->encode = uvc_video_encode_isoc; - return uvcg_video_pump(video); + schedule_work(&video->pump); + + return ret; } /* @@ -394,6 +345,7 @@ int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc) { INIT_LIST_HEAD(&video->req_free); spin_lock_init(&video->req_lock); + INIT_WORK(&video->pump, uvcg_video_pump); video->uvc = uvc; video->fcc = V4L2_PIX_FMT_YUYV; diff --git a/drivers/usb/gadget/function/uvc_video.h b/drivers/usb/gadget/function/uvc_video.h index dff12103f696..03adeefa343b 100644 --- a/drivers/usb/gadget/function/uvc_video.h +++ b/drivers/usb/gadget/function/uvc_video.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * uvc_video.h -- USB Video Class Gadget driver * @@ -14,8 +14,6 @@ struct uvc_video; -int uvcg_video_pump(struct uvc_video *video); - int uvcg_video_enable(struct uvc_video *video, int enable); int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc); diff --git a/drivers/usb/gadget/legacy/mass_storage.c b/drivers/usb/gadget/legacy/mass_storage.c index f18f77584fc2..9ed22c5fb7fe 100644 --- a/drivers/usb/gadget/legacy/mass_storage.c +++ b/drivers/usb/gadget/legacy/mass_storage.c @@ -229,18 +229,8 @@ static struct usb_composite_driver msg_driver = { .unbind = msg_unbind, }; +module_usb_composite_driver(msg_driver); + MODULE_DESCRIPTION(DRIVER_DESC); MODULE_AUTHOR("Michal Nazarewicz"); MODULE_LICENSE("GPL"); - -static int __init msg_init(void) -{ - return usb_composite_probe(&msg_driver); -} -module_init(msg_init); - -static void __exit msg_cleanup(void) -{ - usb_composite_unregister(&msg_driver); -} -module_exit(msg_cleanup); diff --git a/drivers/usb/gadget/udc/aspeed-vhub/core.c b/drivers/usb/gadget/udc/aspeed-vhub/core.c index f8d35dd60c34..cdf96911e4b1 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/core.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/core.c @@ -134,11 +134,15 @@ static irqreturn_t ast_vhub_irq(int irq, void *data) } /* Handle device interrupts */ - for (i = 0; i < vhub->max_ports; i++) { - u32 dev_mask = VHUB_IRQ_DEVICE1 << i; + if (istat & vhub->port_irq_mask) { + unsigned long bitmap = istat; + int offset = VHUB_IRQ_DEV1_BIT; + int size = VHUB_IRQ_DEV1_BIT + vhub->max_ports; - if (istat & dev_mask) + for_each_set_bit_from(offset, &bitmap, size) { + i = offset - VHUB_IRQ_DEV1_BIT; ast_vhub_dev_irq(&vhub->ports[i].dev); + } } /* Handle top-level vHub EP0 interrupts */ @@ -332,6 +336,8 @@ static int ast_vhub_probe(struct platform_device *pdev) spin_lock_init(&vhub->lock); vhub->pdev = pdev; + vhub->port_irq_mask = GENMASK(VHUB_IRQ_DEV1_BIT + vhub->max_ports - 1, + VHUB_IRQ_DEV1_BIT); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); vhub->regs = devm_ioremap_resource(&pdev->dev, res); @@ -402,7 +408,9 @@ static int ast_vhub_probe(struct platform_device *pdev) goto err; /* Init hub emulation */ - ast_vhub_init_hub(vhub); + rc = ast_vhub_init_hub(vhub); + if (rc) + goto err; /* Initialize HW */ ast_vhub_init_hw(vhub); diff --git a/drivers/usb/gadget/udc/aspeed-vhub/hub.c b/drivers/usb/gadget/udc/aspeed-vhub/hub.c index 6e565c3dbb5b..6497185ec4e7 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/hub.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/hub.c @@ -50,6 +50,7 @@ #define KERNEL_VER bin2bcd(((LINUX_VERSION_CODE >> 8) & 0x0ff)) enum { + AST_VHUB_STR_INDEX_MAX = 4, AST_VHUB_STR_MANUF = 3, AST_VHUB_STR_PRODUCT = 2, AST_VHUB_STR_SERIAL = 1, @@ -72,13 +73,6 @@ static const struct usb_device_descriptor ast_vhub_dev_desc = { .bNumConfigurations = 1, }; -/* Patches to the above when forcing USB1 mode */ -static void ast_vhub_patch_dev_desc_usb1(struct usb_device_descriptor *desc) -{ - desc->bcdUSB = cpu_to_le16(0x0100); - desc->bDeviceProtocol = 0; -} - /* * Configuration descriptor: same comments as above * regarding handling USB1 mode. @@ -302,31 +296,81 @@ static int ast_vhub_rep_desc(struct ast_vhub_ep *ep, if (len > dsize) len = dsize; - /* Patch it if forcing USB1 */ - if (desc_type == USB_DT_DEVICE && ep->vhub->force_usb1) - ast_vhub_patch_dev_desc_usb1(ep->buf); - /* Shoot it from the EP buffer */ return ast_vhub_reply(ep, NULL, len); } +static struct usb_gadget_strings* +ast_vhub_str_of_container(struct usb_gadget_string_container *container) +{ + return (struct usb_gadget_strings *)container->stash; +} + +static int ast_vhub_collect_languages(struct ast_vhub *vhub, void *buf, + size_t size) +{ + int rc, hdr_len, nlangs, max_langs; + struct usb_gadget_strings *lang_str; + struct usb_gadget_string_container *container; + struct usb_string_descriptor *sdesc = buf; + + nlangs = 0; + hdr_len = sizeof(struct usb_descriptor_header); + max_langs = (size - hdr_len) / sizeof(sdesc->wData[0]); + list_for_each_entry(container, &vhub->vhub_str_desc, list) { + if (nlangs >= max_langs) + break; + + lang_str = ast_vhub_str_of_container(container); + sdesc->wData[nlangs++] = cpu_to_le16(lang_str->language); + } + + rc = hdr_len + nlangs * sizeof(sdesc->wData[0]); + sdesc->bLength = rc; + sdesc->bDescriptorType = USB_DT_STRING; + + return rc; +} + +static struct usb_gadget_strings *ast_vhub_lookup_string(struct ast_vhub *vhub, + u16 lang_id) +{ + struct usb_gadget_strings *lang_str; + struct usb_gadget_string_container *container; + + list_for_each_entry(container, &vhub->vhub_str_desc, list) { + lang_str = ast_vhub_str_of_container(container); + if (lang_str->language == lang_id) + return lang_str; + } + + return NULL; +} + static int ast_vhub_rep_string(struct ast_vhub_ep *ep, u8 string_id, u16 lang_id, u16 len) { - int rc = usb_gadget_get_string(&ep->vhub->vhub_str_desc, - string_id, ep->buf); + int rc; + u8 buf[256]; + struct ast_vhub *vhub = ep->vhub; + struct usb_gadget_strings *lang_str; - /* - * This should never happen unless we put too big strings in - * the array above - */ - BUG_ON(rc >= AST_VHUB_EP0_MAX_PACKET); + if (string_id == 0) { + rc = ast_vhub_collect_languages(vhub, buf, sizeof(buf)); + } else { + lang_str = ast_vhub_lookup_string(vhub, lang_id); + if (!lang_str) + return std_req_stall; - if (rc < 0) + rc = usb_gadget_get_string(lang_str, string_id, buf); + } + + if (rc < 0 || rc >= AST_VHUB_EP0_MAX_PACKET) return std_req_stall; /* Shoot it from the EP buffer */ + memcpy(ep->buf, buf, rc); return ast_vhub_reply(ep, NULL, min_t(u16, rc, len)); } @@ -832,11 +876,148 @@ void ast_vhub_hub_reset(struct ast_vhub *vhub) writel(0, vhub->regs + AST_VHUB_EP1_STS_CHG); } -static void ast_vhub_init_desc(struct ast_vhub *vhub) +static void ast_vhub_of_parse_dev_desc(struct ast_vhub *vhub, + const struct device_node *vhub_np) +{ + u16 id; + u32 data; + + if (!of_property_read_u32(vhub_np, "vhub-vendor-id", &data)) { + id = (u16)data; + vhub->vhub_dev_desc.idVendor = cpu_to_le16(id); + } + if (!of_property_read_u32(vhub_np, "vhub-product-id", &data)) { + id = (u16)data; + vhub->vhub_dev_desc.idProduct = cpu_to_le16(id); + } + if (!of_property_read_u32(vhub_np, "vhub-device-revision", &data)) { + id = (u16)data; + vhub->vhub_dev_desc.bcdDevice = cpu_to_le16(id); + } +} + +static void ast_vhub_fixup_usb1_dev_desc(struct ast_vhub *vhub) +{ + vhub->vhub_dev_desc.bcdUSB = cpu_to_le16(0x0100); + vhub->vhub_dev_desc.bDeviceProtocol = 0; +} + +static struct usb_gadget_string_container* +ast_vhub_str_container_alloc(struct ast_vhub *vhub) +{ + unsigned int size; + struct usb_string *str_array; + struct usb_gadget_strings *lang_str; + struct usb_gadget_string_container *container; + + size = sizeof(*container); + size += sizeof(struct usb_gadget_strings); + size += sizeof(struct usb_string) * AST_VHUB_STR_INDEX_MAX; + container = devm_kzalloc(&vhub->pdev->dev, size, GFP_KERNEL); + if (!container) + return ERR_PTR(-ENOMEM); + + lang_str = ast_vhub_str_of_container(container); + str_array = (struct usb_string *)(lang_str + 1); + lang_str->strings = str_array; + return container; +} + +static void ast_vhub_str_deep_copy(struct usb_gadget_strings *dest, + const struct usb_gadget_strings *src) { + struct usb_string *src_array = src->strings; + struct usb_string *dest_array = dest->strings; + + dest->language = src->language; + if (src_array && dest_array) { + do { + *dest_array = *src_array; + dest_array++; + src_array++; + } while (src_array->s); + } +} + +static int ast_vhub_str_alloc_add(struct ast_vhub *vhub, + const struct usb_gadget_strings *src_str) +{ + struct usb_gadget_strings *dest_str; + struct usb_gadget_string_container *container; + + container = ast_vhub_str_container_alloc(vhub); + if (IS_ERR(container)) + return PTR_ERR(container); + + dest_str = ast_vhub_str_of_container(container); + ast_vhub_str_deep_copy(dest_str, src_str); + list_add_tail(&container->list, &vhub->vhub_str_desc); + + return 0; +} + +static const struct { + const char *name; + u8 id; +} str_id_map[] = { + {"manufacturer", AST_VHUB_STR_MANUF}, + {"product", AST_VHUB_STR_PRODUCT}, + {"serial-number", AST_VHUB_STR_SERIAL}, + {}, +}; + +static int ast_vhub_of_parse_str_desc(struct ast_vhub *vhub, + const struct device_node *desc_np) +{ + u32 langid; + int ret = 0; + int i, offset; + const char *str; + struct device_node *child; + struct usb_string str_array[AST_VHUB_STR_INDEX_MAX]; + struct usb_gadget_strings lang_str = { + .strings = (struct usb_string *)str_array, + }; + + for_each_child_of_node(desc_np, child) { + if (of_property_read_u32(child, "reg", &langid)) + continue; /* no language identifier specified */ + + if (!usb_validate_langid(langid)) + continue; /* invalid language identifier */ + + lang_str.language = langid; + for (i = offset = 0; str_id_map[i].name; i++) { + str = of_get_property(child, str_id_map[i].name, NULL); + if (str) { + str_array[offset].s = str; + str_array[offset].id = str_id_map[i].id; + offset++; + } + } + str_array[offset].id = 0; + str_array[offset].s = NULL; + + ret = ast_vhub_str_alloc_add(vhub, &lang_str); + if (ret) + break; + } + + return ret; +} + +static int ast_vhub_init_desc(struct ast_vhub *vhub) +{ + int ret; + struct device_node *desc_np; + const struct device_node *vhub_np = vhub->pdev->dev.of_node; + /* Initialize vhub Device Descriptor. */ memcpy(&vhub->vhub_dev_desc, &ast_vhub_dev_desc, sizeof(vhub->vhub_dev_desc)); + ast_vhub_of_parse_dev_desc(vhub, vhub_np); + if (vhub->force_usb1) + ast_vhub_fixup_usb1_dev_desc(vhub); /* Initialize vhub Configuration Descriptor. */ memcpy(&vhub->vhub_conf_desc, &ast_vhub_conf_desc, @@ -848,15 +1029,20 @@ static void ast_vhub_init_desc(struct ast_vhub *vhub) vhub->vhub_hub_desc.bNbrPorts = vhub->max_ports; /* Initialize vhub String Descriptors. */ - memcpy(&vhub->vhub_str_desc, &ast_vhub_strings, - sizeof(vhub->vhub_str_desc)); + INIT_LIST_HEAD(&vhub->vhub_str_desc); + desc_np = of_get_child_by_name(vhub_np, "vhub-strings"); + if (desc_np) + ret = ast_vhub_of_parse_str_desc(vhub, desc_np); + else + ret = ast_vhub_str_alloc_add(vhub, &ast_vhub_strings); + + return ret; } -void ast_vhub_init_hub(struct ast_vhub *vhub) +int ast_vhub_init_hub(struct ast_vhub *vhub) { vhub->speed = USB_SPEED_UNKNOWN; INIT_WORK(&vhub->wake_work, ast_vhub_wake_work); - ast_vhub_init_desc(vhub); + return ast_vhub_init_desc(vhub); } - diff --git a/drivers/usb/gadget/udc/aspeed-vhub/vhub.h b/drivers/usb/gadget/udc/aspeed-vhub/vhub.h index fac79ef6d669..2e5a1ef14a75 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/vhub.h +++ b/drivers/usb/gadget/udc/aspeed-vhub/vhub.h @@ -51,14 +51,11 @@ #define VHUB_CTRL_UPSTREAM_CONNECT (1 << 0) /* IER & ISR */ +#define VHUB_IRQ_DEV1_BIT 9 #define VHUB_IRQ_USB_CMD_DEADLOCK (1 << 18) #define VHUB_IRQ_EP_POOL_NAK (1 << 17) #define VHUB_IRQ_EP_POOL_ACK_STALL (1 << 16) -#define VHUB_IRQ_DEVICE5 (1 << 13) -#define VHUB_IRQ_DEVICE4 (1 << 12) -#define VHUB_IRQ_DEVICE3 (1 << 11) -#define VHUB_IRQ_DEVICE2 (1 << 10) -#define VHUB_IRQ_DEVICE1 (1 << 9) +#define VHUB_IRQ_DEVICE1 (1 << (VHUB_IRQ_DEV1_BIT)) #define VHUB_IRQ_BUS_RESUME (1 << 8) #define VHUB_IRQ_BUS_SUSPEND (1 << 7) #define VHUB_IRQ_BUS_RESET (1 << 6) @@ -402,6 +399,7 @@ struct ast_vhub { /* Per-port info */ struct ast_vhub_port *ports; u32 max_ports; + u32 port_irq_mask; /* Generic EP data structures */ struct ast_vhub_ep *epns; @@ -423,7 +421,7 @@ struct ast_vhub { struct usb_device_descriptor vhub_dev_desc; struct ast_vhub_full_cdesc vhub_conf_desc; struct usb_hub_descriptor vhub_hub_desc; - struct usb_gadget_strings vhub_str_desc; + struct list_head vhub_str_desc; }; /* Standard request handlers result codes */ @@ -533,7 +531,7 @@ int __ast_vhub_simple_reply(struct ast_vhub_ep *ep, int len, ...); __VA_ARGS__) /* hub.c */ -void ast_vhub_init_hub(struct ast_vhub *vhub); +int ast_vhub_init_hub(struct ast_vhub *vhub); enum std_req_rc ast_vhub_std_hub_request(struct ast_vhub_ep *ep, struct usb_ctrlrequest *crq); enum std_req_rc ast_vhub_class_hub_request(struct ast_vhub_ep *ep, diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index b771a854e29c..d69f61ff0181 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -2043,10 +2043,56 @@ static const struct usba_udc_errata at91sam9g45_errata = { .pulse_bias = at91sam9g45_pulse_bias, }; +static const struct usba_ep_config ep_config_sam9[] __initconst = { + { .nr_banks = 1 }, /* ep 0 */ + { .nr_banks = 2, .can_dma = 1, .can_isoc = 1 }, /* ep 1 */ + { .nr_banks = 2, .can_dma = 1, .can_isoc = 1 }, /* ep 2 */ + { .nr_banks = 3, .can_dma = 1 }, /* ep 3 */ + { .nr_banks = 3, .can_dma = 1 }, /* ep 4 */ + { .nr_banks = 3, .can_dma = 1, .can_isoc = 1 }, /* ep 5 */ + { .nr_banks = 3, .can_dma = 1, .can_isoc = 1 }, /* ep 6 */ +}; + +static const struct usba_ep_config ep_config_sama5[] __initconst = { + { .nr_banks = 1 }, /* ep 0 */ + { .nr_banks = 3, .can_dma = 1, .can_isoc = 1 }, /* ep 1 */ + { .nr_banks = 3, .can_dma = 1, .can_isoc = 1 }, /* ep 2 */ + { .nr_banks = 2, .can_dma = 1, .can_isoc = 1 }, /* ep 3 */ + { .nr_banks = 2, .can_dma = 1, .can_isoc = 1 }, /* ep 4 */ + { .nr_banks = 2, .can_dma = 1, .can_isoc = 1 }, /* ep 5 */ + { .nr_banks = 2, .can_dma = 1, .can_isoc = 1 }, /* ep 6 */ + { .nr_banks = 2, .can_dma = 1, .can_isoc = 1 }, /* ep 7 */ + { .nr_banks = 2, .can_isoc = 1 }, /* ep 8 */ + { .nr_banks = 2, .can_isoc = 1 }, /* ep 9 */ + { .nr_banks = 2, .can_isoc = 1 }, /* ep 10 */ + { .nr_banks = 2, .can_isoc = 1 }, /* ep 11 */ + { .nr_banks = 2, .can_isoc = 1 }, /* ep 12 */ + { .nr_banks = 2, .can_isoc = 1 }, /* ep 13 */ + { .nr_banks = 2, .can_isoc = 1 }, /* ep 14 */ + { .nr_banks = 2, .can_isoc = 1 }, /* ep 15 */ +}; + +static const struct usba_udc_config udc_at91sam9rl_cfg = { + .errata = &at91sam9rl_errata, + .config = ep_config_sam9, + .num_ep = ARRAY_SIZE(ep_config_sam9), +}; + +static const struct usba_udc_config udc_at91sam9g45_cfg = { + .errata = &at91sam9g45_errata, + .config = ep_config_sam9, + .num_ep = ARRAY_SIZE(ep_config_sam9), +}; + +static const struct usba_udc_config udc_sama5d3_cfg = { + .config = ep_config_sama5, + .num_ep = ARRAY_SIZE(ep_config_sama5), +}; + static const struct of_device_id atmel_udc_dt_ids[] = { - { .compatible = "atmel,at91sam9rl-udc", .data = &at91sam9rl_errata }, - { .compatible = "atmel,at91sam9g45-udc", .data = &at91sam9g45_errata }, - { .compatible = "atmel,sama5d3-udc" }, + { .compatible = "atmel,at91sam9rl-udc", .data = &udc_at91sam9rl_cfg }, + { .compatible = "atmel,at91sam9g45-udc", .data = &udc_at91sam9g45_cfg }, + { .compatible = "atmel,sama5d3-udc", .data = &udc_sama5d3_cfg }, { /* sentinel */ } }; @@ -2055,18 +2101,19 @@ MODULE_DEVICE_TABLE(of, atmel_udc_dt_ids); static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, struct usba_udc *udc) { - u32 val; struct device_node *np = pdev->dev.of_node; const struct of_device_id *match; struct device_node *pp; int i, ret; struct usba_ep *eps, *ep; + const struct usba_udc_config *udc_config; match = of_match_node(atmel_udc_dt_ids, np); if (!match) return ERR_PTR(-EINVAL); - udc->errata = match->data; + udc_config = match->data; + udc->errata = udc_config->errata; udc->pmc = syscon_regmap_lookup_by_compatible("atmel,at91sam9g45-pmc"); if (IS_ERR(udc->pmc)) udc->pmc = syscon_regmap_lookup_by_compatible("atmel,at91sam9rl-pmc"); @@ -2082,8 +2129,7 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, if (fifo_mode == 0) { pp = NULL; - while ((pp = of_get_next_child(np, pp))) - udc->num_ep++; + udc->num_ep = udc_config->num_ep; udc->configured_ep = 1; } else { udc->num_ep = usba_config_fifo_table(udc); @@ -2100,52 +2146,38 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, pp = NULL; i = 0; - while ((pp = of_get_next_child(np, pp)) && i < udc->num_ep) { + while (i < udc->num_ep) { + const struct usba_ep_config *ep_cfg = &udc_config->config[i]; + ep = &eps[i]; - ret = of_property_read_u32(pp, "reg", &val); - if (ret) { - dev_err(&pdev->dev, "of_probe: reg error(%d)\n", ret); - goto err; - } - ep->index = fifo_mode ? udc->fifo_cfg[i].hw_ep_num : val; + ep->index = fifo_mode ? udc->fifo_cfg[i].hw_ep_num : i; + + /* Only the first EP is 64 bytes */ + if (ep->index == 0) + ep->fifo_size = 64; + else + ep->fifo_size = 1024; - ret = of_property_read_u32(pp, "atmel,fifo-size", &val); - if (ret) { - dev_err(&pdev->dev, "of_probe: fifo-size error(%d)\n", ret); - goto err; - } if (fifo_mode) { - if (val < udc->fifo_cfg[i].fifo_size) { + if (ep->fifo_size < udc->fifo_cfg[i].fifo_size) dev_warn(&pdev->dev, - "Using max fifo-size value from DT\n"); - ep->fifo_size = val; - } else { + "Using default max fifo-size value\n"); + else ep->fifo_size = udc->fifo_cfg[i].fifo_size; - } - } else { - ep->fifo_size = val; } - ret = of_property_read_u32(pp, "atmel,nb-banks", &val); - if (ret) { - dev_err(&pdev->dev, "of_probe: nb-banks error(%d)\n", ret); - goto err; - } + ep->nr_banks = ep_cfg->nr_banks; if (fifo_mode) { - if (val < udc->fifo_cfg[i].nr_banks) { + if (ep->nr_banks < udc->fifo_cfg[i].nr_banks) dev_warn(&pdev->dev, - "Using max nb-banks value from DT\n"); - ep->nr_banks = val; - } else { + "Using default max nb-banks value\n"); + else ep->nr_banks = udc->fifo_cfg[i].nr_banks; - } - } else { - ep->nr_banks = val; } - ep->can_dma = of_property_read_bool(pp, "atmel,can-dma"); - ep->can_isoc = of_property_read_bool(pp, "atmel,can-isoc"); + ep->can_dma = ep_cfg->can_dma; + ep->can_isoc = ep_cfg->can_isoc; sprintf(ep->name, "ep%d", ep->index); ep->ep.name = ep->name; diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.h b/drivers/usb/gadget/udc/atmel_usba_udc.h index a0225e4543d4..48e332439ed5 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.h +++ b/drivers/usb/gadget/udc/atmel_usba_udc.h @@ -290,6 +290,12 @@ struct usba_ep { #endif }; +struct usba_ep_config { + u8 nr_banks; + unsigned int can_dma:1; + unsigned int can_isoc:1; +}; + struct usba_request { struct usb_request req; struct list_head queue; @@ -307,6 +313,12 @@ struct usba_udc_errata { void (*pulse_bias)(struct usba_udc *udc); }; +struct usba_udc_config { + const struct usba_udc_errata *errata; + const struct usba_ep_config *config; + const int num_ep; +}; + struct usba_udc { /* Protect hw registers from concurrent modifications */ spinlock_t lock; diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index 9b11046480fe..2e28dde8376f 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -1297,6 +1297,8 @@ static void usb_gadget_remove_driver(struct usb_udc *udc) kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); usb_gadget_disconnect(udc->gadget); + if (udc->gadget->irq) + synchronize_irq(udc->gadget->irq); udc->driver->unbind(udc->gadget); usb_gadget_udc_stop(udc); diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 6e3e3ebf715f..0eeaead5acea 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -187,31 +187,31 @@ static const struct { USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), /* and now some generic EPs so we have enough in multi config */ - EP_INFO("ep3out", + EP_INFO("ep-aout", USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_OUT)), - EP_INFO("ep4in", + EP_INFO("ep-bin", USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_IN)), - EP_INFO("ep5out", + EP_INFO("ep-cout", USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_OUT)), - EP_INFO("ep6out", + EP_INFO("ep-dout", USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_OUT)), - EP_INFO("ep7in", + EP_INFO("ep-ein", USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_IN)), - EP_INFO("ep8out", + EP_INFO("ep-fout", USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_OUT)), - EP_INFO("ep9in", + EP_INFO("ep-gin", USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_IN)), - EP_INFO("ep10out", + EP_INFO("ep-hout", USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_OUT)), - EP_INFO("ep11out", + EP_INFO("ep-iout", USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_OUT)), - EP_INFO("ep12in", + EP_INFO("ep-jin", USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_IN)), - EP_INFO("ep13out", + EP_INFO("ep-kout", USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_OUT)), - EP_INFO("ep14in", + EP_INFO("ep-lin", USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_IN)), - EP_INFO("ep15out", + EP_INFO("ep-mout", USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_OUT)), #undef EP_INFO @@ -427,6 +427,7 @@ static void set_link_state_by_speed(struct dummy_hcd *dum_hcd) /* caller must hold lock */ static void set_link_state(struct dummy_hcd *dum_hcd) + __must_hold(&dum->lock) { struct dummy *dum = dum_hcd->dum; unsigned int power_bit; diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c index febabde62f71..b2638e83bb49 100644 --- a/drivers/usb/gadget/udc/fsl_udc_core.c +++ b/drivers/usb/gadget/udc/fsl_udc_core.c @@ -2440,8 +2440,8 @@ static int fsl_udc_probe(struct platform_device *pdev) udc_controller->max_ep = (dccparams & DCCPARAMS_DEN_MASK) * 2; udc_controller->irq = platform_get_irq(pdev, 0); - if (!udc_controller->irq) { - ret = -ENODEV; + if (udc_controller->irq <= 0) { + ret = udc_controller->irq ? : -ENODEV; goto err_iounmap; } diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c index cb997b82c008..465d0b7c6522 100644 --- a/drivers/usb/gadget/udc/lpc32xx_udc.c +++ b/drivers/usb/gadget/udc/lpc32xx_udc.c @@ -1614,17 +1614,17 @@ static int lpc32xx_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) { struct lpc32xx_ep *ep = container_of(_ep, struct lpc32xx_ep, ep); - struct lpc32xx_udc *udc = ep->udc; + struct lpc32xx_udc *udc; u16 maxpacket; u32 tmp; unsigned long flags; /* Verify EP data */ if ((!_ep) || (!ep) || (!desc) || - (desc->bDescriptorType != USB_DT_ENDPOINT)) { - dev_dbg(udc->dev, "bad ep or descriptor\n"); + (desc->bDescriptorType != USB_DT_ENDPOINT)) return -EINVAL; - } + + udc = ep->udc; maxpacket = usb_endpoint_maxp(desc); if ((maxpacket == 0) || (maxpacket > ep->maxpacket)) { dev_dbg(udc->dev, "bad ep descriptor's packet size\n"); @@ -1872,7 +1872,7 @@ static int lpc32xx_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) static int lpc32xx_ep_set_halt(struct usb_ep *_ep, int value) { struct lpc32xx_ep *ep = container_of(_ep, struct lpc32xx_ep, ep); - struct lpc32xx_udc *udc = ep->udc; + struct lpc32xx_udc *udc; unsigned long flags; if ((!ep) || (ep->hwep_num <= 1)) @@ -1882,6 +1882,7 @@ static int lpc32xx_ep_set_halt(struct usb_ep *_ep, int value) if (ep->is_in) return -EAGAIN; + udc = ep->udc; spin_lock_irqsave(&udc->lock, flags); if (value == 1) { diff --git a/drivers/usb/gadget/udc/m66592-udc.c b/drivers/usb/gadget/udc/m66592-udc.c index 75d16a8902e6..931e6362a13d 100644 --- a/drivers/usb/gadget/udc/m66592-udc.c +++ b/drivers/usb/gadget/udc/m66592-udc.c @@ -1667,7 +1667,7 @@ static int m66592_probe(struct platform_device *pdev) err_add_udc: m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req); - + m66592->ep0_req = NULL; clean_up3: if (m66592->pdata->on_chip) { clk_disable(m66592->clk); diff --git a/drivers/usb/gadget/udc/max3420_udc.c b/drivers/usb/gadget/udc/max3420_udc.c index 8fbc083b6732..23f33946d80c 100644 --- a/drivers/usb/gadget/udc/max3420_udc.c +++ b/drivers/usb/gadget/udc/max3420_udc.c @@ -901,7 +901,7 @@ loop: } set_current_state(TASK_RUNNING); - dev_info(udc->dev, "SPI thread exiting"); + dev_info(udc->dev, "SPI thread exiting\n"); return 0; } diff --git a/drivers/usb/gadget/udc/mv_u3d_core.c b/drivers/usb/gadget/udc/mv_u3d_core.c index 35e02a8d0091..5bb0568b934e 100644 --- a/drivers/usb/gadget/udc/mv_u3d_core.c +++ b/drivers/usb/gadget/udc/mv_u3d_core.c @@ -1548,7 +1548,7 @@ static void mv_u3d_handle_setup_packet(struct mv_u3d *u3d, u8 ep_num, delegate = true; /* delegate USB standard requests to the gadget driver */ - if (delegate == true) { + if (delegate) { /* USB requests handled by gadget */ if (setup->wLength) { /* DATA phase from gadget, STATUS phase from u3d */ diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c index 5af0fe9c61d7..928057b206f1 100644 --- a/drivers/usb/gadget/udc/net2272.c +++ b/drivers/usb/gadget/udc/net2272.c @@ -54,7 +54,7 @@ static const char * const ep_name[] = { * * If use_dma is disabled, pio will be used instead. */ -static bool use_dma = 0; +static bool use_dma = false; module_param(use_dma, bool, 0644); /* diff --git a/drivers/usb/gadget/udc/omap_udc.c b/drivers/usb/gadget/udc/omap_udc.c index bf87c6c0d7f6..4139da885651 100644 --- a/drivers/usb/gadget/udc/omap_udc.c +++ b/drivers/usb/gadget/udc/omap_udc.c @@ -2576,7 +2576,7 @@ omap_ep_setup(char *name, u8 addr, u8 type, case USB_ENDPOINT_XFER_INT: ep->ep.caps.type_int = true; break; - }; + } if (addr & USB_DIR_IN) ep->ep.caps.dir_in = true; diff --git a/drivers/usb/gadget/udc/s3c2410_udc.c b/drivers/usb/gadget/udc/s3c2410_udc.c index 0507a2ca0f55..80002d97b59d 100644 --- a/drivers/usb/gadget/udc/s3c2410_udc.c +++ b/drivers/usb/gadget/udc/s3c2410_udc.c @@ -251,10 +251,6 @@ static void s3c2410_udc_done(struct s3c2410_ep *ep, static void s3c2410_udc_nuke(struct s3c2410_udc *udc, struct s3c2410_ep *ep, int status) { - /* Sanity check */ - if (&ep->queue == NULL) - return; - while (!list_empty(&ep->queue)) { struct s3c2410_request *req; req = list_entry(ep->queue.next, struct s3c2410_request, diff --git a/drivers/usb/gadget/udc/tegra-xudc.c b/drivers/usb/gadget/udc/tegra-xudc.c index dfabc54cdc27..bbe1a04686da 100644 --- a/drivers/usb/gadget/udc/tegra-xudc.c +++ b/drivers/usb/gadget/udc/tegra-xudc.c @@ -158,6 +158,30 @@ #define SSPX_CORE_CNT32_POLL_TBURST_MAX_MASK GENMASK(7, 0) #define SSPX_CORE_CNT32_POLL_TBURST_MAX(x) ((x) & \ SSPX_CORE_CNT32_POLL_TBURST_MAX_MASK) +#define SSPX_CORE_CNT56 0x6fc +#define SSPX_CORE_CNT56_SCD_BIT0_TRPT_MAX_MASK GENMASK(19, 0) +#define SSPX_CORE_CNT56_SCD_BIT0_TRPT_MAX(x) ((x) & \ + SSPX_CORE_CNT56_SCD_BIT0_TRPT_MAX_MASK) +#define SSPX_CORE_CNT57 0x700 +#define SSPX_CORE_CNT57_SCD_BIT1_TRPT_MAX_MASK GENMASK(19, 0) +#define SSPX_CORE_CNT57_SCD_BIT1_TRPT_MAX(x) ((x) & \ + SSPX_CORE_CNT57_SCD_BIT1_TRPT_MAX_MASK) +#define SSPX_CORE_CNT65 0x720 +#define SSPX_CORE_CNT65_TX_SCD_END_TRPT_MID_MASK GENMASK(19, 0) +#define SSPX_CORE_CNT65_TX_SCD_END_TRPT_MID(x) ((x) & \ + SSPX_CORE_CNT65_TX_SCD_END_TRPT_MID_MASK) +#define SSPX_CORE_CNT66 0x724 +#define SSPX_CORE_CNT66_TX_SCD_BIT0_TRPT_MID_MASK GENMASK(19, 0) +#define SSPX_CORE_CNT66_TX_SCD_BIT0_TRPT_MID(x) ((x) & \ + SSPX_CORE_CNT66_TX_SCD_BIT0_TRPT_MID_MASK) +#define SSPX_CORE_CNT67 0x728 +#define SSPX_CORE_CNT67_TX_SCD_BIT1_TRPT_MID_MASK GENMASK(19, 0) +#define SSPX_CORE_CNT67_TX_SCD_BIT1_TRPT_MID(x) ((x) & \ + SSPX_CORE_CNT67_TX_SCD_BIT1_TRPT_MID_MASK) +#define SSPX_CORE_CNT72 0x73c +#define SSPX_CORE_CNT72_SCD_LFPS_TIMEOUT_MASK GENMASK(19, 0) +#define SSPX_CORE_CNT72_SCD_LFPS_TIMEOUT(x) ((x) & \ + SSPX_CORE_CNT72_SCD_LFPS_TIMEOUT_MASK) #define SSPX_CORE_PADCTL4 0x750 #define SSPX_CORE_PADCTL4_RXDAT_VLD_TIMEOUT_U3_MASK GENMASK(19, 0) #define SSPX_CORE_PADCTL4_RXDAT_VLD_TIMEOUT_U3(x) ((x) & \ @@ -492,6 +516,7 @@ struct tegra_xudc { bool powergated; struct usb_phy **usbphy; + struct usb_phy *curr_usbphy; struct notifier_block vbus_nb; struct completion disconnect_complete; @@ -530,6 +555,7 @@ struct tegra_xudc_soc { bool invalid_seq_num; bool pls_quirk; bool port_reset_quirk; + bool port_speed_quirk; bool has_ipfs; }; @@ -599,6 +625,78 @@ static inline void dump_trb(struct tegra_xudc *xudc, const char *type, trb->control); } +static void tegra_xudc_limit_port_speed(struct tegra_xudc *xudc) +{ + u32 val; + + /* limit port speed to gen 1 */ + val = xudc_readl(xudc, SSPX_CORE_CNT56); + val &= ~(SSPX_CORE_CNT56_SCD_BIT0_TRPT_MAX_MASK); + val |= SSPX_CORE_CNT56_SCD_BIT0_TRPT_MAX(0x260); + xudc_writel(xudc, val, SSPX_CORE_CNT56); + + val = xudc_readl(xudc, SSPX_CORE_CNT57); + val &= ~(SSPX_CORE_CNT57_SCD_BIT1_TRPT_MAX_MASK); + val |= SSPX_CORE_CNT57_SCD_BIT1_TRPT_MAX(0x6D6); + xudc_writel(xudc, val, SSPX_CORE_CNT57); + + val = xudc_readl(xudc, SSPX_CORE_CNT65); + val &= ~(SSPX_CORE_CNT65_TX_SCD_END_TRPT_MID_MASK); + val |= SSPX_CORE_CNT65_TX_SCD_END_TRPT_MID(0x4B0); + xudc_writel(xudc, val, SSPX_CORE_CNT66); + + val = xudc_readl(xudc, SSPX_CORE_CNT66); + val &= ~(SSPX_CORE_CNT66_TX_SCD_BIT0_TRPT_MID_MASK); + val |= SSPX_CORE_CNT66_TX_SCD_BIT0_TRPT_MID(0x4B0); + xudc_writel(xudc, val, SSPX_CORE_CNT66); + + val = xudc_readl(xudc, SSPX_CORE_CNT67); + val &= ~(SSPX_CORE_CNT67_TX_SCD_BIT1_TRPT_MID_MASK); + val |= SSPX_CORE_CNT67_TX_SCD_BIT1_TRPT_MID(0x4B0); + xudc_writel(xudc, val, SSPX_CORE_CNT67); + + val = xudc_readl(xudc, SSPX_CORE_CNT72); + val &= ~(SSPX_CORE_CNT72_SCD_LFPS_TIMEOUT_MASK); + val |= SSPX_CORE_CNT72_SCD_LFPS_TIMEOUT(0x10); + xudc_writel(xudc, val, SSPX_CORE_CNT72); +} + +static void tegra_xudc_restore_port_speed(struct tegra_xudc *xudc) +{ + u32 val; + + /* restore port speed to gen2 */ + val = xudc_readl(xudc, SSPX_CORE_CNT56); + val &= ~(SSPX_CORE_CNT56_SCD_BIT0_TRPT_MAX_MASK); + val |= SSPX_CORE_CNT56_SCD_BIT0_TRPT_MAX(0x438); + xudc_writel(xudc, val, SSPX_CORE_CNT56); + + val = xudc_readl(xudc, SSPX_CORE_CNT57); + val &= ~(SSPX_CORE_CNT57_SCD_BIT1_TRPT_MAX_MASK); + val |= SSPX_CORE_CNT57_SCD_BIT1_TRPT_MAX(0x528); + xudc_writel(xudc, val, SSPX_CORE_CNT57); + + val = xudc_readl(xudc, SSPX_CORE_CNT65); + val &= ~(SSPX_CORE_CNT65_TX_SCD_END_TRPT_MID_MASK); + val |= SSPX_CORE_CNT65_TX_SCD_END_TRPT_MID(0xE10); + xudc_writel(xudc, val, SSPX_CORE_CNT66); + + val = xudc_readl(xudc, SSPX_CORE_CNT66); + val &= ~(SSPX_CORE_CNT66_TX_SCD_BIT0_TRPT_MID_MASK); + val |= SSPX_CORE_CNT66_TX_SCD_BIT0_TRPT_MID(0x348); + xudc_writel(xudc, val, SSPX_CORE_CNT66); + + val = xudc_readl(xudc, SSPX_CORE_CNT67); + val &= ~(SSPX_CORE_CNT67_TX_SCD_BIT1_TRPT_MID_MASK); + val |= SSPX_CORE_CNT67_TX_SCD_BIT1_TRPT_MID(0x5a0); + xudc_writel(xudc, val, SSPX_CORE_CNT67); + + val = xudc_readl(xudc, SSPX_CORE_CNT72); + val &= ~(SSPX_CORE_CNT72_SCD_LFPS_TIMEOUT_MASK); + val |= SSPX_CORE_CNT72_SCD_LFPS_TIMEOUT(0x1c21); + xudc_writel(xudc, val, SSPX_CORE_CNT72); +} + static void tegra_xudc_device_mode_on(struct tegra_xudc *xudc) { int err; @@ -631,6 +729,9 @@ static void tegra_xudc_device_mode_off(struct tegra_xudc *xudc) reinit_completion(&xudc->disconnect_complete); + if (xudc->soc->port_speed_quirk) + tegra_xudc_restore_port_speed(xudc); + phy_set_mode_ext(xudc->curr_utmi_phy, PHY_MODE_USB_OTG, USB_ROLE_NONE); pls = (xudc_readl(xudc, PORTSC) & PORTSC_PLS_MASK) >> @@ -719,6 +820,7 @@ static int tegra_xudc_vbus_notify(struct notifier_block *nb, if (!xudc->suspended && phy_index != -1) { xudc->curr_utmi_phy = xudc->utmi_phy[phy_index]; xudc->curr_usb3_phy = xudc->usb3_phy[phy_index]; + xudc->curr_usbphy = usbphy; schedule_work(&xudc->usb_role_sw_work); } @@ -2042,6 +2144,20 @@ static int tegra_xudc_gadget_stop(struct usb_gadget *gadget) return 0; } +static int tegra_xudc_gadget_vbus_draw(struct usb_gadget *gadget, + unsigned int m_a) +{ + int ret = 0; + struct tegra_xudc *xudc = to_xudc(gadget); + + dev_dbg(xudc->dev, "%s: %u mA\n", __func__, m_a); + + if (xudc->curr_usbphy->chg_type == SDP_TYPE) + ret = usb_phy_set_power(xudc->curr_usbphy, m_a); + + return ret; +} + static int tegra_xudc_set_selfpowered(struct usb_gadget *gadget, int is_on) { struct tegra_xudc *xudc = to_xudc(gadget); @@ -2058,6 +2174,7 @@ static struct usb_gadget_ops tegra_xudc_gadget_ops = { .pullup = tegra_xudc_gadget_pullup, .udc_start = tegra_xudc_gadget_start, .udc_stop = tegra_xudc_gadget_stop, + .vbus_draw = tegra_xudc_gadget_vbus_draw, .set_selfpowered = tegra_xudc_set_selfpowered, }; @@ -3274,6 +3391,9 @@ static void tegra_xudc_device_params_init(struct tegra_xudc *xudc) xudc_writel(xudc, val, BLCG); } + if (xudc->soc->port_speed_quirk) + tegra_xudc_limit_port_speed(xudc); + /* Set a reasonable U3 exit timer value. */ val = xudc_readl(xudc, SSPX_CORE_PADCTL4); val &= ~(SSPX_CORE_PADCTL4_RXDAT_VLD_TIMEOUT_U3_MASK); @@ -3506,6 +3626,7 @@ static struct tegra_xudc_soc tegra210_xudc_soc_data = { .invalid_seq_num = true, .pls_quirk = true, .port_reset_quirk = true, + .port_speed_quirk = false, .has_ipfs = true, }; @@ -3519,6 +3640,21 @@ static struct tegra_xudc_soc tegra186_xudc_soc_data = { .invalid_seq_num = false, .pls_quirk = false, .port_reset_quirk = false, + .port_speed_quirk = false, + .has_ipfs = false, +}; + +static struct tegra_xudc_soc tegra194_xudc_soc_data = { + .clock_names = tegra186_xudc_clock_names, + .num_clks = ARRAY_SIZE(tegra186_xudc_clock_names), + .num_phys = 4, + .u1_enable = true, + .u2_enable = true, + .lpm_enable = true, + .invalid_seq_num = false, + .pls_quirk = false, + .port_reset_quirk = false, + .port_speed_quirk = true, .has_ipfs = false, }; @@ -3531,6 +3667,10 @@ static const struct of_device_id tegra_xudc_of_match[] = { .compatible = "nvidia,tegra186-xudc", .data = &tegra186_xudc_soc_data }, + { + .compatible = "nvidia,tegra194-xudc", + .data = &tegra194_xudc_soc_data + }, { } }; MODULE_DEVICE_TABLE(of, tegra_xudc_of_match); diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c index b1cfc8279c3d..709553bdb233 100644 --- a/drivers/usb/gadget/udc/udc-xilinx.c +++ b/drivers/usb/gadget/udc/udc-xilinx.c @@ -1732,6 +1732,7 @@ static void xudc_set_clear_feature(struct xusb_udc *udc) * Process setup packet and delegate to gadget layer. */ static void xudc_handle_setup(struct xusb_udc *udc) + __must_hold(&udc->lock) { struct xusb_ep *ep0 = &udc->ep[0]; struct usb_ctrlrequest setup; diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c index 7c24d1ce1088..58a4d3325090 100644 --- a/drivers/usb/gadget/usbstring.c +++ b/drivers/usb/gadget/usbstring.c @@ -65,3 +65,27 @@ usb_gadget_get_string (const struct usb_gadget_strings *table, int id, u8 *buf) return buf [0]; } EXPORT_SYMBOL_GPL(usb_gadget_get_string); + +/** + * usb_validate_langid - validate usb language identifiers + * @lang: usb language identifier + * + * Returns true for valid language identifier, otherwise false. + */ +bool usb_validate_langid(u16 langid) +{ + u16 primary_lang = langid & 0x3ff; /* bit [9:0] */ + u16 sub_lang = langid >> 10; /* bit [15:10] */ + + switch (primary_lang) { + case 0: + case 0x62 ... 0xfe: + case 0x100 ... 0x3ff: + return false; + } + if (!sub_lang) + return false; + + return true; +} +EXPORT_SYMBOL_GPL(usb_validate_langid); |