mirror of https://gitee.com/openkylin/linux.git
USB fixes for 4.10-rc3
Here are a bunch of USB fixes for 4.10-rc3. Yeah, it's a lot, an artifact of the holiday break I think. Lots of gadget and the usual XHCI fixups for reported issues (one day that driver will calm down...) Also included are a bunch of usb-serial driver fixes, and for good measure, a number of much-reported MUSB driver issues have finally been resolved. All of these have been in linux-next with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCWHI4oA8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ykL7QCgukj1bSdNrJtaT+YWprj4w59bikQAoJKidiUu aUMgZMng+IuE7lPo1bjQ =tCln -----END PGP SIGNATURE----- Merge tag 'usb-4.10-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 4.10-rc3. Yeah, it's a lot, an artifact of the holiday break I think. Lots of gadget and the usual XHCI fixups for reported issues (one day that driver will calm down...) Also included are a bunch of usb-serial driver fixes, and for good measure, a number of much-reported MUSB driver issues have finally been resolved. All of these have been in linux-next with no reported issues" * tag 'usb-4.10-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (72 commits) USB: fix problems with duplicate endpoint addresses usb: ohci-at91: use descriptor-based gpio APIs correctly usb: storage: unusual_uas: Add JMicron JMS56x to unusual device usb: hub: Move hub_port_disable() to fix warning if PM is disabled usb: musb: blackfin: add bfin_fifo_offset in bfin_ops usb: musb: fix compilation warning on unused function usb: musb: Fix trying to free already-free IRQ 4 usb: musb: dsps: implement clear_ep_rxintr() callback usb: musb: core: add clear_ep_rxintr() to musb_platform_ops USB: serial: ti_usb_3410_5052: fix NULL-deref at open USB: serial: spcp8x5: fix NULL-deref at open USB: serial: quatech2: fix sleep-while-atomic in close USB: serial: pl2303: fix NULL-deref at open USB: serial: oti6858: fix NULL-deref at open USB: serial: omninet: fix NULL-derefs at open and disconnect USB: serial: mos7840: fix misleading interrupt-URB comment USB: serial: mos7840: remove unused write URB USB: serial: mos7840: fix NULL-deref at open USB: serial: mos7720: remove obsolete port initialisation USB: serial: mos7720: fix parallel probe ...
This commit is contained in:
commit
83280e90ef
|
@ -239,6 +239,16 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
|
|||
if (ifp->desc.bNumEndpoints >= num_ep)
|
||||
goto skip_to_next_endpoint_or_interface_descriptor;
|
||||
|
||||
/* Check for duplicate endpoint addresses */
|
||||
for (i = 0; i < ifp->desc.bNumEndpoints; ++i) {
|
||||
if (ifp->endpoint[i].desc.bEndpointAddress ==
|
||||
d->bEndpointAddress) {
|
||||
dev_warn(ddev, "config %d interface %d altsetting %d has a duplicate endpoint with address 0x%X, skipping\n",
|
||||
cfgno, inum, asnum, d->bEndpointAddress);
|
||||
goto skip_to_next_endpoint_or_interface_descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
endpoint = &ifp->endpoint[ifp->desc.bNumEndpoints];
|
||||
++ifp->desc.bNumEndpoints;
|
||||
|
||||
|
|
|
@ -103,8 +103,7 @@ EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem);
|
|||
|
||||
static void hub_release(struct kref *kref);
|
||||
static int usb_reset_and_verify_device(struct usb_device *udev);
|
||||
static void hub_usb3_port_prepare_disable(struct usb_hub *hub,
|
||||
struct usb_port *port_dev);
|
||||
static int hub_port_disable(struct usb_hub *hub, int port1, int set_state);
|
||||
|
||||
static inline char *portspeed(struct usb_hub *hub, int portstatus)
|
||||
{
|
||||
|
@ -902,34 +901,6 @@ static int hub_set_port_link_state(struct usb_hub *hub, int port1,
|
|||
USB_PORT_FEAT_LINK_STATE);
|
||||
}
|
||||
|
||||
/*
|
||||
* USB-3 does not have a similar link state as USB-2 that will avoid negotiating
|
||||
* a connection with a plugged-in cable but will signal the host when the cable
|
||||
* is unplugged. Disable remote wake and set link state to U3 for USB-3 devices
|
||||
*/
|
||||
static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
|
||||
{
|
||||
struct usb_port *port_dev = hub->ports[port1 - 1];
|
||||
struct usb_device *hdev = hub->hdev;
|
||||
int ret = 0;
|
||||
|
||||
if (!hub->error) {
|
||||
if (hub_is_superspeed(hub->hdev)) {
|
||||
hub_usb3_port_prepare_disable(hub, port_dev);
|
||||
ret = hub_set_port_link_state(hub, port_dev->portnum,
|
||||
USB_SS_PORT_LS_U3);
|
||||
} else {
|
||||
ret = usb_clear_port_feature(hdev, port1,
|
||||
USB_PORT_FEAT_ENABLE);
|
||||
}
|
||||
}
|
||||
if (port_dev->child && set_state)
|
||||
usb_set_device_state(port_dev->child, USB_STATE_NOTATTACHED);
|
||||
if (ret && ret != -ENODEV)
|
||||
dev_err(&port_dev->dev, "cannot disable (err = %d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable a port and mark a logical connect-change event, so that some
|
||||
* time later hub_wq will disconnect() any existing usb_device on the port
|
||||
|
@ -4162,6 +4133,34 @@ static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port,
|
|||
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
/*
|
||||
* USB-3 does not have a similar link state as USB-2 that will avoid negotiating
|
||||
* a connection with a plugged-in cable but will signal the host when the cable
|
||||
* is unplugged. Disable remote wake and set link state to U3 for USB-3 devices
|
||||
*/
|
||||
static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
|
||||
{
|
||||
struct usb_port *port_dev = hub->ports[port1 - 1];
|
||||
struct usb_device *hdev = hub->hdev;
|
||||
int ret = 0;
|
||||
|
||||
if (!hub->error) {
|
||||
if (hub_is_superspeed(hub->hdev)) {
|
||||
hub_usb3_port_prepare_disable(hub, port_dev);
|
||||
ret = hub_set_port_link_state(hub, port_dev->portnum,
|
||||
USB_SS_PORT_LS_U3);
|
||||
} else {
|
||||
ret = usb_clear_port_feature(hdev, port1,
|
||||
USB_PORT_FEAT_ENABLE);
|
||||
}
|
||||
}
|
||||
if (port_dev->child && set_state)
|
||||
usb_set_device_state(port_dev->child, USB_STATE_NOTATTACHED);
|
||||
if (ret && ret != -ENODEV)
|
||||
dev_err(&port_dev->dev, "cannot disable (err = %d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* USB 2.0 spec, 7.1.7.3 / fig 7-29:
|
||||
*
|
||||
|
|
|
@ -3753,7 +3753,7 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
|
|||
hs_ep->desc_list = dma_alloc_coherent(hsotg->dev,
|
||||
MAX_DMA_DESC_NUM_GENERIC *
|
||||
sizeof(struct dwc2_dma_desc),
|
||||
&hs_ep->desc_list_dma, GFP_KERNEL);
|
||||
&hs_ep->desc_list_dma, GFP_ATOMIC);
|
||||
if (!hs_ep->desc_list) {
|
||||
ret = -ENOMEM;
|
||||
goto error2;
|
||||
|
|
|
@ -247,8 +247,6 @@ MODULE_DEVICE_TABLE(of, dwc2_of_match_table);
|
|||
static void dwc2_get_device_property(struct dwc2_hsotg *hsotg,
|
||||
char *property, u8 size, u64 *value)
|
||||
{
|
||||
u8 val8;
|
||||
u16 val16;
|
||||
u32 val32;
|
||||
|
||||
switch (size) {
|
||||
|
@ -256,17 +254,7 @@ static void dwc2_get_device_property(struct dwc2_hsotg *hsotg,
|
|||
*value = device_property_read_bool(hsotg->dev, property);
|
||||
break;
|
||||
case 1:
|
||||
if (device_property_read_u8(hsotg->dev, property, &val8))
|
||||
return;
|
||||
|
||||
*value = val8;
|
||||
break;
|
||||
case 2:
|
||||
if (device_property_read_u16(hsotg->dev, property, &val16))
|
||||
return;
|
||||
|
||||
*value = val16;
|
||||
break;
|
||||
case 4:
|
||||
if (device_property_read_u32(hsotg->dev, property, &val32))
|
||||
return;
|
||||
|
@ -1100,13 +1088,13 @@ static void dwc2_set_gadget_dma(struct dwc2_hsotg *hsotg)
|
|||
/* Buffer DMA */
|
||||
dwc2_set_param_bool(hsotg, &p->g_dma,
|
||||
false, "gadget-dma",
|
||||
true, false,
|
||||
dma_capable, false,
|
||||
dma_capable);
|
||||
|
||||
/* DMA Descriptor */
|
||||
dwc2_set_param_bool(hsotg, &p->g_dma_desc, false,
|
||||
"gadget-dma-desc",
|
||||
p->g_dma, false,
|
||||
!!hw->dma_desc_enable, false,
|
||||
!!hw->dma_desc_enable);
|
||||
}
|
||||
|
||||
|
@ -1130,8 +1118,14 @@ static void dwc2_set_parameters(struct dwc2_hsotg *hsotg,
|
|||
|
||||
dwc2_set_param_bool(hsotg, &p->host_dma,
|
||||
false, "host-dma",
|
||||
true, false,
|
||||
dma_capable, false,
|
||||
dma_capable);
|
||||
dwc2_set_param_host_rx_fifo_size(hsotg,
|
||||
params->host_rx_fifo_size);
|
||||
dwc2_set_param_host_nperio_tx_fifo_size(hsotg,
|
||||
params->host_nperio_tx_fifo_size);
|
||||
dwc2_set_param_host_perio_tx_fifo_size(hsotg,
|
||||
params->host_perio_tx_fifo_size);
|
||||
}
|
||||
dwc2_set_param_dma_desc_enable(hsotg, params->dma_desc_enable);
|
||||
dwc2_set_param_dma_desc_fs_enable(hsotg, params->dma_desc_fs_enable);
|
||||
|
@ -1140,12 +1134,6 @@ static void dwc2_set_parameters(struct dwc2_hsotg *hsotg,
|
|||
params->host_support_fs_ls_low_power);
|
||||
dwc2_set_param_enable_dynamic_fifo(hsotg,
|
||||
params->enable_dynamic_fifo);
|
||||
dwc2_set_param_host_rx_fifo_size(hsotg,
|
||||
params->host_rx_fifo_size);
|
||||
dwc2_set_param_host_nperio_tx_fifo_size(hsotg,
|
||||
params->host_nperio_tx_fifo_size);
|
||||
dwc2_set_param_host_perio_tx_fifo_size(hsotg,
|
||||
params->host_perio_tx_fifo_size);
|
||||
dwc2_set_param_max_transfer_size(hsotg,
|
||||
params->max_transfer_size);
|
||||
dwc2_set_param_max_packet_count(hsotg,
|
||||
|
|
|
@ -45,9 +45,7 @@
|
|||
#define DWC3_XHCI_RESOURCES_NUM 2
|
||||
|
||||
#define DWC3_SCRATCHBUF_SIZE 4096 /* each buffer is assumed to be 4KiB */
|
||||
#define DWC3_EVENT_SIZE 4 /* bytes */
|
||||
#define DWC3_EVENT_MAX_NUM 64 /* 2 events/endpoint */
|
||||
#define DWC3_EVENT_BUFFERS_SIZE (DWC3_EVENT_SIZE * DWC3_EVENT_MAX_NUM)
|
||||
#define DWC3_EVENT_BUFFERS_SIZE 4096
|
||||
#define DWC3_EVENT_TYPE_MASK 0xfe
|
||||
|
||||
#define DWC3_EVENT_TYPE_DEV 0
|
||||
|
@ -311,9 +309,8 @@
|
|||
#define DWC3_DCFG_SUPERSPEED_PLUS (5 << 0) /* DWC_usb31 only */
|
||||
#define DWC3_DCFG_SUPERSPEED (4 << 0)
|
||||
#define DWC3_DCFG_HIGHSPEED (0 << 0)
|
||||
#define DWC3_DCFG_FULLSPEED2 (1 << 0)
|
||||
#define DWC3_DCFG_FULLSPEED (1 << 0)
|
||||
#define DWC3_DCFG_LOWSPEED (2 << 0)
|
||||
#define DWC3_DCFG_FULLSPEED1 (3 << 0)
|
||||
|
||||
#define DWC3_DCFG_NUMP_SHIFT 17
|
||||
#define DWC3_DCFG_NUMP(n) (((n) >> DWC3_DCFG_NUMP_SHIFT) & 0x1f)
|
||||
|
@ -405,9 +402,8 @@
|
|||
#define DWC3_DSTS_SUPERSPEED_PLUS (5 << 0) /* DWC_usb31 only */
|
||||
#define DWC3_DSTS_SUPERSPEED (4 << 0)
|
||||
#define DWC3_DSTS_HIGHSPEED (0 << 0)
|
||||
#define DWC3_DSTS_FULLSPEED2 (1 << 0)
|
||||
#define DWC3_DSTS_FULLSPEED (1 << 0)
|
||||
#define DWC3_DSTS_LOWSPEED (2 << 0)
|
||||
#define DWC3_DSTS_FULLSPEED1 (3 << 0)
|
||||
|
||||
/* Device Generic Command Register */
|
||||
#define DWC3_DGCMD_SET_LMP 0x01
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/platform_data/dwc3-omap.h>
|
||||
|
@ -510,7 +511,7 @@ static int dwc3_omap_probe(struct platform_device *pdev)
|
|||
|
||||
/* check the DMA Status */
|
||||
reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG);
|
||||
|
||||
irq_set_status_flags(omap->irq, IRQ_NOAUTOEN);
|
||||
ret = devm_request_threaded_irq(dev, omap->irq, dwc3_omap_interrupt,
|
||||
dwc3_omap_interrupt_thread, IRQF_SHARED,
|
||||
"dwc3-omap", omap);
|
||||
|
@ -531,7 +532,7 @@ static int dwc3_omap_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
dwc3_omap_enable_irqs(omap);
|
||||
|
||||
enable_irq(omap->irq);
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
|
@ -552,6 +553,7 @@ static int dwc3_omap_remove(struct platform_device *pdev)
|
|||
extcon_unregister_notifier(omap->edev, EXTCON_USB, &omap->vbus_nb);
|
||||
extcon_unregister_notifier(omap->edev, EXTCON_USB_HOST, &omap->id_nb);
|
||||
dwc3_omap_disable_irqs(omap);
|
||||
disable_irq(omap->irq);
|
||||
of_platform_depopulate(omap->dev);
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#define PCI_DEVICE_ID_INTEL_BXT_M 0x1aaa
|
||||
#define PCI_DEVICE_ID_INTEL_APL 0x5aaa
|
||||
#define PCI_DEVICE_ID_INTEL_KBP 0xa2b0
|
||||
#define PCI_DEVICE_ID_INTEL_GLK 0x31aa
|
||||
|
||||
#define PCI_INTEL_BXT_DSM_UUID "732b85d5-b7a7-4a1b-9ba0-4bbd00ffd511"
|
||||
#define PCI_INTEL_BXT_FUNC_PMU_PWR 4
|
||||
|
@ -73,16 +74,6 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc)
|
|||
{
|
||||
struct platform_device *dwc3 = dwc->dwc3;
|
||||
struct pci_dev *pdev = dwc->pci;
|
||||
int ret;
|
||||
|
||||
struct property_entry sysdev_property[] = {
|
||||
PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
|
||||
{ },
|
||||
};
|
||||
|
||||
ret = platform_device_add_properties(dwc3, sysdev_property);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (pdev->vendor == PCI_VENDOR_ID_AMD &&
|
||||
pdev->device == PCI_DEVICE_ID_AMD_NL_USB) {
|
||||
|
@ -105,6 +96,7 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc)
|
|||
PROPERTY_ENTRY_BOOL("snps,disable_scramble_quirk"),
|
||||
PROPERTY_ENTRY_BOOL("snps,dis_u3_susphy_quirk"),
|
||||
PROPERTY_ENTRY_BOOL("snps,dis_u2_susphy_quirk"),
|
||||
PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
|
||||
{ },
|
||||
};
|
||||
|
||||
|
@ -115,7 +107,8 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc)
|
|||
int ret;
|
||||
|
||||
struct property_entry properties[] = {
|
||||
PROPERTY_ENTRY_STRING("dr-mode", "peripheral"),
|
||||
PROPERTY_ENTRY_STRING("dr_mode", "peripheral"),
|
||||
PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -167,6 +160,7 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc)
|
|||
PROPERTY_ENTRY_BOOL("snps,usb3_lpm_capable"),
|
||||
PROPERTY_ENTRY_BOOL("snps,has-lpm-erratum"),
|
||||
PROPERTY_ENTRY_BOOL("snps,dis_enblslpm_quirk"),
|
||||
PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
|
||||
{ },
|
||||
};
|
||||
|
||||
|
@ -274,6 +268,7 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
|
|||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT_M), },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_APL), },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KBP), },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GLK), },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB), },
|
||||
{ } /* Terminating Entry */
|
||||
};
|
||||
|
|
|
@ -39,18 +39,13 @@ static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep);
|
|||
static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
||||
struct dwc3_ep *dep, struct dwc3_request *req);
|
||||
|
||||
static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
|
||||
u32 len, u32 type, bool chain)
|
||||
static void dwc3_ep0_prepare_one_trb(struct dwc3 *dwc, u8 epnum,
|
||||
dma_addr_t buf_dma, u32 len, u32 type, bool chain)
|
||||
{
|
||||
struct dwc3_gadget_ep_cmd_params params;
|
||||
struct dwc3_trb *trb;
|
||||
struct dwc3_ep *dep;
|
||||
|
||||
int ret;
|
||||
|
||||
dep = dwc->eps[epnum];
|
||||
if (dep->flags & DWC3_EP_BUSY)
|
||||
return 0;
|
||||
|
||||
trb = &dwc->ep0_trb[dep->trb_enqueue];
|
||||
|
||||
|
@ -71,15 +66,23 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
|
|||
trb->ctrl |= (DWC3_TRB_CTRL_IOC
|
||||
| DWC3_TRB_CTRL_LST);
|
||||
|
||||
if (chain)
|
||||
trace_dwc3_prepare_trb(dep, trb);
|
||||
}
|
||||
|
||||
static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum)
|
||||
{
|
||||
struct dwc3_gadget_ep_cmd_params params;
|
||||
struct dwc3_ep *dep;
|
||||
int ret;
|
||||
|
||||
dep = dwc->eps[epnum];
|
||||
if (dep->flags & DWC3_EP_BUSY)
|
||||
return 0;
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
params.param0 = upper_32_bits(dwc->ep0_trb_addr);
|
||||
params.param1 = lower_32_bits(dwc->ep0_trb_addr);
|
||||
|
||||
trace_dwc3_prepare_trb(dep, trb);
|
||||
|
||||
ret = dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_STARTTRANSFER, ¶ms);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -280,8 +283,9 @@ void dwc3_ep0_out_start(struct dwc3 *dwc)
|
|||
|
||||
complete(&dwc->ep0_in_setup);
|
||||
|
||||
ret = dwc3_ep0_start_trans(dwc, 0, dwc->ctrl_req_addr, 8,
|
||||
dwc3_ep0_prepare_one_trb(dwc, 0, dwc->ctrl_req_addr, 8,
|
||||
DWC3_TRBCTL_CONTROL_SETUP, false);
|
||||
ret = dwc3_ep0_start_trans(dwc, 0);
|
||||
WARN_ON(ret < 0);
|
||||
}
|
||||
|
||||
|
@ -912,9 +916,9 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
|
|||
|
||||
dwc->ep0_next_event = DWC3_EP0_COMPLETE;
|
||||
|
||||
ret = dwc3_ep0_start_trans(dwc, epnum,
|
||||
dwc->ctrl_req_addr, 0,
|
||||
DWC3_TRBCTL_CONTROL_DATA, false);
|
||||
dwc3_ep0_prepare_one_trb(dwc, epnum, dwc->ctrl_req_addr,
|
||||
0, DWC3_TRBCTL_CONTROL_DATA, false);
|
||||
ret = dwc3_ep0_start_trans(dwc, epnum);
|
||||
WARN_ON(ret < 0);
|
||||
}
|
||||
}
|
||||
|
@ -993,9 +997,10 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
|||
req->direction = !!dep->number;
|
||||
|
||||
if (req->request.length == 0) {
|
||||
ret = dwc3_ep0_start_trans(dwc, dep->number,
|
||||
dwc3_ep0_prepare_one_trb(dwc, dep->number,
|
||||
dwc->ctrl_req_addr, 0,
|
||||
DWC3_TRBCTL_CONTROL_DATA, false);
|
||||
ret = dwc3_ep0_start_trans(dwc, dep->number);
|
||||
} else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket)
|
||||
&& (dep->number == 0)) {
|
||||
u32 transfer_size = 0;
|
||||
|
@ -1011,7 +1016,7 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
|||
if (req->request.length > DWC3_EP0_BOUNCE_SIZE) {
|
||||
transfer_size = ALIGN(req->request.length - maxpacket,
|
||||
maxpacket);
|
||||
ret = dwc3_ep0_start_trans(dwc, dep->number,
|
||||
dwc3_ep0_prepare_one_trb(dwc, dep->number,
|
||||
req->request.dma,
|
||||
transfer_size,
|
||||
DWC3_TRBCTL_CONTROL_DATA,
|
||||
|
@ -1023,18 +1028,20 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
|||
|
||||
dwc->ep0_bounced = true;
|
||||
|
||||
ret = dwc3_ep0_start_trans(dwc, dep->number,
|
||||
dwc3_ep0_prepare_one_trb(dwc, dep->number,
|
||||
dwc->ep0_bounce_addr, transfer_size,
|
||||
DWC3_TRBCTL_CONTROL_DATA, false);
|
||||
ret = dwc3_ep0_start_trans(dwc, dep->number);
|
||||
} else {
|
||||
ret = usb_gadget_map_request_by_dev(dwc->sysdev,
|
||||
&req->request, dep->number);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
ret = dwc3_ep0_start_trans(dwc, dep->number, req->request.dma,
|
||||
dwc3_ep0_prepare_one_trb(dwc, dep->number, req->request.dma,
|
||||
req->request.length, DWC3_TRBCTL_CONTROL_DATA,
|
||||
false);
|
||||
ret = dwc3_ep0_start_trans(dwc, dep->number);
|
||||
}
|
||||
|
||||
WARN_ON(ret < 0);
|
||||
|
@ -1048,8 +1055,9 @@ static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)
|
|||
type = dwc->three_stage_setup ? DWC3_TRBCTL_CONTROL_STATUS3
|
||||
: DWC3_TRBCTL_CONTROL_STATUS2;
|
||||
|
||||
return dwc3_ep0_start_trans(dwc, dep->number,
|
||||
dwc3_ep0_prepare_one_trb(dwc, dep->number,
|
||||
dwc->ctrl_req_addr, 0, type, false);
|
||||
return dwc3_ep0_start_trans(dwc, dep->number);
|
||||
}
|
||||
|
||||
static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep)
|
||||
|
|
|
@ -180,11 +180,11 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
|
|||
if (req->request.status == -EINPROGRESS)
|
||||
req->request.status = status;
|
||||
|
||||
if (dwc->ep0_bounced && dep->number == 0)
|
||||
if (dwc->ep0_bounced && dep->number <= 1)
|
||||
dwc->ep0_bounced = false;
|
||||
else
|
||||
usb_gadget_unmap_request_by_dev(dwc->sysdev,
|
||||
&req->request, req->direction);
|
||||
|
||||
usb_gadget_unmap_request_by_dev(dwc->sysdev,
|
||||
&req->request, req->direction);
|
||||
|
||||
trace_dwc3_gadget_giveback(req);
|
||||
|
||||
|
@ -1720,7 +1720,7 @@ static int __dwc3_gadget_start(struct dwc3 *dwc)
|
|||
reg |= DWC3_DCFG_LOWSPEED;
|
||||
break;
|
||||
case USB_SPEED_FULL:
|
||||
reg |= DWC3_DCFG_FULLSPEED1;
|
||||
reg |= DWC3_DCFG_FULLSPEED;
|
||||
break;
|
||||
case USB_SPEED_HIGH:
|
||||
reg |= DWC3_DCFG_HIGHSPEED;
|
||||
|
@ -2232,9 +2232,14 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
|
|||
|
||||
dep = dwc->eps[epnum];
|
||||
|
||||
if (!(dep->flags & DWC3_EP_ENABLED) &&
|
||||
!(dep->flags & DWC3_EP_END_TRANSFER_PENDING))
|
||||
return;
|
||||
if (!(dep->flags & DWC3_EP_ENABLED)) {
|
||||
if (!(dep->flags & DWC3_EP_END_TRANSFER_PENDING))
|
||||
return;
|
||||
|
||||
/* Handle only EPCMDCMPLT when EP disabled */
|
||||
if (event->endpoint_event != DWC3_DEPEVT_EPCMDCMPLT)
|
||||
return;
|
||||
}
|
||||
|
||||
if (epnum == 0 || epnum == 1) {
|
||||
dwc3_ep0_interrupt(dwc, event);
|
||||
|
@ -2531,8 +2536,7 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
|
|||
dwc->gadget.ep0->maxpacket = 64;
|
||||
dwc->gadget.speed = USB_SPEED_HIGH;
|
||||
break;
|
||||
case DWC3_DSTS_FULLSPEED2:
|
||||
case DWC3_DSTS_FULLSPEED1:
|
||||
case DWC3_DSTS_FULLSPEED:
|
||||
dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
|
||||
dwc->gadget.ep0->maxpacket = 64;
|
||||
dwc->gadget.speed = USB_SPEED_FULL;
|
||||
|
|
|
@ -1694,9 +1694,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
|||
value = min(w_length, (u16) 1);
|
||||
break;
|
||||
|
||||
/* function drivers must handle get/set altsetting; if there's
|
||||
* no get() method, we know only altsetting zero works.
|
||||
*/
|
||||
/* function drivers must handle get/set altsetting */
|
||||
case USB_REQ_SET_INTERFACE:
|
||||
if (ctrl->bRequestType != USB_RECIP_INTERFACE)
|
||||
goto unknown;
|
||||
|
@ -1705,7 +1703,13 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
|||
f = cdev->config->interface[intf];
|
||||
if (!f)
|
||||
break;
|
||||
if (w_value && !f->set_alt)
|
||||
|
||||
/*
|
||||
* If there's no get_alt() method, we know only altsetting zero
|
||||
* works. There is no need to check if set_alt() is not NULL
|
||||
* as we check this in usb_add_function().
|
||||
*/
|
||||
if (w_value && !f->get_alt)
|
||||
break;
|
||||
value = f->set_alt(f, w_index, w_value);
|
||||
if (value == USB_GADGET_DELAYED_STATUS) {
|
||||
|
|
|
@ -2091,8 +2091,8 @@ static int __ffs_data_do_entity(enum ffs_entity_type type,
|
|||
|
||||
case FFS_STRING:
|
||||
/*
|
||||
* Strings are indexed from 1 (0 is magic ;) reserved
|
||||
* for languages list or some such)
|
||||
* Strings are indexed from 1 (0 is reserved
|
||||
* for languages list)
|
||||
*/
|
||||
if (*valuep > helper->ffs->strings_count)
|
||||
helper->ffs->strings_count = *valuep;
|
||||
|
@ -2252,7 +2252,7 @@ static int __ffs_data_do_os_desc(enum ffs_os_desc_type type,
|
|||
|
||||
if (len < sizeof(*d) ||
|
||||
d->bFirstInterfaceNumber >= ffs->interfaces_count ||
|
||||
!d->Reserved1)
|
||||
d->Reserved1)
|
||||
return -EINVAL;
|
||||
for (i = 0; i < ARRAY_SIZE(d->Reserved2); ++i)
|
||||
if (d->Reserved2[i])
|
||||
|
@ -3666,6 +3666,7 @@ static void ffs_closed(struct ffs_data *ffs)
|
|||
{
|
||||
struct ffs_dev *ffs_obj;
|
||||
struct f_fs_opts *opts;
|
||||
struct config_item *ci;
|
||||
|
||||
ENTER();
|
||||
ffs_dev_lock();
|
||||
|
@ -3689,8 +3690,11 @@ static void ffs_closed(struct ffs_data *ffs)
|
|||
|| !atomic_read(&opts->func_inst.group.cg_item.ci_kref.refcount))
|
||||
goto done;
|
||||
|
||||
unregister_gadget_item(ffs_obj->opts->
|
||||
func_inst.group.cg_item.ci_parent->ci_parent);
|
||||
ci = opts->func_inst.group.cg_item.ci_parent->ci_parent;
|
||||
ffs_dev_unlock();
|
||||
|
||||
unregister_gadget_item(ci);
|
||||
return;
|
||||
done:
|
||||
ffs_dev_unlock();
|
||||
}
|
||||
|
|
|
@ -593,7 +593,7 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
|||
}
|
||||
status = usb_ep_enable(hidg->out_ep);
|
||||
if (status < 0) {
|
||||
ERROR(cdev, "Enable IN endpoint FAILED!\n");
|
||||
ERROR(cdev, "Enable OUT endpoint FAILED!\n");
|
||||
goto fail;
|
||||
}
|
||||
hidg->out_ep->driver_data = hidg;
|
||||
|
|
|
@ -1126,7 +1126,7 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
|
|||
/* data and/or status stage for control request */
|
||||
} else if (dev->state == STATE_DEV_SETUP) {
|
||||
|
||||
/* IN DATA+STATUS caller makes len <= wLength */
|
||||
len = min_t(size_t, len, dev->setup_wLength);
|
||||
if (dev->setup_in) {
|
||||
retval = setup_req (dev->gadget->ep0, dev->req, len);
|
||||
if (retval == 0) {
|
||||
|
@ -1734,10 +1734,12 @@ static struct usb_gadget_driver gadgetfs_driver = {
|
|||
* such as configuration notifications.
|
||||
*/
|
||||
|
||||
static int is_valid_config (struct usb_config_descriptor *config)
|
||||
static int is_valid_config(struct usb_config_descriptor *config,
|
||||
unsigned int total)
|
||||
{
|
||||
return config->bDescriptorType == USB_DT_CONFIG
|
||||
&& config->bLength == USB_DT_CONFIG_SIZE
|
||||
&& total >= USB_DT_CONFIG_SIZE
|
||||
&& config->bConfigurationValue != 0
|
||||
&& (config->bmAttributes & USB_CONFIG_ATT_ONE) != 0
|
||||
&& (config->bmAttributes & USB_CONFIG_ATT_WAKEUP) == 0;
|
||||
|
@ -1762,7 +1764,8 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
|
|||
}
|
||||
spin_unlock_irq(&dev->lock);
|
||||
|
||||
if (len < (USB_DT_CONFIG_SIZE + USB_DT_DEVICE_SIZE + 4))
|
||||
if ((len < (USB_DT_CONFIG_SIZE + USB_DT_DEVICE_SIZE + 4)) ||
|
||||
(len > PAGE_SIZE * 4))
|
||||
return -EINVAL;
|
||||
|
||||
/* we might need to change message format someday */
|
||||
|
@ -1786,7 +1789,8 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
|
|||
/* full or low speed config */
|
||||
dev->config = (void *) kbuf;
|
||||
total = le16_to_cpu(dev->config->wTotalLength);
|
||||
if (!is_valid_config (dev->config) || total >= length)
|
||||
if (!is_valid_config(dev->config, total) ||
|
||||
total > length - USB_DT_DEVICE_SIZE)
|
||||
goto fail;
|
||||
kbuf += total;
|
||||
length -= total;
|
||||
|
@ -1795,10 +1799,13 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
|
|||
if (kbuf [1] == USB_DT_CONFIG) {
|
||||
dev->hs_config = (void *) kbuf;
|
||||
total = le16_to_cpu(dev->hs_config->wTotalLength);
|
||||
if (!is_valid_config (dev->hs_config) || total >= length)
|
||||
if (!is_valid_config(dev->hs_config, total) ||
|
||||
total > length - USB_DT_DEVICE_SIZE)
|
||||
goto fail;
|
||||
kbuf += total;
|
||||
length -= total;
|
||||
} else {
|
||||
dev->hs_config = NULL;
|
||||
}
|
||||
|
||||
/* could support multiple configs, using another encoding! */
|
||||
|
@ -1811,7 +1818,6 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
|
|||
|| dev->dev->bDescriptorType != USB_DT_DEVICE
|
||||
|| dev->dev->bNumConfigurations != 1)
|
||||
goto fail;
|
||||
dev->dev->bNumConfigurations = 1;
|
||||
dev->dev->bcdUSB = cpu_to_le16 (0x0200);
|
||||
|
||||
/* triggers gadgetfs_bind(); then we can enumerate. */
|
||||
|
|
|
@ -1317,7 +1317,11 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
|
|||
if (!ret)
|
||||
break;
|
||||
}
|
||||
if (!ret && !udc->driver)
|
||||
if (ret)
|
||||
ret = -ENODEV;
|
||||
else if (udc->driver)
|
||||
ret = -EBUSY;
|
||||
else
|
||||
goto found;
|
||||
} else {
|
||||
list_for_each_entry(udc, &udc_list, list) {
|
||||
|
|
|
@ -330,7 +330,7 @@ static void nuke(struct dummy *dum, struct dummy_ep *ep)
|
|||
/* caller must hold lock */
|
||||
static void stop_activity(struct dummy *dum)
|
||||
{
|
||||
struct dummy_ep *ep;
|
||||
int i;
|
||||
|
||||
/* prevent any more requests */
|
||||
dum->address = 0;
|
||||
|
@ -338,8 +338,8 @@ static void stop_activity(struct dummy *dum)
|
|||
/* The timer is left running so that outstanding URBs can fail */
|
||||
|
||||
/* nuke any pending requests first, so driver i/o is quiesced */
|
||||
list_for_each_entry(ep, &dum->gadget.ep_list, ep.ep_list)
|
||||
nuke(dum, ep);
|
||||
for (i = 0; i < DUMMY_ENDPOINTS; ++i)
|
||||
nuke(dum, &dum->ep[i]);
|
||||
|
||||
/* driver now does any non-usb quiescing necessary */
|
||||
}
|
||||
|
|
|
@ -43,7 +43,6 @@ struct at91_usbh_data {
|
|||
struct gpio_desc *overcurrent_pin[AT91_MAX_USBH_PORTS];
|
||||
u8 ports; /* number of ports on root hub */
|
||||
u8 overcurrent_supported;
|
||||
u8 vbus_pin_active_low[AT91_MAX_USBH_PORTS];
|
||||
u8 overcurrent_status[AT91_MAX_USBH_PORTS];
|
||||
u8 overcurrent_changed[AT91_MAX_USBH_PORTS];
|
||||
};
|
||||
|
@ -266,8 +265,7 @@ static void ohci_at91_usb_set_power(struct at91_usbh_data *pdata, int port, int
|
|||
if (!valid_port(port))
|
||||
return;
|
||||
|
||||
gpiod_set_value(pdata->vbus_pin[port],
|
||||
pdata->vbus_pin_active_low[port] ^ enable);
|
||||
gpiod_set_value(pdata->vbus_pin[port], enable);
|
||||
}
|
||||
|
||||
static int ohci_at91_usb_get_power(struct at91_usbh_data *pdata, int port)
|
||||
|
@ -275,8 +273,7 @@ static int ohci_at91_usb_get_power(struct at91_usbh_data *pdata, int port)
|
|||
if (!valid_port(port))
|
||||
return -EINVAL;
|
||||
|
||||
return gpiod_get_value(pdata->vbus_pin[port]) ^
|
||||
pdata->vbus_pin_active_low[port];
|
||||
return gpiod_get_value(pdata->vbus_pin[port]);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -533,18 +530,17 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev)
|
|||
pdata->ports = ports;
|
||||
|
||||
at91_for_each_port(i) {
|
||||
pdata->vbus_pin[i] = devm_gpiod_get_optional(&pdev->dev,
|
||||
"atmel,vbus-gpio",
|
||||
GPIOD_IN);
|
||||
if (i >= pdata->ports)
|
||||
break;
|
||||
|
||||
pdata->vbus_pin[i] =
|
||||
devm_gpiod_get_index_optional(&pdev->dev, "atmel,vbus",
|
||||
i, GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(pdata->vbus_pin[i])) {
|
||||
err = PTR_ERR(pdata->vbus_pin[i]);
|
||||
dev_err(&pdev->dev, "unable to claim gpio \"vbus\": %d\n", err);
|
||||
continue;
|
||||
}
|
||||
|
||||
pdata->vbus_pin_active_low[i] = gpiod_get_value(pdata->vbus_pin[i]);
|
||||
|
||||
ohci_at91_usb_set_power(pdata, i, 1);
|
||||
}
|
||||
|
||||
at91_for_each_port(i) {
|
||||
|
@ -552,8 +548,8 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev)
|
|||
break;
|
||||
|
||||
pdata->overcurrent_pin[i] =
|
||||
devm_gpiod_get_optional(&pdev->dev,
|
||||
"atmel,oc-gpio", GPIOD_IN);
|
||||
devm_gpiod_get_index_optional(&pdev->dev, "atmel,oc",
|
||||
i, GPIOD_IN);
|
||||
if (IS_ERR(pdata->overcurrent_pin[i])) {
|
||||
err = PTR_ERR(pdata->overcurrent_pin[i]);
|
||||
dev_err(&pdev->dev, "unable to claim gpio \"overcurrent\": %d\n", err);
|
||||
|
|
|
@ -979,6 +979,40 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id)
|
|||
xhci->devs[slot_id] = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free a virt_device structure.
|
||||
* If the virt_device added a tt_info (a hub) and has children pointing to
|
||||
* that tt_info, then free the child first. Recursive.
|
||||
* We can't rely on udev at this point to find child-parent relationships.
|
||||
*/
|
||||
void xhci_free_virt_devices_depth_first(struct xhci_hcd *xhci, int slot_id)
|
||||
{
|
||||
struct xhci_virt_device *vdev;
|
||||
struct list_head *tt_list_head;
|
||||
struct xhci_tt_bw_info *tt_info, *next;
|
||||
int i;
|
||||
|
||||
vdev = xhci->devs[slot_id];
|
||||
if (!vdev)
|
||||
return;
|
||||
|
||||
tt_list_head = &(xhci->rh_bw[vdev->real_port - 1].tts);
|
||||
list_for_each_entry_safe(tt_info, next, tt_list_head, tt_list) {
|
||||
/* is this a hub device that added a tt_info to the tts list */
|
||||
if (tt_info->slot_id == slot_id) {
|
||||
/* are any devices using this tt_info? */
|
||||
for (i = 1; i < HCS_MAX_SLOTS(xhci->hcs_params1); i++) {
|
||||
vdev = xhci->devs[i];
|
||||
if (vdev && (vdev->tt_info == tt_info))
|
||||
xhci_free_virt_devices_depth_first(
|
||||
xhci, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* we are now at a leaf device */
|
||||
xhci_free_virt_device(xhci, slot_id);
|
||||
}
|
||||
|
||||
int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
|
||||
struct usb_device *udev, gfp_t flags)
|
||||
{
|
||||
|
@ -1795,7 +1829,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
|
|||
int size;
|
||||
int i, j, num_ports;
|
||||
|
||||
del_timer_sync(&xhci->cmd_timer);
|
||||
cancel_delayed_work_sync(&xhci->cmd_timer);
|
||||
|
||||
/* Free the Event Ring Segment Table and the actual Event Ring */
|
||||
size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries);
|
||||
|
@ -1828,8 +1862,8 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
|
|||
}
|
||||
}
|
||||
|
||||
for (i = 1; i < MAX_HC_SLOTS; ++i)
|
||||
xhci_free_virt_device(xhci, i);
|
||||
for (i = HCS_MAX_SLOTS(xhci->hcs_params1); i > 0; i--)
|
||||
xhci_free_virt_devices_depth_first(xhci, i);
|
||||
|
||||
dma_pool_destroy(xhci->segment_pool);
|
||||
xhci->segment_pool = NULL;
|
||||
|
@ -2342,9 +2376,9 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
|
|||
|
||||
INIT_LIST_HEAD(&xhci->cmd_list);
|
||||
|
||||
/* init command timeout timer */
|
||||
setup_timer(&xhci->cmd_timer, xhci_handle_command_timeout,
|
||||
(unsigned long)xhci);
|
||||
/* init command timeout work */
|
||||
INIT_DELAYED_WORK(&xhci->cmd_timer, xhci_handle_command_timeout);
|
||||
init_completion(&xhci->cmd_ring_stop_completion);
|
||||
|
||||
page_size = readl(&xhci->op_regs->page_size);
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
|
||||
|
|
|
@ -579,8 +579,10 @@ static int xhci_mtk_probe(struct platform_device *pdev)
|
|||
goto disable_ldos;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
if (irq < 0) {
|
||||
ret = irq;
|
||||
goto disable_clk;
|
||||
}
|
||||
|
||||
/* Initialize dma_mask and coherent_dma_mask to 32-bits */
|
||||
ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
|
||||
|
|
|
@ -165,7 +165,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
|
|||
pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI ||
|
||||
pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI ||
|
||||
pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI ||
|
||||
pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI)) {
|
||||
pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI ||
|
||||
pdev->device == PCI_DEVICE_ID_INTEL_APL_XHCI)) {
|
||||
xhci->quirks |= XHCI_PME_STUCK_QUIRK;
|
||||
}
|
||||
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
|
||||
|
|
|
@ -279,23 +279,76 @@ void xhci_ring_cmd_db(struct xhci_hcd *xhci)
|
|||
readl(&xhci->dba->doorbell[0]);
|
||||
}
|
||||
|
||||
static int xhci_abort_cmd_ring(struct xhci_hcd *xhci)
|
||||
static bool xhci_mod_cmd_timer(struct xhci_hcd *xhci, unsigned long delay)
|
||||
{
|
||||
return mod_delayed_work(system_wq, &xhci->cmd_timer, delay);
|
||||
}
|
||||
|
||||
static struct xhci_command *xhci_next_queued_cmd(struct xhci_hcd *xhci)
|
||||
{
|
||||
return list_first_entry_or_null(&xhci->cmd_list, struct xhci_command,
|
||||
cmd_list);
|
||||
}
|
||||
|
||||
/*
|
||||
* Turn all commands on command ring with status set to "aborted" to no-op trbs.
|
||||
* If there are other commands waiting then restart the ring and kick the timer.
|
||||
* This must be called with command ring stopped and xhci->lock held.
|
||||
*/
|
||||
static void xhci_handle_stopped_cmd_ring(struct xhci_hcd *xhci,
|
||||
struct xhci_command *cur_cmd)
|
||||
{
|
||||
struct xhci_command *i_cmd;
|
||||
u32 cycle_state;
|
||||
|
||||
/* Turn all aborted commands in list to no-ops, then restart */
|
||||
list_for_each_entry(i_cmd, &xhci->cmd_list, cmd_list) {
|
||||
|
||||
if (i_cmd->status != COMP_CMD_ABORT)
|
||||
continue;
|
||||
|
||||
i_cmd->status = COMP_CMD_STOP;
|
||||
|
||||
xhci_dbg(xhci, "Turn aborted command %p to no-op\n",
|
||||
i_cmd->command_trb);
|
||||
/* get cycle state from the original cmd trb */
|
||||
cycle_state = le32_to_cpu(
|
||||
i_cmd->command_trb->generic.field[3]) & TRB_CYCLE;
|
||||
/* modify the command trb to no-op command */
|
||||
i_cmd->command_trb->generic.field[0] = 0;
|
||||
i_cmd->command_trb->generic.field[1] = 0;
|
||||
i_cmd->command_trb->generic.field[2] = 0;
|
||||
i_cmd->command_trb->generic.field[3] = cpu_to_le32(
|
||||
TRB_TYPE(TRB_CMD_NOOP) | cycle_state);
|
||||
|
||||
/*
|
||||
* caller waiting for completion is called when command
|
||||
* completion event is received for these no-op commands
|
||||
*/
|
||||
}
|
||||
|
||||
xhci->cmd_ring_state = CMD_RING_STATE_RUNNING;
|
||||
|
||||
/* ring command ring doorbell to restart the command ring */
|
||||
if ((xhci->cmd_ring->dequeue != xhci->cmd_ring->enqueue) &&
|
||||
!(xhci->xhc_state & XHCI_STATE_DYING)) {
|
||||
xhci->current_cmd = cur_cmd;
|
||||
xhci_mod_cmd_timer(xhci, XHCI_CMD_DEFAULT_TIMEOUT);
|
||||
xhci_ring_cmd_db(xhci);
|
||||
}
|
||||
}
|
||||
|
||||
/* Must be called with xhci->lock held, releases and aquires lock back */
|
||||
static int xhci_abort_cmd_ring(struct xhci_hcd *xhci, unsigned long flags)
|
||||
{
|
||||
u64 temp_64;
|
||||
int ret;
|
||||
|
||||
xhci_dbg(xhci, "Abort command ring\n");
|
||||
|
||||
temp_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
|
||||
xhci->cmd_ring_state = CMD_RING_STATE_ABORTED;
|
||||
reinit_completion(&xhci->cmd_ring_stop_completion);
|
||||
|
||||
/*
|
||||
* Writing the CMD_RING_ABORT bit should cause a cmd completion event,
|
||||
* however on some host hw the CMD_RING_RUNNING bit is correctly cleared
|
||||
* but the completion event in never sent. Use the cmd timeout timer to
|
||||
* handle those cases. Use twice the time to cover the bit polling retry
|
||||
*/
|
||||
mod_timer(&xhci->cmd_timer, jiffies + (2 * XHCI_CMD_DEFAULT_TIMEOUT));
|
||||
temp_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
|
||||
xhci_write_64(xhci, temp_64 | CMD_RING_ABORT,
|
||||
&xhci->op_regs->cmd_ring);
|
||||
|
||||
|
@ -315,17 +368,30 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci)
|
|||
udelay(1000);
|
||||
ret = xhci_handshake(&xhci->op_regs->cmd_ring,
|
||||
CMD_RING_RUNNING, 0, 3 * 1000 * 1000);
|
||||
if (ret == 0)
|
||||
return 0;
|
||||
|
||||
xhci_err(xhci, "Stopped the command ring failed, "
|
||||
"maybe the host is dead\n");
|
||||
del_timer(&xhci->cmd_timer);
|
||||
xhci->xhc_state |= XHCI_STATE_DYING;
|
||||
xhci_halt(xhci);
|
||||
return -ESHUTDOWN;
|
||||
if (ret < 0) {
|
||||
xhci_err(xhci, "Stopped the command ring failed, "
|
||||
"maybe the host is dead\n");
|
||||
xhci->xhc_state |= XHCI_STATE_DYING;
|
||||
xhci_halt(xhci);
|
||||
return -ESHUTDOWN;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Writing the CMD_RING_ABORT bit should cause a cmd completion event,
|
||||
* however on some host hw the CMD_RING_RUNNING bit is correctly cleared
|
||||
* but the completion event in never sent. Wait 2 secs (arbitrary
|
||||
* number) to handle those cases after negation of CMD_RING_RUNNING.
|
||||
*/
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
ret = wait_for_completion_timeout(&xhci->cmd_ring_stop_completion,
|
||||
msecs_to_jiffies(2000));
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
if (!ret) {
|
||||
xhci_dbg(xhci, "No stop event for abort, ring start fail?\n");
|
||||
xhci_cleanup_command_queue(xhci);
|
||||
} else {
|
||||
xhci_handle_stopped_cmd_ring(xhci, xhci_next_queued_cmd(xhci));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1207,101 +1273,62 @@ void xhci_cleanup_command_queue(struct xhci_hcd *xhci)
|
|||
xhci_complete_del_and_free_cmd(cur_cmd, COMP_CMD_ABORT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Turn all commands on command ring with status set to "aborted" to no-op trbs.
|
||||
* If there are other commands waiting then restart the ring and kick the timer.
|
||||
* This must be called with command ring stopped and xhci->lock held.
|
||||
*/
|
||||
static void xhci_handle_stopped_cmd_ring(struct xhci_hcd *xhci,
|
||||
struct xhci_command *cur_cmd)
|
||||
{
|
||||
struct xhci_command *i_cmd, *tmp_cmd;
|
||||
u32 cycle_state;
|
||||
|
||||
/* Turn all aborted commands in list to no-ops, then restart */
|
||||
list_for_each_entry_safe(i_cmd, tmp_cmd, &xhci->cmd_list,
|
||||
cmd_list) {
|
||||
|
||||
if (i_cmd->status != COMP_CMD_ABORT)
|
||||
continue;
|
||||
|
||||
i_cmd->status = COMP_CMD_STOP;
|
||||
|
||||
xhci_dbg(xhci, "Turn aborted command %p to no-op\n",
|
||||
i_cmd->command_trb);
|
||||
/* get cycle state from the original cmd trb */
|
||||
cycle_state = le32_to_cpu(
|
||||
i_cmd->command_trb->generic.field[3]) & TRB_CYCLE;
|
||||
/* modify the command trb to no-op command */
|
||||
i_cmd->command_trb->generic.field[0] = 0;
|
||||
i_cmd->command_trb->generic.field[1] = 0;
|
||||
i_cmd->command_trb->generic.field[2] = 0;
|
||||
i_cmd->command_trb->generic.field[3] = cpu_to_le32(
|
||||
TRB_TYPE(TRB_CMD_NOOP) | cycle_state);
|
||||
|
||||
/*
|
||||
* caller waiting for completion is called when command
|
||||
* completion event is received for these no-op commands
|
||||
*/
|
||||
}
|
||||
|
||||
xhci->cmd_ring_state = CMD_RING_STATE_RUNNING;
|
||||
|
||||
/* ring command ring doorbell to restart the command ring */
|
||||
if ((xhci->cmd_ring->dequeue != xhci->cmd_ring->enqueue) &&
|
||||
!(xhci->xhc_state & XHCI_STATE_DYING)) {
|
||||
xhci->current_cmd = cur_cmd;
|
||||
mod_timer(&xhci->cmd_timer, jiffies + XHCI_CMD_DEFAULT_TIMEOUT);
|
||||
xhci_ring_cmd_db(xhci);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void xhci_handle_command_timeout(unsigned long data)
|
||||
void xhci_handle_command_timeout(struct work_struct *work)
|
||||
{
|
||||
struct xhci_hcd *xhci;
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
u64 hw_ring_state;
|
||||
bool second_timeout = false;
|
||||
xhci = (struct xhci_hcd *) data;
|
||||
|
||||
/* mark this command to be cancelled */
|
||||
xhci = container_of(to_delayed_work(work), struct xhci_hcd, cmd_timer);
|
||||
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
if (xhci->current_cmd) {
|
||||
if (xhci->current_cmd->status == COMP_CMD_ABORT)
|
||||
second_timeout = true;
|
||||
xhci->current_cmd->status = COMP_CMD_ABORT;
|
||||
|
||||
/*
|
||||
* If timeout work is pending, or current_cmd is NULL, it means we
|
||||
* raced with command completion. Command is handled so just return.
|
||||
*/
|
||||
if (!xhci->current_cmd || delayed_work_pending(&xhci->cmd_timer)) {
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
return;
|
||||
}
|
||||
/* mark this command to be cancelled */
|
||||
xhci->current_cmd->status = COMP_CMD_ABORT;
|
||||
|
||||
/* Make sure command ring is running before aborting it */
|
||||
hw_ring_state = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
|
||||
if ((xhci->cmd_ring_state & CMD_RING_STATE_RUNNING) &&
|
||||
(hw_ring_state & CMD_RING_RUNNING)) {
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
/* Prevent new doorbell, and start command abort */
|
||||
xhci->cmd_ring_state = CMD_RING_STATE_ABORTED;
|
||||
xhci_dbg(xhci, "Command timeout\n");
|
||||
ret = xhci_abort_cmd_ring(xhci);
|
||||
ret = xhci_abort_cmd_ring(xhci, flags);
|
||||
if (unlikely(ret == -ESHUTDOWN)) {
|
||||
xhci_err(xhci, "Abort command ring failed\n");
|
||||
xhci_cleanup_command_queue(xhci);
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
usb_hc_died(xhci_to_hcd(xhci)->primary_hcd);
|
||||
xhci_dbg(xhci, "xHCI host controller is dead.\n");
|
||||
|
||||
return;
|
||||
}
|
||||
return;
|
||||
|
||||
goto time_out_completed;
|
||||
}
|
||||
|
||||
/* command ring failed to restart, or host removed. Bail out */
|
||||
if (second_timeout || xhci->xhc_state & XHCI_STATE_REMOVING) {
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
xhci_dbg(xhci, "command timed out twice, ring start fail?\n");
|
||||
/* host removed. Bail out */
|
||||
if (xhci->xhc_state & XHCI_STATE_REMOVING) {
|
||||
xhci_dbg(xhci, "host removed, ring start fail?\n");
|
||||
xhci_cleanup_command_queue(xhci);
|
||||
return;
|
||||
|
||||
goto time_out_completed;
|
||||
}
|
||||
|
||||
/* command timeout on stopped ring, ring can't be aborted */
|
||||
xhci_dbg(xhci, "Command timeout on stopped ring\n");
|
||||
xhci_handle_stopped_cmd_ring(xhci, xhci->current_cmd);
|
||||
|
||||
time_out_completed:
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
return;
|
||||
}
|
||||
|
@ -1333,7 +1360,7 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
|
|||
|
||||
cmd = list_entry(xhci->cmd_list.next, struct xhci_command, cmd_list);
|
||||
|
||||
del_timer(&xhci->cmd_timer);
|
||||
cancel_delayed_work(&xhci->cmd_timer);
|
||||
|
||||
trace_xhci_cmd_completion(cmd_trb, (struct xhci_generic_trb *) event);
|
||||
|
||||
|
@ -1341,7 +1368,7 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
|
|||
|
||||
/* If CMD ring stopped we own the trbs between enqueue and dequeue */
|
||||
if (cmd_comp_code == COMP_CMD_STOP) {
|
||||
xhci_handle_stopped_cmd_ring(xhci, cmd);
|
||||
complete_all(&xhci->cmd_ring_stop_completion);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1359,8 +1386,11 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
|
|||
*/
|
||||
if (cmd_comp_code == COMP_CMD_ABORT) {
|
||||
xhci->cmd_ring_state = CMD_RING_STATE_STOPPED;
|
||||
if (cmd->status == COMP_CMD_ABORT)
|
||||
if (cmd->status == COMP_CMD_ABORT) {
|
||||
if (xhci->current_cmd == cmd)
|
||||
xhci->current_cmd = NULL;
|
||||
goto event_handled;
|
||||
}
|
||||
}
|
||||
|
||||
cmd_type = TRB_FIELD_TO_TYPE(le32_to_cpu(cmd_trb->generic.field[3]));
|
||||
|
@ -1421,7 +1451,9 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
|
|||
if (cmd->cmd_list.next != &xhci->cmd_list) {
|
||||
xhci->current_cmd = list_entry(cmd->cmd_list.next,
|
||||
struct xhci_command, cmd_list);
|
||||
mod_timer(&xhci->cmd_timer, jiffies + XHCI_CMD_DEFAULT_TIMEOUT);
|
||||
xhci_mod_cmd_timer(xhci, XHCI_CMD_DEFAULT_TIMEOUT);
|
||||
} else if (xhci->current_cmd == cmd) {
|
||||
xhci->current_cmd = NULL;
|
||||
}
|
||||
|
||||
event_handled:
|
||||
|
@ -1939,8 +1971,9 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
|||
struct xhci_ep_ctx *ep_ctx;
|
||||
u32 trb_comp_code;
|
||||
u32 remaining, requested;
|
||||
bool on_data_stage;
|
||||
u32 trb_type;
|
||||
|
||||
trb_type = TRB_FIELD_TO_TYPE(le32_to_cpu(ep_trb->generic.field[3]));
|
||||
slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags));
|
||||
xdev = xhci->devs[slot_id];
|
||||
ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1;
|
||||
|
@ -1950,14 +1983,11 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
|||
requested = td->urb->transfer_buffer_length;
|
||||
remaining = EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
|
||||
|
||||
/* not setup (dequeue), or status stage means we are at data stage */
|
||||
on_data_stage = (ep_trb != ep_ring->dequeue && ep_trb != td->last_trb);
|
||||
|
||||
switch (trb_comp_code) {
|
||||
case COMP_SUCCESS:
|
||||
if (ep_trb != td->last_trb) {
|
||||
if (trb_type != TRB_STATUS) {
|
||||
xhci_warn(xhci, "WARN: Success on ctrl %s TRB without IOC set?\n",
|
||||
on_data_stage ? "data" : "setup");
|
||||
(trb_type == TRB_DATA) ? "data" : "setup");
|
||||
*status = -ESHUTDOWN;
|
||||
break;
|
||||
}
|
||||
|
@ -1967,15 +1997,25 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
|||
*status = 0;
|
||||
break;
|
||||
case COMP_STOP_SHORT:
|
||||
if (on_data_stage)
|
||||
if (trb_type == TRB_DATA || trb_type == TRB_NORMAL)
|
||||
td->urb->actual_length = remaining;
|
||||
else
|
||||
xhci_warn(xhci, "WARN: Stopped Short Packet on ctrl setup or status TRB\n");
|
||||
goto finish_td;
|
||||
case COMP_STOP:
|
||||
if (on_data_stage)
|
||||
switch (trb_type) {
|
||||
case TRB_SETUP:
|
||||
td->urb->actual_length = 0;
|
||||
goto finish_td;
|
||||
case TRB_DATA:
|
||||
case TRB_NORMAL:
|
||||
td->urb->actual_length = requested - remaining;
|
||||
goto finish_td;
|
||||
goto finish_td;
|
||||
default:
|
||||
xhci_warn(xhci, "WARN: unexpected TRB Type %d\n",
|
||||
trb_type);
|
||||
goto finish_td;
|
||||
}
|
||||
case COMP_STOP_INVAL:
|
||||
goto finish_td;
|
||||
default:
|
||||
|
@ -1987,7 +2027,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
|||
/* else fall through */
|
||||
case COMP_STALL:
|
||||
/* Did we transfer part of the data (middle) phase? */
|
||||
if (on_data_stage)
|
||||
if (trb_type == TRB_DATA || trb_type == TRB_NORMAL)
|
||||
td->urb->actual_length = requested - remaining;
|
||||
else if (!td->urb_length_set)
|
||||
td->urb->actual_length = 0;
|
||||
|
@ -1995,14 +2035,15 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
|||
}
|
||||
|
||||
/* stopped at setup stage, no data transferred */
|
||||
if (ep_trb == ep_ring->dequeue)
|
||||
if (trb_type == TRB_SETUP)
|
||||
goto finish_td;
|
||||
|
||||
/*
|
||||
* if on data stage then update the actual_length of the URB and flag it
|
||||
* as set, so it won't be overwritten in the event for the last TRB.
|
||||
*/
|
||||
if (on_data_stage) {
|
||||
if (trb_type == TRB_DATA ||
|
||||
trb_type == TRB_NORMAL) {
|
||||
td->urb_length_set = true;
|
||||
td->urb->actual_length = requested - remaining;
|
||||
xhci_dbg(xhci, "Waiting for status stage event\n");
|
||||
|
@ -3790,9 +3831,9 @@ static int queue_command(struct xhci_hcd *xhci, struct xhci_command *cmd,
|
|||
|
||||
/* if there are no other commands queued we start the timeout timer */
|
||||
if (xhci->cmd_list.next == &cmd->cmd_list &&
|
||||
!timer_pending(&xhci->cmd_timer)) {
|
||||
!delayed_work_pending(&xhci->cmd_timer)) {
|
||||
xhci->current_cmd = cmd;
|
||||
mod_timer(&xhci->cmd_timer, jiffies + XHCI_CMD_DEFAULT_TIMEOUT);
|
||||
xhci_mod_cmd_timer(xhci, XHCI_CMD_DEFAULT_TIMEOUT);
|
||||
}
|
||||
|
||||
queue_trb(xhci, xhci->cmd_ring, false, field1, field2, field3,
|
||||
|
|
|
@ -3787,8 +3787,10 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
|
|||
|
||||
mutex_lock(&xhci->mutex);
|
||||
|
||||
if (xhci->xhc_state) /* dying, removing or halted */
|
||||
if (xhci->xhc_state) { /* dying, removing or halted */
|
||||
ret = -ESHUTDOWN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!udev->slot_id) {
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_address,
|
||||
|
|
|
@ -1568,7 +1568,8 @@ struct xhci_hcd {
|
|||
#define CMD_RING_STATE_STOPPED (1 << 2)
|
||||
struct list_head cmd_list;
|
||||
unsigned int cmd_ring_reserved_trbs;
|
||||
struct timer_list cmd_timer;
|
||||
struct delayed_work cmd_timer;
|
||||
struct completion cmd_ring_stop_completion;
|
||||
struct xhci_command *current_cmd;
|
||||
struct xhci_ring *event_ring;
|
||||
struct xhci_erst erst;
|
||||
|
@ -1934,7 +1935,7 @@ void xhci_queue_config_ep_quirk(struct xhci_hcd *xhci,
|
|||
unsigned int slot_id, unsigned int ep_index,
|
||||
struct xhci_dequeue_state *deq_state);
|
||||
void xhci_stop_endpoint_command_watchdog(unsigned long arg);
|
||||
void xhci_handle_command_timeout(unsigned long data);
|
||||
void xhci_handle_command_timeout(struct work_struct *work);
|
||||
|
||||
void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id,
|
||||
unsigned int ep_index, unsigned int stream_id);
|
||||
|
|
|
@ -469,6 +469,7 @@ static const struct musb_platform_ops bfin_ops = {
|
|||
.init = bfin_musb_init,
|
||||
.exit = bfin_musb_exit,
|
||||
|
||||
.fifo_offset = bfin_fifo_offset,
|
||||
.readb = bfin_readb,
|
||||
.writeb = bfin_writeb,
|
||||
.readw = bfin_readw,
|
||||
|
|
|
@ -2050,6 +2050,7 @@ struct musb_pending_work {
|
|||
struct list_head node;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
/*
|
||||
* Called from musb_runtime_resume(), musb_resume(), and
|
||||
* musb_queue_resume_work(). Callers must take musb->lock.
|
||||
|
@ -2077,6 +2078,7 @@ static int musb_run_resume_work(struct musb *musb)
|
|||
|
||||
return error;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Called to run work if device is active or else queue the work to happen
|
||||
|
|
|
@ -216,6 +216,7 @@ struct musb_platform_ops {
|
|||
void (*pre_root_reset_end)(struct musb *musb);
|
||||
void (*post_root_reset_end)(struct musb *musb);
|
||||
int (*phy_callback)(enum musb_vbus_id_status status);
|
||||
void (*clear_ep_rxintr)(struct musb *musb, int epnum);
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -626,6 +627,12 @@ static inline void musb_platform_post_root_reset_end(struct musb *musb)
|
|||
musb->ops->post_root_reset_end(musb);
|
||||
}
|
||||
|
||||
static inline void musb_platform_clear_ep_rxintr(struct musb *musb, int epnum)
|
||||
{
|
||||
if (musb->ops->clear_ep_rxintr)
|
||||
musb->ops->clear_ep_rxintr(musb, epnum);
|
||||
}
|
||||
|
||||
/*
|
||||
* gets the "dr_mode" property from DT and converts it into musb_mode
|
||||
* if the property is not found or not recognized returns MUSB_OTG
|
||||
|
|
|
@ -267,6 +267,17 @@ static void otg_timer(unsigned long _musb)
|
|||
pm_runtime_put_autosuspend(dev);
|
||||
}
|
||||
|
||||
void dsps_musb_clear_ep_rxintr(struct musb *musb, int epnum)
|
||||
{
|
||||
u32 epintr;
|
||||
struct dsps_glue *glue = dev_get_drvdata(musb->controller->parent);
|
||||
const struct dsps_musb_wrapper *wrp = glue->wrp;
|
||||
|
||||
/* musb->lock might already been held */
|
||||
epintr = (1 << epnum) << wrp->rxep_shift;
|
||||
musb_writel(musb->ctrl_base, wrp->epintr_status, epintr);
|
||||
}
|
||||
|
||||
static irqreturn_t dsps_interrupt(int irq, void *hci)
|
||||
{
|
||||
struct musb *musb = hci;
|
||||
|
@ -622,6 +633,7 @@ static struct musb_platform_ops dsps_ops = {
|
|||
|
||||
.set_mode = dsps_musb_set_mode,
|
||||
.recover = dsps_musb_recover,
|
||||
.clear_ep_rxintr = dsps_musb_clear_ep_rxintr,
|
||||
};
|
||||
|
||||
static u64 musb_dmamask = DMA_BIT_MASK(32);
|
||||
|
|
|
@ -2374,12 +2374,11 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh)
|
|||
int is_in = usb_pipein(urb->pipe);
|
||||
int status = 0;
|
||||
u16 csr;
|
||||
struct dma_channel *dma = NULL;
|
||||
|
||||
musb_ep_select(regs, hw_end);
|
||||
|
||||
if (is_dma_capable()) {
|
||||
struct dma_channel *dma;
|
||||
|
||||
dma = is_in ? ep->rx_channel : ep->tx_channel;
|
||||
if (dma) {
|
||||
status = ep->musb->dma_controller->channel_abort(dma);
|
||||
|
@ -2395,10 +2394,9 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh)
|
|||
/* giveback saves bulk toggle */
|
||||
csr = musb_h_flush_rxfifo(ep, 0);
|
||||
|
||||
/* REVISIT we still get an irq; should likely clear the
|
||||
* endpoint's irq status here to avoid bogus irqs.
|
||||
* clearing that status is platform-specific...
|
||||
*/
|
||||
/* clear the endpoint's irq status here to avoid bogus irqs */
|
||||
if (is_dma_capable() && dma)
|
||||
musb_platform_clear_ep_rxintr(musb, ep->epnum);
|
||||
} else if (ep->epnum) {
|
||||
musb_h_tx_flush_fifo(ep);
|
||||
csr = musb_readw(epio, MUSB_TXCSR);
|
||||
|
|
|
@ -157,5 +157,5 @@ struct musb_dma_controller {
|
|||
void __iomem *base;
|
||||
u8 channel_count;
|
||||
u8 used_channels;
|
||||
u8 irq;
|
||||
int irq;
|
||||
};
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#define CYBERJACK_PRODUCT_ID 0x0100
|
||||
|
||||
/* Function prototypes */
|
||||
static int cyberjack_attach(struct usb_serial *serial);
|
||||
static int cyberjack_port_probe(struct usb_serial_port *port);
|
||||
static int cyberjack_port_remove(struct usb_serial_port *port);
|
||||
static int cyberjack_open(struct tty_struct *tty,
|
||||
|
@ -77,6 +78,7 @@ static struct usb_serial_driver cyberjack_device = {
|
|||
.description = "Reiner SCT Cyberjack USB card reader",
|
||||
.id_table = id_table,
|
||||
.num_ports = 1,
|
||||
.attach = cyberjack_attach,
|
||||
.port_probe = cyberjack_port_probe,
|
||||
.port_remove = cyberjack_port_remove,
|
||||
.open = cyberjack_open,
|
||||
|
@ -100,6 +102,14 @@ struct cyberjack_private {
|
|||
short wrsent; /* Data already sent */
|
||||
};
|
||||
|
||||
static int cyberjack_attach(struct usb_serial *serial)
|
||||
{
|
||||
if (serial->num_bulk_out < serial->num_ports)
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cyberjack_port_probe(struct usb_serial_port *port)
|
||||
{
|
||||
struct cyberjack_private *priv;
|
||||
|
|
|
@ -1237,6 +1237,7 @@ static int f81534_attach(struct usb_serial *serial)
|
|||
static int f81534_port_probe(struct usb_serial_port *port)
|
||||
{
|
||||
struct f81534_port_private *port_priv;
|
||||
int ret;
|
||||
|
||||
port_priv = devm_kzalloc(&port->dev, sizeof(*port_priv), GFP_KERNEL);
|
||||
if (!port_priv)
|
||||
|
@ -1246,10 +1247,11 @@ static int f81534_port_probe(struct usb_serial_port *port)
|
|||
mutex_init(&port_priv->mcr_mutex);
|
||||
|
||||
/* Assign logic-to-phy mapping */
|
||||
port_priv->phy_num = f81534_logic_to_phy_port(port->serial, port);
|
||||
if (port_priv->phy_num < 0 || port_priv->phy_num >= F81534_NUM_PORT)
|
||||
return -ENODEV;
|
||||
ret = f81534_logic_to_phy_port(port->serial, port);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
port_priv->phy_num = ret;
|
||||
usb_set_serial_port_data(port, port_priv);
|
||||
dev_dbg(&port->dev, "%s: port_number: %d, phy_num: %d\n", __func__,
|
||||
port->port_number, port_priv->phy_num);
|
||||
|
|
|
@ -1043,6 +1043,7 @@ static int garmin_write_bulk(struct usb_serial_port *port,
|
|||
"%s - usb_submit_urb(write bulk) failed with status = %d\n",
|
||||
__func__, status);
|
||||
count = status;
|
||||
kfree(buffer);
|
||||
}
|
||||
|
||||
/* we are done with this urb, so let the host driver
|
||||
|
|
|
@ -2751,6 +2751,11 @@ static int edge_startup(struct usb_serial *serial)
|
|||
EDGE_COMPATIBILITY_MASK1,
|
||||
EDGE_COMPATIBILITY_MASK2 };
|
||||
|
||||
if (serial->num_bulk_in < 1 || serial->num_interrupt_in < 1) {
|
||||
dev_err(&serial->interface->dev, "missing endpoints\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dev = serial->dev;
|
||||
|
||||
/* create our private serial structure */
|
||||
|
|
|
@ -1499,8 +1499,7 @@ static int do_boot_mode(struct edgeport_serial *serial,
|
|||
|
||||
dev_dbg(dev, "%s - Download successful -- Device rebooting...\n", __func__);
|
||||
|
||||
/* return an error on purpose */
|
||||
return -ENODEV;
|
||||
return 1;
|
||||
}
|
||||
|
||||
stayinbootmode:
|
||||
|
@ -1508,7 +1507,7 @@ static int do_boot_mode(struct edgeport_serial *serial,
|
|||
dev_dbg(dev, "%s - STAYING IN BOOT MODE\n", __func__);
|
||||
serial->product_info.TiMode = TI_MODE_BOOT;
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ti_do_config(struct edgeport_port *port, int feature, int on)
|
||||
|
@ -2546,6 +2545,13 @@ static int edge_startup(struct usb_serial *serial)
|
|||
int status;
|
||||
u16 product_id;
|
||||
|
||||
/* Make sure we have the required endpoints when in download mode. */
|
||||
if (serial->interface->cur_altsetting->desc.bNumEndpoints > 1) {
|
||||
if (serial->num_bulk_in < serial->num_ports ||
|
||||
serial->num_bulk_out < serial->num_ports)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* create our private serial structure */
|
||||
edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL);
|
||||
if (!edge_serial)
|
||||
|
@ -2553,14 +2559,18 @@ static int edge_startup(struct usb_serial *serial)
|
|||
|
||||
mutex_init(&edge_serial->es_lock);
|
||||
edge_serial->serial = serial;
|
||||
INIT_DELAYED_WORK(&edge_serial->heartbeat_work, edge_heartbeat_work);
|
||||
usb_set_serial_data(serial, edge_serial);
|
||||
|
||||
status = download_fw(edge_serial);
|
||||
if (status) {
|
||||
if (status < 0) {
|
||||
kfree(edge_serial);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (status > 0)
|
||||
return 1; /* bind but do not register any ports */
|
||||
|
||||
product_id = le16_to_cpu(
|
||||
edge_serial->serial->dev->descriptor.idProduct);
|
||||
|
||||
|
@ -2572,7 +2582,6 @@ static int edge_startup(struct usb_serial *serial)
|
|||
}
|
||||
}
|
||||
|
||||
INIT_DELAYED_WORK(&edge_serial->heartbeat_work, edge_heartbeat_work);
|
||||
edge_heartbeat_schedule(edge_serial);
|
||||
|
||||
return 0;
|
||||
|
@ -2580,6 +2589,9 @@ static int edge_startup(struct usb_serial *serial)
|
|||
|
||||
static void edge_disconnect(struct usb_serial *serial)
|
||||
{
|
||||
struct edgeport_serial *edge_serial = usb_get_serial_data(serial);
|
||||
|
||||
cancel_delayed_work_sync(&edge_serial->heartbeat_work);
|
||||
}
|
||||
|
||||
static void edge_release(struct usb_serial *serial)
|
||||
|
|
|
@ -68,6 +68,16 @@ struct iuu_private {
|
|||
u32 clk;
|
||||
};
|
||||
|
||||
static int iuu_attach(struct usb_serial *serial)
|
||||
{
|
||||
unsigned char num_ports = serial->num_ports;
|
||||
|
||||
if (serial->num_bulk_in < num_ports || serial->num_bulk_out < num_ports)
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iuu_port_probe(struct usb_serial_port *port)
|
||||
{
|
||||
struct iuu_private *priv;
|
||||
|
@ -1196,6 +1206,7 @@ static struct usb_serial_driver iuu_device = {
|
|||
.tiocmset = iuu_tiocmset,
|
||||
.set_termios = iuu_set_termios,
|
||||
.init_termios = iuu_init_termios,
|
||||
.attach = iuu_attach,
|
||||
.port_probe = iuu_port_probe,
|
||||
.port_remove = iuu_port_remove,
|
||||
};
|
||||
|
|
|
@ -699,6 +699,19 @@ MODULE_FIRMWARE("keyspan_pda/keyspan_pda.fw");
|
|||
MODULE_FIRMWARE("keyspan_pda/xircom_pgs.fw");
|
||||
#endif
|
||||
|
||||
static int keyspan_pda_attach(struct usb_serial *serial)
|
||||
{
|
||||
unsigned char num_ports = serial->num_ports;
|
||||
|
||||
if (serial->num_bulk_out < num_ports ||
|
||||
serial->num_interrupt_in < num_ports) {
|
||||
dev_err(&serial->interface->dev, "missing endpoints\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int keyspan_pda_port_probe(struct usb_serial_port *port)
|
||||
{
|
||||
|
||||
|
@ -776,6 +789,7 @@ static struct usb_serial_driver keyspan_pda_device = {
|
|||
.break_ctl = keyspan_pda_break_ctl,
|
||||
.tiocmget = keyspan_pda_tiocmget,
|
||||
.tiocmset = keyspan_pda_tiocmset,
|
||||
.attach = keyspan_pda_attach,
|
||||
.port_probe = keyspan_pda_port_probe,
|
||||
.port_remove = keyspan_pda_port_remove,
|
||||
};
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
|
||||
|
||||
/* Function prototypes */
|
||||
static int kobil_attach(struct usb_serial *serial);
|
||||
static int kobil_port_probe(struct usb_serial_port *probe);
|
||||
static int kobil_port_remove(struct usb_serial_port *probe);
|
||||
static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port);
|
||||
|
@ -86,6 +87,7 @@ static struct usb_serial_driver kobil_device = {
|
|||
.description = "KOBIL USB smart card terminal",
|
||||
.id_table = id_table,
|
||||
.num_ports = 1,
|
||||
.attach = kobil_attach,
|
||||
.port_probe = kobil_port_probe,
|
||||
.port_remove = kobil_port_remove,
|
||||
.ioctl = kobil_ioctl,
|
||||
|
@ -113,6 +115,16 @@ struct kobil_private {
|
|||
};
|
||||
|
||||
|
||||
static int kobil_attach(struct usb_serial *serial)
|
||||
{
|
||||
if (serial->num_interrupt_out < serial->num_ports) {
|
||||
dev_err(&serial->interface->dev, "missing interrupt-out endpoint\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kobil_port_probe(struct usb_serial_port *port)
|
||||
{
|
||||
struct usb_serial *serial = port->serial;
|
||||
|
|
|
@ -65,8 +65,6 @@ struct moschip_port {
|
|||
struct urb *write_urb_pool[NUM_URBS];
|
||||
};
|
||||
|
||||
static struct usb_serial_driver moschip7720_2port_driver;
|
||||
|
||||
#define USB_VENDOR_ID_MOSCHIP 0x9710
|
||||
#define MOSCHIP_DEVICE_ID_7720 0x7720
|
||||
#define MOSCHIP_DEVICE_ID_7715 0x7715
|
||||
|
@ -970,25 +968,6 @@ static void mos7720_bulk_out_data_callback(struct urb *urb)
|
|||
tty_port_tty_wakeup(&mos7720_port->port->port);
|
||||
}
|
||||
|
||||
/*
|
||||
* mos77xx_probe
|
||||
* this function installs the appropriate read interrupt endpoint callback
|
||||
* depending on whether the device is a 7720 or 7715, thus avoiding costly
|
||||
* run-time checks in the high-frequency callback routine itself.
|
||||
*/
|
||||
static int mos77xx_probe(struct usb_serial *serial,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
if (id->idProduct == MOSCHIP_DEVICE_ID_7715)
|
||||
moschip7720_2port_driver.read_int_callback =
|
||||
mos7715_interrupt_callback;
|
||||
else
|
||||
moschip7720_2port_driver.read_int_callback =
|
||||
mos7720_interrupt_callback;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mos77xx_calc_num_ports(struct usb_serial *serial)
|
||||
{
|
||||
u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);
|
||||
|
@ -1917,6 +1896,11 @@ static int mos7720_startup(struct usb_serial *serial)
|
|||
u16 product;
|
||||
int ret_val;
|
||||
|
||||
if (serial->num_bulk_in < 2 || serial->num_bulk_out < 2) {
|
||||
dev_err(&serial->interface->dev, "missing bulk endpoints\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
product = le16_to_cpu(serial->dev->descriptor.idProduct);
|
||||
dev = serial->dev;
|
||||
|
||||
|
@ -1941,19 +1925,18 @@ static int mos7720_startup(struct usb_serial *serial)
|
|||
tmp->interrupt_in_endpointAddress;
|
||||
serial->port[1]->interrupt_in_urb = NULL;
|
||||
serial->port[1]->interrupt_in_buffer = NULL;
|
||||
|
||||
if (serial->port[0]->interrupt_in_urb) {
|
||||
struct urb *urb = serial->port[0]->interrupt_in_urb;
|
||||
|
||||
urb->complete = mos7715_interrupt_callback;
|
||||
}
|
||||
}
|
||||
|
||||
/* setting configuration feature to one */
|
||||
usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
|
||||
(__u8)0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5000);
|
||||
|
||||
/* start the interrupt urb */
|
||||
ret_val = usb_submit_urb(serial->port[0]->interrupt_in_urb, GFP_KERNEL);
|
||||
if (ret_val)
|
||||
dev_err(&dev->dev,
|
||||
"%s - Error %d submitting control urb\n",
|
||||
__func__, ret_val);
|
||||
|
||||
#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT
|
||||
if (product == MOSCHIP_DEVICE_ID_7715) {
|
||||
ret_val = mos7715_parport_init(serial);
|
||||
|
@ -1961,6 +1944,13 @@ static int mos7720_startup(struct usb_serial *serial)
|
|||
return ret_val;
|
||||
}
|
||||
#endif
|
||||
/* start the interrupt urb */
|
||||
ret_val = usb_submit_urb(serial->port[0]->interrupt_in_urb, GFP_KERNEL);
|
||||
if (ret_val) {
|
||||
dev_err(&dev->dev, "failed to submit interrupt urb: %d\n",
|
||||
ret_val);
|
||||
}
|
||||
|
||||
/* LSR For Port 1 */
|
||||
read_mos_reg(serial, 0, MOS7720_LSR, &data);
|
||||
dev_dbg(&dev->dev, "LSR:%x\n", data);
|
||||
|
@ -1970,6 +1960,8 @@ static int mos7720_startup(struct usb_serial *serial)
|
|||
|
||||
static void mos7720_release(struct usb_serial *serial)
|
||||
{
|
||||
usb_kill_urb(serial->port[0]->interrupt_in_urb);
|
||||
|
||||
#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT
|
||||
/* close the parallel port */
|
||||
|
||||
|
@ -2019,11 +2011,6 @@ static int mos7720_port_probe(struct usb_serial_port *port)
|
|||
if (!mos7720_port)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Initialize all port interrupt end point to port 0 int endpoint.
|
||||
* Our device has only one interrupt endpoint common to all ports.
|
||||
*/
|
||||
port->interrupt_in_endpointAddress =
|
||||
port->serial->port[0]->interrupt_in_endpointAddress;
|
||||
mos7720_port->port = port;
|
||||
|
||||
usb_set_serial_port_data(port, mos7720_port);
|
||||
|
@ -2053,7 +2040,6 @@ static struct usb_serial_driver moschip7720_2port_driver = {
|
|||
.close = mos7720_close,
|
||||
.throttle = mos7720_throttle,
|
||||
.unthrottle = mos7720_unthrottle,
|
||||
.probe = mos77xx_probe,
|
||||
.attach = mos7720_startup,
|
||||
.release = mos7720_release,
|
||||
.port_probe = mos7720_port_probe,
|
||||
|
@ -2067,7 +2053,7 @@ static struct usb_serial_driver moschip7720_2port_driver = {
|
|||
.chars_in_buffer = mos7720_chars_in_buffer,
|
||||
.break_ctl = mos7720_break,
|
||||
.read_bulk_callback = mos7720_bulk_in_callback,
|
||||
.read_int_callback = NULL /* dynamically assigned in probe() */
|
||||
.read_int_callback = mos7720_interrupt_callback,
|
||||
};
|
||||
|
||||
static struct usb_serial_driver * const serial_drivers[] = {
|
||||
|
|
|
@ -214,7 +214,6 @@ MODULE_DEVICE_TABLE(usb, id_table);
|
|||
|
||||
struct moschip_port {
|
||||
int port_num; /*Actual port number in the device(1,2,etc) */
|
||||
struct urb *write_urb; /* write URB for this port */
|
||||
struct urb *read_urb; /* read URB for this port */
|
||||
__u8 shadowLCR; /* last LCR value received */
|
||||
__u8 shadowMCR; /* last MCR value received */
|
||||
|
@ -1037,9 +1036,7 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
|
|||
serial,
|
||||
serial->port[0]->interrupt_in_urb->interval);
|
||||
|
||||
/* start interrupt read for mos7840 *
|
||||
* will continue as long as mos7840 is connected */
|
||||
|
||||
/* start interrupt read for mos7840 */
|
||||
response =
|
||||
usb_submit_urb(serial->port[0]->interrupt_in_urb,
|
||||
GFP_KERNEL);
|
||||
|
@ -1186,7 +1183,6 @@ static void mos7840_close(struct usb_serial_port *port)
|
|||
}
|
||||
}
|
||||
|
||||
usb_kill_urb(mos7840_port->write_urb);
|
||||
usb_kill_urb(mos7840_port->read_urb);
|
||||
mos7840_port->read_urb_busy = false;
|
||||
|
||||
|
@ -1199,12 +1195,6 @@ static void mos7840_close(struct usb_serial_port *port)
|
|||
}
|
||||
}
|
||||
|
||||
if (mos7840_port->write_urb) {
|
||||
/* if this urb had a transfer buffer already (old tx) free it */
|
||||
kfree(mos7840_port->write_urb->transfer_buffer);
|
||||
usb_free_urb(mos7840_port->write_urb);
|
||||
}
|
||||
|
||||
Data = 0x0;
|
||||
mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
|
||||
|
||||
|
@ -2113,6 +2103,17 @@ static int mos7840_calc_num_ports(struct usb_serial *serial)
|
|||
return mos7840_num_ports;
|
||||
}
|
||||
|
||||
static int mos7840_attach(struct usb_serial *serial)
|
||||
{
|
||||
if (serial->num_bulk_in < serial->num_ports ||
|
||||
serial->num_bulk_out < serial->num_ports) {
|
||||
dev_err(&serial->interface->dev, "missing endpoints\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mos7840_port_probe(struct usb_serial_port *port)
|
||||
{
|
||||
struct usb_serial *serial = port->serial;
|
||||
|
@ -2388,6 +2389,7 @@ static struct usb_serial_driver moschip7840_4port_device = {
|
|||
.tiocmset = mos7840_tiocmset,
|
||||
.tiocmiwait = usb_serial_generic_tiocmiwait,
|
||||
.get_icount = usb_serial_generic_get_icount,
|
||||
.attach = mos7840_attach,
|
||||
.port_probe = mos7840_port_probe,
|
||||
.port_remove = mos7840_port_remove,
|
||||
.read_bulk_callback = mos7840_bulk_in_callback,
|
||||
|
|
|
@ -38,6 +38,7 @@ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port,
|
|||
const unsigned char *buf, int count);
|
||||
static int omninet_write_room(struct tty_struct *tty);
|
||||
static void omninet_disconnect(struct usb_serial *serial);
|
||||
static int omninet_attach(struct usb_serial *serial);
|
||||
static int omninet_port_probe(struct usb_serial_port *port);
|
||||
static int omninet_port_remove(struct usb_serial_port *port);
|
||||
|
||||
|
@ -56,6 +57,7 @@ static struct usb_serial_driver zyxel_omninet_device = {
|
|||
.description = "ZyXEL - omni.net lcd plus usb",
|
||||
.id_table = id_table,
|
||||
.num_ports = 1,
|
||||
.attach = omninet_attach,
|
||||
.port_probe = omninet_port_probe,
|
||||
.port_remove = omninet_port_remove,
|
||||
.open = omninet_open,
|
||||
|
@ -104,6 +106,17 @@ struct omninet_data {
|
|||
__u8 od_outseq; /* Sequence number for bulk_out URBs */
|
||||
};
|
||||
|
||||
static int omninet_attach(struct usb_serial *serial)
|
||||
{
|
||||
/* The second bulk-out endpoint is used for writing. */
|
||||
if (serial->num_bulk_out < 2) {
|
||||
dev_err(&serial->interface->dev, "missing endpoints\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omninet_port_probe(struct usb_serial_port *port)
|
||||
{
|
||||
struct omninet_data *od;
|
||||
|
|
|
@ -134,6 +134,7 @@ static int oti6858_chars_in_buffer(struct tty_struct *tty);
|
|||
static int oti6858_tiocmget(struct tty_struct *tty);
|
||||
static int oti6858_tiocmset(struct tty_struct *tty,
|
||||
unsigned int set, unsigned int clear);
|
||||
static int oti6858_attach(struct usb_serial *serial);
|
||||
static int oti6858_port_probe(struct usb_serial_port *port);
|
||||
static int oti6858_port_remove(struct usb_serial_port *port);
|
||||
|
||||
|
@ -158,6 +159,7 @@ static struct usb_serial_driver oti6858_device = {
|
|||
.write_bulk_callback = oti6858_write_bulk_callback,
|
||||
.write_room = oti6858_write_room,
|
||||
.chars_in_buffer = oti6858_chars_in_buffer,
|
||||
.attach = oti6858_attach,
|
||||
.port_probe = oti6858_port_probe,
|
||||
.port_remove = oti6858_port_remove,
|
||||
};
|
||||
|
@ -324,6 +326,20 @@ static void send_data(struct work_struct *work)
|
|||
usb_serial_port_softint(port);
|
||||
}
|
||||
|
||||
static int oti6858_attach(struct usb_serial *serial)
|
||||
{
|
||||
unsigned char num_ports = serial->num_ports;
|
||||
|
||||
if (serial->num_bulk_in < num_ports ||
|
||||
serial->num_bulk_out < num_ports ||
|
||||
serial->num_interrupt_in < num_ports) {
|
||||
dev_err(&serial->interface->dev, "missing endpoints\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int oti6858_port_probe(struct usb_serial_port *port)
|
||||
{
|
||||
struct oti6858_private *priv;
|
||||
|
|
|
@ -220,9 +220,17 @@ static int pl2303_probe(struct usb_serial *serial,
|
|||
static int pl2303_startup(struct usb_serial *serial)
|
||||
{
|
||||
struct pl2303_serial_private *spriv;
|
||||
unsigned char num_ports = serial->num_ports;
|
||||
enum pl2303_type type = TYPE_01;
|
||||
unsigned char *buf;
|
||||
|
||||
if (serial->num_bulk_in < num_ports ||
|
||||
serial->num_bulk_out < num_ports ||
|
||||
serial->num_interrupt_in < num_ports) {
|
||||
dev_err(&serial->interface->dev, "missing endpoints\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
spriv = kzalloc(sizeof(*spriv), GFP_KERNEL);
|
||||
if (!spriv)
|
||||
return -ENOMEM;
|
||||
|
|
|
@ -408,16 +408,12 @@ static void qt2_close(struct usb_serial_port *port)
|
|||
{
|
||||
struct usb_serial *serial;
|
||||
struct qt2_port_private *port_priv;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
serial = port->serial;
|
||||
port_priv = usb_get_serial_port_data(port);
|
||||
|
||||
spin_lock_irqsave(&port_priv->urb_lock, flags);
|
||||
usb_kill_urb(port_priv->write_urb);
|
||||
port_priv->urb_in_use = false;
|
||||
spin_unlock_irqrestore(&port_priv->urb_lock, flags);
|
||||
|
||||
/* flush the port transmit buffer */
|
||||
i = usb_control_msg(serial->dev,
|
||||
|
|
|
@ -154,6 +154,19 @@ static int spcp8x5_probe(struct usb_serial *serial,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int spcp8x5_attach(struct usb_serial *serial)
|
||||
{
|
||||
unsigned char num_ports = serial->num_ports;
|
||||
|
||||
if (serial->num_bulk_in < num_ports ||
|
||||
serial->num_bulk_out < num_ports) {
|
||||
dev_err(&serial->interface->dev, "missing endpoints\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int spcp8x5_port_probe(struct usb_serial_port *port)
|
||||
{
|
||||
const struct usb_device_id *id = usb_get_serial_data(port->serial);
|
||||
|
@ -477,6 +490,7 @@ static struct usb_serial_driver spcp8x5_device = {
|
|||
.tiocmget = spcp8x5_tiocmget,
|
||||
.tiocmset = spcp8x5_tiocmset,
|
||||
.probe = spcp8x5_probe,
|
||||
.attach = spcp8x5_attach,
|
||||
.port_probe = spcp8x5_port_probe,
|
||||
.port_remove = spcp8x5_port_remove,
|
||||
};
|
||||
|
|
|
@ -579,6 +579,13 @@ static int ti_startup(struct usb_serial *serial)
|
|||
goto free_tdev;
|
||||
}
|
||||
|
||||
if (serial->num_bulk_in < serial->num_ports ||
|
||||
serial->num_bulk_out < serial->num_ports) {
|
||||
dev_err(&serial->interface->dev, "missing endpoints\n");
|
||||
status = -ENODEV;
|
||||
goto free_tdev;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
free_tdev:
|
||||
|
|
|
@ -2109,6 +2109,13 @@ UNUSUAL_DEV( 0x152d, 0x2566, 0x0114, 0x0114,
|
|||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_BROKEN_FUA ),
|
||||
|
||||
/* Reported-by George Cherian <george.cherian@cavium.com> */
|
||||
UNUSUAL_DEV(0x152d, 0x9561, 0x0000, 0x9999,
|
||||
"JMicron",
|
||||
"JMS56x",
|
||||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_NO_REPORT_OPCODES),
|
||||
|
||||
/*
|
||||
* Entrega Technologies U1-SC25 (later Xircom PortGear PGSCSI)
|
||||
* and Mac USB Dock USB-SCSI */
|
||||
|
|
|
@ -93,6 +93,7 @@ struct usb_ext_prop_desc {
|
|||
* | 0 | magic | LE32 | FUNCTIONFS_DESCRIPTORS_MAGIC_V2 |
|
||||
* | 4 | length | LE32 | length of the whole data chunk |
|
||||
* | 8 | flags | LE32 | combination of functionfs_flags |
|
||||
* | | eventfd | LE32 | eventfd file descriptor |
|
||||
* | | fs_count | LE32 | number of full-speed descriptors |
|
||||
* | | hs_count | LE32 | number of high-speed descriptors |
|
||||
* | | ss_count | LE32 | number of super-speed descriptors |
|
||||
|
|
Loading…
Reference in New Issue