aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-11-01 15:08:04 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2014-11-01 15:08:04 -0700
commit528a506e4bcd77dfce5d405e73a95e340bb6e8fd (patch)
tree2ed701d69aea839b461ca8a9107a7b59692d3452
parent4f4274af7009890f0d4724909bf9038193955489 (diff)
parent9c19db5b11487da704d29dee48345c4841831bac (diff)
Merge tag 'usb-3.18-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB fixes from Greg KH: "Here are a bunch of USB fixes for 3.18-rc3. Mostly usb-serial device ids and gadget fixes for issues that have been reported. Full details are in the shortlog. All of these have been in linux-next for a while" * tag 'usb-3.18-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (42 commits) usb: chipidea: Fix oops when removing the ci_hdrc module usb: gadget: function: Fixed the return value on error path usb: dwc2: gadget: disable phy before turning off power regulators usb: gadget: function: Remove redundant usb_free_all_descriptors usb: dwc3: gadget: Properly initialize LINK TRB usb: dwc2: gadget: fix gadget unregistration in udc_stop() function usb: dwc2: Bits in bitfield should add up to 32 usb: dwc2: gadget: sparse warning of context imbalance usb: gadget: udc: core: fix kernel oops with soft-connect usb: musb: musb_dsps: fix NULL pointer in suspend usb: musb: dsps: start OTG timer on resume again usb: gadget: loopback: don't queue requests to bogus endpoints usb: ffs: fix regression when quirk_ep_out_aligned_size flag is set usb: gadget: f_fs: remove redundant ffs_data_get() usb: gadget: udc: USB_GADGET_XILINX should depend on HAS_DMA Revert "usb: dwc3: dwc3-omap: Disable/Enable only wrapper interrupts in prepare/complete" usb: gadget: composite: enable BESL support usb: musb: cppi41: restart hrtimer only if not yet done usb: dwc3: ep0: fix Data Phase for transfer sizes aligned to wMaxPacketSize usb: serial: ftdi_sio: add "bricked" FTDI device PID ...
-rw-r--r--drivers/usb/chipidea/core.c1
-rw-r--r--drivers/usb/dwc2/core.h2
-rw-r--r--drivers/usb/dwc2/gadget.c14
-rw-r--r--drivers/usb/dwc3/dwc3-omap.c15
-rw-r--r--drivers/usb/dwc3/dwc3-pci.c2
-rw-r--r--drivers/usb/dwc3/ep0.c48
-rw-r--r--drivers/usb/dwc3/gadget.c39
-rw-r--r--drivers/usb/dwc3/gadget.h3
-rw-r--r--drivers/usb/dwc3/trace.h53
-rw-r--r--drivers/usb/gadget/composite.c2
-rw-r--r--drivers/usb/gadget/function/f_acm.c8
-rw-r--r--drivers/usb/gadget/function/f_eem.c1
-rw-r--r--drivers/usb/gadget/function/f_fs.c42
-rw-r--r--drivers/usb/gadget/function/f_hid.c5
-rw-r--r--drivers/usb/gadget/function/f_loopback.c87
-rw-r--r--drivers/usb/gadget/function/f_ncm.c1
-rw-r--r--drivers/usb/gadget/function/f_obex.c9
-rw-r--r--drivers/usb/gadget/function/f_phonet.c2
-rw-r--r--drivers/usb/gadget/function/f_rndis.c9
-rw-r--r--drivers/usb/gadget/function/f_subset.c1
-rw-r--r--drivers/usb/gadget/function/f_uac2.c23
-rw-r--r--drivers/usb/gadget/function/f_uvc.c54
-rw-r--r--drivers/usb/gadget/function/uvc_video.c3
-rw-r--r--drivers/usb/gadget/udc/Kconfig1
-rw-r--r--drivers/usb/gadget/udc/udc-core.c5
-rw-r--r--drivers/usb/musb/musb_cppi41.c3
-rw-r--r--drivers/usb/musb/musb_dsps.c18
-rw-r--r--drivers/usb/serial/cp210x.c1
-rw-r--r--drivers/usb/serial/ftdi_sio.c3
-rw-r--r--drivers/usb/serial/ftdi_sio_ids.h12
-rw-r--r--drivers/usb/serial/kobil_sct.c15
-rw-r--r--drivers/usb/serial/option.c10
32 files changed, 319 insertions, 173 deletions
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 3df5005c554d..9bdc6bd73432 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -742,7 +742,6 @@ static int ci_hdrc_remove(struct platform_device *pdev)
ci_role_destroy(ci);
ci_hdrc_enter_lpm(ci, true);
usb_phy_shutdown(ci->transceiver);
- kfree(ci->hw_bank.regmap);
return 0;
}
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index bf015ab3b44c..55c90c53f2d6 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -619,7 +619,7 @@ struct dwc2_hsotg {
unsigned port_suspend_change:1;
unsigned port_over_current_change:1;
unsigned port_l1_change:1;
- unsigned reserved:26;
+ unsigned reserved:25;
} b;
} flags;
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index 7b5856fadd93..eee87098bb8b 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -2561,8 +2561,10 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
hs_ep->fifo_size = val;
break;
}
- if (i == 8)
- return -ENOMEM;
+ if (i == 8) {
+ ret = -ENOMEM;
+ goto error;
+ }
}
/* for non control endpoints, set PID to D0 */
@@ -2579,6 +2581,7 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
/* enable the endpoint interrupt */
s3c_hsotg_ctrl_epint(hsotg, index, dir_in, 1);
+error:
spin_unlock_irqrestore(&hsotg->lock, flags);
return ret;
}
@@ -2934,9 +2937,7 @@ static int s3c_hsotg_udc_stop(struct usb_gadget *gadget,
spin_lock_irqsave(&hsotg->lock, flags);
- if (!driver)
- hsotg->driver = NULL;
-
+ hsotg->driver = NULL;
hsotg->gadget.speed = USB_SPEED_UNKNOWN;
spin_unlock_irqrestore(&hsotg->lock, flags);
@@ -3567,6 +3568,7 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
s3c_hsotg_initep(hsotg, &hsotg->eps[epnum], epnum);
/* disable power and clock */
+ s3c_hsotg_phy_disable(hsotg);
ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies),
hsotg->supplies);
@@ -3575,8 +3577,6 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
goto err_ep_mem;
}
- s3c_hsotg_phy_disable(hsotg);
-
ret = usb_add_gadget_udc(&pdev->dev, &hsotg->gadget);
if (ret)
goto err_ep_mem;
diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
index 2f537d588225..a0aa9f3da441 100644
--- a/drivers/usb/dwc3/dwc3-omap.c
+++ b/drivers/usb/dwc3/dwc3-omap.c
@@ -597,7 +597,7 @@ static int dwc3_omap_prepare(struct device *dev)
{
struct dwc3_omap *omap = dev_get_drvdata(dev);
- dwc3_omap_write_irqmisc_set(omap, 0x00);
+ dwc3_omap_disable_irqs(omap);
return 0;
}
@@ -605,19 +605,8 @@ static int dwc3_omap_prepare(struct device *dev)
static void dwc3_omap_complete(struct device *dev)
{
struct dwc3_omap *omap = dev_get_drvdata(dev);
- u32 reg;
- reg = (USBOTGSS_IRQMISC_OEVT |
- USBOTGSS_IRQMISC_DRVVBUS_RISE |
- USBOTGSS_IRQMISC_CHRGVBUS_RISE |
- USBOTGSS_IRQMISC_DISCHRGVBUS_RISE |
- USBOTGSS_IRQMISC_IDPULLUP_RISE |
- USBOTGSS_IRQMISC_DRVVBUS_FALL |
- USBOTGSS_IRQMISC_CHRGVBUS_FALL |
- USBOTGSS_IRQMISC_DISCHRGVBUS_FALL |
- USBOTGSS_IRQMISC_IDPULLUP_FALL);
-
- dwc3_omap_write_irqmisc_set(omap, reg);
+ dwc3_omap_enable_irqs(omap);
}
static int dwc3_omap_suspend(struct device *dev)
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index 436fb08c40b8..a36cf66302fb 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -30,6 +30,7 @@
#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd
#define PCI_DEVICE_ID_INTEL_BYT 0x0f37
#define PCI_DEVICE_ID_INTEL_MRFLD 0x119e
+#define PCI_DEVICE_ID_INTEL_BSW 0x22B7
struct dwc3_pci {
struct device *dev;
@@ -181,6 +182,7 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),
},
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW), },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), },
{ } /* Terminating Entry */
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index b35938777dde..711b23019d54 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -256,7 +256,7 @@ static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc)
/* stall is always issued on EP0 */
dep = dwc->eps[0];
- __dwc3_gadget_ep_set_halt(dep, 1);
+ __dwc3_gadget_ep_set_halt(dep, 1, false);
dep->flags = DWC3_EP_ENABLED;
dwc->delayed_status = false;
@@ -271,7 +271,7 @@ static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc)
dwc3_ep0_out_start(dwc);
}
-int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value)
+int __dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value)
{
struct dwc3_ep *dep = to_dwc3_ep(ep);
struct dwc3 *dwc = dep->dwc;
@@ -281,6 +281,20 @@ int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value)
return 0;
}
+int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value)
+{
+ struct dwc3_ep *dep = to_dwc3_ep(ep);
+ struct dwc3 *dwc = dep->dwc;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+ ret = __dwc3_gadget_ep0_set_halt(ep, value);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return ret;
+}
+
void dwc3_ep0_out_start(struct dwc3 *dwc)
{
int ret;
@@ -466,7 +480,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
return -EINVAL;
if (set == 0 && (dep->flags & DWC3_EP_WEDGE))
break;
- ret = __dwc3_gadget_ep_set_halt(dep, set);
+ ret = __dwc3_gadget_ep_set_halt(dep, set, true);
if (ret)
return -EINVAL;
break;
@@ -775,9 +789,6 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS;
- r = next_request(&ep0->request_list);
- ur = &r->request;
-
trb = dwc->ep0_trb;
status = DWC3_TRB_SIZE_TRBSTS(trb->size);
@@ -790,6 +801,12 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
return;
}
+ r = next_request(&ep0->request_list);
+ if (!r)
+ return;
+
+ ur = &r->request;
+
length = trb->size & DWC3_TRB_SIZE_MASK;
if (dwc->ep0_bounced) {
@@ -811,12 +828,19 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
dwc3_ep0_stall_and_restart(dwc);
} else {
- /*
- * handle the case where we have to send a zero packet. This
- * seems to be case when req.length > maxpacket. Could it be?
- */
- if (r)
- dwc3_gadget_giveback(ep0, r, 0);
+ dwc3_gadget_giveback(ep0, r, 0);
+
+ if (IS_ALIGNED(ur->length, ep0->endpoint.maxpacket) &&
+ ur->length && ur->zero) {
+ int ret;
+
+ dwc->ep0_next_event = DWC3_EP0_COMPLETE;
+
+ ret = dwc3_ep0_start_trans(dwc, epnum,
+ dwc->ctrl_req_addr, 0,
+ DWC3_TRBCTL_CONTROL_DATA);
+ WARN_ON(ret < 0);
+ }
}
}
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 3818b26bfc05..546ea5431b8c 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -525,12 +525,11 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
if (!usb_endpoint_xfer_isoc(desc))
return 0;
- memset(&trb_link, 0, sizeof(trb_link));
-
/* Link TRB for ISOC. The HWO bit is never reset */
trb_st_hw = &dep->trb_pool[0];
trb_link = &dep->trb_pool[DWC3_TRB_NUM - 1];
+ memset(trb_link, 0, sizeof(*trb_link));
trb_link->bpl = lower_32_bits(dwc3_trb_dma_offset(dep, trb_st_hw));
trb_link->bph = upper_32_bits(dwc3_trb_dma_offset(dep, trb_st_hw));
@@ -581,7 +580,7 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
/* make sure HW endpoint isn't stalled */
if (dep->flags & DWC3_EP_STALL)
- __dwc3_gadget_ep_set_halt(dep, 0);
+ __dwc3_gadget_ep_set_halt(dep, 0, false);
reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
reg &= ~DWC3_DALEPENA_EP(dep->number);
@@ -1202,15 +1201,28 @@ out0:
return ret;
}
-int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value)
+int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol)
{
struct dwc3_gadget_ep_cmd_params params;
struct dwc3 *dwc = dep->dwc;
int ret;
+ if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
+ dev_err(dwc->dev, "%s is of Isochronous type\n", dep->name);
+ return -EINVAL;
+ }
+
memset(&params, 0x00, sizeof(params));
if (value) {
+ if (!protocol && ((dep->direction && dep->flags & DWC3_EP_BUSY) ||
+ (!list_empty(&dep->req_queued) ||
+ !list_empty(&dep->request_list)))) {
+ dev_dbg(dwc->dev, "%s: pending request, cannot halt\n",
+ dep->name);
+ return -EAGAIN;
+ }
+
ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
DWC3_DEPCMD_SETSTALL, &params);
if (ret)
@@ -1241,15 +1253,7 @@ static int dwc3_gadget_ep_set_halt(struct usb_ep *ep, int value)
int ret;
spin_lock_irqsave(&dwc->lock, flags);
-
- if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
- dev_err(dwc->dev, "%s is of Isochronous type\n", dep->name);
- ret = -EINVAL;
- goto out;
- }
-
- ret = __dwc3_gadget_ep_set_halt(dep, value);
-out:
+ ret = __dwc3_gadget_ep_set_halt(dep, value, false);
spin_unlock_irqrestore(&dwc->lock, flags);
return ret;
@@ -1260,15 +1264,18 @@ static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep)
struct dwc3_ep *dep = to_dwc3_ep(ep);
struct dwc3 *dwc = dep->dwc;
unsigned long flags;
+ int ret;
spin_lock_irqsave(&dwc->lock, flags);
dep->flags |= DWC3_EP_WEDGE;
- spin_unlock_irqrestore(&dwc->lock, flags);
if (dep->number == 0 || dep->number == 1)
- return dwc3_gadget_ep0_set_halt(ep, 1);
+ ret = __dwc3_gadget_ep0_set_halt(ep, 1);
else
- return dwc3_gadget_ep_set_halt(ep, 1);
+ ret = __dwc3_gadget_ep_set_halt(dep, 1, false);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return ret;
}
/* -------------------------------------------------------------------------- */
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
index 178ad8982206..18ae3eaa8b6f 100644
--- a/drivers/usb/dwc3/gadget.h
+++ b/drivers/usb/dwc3/gadget.h
@@ -82,10 +82,11 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
void dwc3_ep0_interrupt(struct dwc3 *dwc,
const struct dwc3_event_depevt *event);
void dwc3_ep0_out_start(struct dwc3 *dwc);
+int __dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value);
int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value);
int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
gfp_t gfp_flags);
-int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value);
+int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol);
/**
* dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW
diff --git a/drivers/usb/dwc3/trace.h b/drivers/usb/dwc3/trace.h
index 78aff1da089a..60b0f41eafc4 100644
--- a/drivers/usb/dwc3/trace.h
+++ b/drivers/usb/dwc3/trace.h
@@ -73,15 +73,23 @@ DECLARE_EVENT_CLASS(dwc3_log_ctrl,
TP_PROTO(struct usb_ctrlrequest *ctrl),
TP_ARGS(ctrl),
TP_STRUCT__entry(
- __field(struct usb_ctrlrequest *, ctrl)
+ __field(__u8, bRequestType)
+ __field(__u8, bRequest)
+ __field(__le16, wValue)
+ __field(__le16, wIndex)
+ __field(__le16, wLength)
),
TP_fast_assign(
- __entry->ctrl = ctrl;
+ __entry->bRequestType = ctrl->bRequestType;
+ __entry->bRequest = ctrl->bRequest;
+ __entry->wValue = ctrl->wValue;
+ __entry->wIndex = ctrl->wIndex;
+ __entry->wLength = ctrl->wLength;
),
TP_printk("bRequestType %02x bRequest %02x wValue %04x wIndex %04x wLength %d",
- __entry->ctrl->bRequestType, __entry->ctrl->bRequest,
- le16_to_cpu(__entry->ctrl->wValue), le16_to_cpu(__entry->ctrl->wIndex),
- le16_to_cpu(__entry->ctrl->wLength)
+ __entry->bRequestType, __entry->bRequest,
+ le16_to_cpu(__entry->wValue), le16_to_cpu(__entry->wIndex),
+ le16_to_cpu(__entry->wLength)
)
);
@@ -94,15 +102,22 @@ DECLARE_EVENT_CLASS(dwc3_log_request,
TP_PROTO(struct dwc3_request *req),
TP_ARGS(req),
TP_STRUCT__entry(
+ __dynamic_array(char, name, DWC3_MSG_MAX)
__field(struct dwc3_request *, req)
+ __field(unsigned, actual)
+ __field(unsigned, length)
+ __field(int, status)
),
TP_fast_assign(
+ snprintf(__get_str(name), DWC3_MSG_MAX, "%s", req->dep->name);
__entry->req = req;
+ __entry->actual = req->request.actual;
+ __entry->length = req->request.length;
+ __entry->status = req->request.status;
),
TP_printk("%s: req %p length %u/%u ==> %d",
- __entry->req->dep->name, __entry->req,
- __entry->req->request.actual, __entry->req->request.length,
- __entry->req->request.status
+ __get_str(name), __entry->req, __entry->actual, __entry->length,
+ __entry->status
)
);
@@ -158,17 +173,17 @@ DECLARE_EVENT_CLASS(dwc3_log_gadget_ep_cmd,
struct dwc3_gadget_ep_cmd_params *params),
TP_ARGS(dep, cmd, params),
TP_STRUCT__entry(
- __field(struct dwc3_ep *, dep)
+ __dynamic_array(char, name, DWC3_MSG_MAX)
__field(unsigned int, cmd)
__field(struct dwc3_gadget_ep_cmd_params *, params)
),
TP_fast_assign(
- __entry->dep = dep;
+ snprintf(__get_str(name), DWC3_MSG_MAX, "%s", dep->name);
__entry->cmd = cmd;
__entry->params = params;
),
TP_printk("%s: cmd '%s' [%d] params %08x %08x %08x\n",
- __entry->dep->name, dwc3_gadget_ep_cmd_string(__entry->cmd),
+ __get_str(name), dwc3_gadget_ep_cmd_string(__entry->cmd),
__entry->cmd, __entry->params->param0,
__entry->params->param1, __entry->params->param2
)
@@ -184,16 +199,24 @@ DECLARE_EVENT_CLASS(dwc3_log_trb,
TP_PROTO(struct dwc3_ep *dep, struct dwc3_trb *trb),
TP_ARGS(dep, trb),
TP_STRUCT__entry(
- __field(struct dwc3_ep *, dep)
+ __dynamic_array(char, name, DWC3_MSG_MAX)
__field(struct dwc3_trb *, trb)
+ __field(u32, bpl)
+ __field(u32, bph)
+ __field(u32, size)
+ __field(u32, ctrl)
),
TP_fast_assign(
- __entry->dep = dep;
+ snprintf(__get_str(name), DWC3_MSG_MAX, "%s", dep->name);
__entry->trb = trb;
+ __entry->bpl = trb->bpl;
+ __entry->bph = trb->bph;
+ __entry->size = trb->size;
+ __entry->ctrl = trb->ctrl;
),
TP_printk("%s: trb %p bph %08x bpl %08x size %08x ctrl %08x\n",
- __entry->dep->name, __entry->trb, __entry->trb->bph,
- __entry->trb->bpl, __entry->trb->size, __entry->trb->ctrl
+ __get_str(name), __entry->trb, __entry->bph, __entry->bpl,
+ __entry->size, __entry->ctrl
)
);
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index a8c18df171c3..f6a51fddd5b5 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -560,7 +560,7 @@ static int bos_desc(struct usb_composite_dev *cdev)
usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE;
usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT;
- usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT);
+ usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT | USB_BESL_SUPPORT);
/*
* The Superspeed USB Capability descriptor shall be implemented by all
diff --git a/drivers/usb/gadget/function/f_acm.c b/drivers/usb/gadget/function/f_acm.c
index 6da4685490ef..aad8165e98ef 100644
--- a/drivers/usb/gadget/function/f_acm.c
+++ b/drivers/usb/gadget/function/f_acm.c
@@ -433,12 +433,12 @@ static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
dev_vdbg(&cdev->gadget->dev,
"reset acm control interface %d\n", intf);
usb_ep_disable(acm->notify);
- } else {
- dev_vdbg(&cdev->gadget->dev,
- "init acm ctrl interface %d\n", intf);
+ }
+
+ if (!acm->notify->desc)
if (config_ep_by_speed(cdev->gadget, f, acm->notify))
return -EINVAL;
- }
+
usb_ep_enable(acm->notify);
acm->notify->driver_data = acm;
diff --git a/drivers/usb/gadget/function/f_eem.c b/drivers/usb/gadget/function/f_eem.c
index 4d8b236ea608..c9e90de5bdd9 100644
--- a/drivers/usb/gadget/function/f_eem.c
+++ b/drivers/usb/gadget/function/f_eem.c
@@ -325,7 +325,6 @@ static int eem_bind(struct usb_configuration *c, struct usb_function *f)
return 0;
fail:
- usb_free_all_descriptors(f);
if (eem->port.out_ep)
eem->port.out_ep->driver_data = NULL;
if (eem->port.in_ep)
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 7c6771d027a2..63314ede7ba6 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -647,15 +647,26 @@ static void ffs_user_copy_worker(struct work_struct *work)
if (io_data->read && ret > 0) {
int i;
size_t pos = 0;
+
+ /*
+ * Since req->length may be bigger than io_data->len (after
+ * being rounded up to maxpacketsize), we may end up with more
+ * data then user space has space for.
+ */
+ ret = min_t(int, ret, io_data->len);
+
use_mm(io_data->mm);
for (i = 0; i < io_data->nr_segs; i++) {
+ size_t len = min_t(size_t, ret - pos,
+ io_data->iovec[i].iov_len);
+ if (!len)
+ break;
if (unlikely(copy_to_user(io_data->iovec[i].iov_base,
- &io_data->buf[pos],
- io_data->iovec[i].iov_len))) {
+ &io_data->buf[pos], len))) {
ret = -EFAULT;
break;
}
- pos += io_data->iovec[i].iov_len;
+ pos += len;
}
unuse_mm(io_data->mm);
}
@@ -687,7 +698,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
struct ffs_epfile *epfile = file->private_data;
struct ffs_ep *ep;
char *data = NULL;
- ssize_t ret, data_len;
+ ssize_t ret, data_len = -EINVAL;
int halt;
/* Are we still active? */
@@ -787,13 +798,30 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
/* Fire the request */
struct usb_request *req;
+ /*
+ * Sanity Check: even though data_len can't be used
+ * uninitialized at the time I write this comment, some
+ * compilers complain about this situation.
+ * In order to keep the code clean from warnings, data_len is
+ * being initialized to -EINVAL during its declaration, which
+ * means we can't rely on compiler anymore to warn no future
+ * changes won't result in data_len being used uninitialized.
+ * For such reason, we're adding this redundant sanity check
+ * here.
+ */
+ if (unlikely(data_len == -EINVAL)) {
+ WARN(1, "%s: data_len == -EINVAL\n", __func__);
+ ret = -EINVAL;
+ goto error_lock;
+ }
+
if (io_data->aio) {
req = usb_ep_alloc_request(ep->ep, GFP_KERNEL);
if (unlikely(!req))
goto error_lock;
req->buf = data;
- req->length = io_data->len;
+ req->length = data_len;
io_data->buf = data;
io_data->ep = ep->ep;
@@ -815,7 +843,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
req = ep->req;
req->buf = data;
- req->length = io_data->len;
+ req->length = data_len;
req->context = &done;
req->complete = ffs_epfile_io_complete;
@@ -2663,8 +2691,6 @@ static inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f,
func->conf = c;
func->gadget = c->cdev->gadget;
- ffs_data_get(func->ffs);
-
/*
* in drivers/usb/gadget/configfs.c:configfs_composite_bind()
* configurations are bound in sequence with list_for_each_entry,
diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c
index a95290a1289f..59ab62c92b66 100644
--- a/drivers/usb/gadget/function/f_hid.c
+++ b/drivers/usb/gadget/function/f_hid.c
@@ -621,12 +621,14 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)
dev = MKDEV(major, hidg->minor);
status = cdev_add(&hidg->cdev, dev, 1);
if (status)
- goto fail;
+ goto fail_free_descs;
device_create(hidg_class, NULL, dev, NULL, "%s%d", "hidg", hidg->minor);
return 0;
+fail_free_descs:
+ usb_free_all_descriptors(f);
fail:
ERROR(f->config->cdev, "hidg_bind FAILED\n");
if (hidg->req != NULL) {
@@ -635,7 +637,6 @@ fail:
usb_ep_free_request(hidg->in_ep, hidg->req);
}
- usb_free_all_descriptors(f);
return status;
}
diff --git a/drivers/usb/gadget/function/f_loopback.c b/drivers/usb/gadget/function/f_loopback.c
index bf04389137e6..298b46112b1a 100644
--- a/drivers/usb/gadget/function/f_loopback.c
+++ b/drivers/usb/gadget/function/f_loopback.c
@@ -253,22 +253,13 @@ static void loopback_complete(struct usb_ep *ep, struct usb_request *req)
case 0: /* normal completion? */
if (ep == loop->out_ep) {
- /* loop this OUT packet back IN to the host */
req->zero = (req->actual < req->length);
req->length = req->actual;
- status = usb_ep_queue(loop->in_ep, req, GFP_ATOMIC);
- if (status == 0)
- return;
-
- /* "should never get here" */
- ERROR(cdev, "can't loop %s to %s: %d\n",
- ep->name, loop->in_ep->name,
- status);
}
/* queue the buffer for some later OUT packet */
req->length = buflen;
- status = usb_ep_queue(loop->out_ep, req, GFP_ATOMIC);
+ status = usb_ep_queue(ep, req, GFP_ATOMIC);
if (status == 0)
return;
@@ -308,60 +299,66 @@ static inline struct usb_request *lb_alloc_ep_req(struct usb_ep *ep, int len)
return alloc_ep_req(ep, len, buflen);
}
-static int
-enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop)
+static int enable_endpoint(struct usb_composite_dev *cdev, struct f_loopback *loop,
+ struct usb_ep *ep)
{
- int result = 0;
- struct usb_ep *ep;
struct usb_request *req;
unsigned i;
+ int result;
- /* one endpoint writes data back IN to the host */
- ep = loop->in_ep;
+ /*
+ * one endpoint writes data back IN to the host while another endpoint
+ * just reads OUT packets
+ */
result = config_ep_by_speed(cdev->gadget, &(loop->function), ep);
if (result)
- return result;
+ goto fail0;
result = usb_ep_enable(ep);
if (result < 0)
- return result;
- ep->driver_data = loop;
-
- /* one endpoint just reads OUT packets */
- ep = loop->out_ep;
- result = config_ep_by_speed(cdev->gadget, &(loop->function), ep);
- if (result)
goto fail0;
-
- result = usb_ep_enable(ep);
- if (result < 0) {
-fail0:
- ep = loop->in_ep;
- usb_ep_disable(ep);
- ep->driver_data = NULL;
- return result;
- }
ep->driver_data = loop;
- /* allocate a bunch of read buffers and queue them all at once.
+ /*
+ * allocate a bunch of read buffers and queue them all at once.
* we buffer at most 'qlen' transfers; fewer if any need more
* than 'buflen' bytes each.
*/
for (i = 0; i < qlen && result == 0; i++) {
req = lb_alloc_ep_req(ep, 0);
- if (req) {
- req->complete = loopback_complete;
- result = usb_ep_queue(ep, req, GFP_ATOMIC);
- if (result)
- ERROR(cdev, "%s queue req --> %d\n",
- ep->name, result);
- } else {
- usb_ep_disable(ep);
- ep->driver_data = NULL;
- result = -ENOMEM;
- goto fail0;
+ if (!req)
+ goto fail1;
+
+ req->complete = loopback_complete;
+ result = usb_ep_queue(ep, req, GFP_ATOMIC);
+ if (result) {
+ ERROR(cdev, "%s queue req --> %d\n",
+ ep->name, result);
+ goto fail1;
}
}
+ return 0;
+
+fail1:
+ usb_ep_disable(ep);
+
+fail0:
+ return result;
+}
+
+static int
+enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop)
+{
+ int result = 0;
+
+ result = enable_endpoint(cdev, loop, loop->in_ep);
+ if (result)
+ return result;
+
+ result = enable_endpoint(cdev, loop, loop->out_ep);
+ if (result)
+ return result;
+
DBG(cdev, "%s enabled\n", loop->function.name);
return result;
}
diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c
index 146f48cc65d7..16361b0a8b46 100644
--- a/drivers/usb/gadget/function/f_ncm.c
+++ b/drivers/usb/gadget/function/f_ncm.c
@@ -1461,7 +1461,6 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
return 0;
fail:
- usb_free_all_descriptors(f);
if (ncm->notify_req) {
kfree(ncm->notify_req->buf);
usb_ep_free_request(ncm->notify, ncm->notify_req);
diff --git a/drivers/usb/gadget/function/f_obex.c b/drivers/usb/gadget/function/f_obex.c
index 5f40080c92cc..a1b79c53499c 100644
--- a/drivers/usb/gadget/function/f_obex.c
+++ b/drivers/usb/gadget/function/f_obex.c
@@ -35,6 +35,7 @@ struct f_obex {
struct gserial port;
u8 ctrl_id;
u8 data_id;
+ u8 cur_alt;
u8 port_num;
u8 can_activate;
};
@@ -235,6 +236,8 @@ static int obex_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
} else
goto fail;
+ obex->cur_alt = alt;
+
return 0;
fail:
@@ -245,10 +248,7 @@ static int obex_get_alt(struct usb_function *f, unsigned intf)
{
struct f_obex *obex = func_to_obex(f);
- if (intf == obex->ctrl_id)
- return 0;
-
- return obex->port.in->driver_data ? 1 : 0;
+ return obex->cur_alt;
}
static void obex_disable(struct usb_function *f)
@@ -397,7 +397,6 @@ static int obex_bind(struct usb_configuration *c, struct usb_function *f)
return 0;
fail:
- usb_free_all_descriptors(f);
/* we might as well release our claims on endpoints */
if (obex->port.out)
obex->port.out->driver_data = NULL;
diff --git a/drivers/usb/gadget/function/f_phonet.c b/drivers/usb/gadget/function/f_phonet.c
index b9cfc1571d71..1ec8b7ffdccd 100644
--- a/drivers/usb/gadget/function/f_phonet.c
+++ b/drivers/usb/gadget/function/f_phonet.c
@@ -570,8 +570,8 @@ static int pn_bind(struct usb_configuration *c, struct usb_function *f)
err_req:
for (i = 0; i < phonet_rxq_size && fp->out_reqv[i]; i++)
usb_ep_free_request(fp->out_ep, fp->out_reqv[i]);
-err:
usb_free_all_descriptors(f);
+err:
if (fp->out_ep)
fp->out_ep->driver_data = NULL;
if (fp->in_ep)
diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c
index ddb09dc6d1f2..f13fc6a58565 100644
--- a/drivers/usb/gadget/function/f_rndis.c
+++ b/drivers/usb/gadget/function/f_rndis.c
@@ -802,8 +802,10 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
if (rndis->manufacturer && rndis->vendorID &&
rndis_set_param_vendor(rndis->config, rndis->vendorID,
- rndis->manufacturer))
- goto fail;
+ rndis->manufacturer)) {
+ status = -EINVAL;
+ goto fail_free_descs;
+ }
/* NOTE: all that is done without knowing or caring about
* the network link ... which is unavailable to this code
@@ -817,10 +819,11 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
rndis->notify->name);
return 0;
+fail_free_descs:
+ usb_free_all_descriptors(f);
fail:
kfree(f->os_desc_table);
f->os_desc_n = 0;
- usb_free_all_descriptors(f);
if (rndis->notify_req) {
kfree(rndis->notify_req->buf);
diff --git a/drivers/usb/gadget/function/f_subset.c b/drivers/usb/gadget/function/f_subset.c
index 1ea8baf33333..e3dfa675ff06 100644
--- a/drivers/usb/gadget/function/f_subset.c
+++ b/drivers/usb/gadget/function/f_subset.c
@@ -380,7 +380,6 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
return 0;
fail:
- usb_free_all_descriptors(f);
/* we might as well release our claims on endpoints */
if (geth->port.out_ep)
geth->port.out_ep->driver_data = NULL;
diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c
index a5a27a504d67..33e16658e5cf 100644
--- a/drivers/usb/gadget/function/f_uac2.c
+++ b/drivers/usb/gadget/function/f_uac2.c
@@ -512,6 +512,11 @@ static int snd_uac2_remove(struct platform_device *pdev)
return 0;
}
+static void snd_uac2_release(struct device *dev)
+{
+ dev_dbg(dev, "releasing '%s'\n", dev_name(dev));
+}
+
static int alsa_uac2_init(struct audio_dev *agdev)
{
struct snd_uac2_chip *uac2 = &agdev->uac2;
@@ -523,6 +528,7 @@ static int alsa_uac2_init(struct audio_dev *agdev)
uac2->pdev.id = 0;
uac2->pdev.name = uac2_name;
+ uac2->pdev.dev.release = snd_uac2_release;
/* Register snd_uac2 driver */
err = platform_driver_register(&uac2->pdrv);
@@ -772,6 +778,7 @@ struct usb_endpoint_descriptor fs_epout_desc = {
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
+ .wMaxPacketSize = cpu_to_le16(1023),
.bInterval = 1,
};
@@ -780,6 +787,7 @@ struct usb_endpoint_descriptor hs_epout_desc = {
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
+ .wMaxPacketSize = cpu_to_le16(1024),
.bInterval = 4,
};
@@ -847,6 +855,7 @@ struct usb_endpoint_descriptor fs_epin_desc = {
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
+ .wMaxPacketSize = cpu_to_le16(1023),
.bInterval = 1,
};
@@ -855,6 +864,7 @@ struct usb_endpoint_descriptor hs_epin_desc = {
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
+ .wMaxPacketSize = cpu_to_le16(1024),
.bInterval = 4,
};
@@ -947,6 +957,9 @@ free_ep(struct uac2_rtd_params *prm, struct usb_ep *ep)
struct snd_uac2_chip *uac2 = prm->uac2;
int i;
+ if (!prm->ep_enabled)
+ return;
+
prm->ep_enabled = false;
for (i = 0; i < USB_XFERS; i++) {
@@ -1071,7 +1084,7 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL);
if (!prm->rbuf) {
prm->max_psize = 0;
- goto err;
+ goto err_free_descs;
}
prm = &agdev->uac2.p_prm;
@@ -1079,17 +1092,19 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL);
if (!prm->rbuf) {
prm->max_psize = 0;
- goto err;
+ goto err_free_descs;
}
ret = alsa_uac2_init(agdev);
if (ret)
- goto err;
+ goto err_free_descs;
return 0;
+
+err_free_descs:
+ usb_free_all_descriptors(fn);
err:
kfree(agdev->uac2.p_prm.rbuf);
kfree(agdev->uac2.c_prm.rbuf);
- usb_free_all_descriptors(fn);
if (agdev->in_ep)
agdev->in_ep->driver_data = NULL;
if (agdev->out_ep)
diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index e126439e4b65..945b3bd2ca98 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -279,27 +279,41 @@ uvc_function_get_alt(struct usb_function *f, unsigned interface)
else if (interface != uvc->streaming_intf)
return -EINVAL;
else
- return uvc->state == UVC_STATE_STREAMING ? 1 : 0;
+ return uvc->video.ep->driver_data ? 1 : 0;
}
static int
uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
{
struct uvc_device *uvc = to_uvc(f);
+ struct usb_composite_dev *cdev = f->config->cdev;
struct v4l2_event v4l2_event;
struct uvc_event *uvc_event = (void *)&v4l2_event.u.data;
int ret;
- INFO(f->config->cdev, "uvc_function_set_alt(%u, %u)\n", interface, alt);
+ INFO(cdev, "uvc_function_set_alt(%u, %u)\n", interface, alt);
if (interface == uvc->control_intf) {
if (alt)
return -EINVAL;
+ if (uvc->control_ep->driver_data) {
+ INFO(cdev, "reset UVC Control\n");
+ usb_ep_disable(uvc->control_ep);
+ uvc->control_ep->driver_data = NULL;
+ }
+
+ if (!uvc->control_ep->desc)
+ if (config_ep_by_speed(cdev->gadget, f, uvc->control_ep))
+ return -EINVAL;
+
+ usb_ep_enable(uvc->control_ep);
+ uvc->control_ep->driver_data = uvc;
+
if (uvc->state == UVC_STATE_DISCONNECTED) {
memset(&v4l2_event, 0, sizeof(v4l2_event));
v4l2_event.type = UVC_EVENT_CONNECT;
- uvc_event->speed = f->config->cdev->gadget->speed;
+ uvc_event->speed = cdev->gadget->speed;
v4l2_event_queue(uvc->vdev, &v4l2_event);
uvc->state = UVC_STATE_CONNECTED;
@@ -321,8 +335,10 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
if (uvc->state != UVC_STATE_STREAMING)
return 0;
- if (uvc->video.ep)
+ if (uvc->video.ep) {
usb_ep_disable(uvc->video.ep);
+ uvc->video.ep->driver_data = NULL;
+ }
memset(&v4l2_event, 0, sizeof(v4l2_event));
v4l2_event.type = UVC_EVENT_STREAMOFF;
@@ -335,14 +351,22 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
if (uvc->state != UVC_STATE_CONNECTED)
return 0;
- if (uvc->video.ep) {
- ret = config_ep_by_speed(f->config->cdev->gadget,
- &(uvc->func), uvc->video.ep);
- if (ret)
- return ret;
- usb_ep_enable(uvc->video.ep);
+ if (!uvc->video.ep)
+ return -EINVAL;
+
+ if (uvc->video.ep->driver_data) {
+ INFO(cdev, "reset UVC\n");
+ usb_ep_disable(uvc->video.ep);
+ uvc->video.ep->driver_data = NULL;
}
+ ret = config_ep_by_speed(f->config->cdev->gadget,
+ &(uvc->func), uvc->video.ep);
+ if (ret)
+ return ret;
+ usb_ep_enable(uvc->video.ep);
+ uvc->video.ep->driver_data = uvc;
+
memset(&v4l2_event, 0, sizeof(v4l2_event));
v4l2_event.type = UVC_EVENT_STREAMON;
v4l2_event_queue(uvc->vdev, &v4l2_event);
@@ -366,6 +390,16 @@ uvc_function_disable(struct usb_function *f)
v4l2_event_queue(uvc->vdev, &v4l2_event);
uvc->state = UVC_STATE_DISCONNECTED;
+
+ if (uvc->video.ep->driver_data) {
+ usb_ep_disable(uvc->video.ep);
+ uvc->video.ep->driver_data = NULL;
+ }
+
+ if (uvc->control_ep->driver_data) {
+ usb_ep_disable(uvc->control_ep);
+ uvc->control_ep->driver_data = NULL;
+ }
}
/* --------------------------------------------------------------------------
diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c
index c3e1f27dbbef..9cb86bc1a9a5 100644
--- a/drivers/usb/gadget/function/uvc_video.c
+++ b/drivers/usb/gadget/function/uvc_video.c
@@ -352,7 +352,8 @@ int uvcg_video_enable(struct uvc_video *video, int enable)
if (!enable) {
for (i = 0; i < UVC_NUM_REQUESTS; ++i)
- usb_ep_dequeue(video->ep, video->req[i]);
+ if (video->req[i])
+ usb_ep_dequeue(video->ep, video->req[i]);
uvc_video_free_requests(video);
uvcg_queue_enable(&video->queue, 0);
diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig
index 3ea287b0e448..217365d35a25 100644
--- a/drivers/usb/gadget/udc/Kconfig
+++ b/drivers/usb/gadget/udc/Kconfig
@@ -357,6 +357,7 @@ config USB_EG20T
config USB_GADGET_XILINX
tristate "Xilinx USB Driver"
+ depends on HAS_DMA
depends on OF || COMPILE_TEST
help
USB peripheral controller driver for Xilinx USB2 device.
diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c
index f107bb60a5ab..f2054659f25b 100644
--- a/drivers/usb/gadget/udc/udc-core.c
+++ b/drivers/usb/gadget/udc/udc-core.c
@@ -507,6 +507,11 @@ static ssize_t usb_udc_softconn_store(struct device *dev,
{
struct usb_udc *udc = container_of(dev, struct usb_udc, dev);
+ if (!udc->driver) {
+ dev_err(dev, "soft-connect without a gadget driver\n");
+ return -EOPNOTSUPP;
+ }
+
if (sysfs_streq(buf, "connect")) {
usb_gadget_udc_start(udc->gadget, udc->driver);
usb_gadget_connect(udc->gadget);
diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c
index acdfb3e68a90..5a9b977fbc19 100644
--- a/drivers/usb/musb/musb_cppi41.c
+++ b/drivers/usb/musb/musb_cppi41.c
@@ -209,7 +209,8 @@ static enum hrtimer_restart cppi41_recheck_tx_req(struct hrtimer *timer)
}
}
- if (!list_empty(&controller->early_tx_list)) {
+ if (!list_empty(&controller->early_tx_list) &&
+ !hrtimer_is_queued(&controller->early_tx)) {
ret = HRTIMER_RESTART;
hrtimer_forward_now(&controller->early_tx,
ktime_set(0, 20 * NSEC_PER_USEC));
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
index 154bcf1b5dfa..48bc09e7b83b 100644
--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -868,9 +868,15 @@ static int dsps_suspend(struct device *dev)
struct dsps_glue *glue = dev_get_drvdata(dev);
const struct dsps_musb_wrapper *wrp = glue->wrp;
struct musb *musb = platform_get_drvdata(glue->musb);
- void __iomem *mbase = musb->ctrl_base;
+ void __iomem *mbase;
del_timer_sync(&glue->timer);
+
+ if (!musb)
+ /* This can happen if the musb device is in -EPROBE_DEFER */
+ return 0;
+
+ mbase = musb->ctrl_base;
glue->context.control = dsps_readl(mbase, wrp->control);
glue->context.epintr = dsps_readl(mbase, wrp->epintr_set);
glue->context.coreintr = dsps_readl(mbase, wrp->coreintr_set);
@@ -887,8 +893,12 @@ static int dsps_resume(struct device *dev)
struct dsps_glue *glue = dev_get_drvdata(dev);
const struct dsps_musb_wrapper *wrp = glue->wrp;
struct musb *musb = platform_get_drvdata(glue->musb);
- void __iomem *mbase = musb->ctrl_base;
+ void __iomem *mbase;
+
+ if (!musb)
+ return 0;
+ mbase = musb->ctrl_base;
dsps_writel(mbase, wrp->control, glue->context.control);
dsps_writel(mbase, wrp->epintr_set, glue->context.epintr);
dsps_writel(mbase, wrp->coreintr_set, glue->context.coreintr);
@@ -896,7 +906,9 @@ static int dsps_resume(struct device *dev)
dsps_writel(mbase, wrp->mode, glue->context.mode);
dsps_writel(mbase, wrp->tx_mode, glue->context.tx_mode);
dsps_writel(mbase, wrp->rx_mode, glue->context.rx_mode);
- setup_timer(&glue->timer, otg_timer, (unsigned long) musb);
+ if (musb->xceiv->state == OTG_STATE_B_IDLE &&
+ musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE)
+ mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ);
return 0;
}
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index eca1747ca8c7..cfd009dc4018 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -155,6 +155,7 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
{ USB_DEVICE(0x1ADB, 0x0001) }, /* Schweitzer Engineering C662 Cable */
{ USB_DEVICE(0x1B1C, 0x1C00) }, /* Corsair USB Dongle */
+ { USB_DEVICE(0x1BA4, 0x0002) }, /* Silicon Labs 358x factory default */
{ USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */
{ USB_DEVICE(0x1D6F, 0x0010) }, /* Seluxit ApS RF Dongle */
{ USB_DEVICE(0x1E29, 0x0102) }, /* Festo CPX-USB */
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index dc72b924c399..0dad8ce5a609 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -140,6 +140,7 @@ static struct ftdi_sio_quirk ftdi_8u2232c_quirk = {
* /sys/bus/usb-serial/drivers/ftdi_sio/new_id and send a patch or report.
*/
static const struct usb_device_id id_table_combined[] = {
+ { USB_DEVICE(FTDI_VID, FTDI_BRICK_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CTI_MINI_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CTI_NANO_PID) },
@@ -661,6 +662,8 @@ static const struct usb_device_id id_table_combined[] = {
{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_5_PID) },
{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_6_PID) },
{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_7_PID) },
+ { USB_DEVICE(XSENS_VID, XSENS_AWINDA_DONGLE_PID) },
+ { USB_DEVICE(XSENS_VID, XSENS_AWINDA_STATION_PID) },
{ USB_DEVICE(XSENS_VID, XSENS_CONVERTER_PID) },
{ USB_DEVICE(XSENS_VID, XSENS_MTW_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_OMNI1509) },
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
index 5937b2d242f2..6786b705ccf6 100644
--- a/drivers/usb/serial/ftdi_sio_ids.h
+++ b/drivers/usb/serial/ftdi_sio_ids.h
@@ -30,6 +30,12 @@
/*** third-party PIDs (using FTDI_VID) ***/
+/*
+ * Certain versions of the official Windows FTDI driver reprogrammed
+ * counterfeit FTDI devices to PID 0. Support these devices anyway.
+ */
+#define FTDI_BRICK_PID 0x0000
+
#define FTDI_LUMEL_PD12_PID 0x6002
/*
@@ -143,8 +149,12 @@
* Xsens Technologies BV products (http://www.xsens.com).
*/
#define XSENS_VID 0x2639
-#define XSENS_CONVERTER_PID 0xD00D /* Xsens USB-serial converter */
+#define XSENS_AWINDA_STATION_PID 0x0101
+#define XSENS_AWINDA_DONGLE_PID 0x0102
#define XSENS_MTW_PID 0x0200 /* Xsens MTw */
+#define XSENS_CONVERTER_PID 0xD00D /* Xsens USB-serial converter */
+
+/* Xsens devices using FTDI VID */
#define XSENS_CONVERTER_0_PID 0xD388 /* Xsens USB converter */
#define XSENS_CONVERTER_1_PID 0xD389 /* Xsens Wireless Receiver */
#define XSENS_CONVERTER_2_PID 0xD38A
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index 078f9ed419c8..3d2bd65df0fc 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -414,8 +414,6 @@ static int kobil_tiocmset(struct tty_struct *tty,
int result;
int dtr = 0;
int rts = 0;
- unsigned char *transfer_buffer;
- int transfer_buffer_length = 8;
/* FIXME: locking ? */
priv = usb_get_serial_port_data(port);
@@ -425,11 +423,6 @@ static int kobil_tiocmset(struct tty_struct *tty,
return -EINVAL;
}
- /* allocate memory for transfer buffer */
- transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
- if (!transfer_buffer)
- return -ENOMEM;
-
if (set & TIOCM_RTS)
rts = 1;
if (set & TIOCM_DTR)
@@ -469,7 +462,6 @@ static int kobil_tiocmset(struct tty_struct *tty,
KOBIL_TIMEOUT);
}
dev_dbg(dev, "%s - Send set_status_line URB returns: %i\n", __func__, result);
- kfree(transfer_buffer);
return (result < 0) ? result : 0;
}
@@ -530,8 +522,6 @@ static int kobil_ioctl(struct tty_struct *tty,
{
struct usb_serial_port *port = tty->driver_data;
struct kobil_private *priv = usb_get_serial_port_data(port);
- unsigned char *transfer_buffer;
- int transfer_buffer_length = 8;
int result;
if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID ||
@@ -541,10 +531,6 @@ static int kobil_ioctl(struct tty_struct *tty,
switch (cmd) {
case TCFLSH:
- transfer_buffer = kmalloc(transfer_buffer_length, GFP_KERNEL);
- if (!transfer_buffer)
- return -ENOBUFS;
-
result = usb_control_msg(port->serial->dev,
usb_sndctrlpipe(port->serial->dev, 0),
SUSBCRequest_Misc,
@@ -559,7 +545,6 @@ static int kobil_ioctl(struct tty_struct *tty,
dev_dbg(&port->dev,
"%s - Send reset_all_queues (FLUSH) URB returns: %i\n",
__func__, result);
- kfree(transfer_buffer);
return (result < 0) ? -EIO: 0;
default:
return -ENOIOCTLCMD;
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index d1a3f6044c8a..7a4c21b4f676 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -269,6 +269,7 @@ static void option_instat_callback(struct urb *urb);
#define TELIT_PRODUCT_DE910_DUAL 0x1010
#define TELIT_PRODUCT_UE910_V2 0x1012
#define TELIT_PRODUCT_LE920 0x1200
+#define TELIT_PRODUCT_LE910 0x1201
/* ZTE PRODUCTS */
#define ZTE_VENDOR_ID 0x19d2
@@ -362,6 +363,7 @@ static void option_instat_callback(struct urb *urb);
/* Haier products */
#define HAIER_VENDOR_ID 0x201e
+#define HAIER_PRODUCT_CE81B 0x10f8
#define HAIER_PRODUCT_CE100 0x2009
/* Cinterion (formerly Siemens) products */
@@ -589,6 +591,11 @@ static const struct option_blacklist_info zte_1255_blacklist = {
.reserved = BIT(3) | BIT(4),
};
+static const struct option_blacklist_info telit_le910_blacklist = {
+ .sendsetup = BIT(0),
+ .reserved = BIT(1) | BIT(2),
+};
+
static const struct option_blacklist_info telit_le920_blacklist = {
.sendsetup = BIT(0),
.reserved = BIT(1) | BIT(5),
@@ -1138,6 +1145,8 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_SINGLE) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_DE910_DUAL) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UE910_V2) },
+ { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910),
+ .driver_info = (kernel_ulong_t)&telit_le910_blacklist },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920),
.driver_info = (kernel_ulong_t)&telit_le920_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */
@@ -1621,6 +1630,7 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(LONGCHEER_VENDOR_ID, ZOOM_PRODUCT_4597) },
{ USB_DEVICE(LONGCHEER_VENDOR_ID, IBALL_3_5G_CONNECT) },
{ USB_DEVICE(HAIER_VENDOR_ID, HAIER_PRODUCT_CE100) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HAIER_VENDOR_ID, HAIER_PRODUCT_CE81B, 0xff, 0xff, 0xff) },
/* Pirelli */
{ USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_C100_1, 0xff) },
{ USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_C100_2, 0xff) },