usb: fixes for v3.18-rc2
Here's the first set of fixes for v3.18-rc cycle. It includes a whole bunch of bug fixes related to USB20CV and USB30CV when running on DWC3 and MUSB. After this series, we have clean chapter 9 and MSC tests for all gadget drivers. We also have a new PCI ID for Intel Braswell platform so they can use DWC3 out-of-the-box. A regression on functionfs wrt quirk_ep_out_aligned_size flag has also been fixed. DWC2 got a couple of fixes for the gadget role. The first of which fixes rmmod followed by modprobe while the second makes sure to disable PHYs before killing the regulators powering them. These are the most important fixes worth mentioning, there are a few other minor fixes as well. Signed-off-by: Felipe Balbi <balbi@ti.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJUScWbAAoJEIaOsuA1yqREeoIQAKhr1MX2CKu4CchKhsuKXw+N IIrhZUA/9qLntXzP5DTK7EX9RRUa1fhYMDvkMG/PgWP9IE6A1PxqpjGLqv+BotRf /YCu2QnetFTO8+uf0zsBjT/t5zK8hFLBt0O2fCdTU5rs89jobfT8Jyvhx2RXz3K3 zp3BZ9RR+GFcPSzTjSAVhtIntpYv5J6lgLuzCB93OwLCkEYli8trZ3i7FwJrr9M9 3mMGy0GE0s9Nut2fd/qVGzVRlviQvanfRGPI+IeNsUrBNNfaANrRyf++aGk+wS4l npRPX2fToT74+jfUVXS3kKScEEtrQQnwLyFqAw4lQaxUP1CKfcE2KchDwEvyOAxC tf6jADg1PUKRmjHmAxJg4ioIX2Y/j+R+J28JXq2ef4AtxmxC64X67YNF3DuNxLp7 xUkXuBKpylccxbRpofgduuBbR3Vlv/gQ/Q/6qAZN72BWTKa0BAn17QrTUmyk1MIJ Q40hpJP1BgvXm1IgLeHheewMRFwi3GczxmGlZ3xl1t5fzGW27GdipkH/YDg3BQUA vM9lZAUSGtlp14I+k+lkV7OB12j2bckx509eX9Y1fNqGNSaAFwISKSrSaK0Dti0L Rl1g3N4eyZS95OqfbBhTWCAo1kvE6sEmnnJUzcs0yOnynLRoSI9I6Xuhxl17pov4 +Wj30xCHAL3bRB5If5Ol =UO7c -----END PGP SIGNATURE----- Merge tag 'fixes-for-v3.18-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-linus Felipe writes: usb: fixes for v3.18-rc2 Here's the first set of fixes for v3.18-rc cycle. It includes a whole bunch of bug fixes related to USB20CV and USB30CV when running on DWC3 and MUSB. After this series, we have clean chapter 9 and MSC tests for all gadget drivers. We also have a new PCI ID for Intel Braswell platform so they can use DWC3 out-of-the-box. A regression on functionfs wrt quirk_ep_out_aligned_size flag has also been fixed. DWC2 got a couple of fixes for the gadget role. The first of which fixes rmmod followed by modprobe while the second makes sure to disable PHYs before killing the regulators powering them. These are the most important fixes worth mentioning, there are a few other minor fixes as well. Signed-off-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
commit
8071e6f8b4
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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(¶ms, 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, ¶ms);
|
||||
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;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
result = config_ep_by_speed(cdev->gadget, &(loop->function), ep);
|
||||
if (result)
|
||||
return result;
|
||||
result = usb_ep_enable(ep);
|
||||
if (result < 0)
|
||||
return result;
|
||||
ep->driver_data = loop;
|
||||
|
||||
/* one endpoint just reads OUT packets */
|
||||
ep = loop->out_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)
|
||||
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;
|
||||
}
|
||||
if (result < 0)
|
||||
goto fail0;
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue