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:
Linus Torvalds
2017-01-08 11:42:04 -08:00
46 changed files with 550 additions and 316 deletions

View File

@@ -239,6 +239,16 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
if (ifp->desc.bNumEndpoints >= num_ep) if (ifp->desc.bNumEndpoints >= num_ep)
goto skip_to_next_endpoint_or_interface_descriptor; 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]; endpoint = &ifp->endpoint[ifp->desc.bNumEndpoints];
++ifp->desc.bNumEndpoints; ++ifp->desc.bNumEndpoints;

View File

@@ -103,8 +103,7 @@ EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem);
static void hub_release(struct kref *kref); static void hub_release(struct kref *kref);
static int usb_reset_and_verify_device(struct usb_device *udev); static int usb_reset_and_verify_device(struct usb_device *udev);
static void hub_usb3_port_prepare_disable(struct usb_hub *hub, static int hub_port_disable(struct usb_hub *hub, int port1, int set_state);
struct usb_port *port_dev);
static inline char *portspeed(struct usb_hub *hub, int portstatus) 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_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 * 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 * 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 */ #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: /* USB 2.0 spec, 7.1.7.3 / fig 7-29:
* *

View File

@@ -3753,7 +3753,7 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
hs_ep->desc_list = dma_alloc_coherent(hsotg->dev, hs_ep->desc_list = dma_alloc_coherent(hsotg->dev,
MAX_DMA_DESC_NUM_GENERIC * MAX_DMA_DESC_NUM_GENERIC *
sizeof(struct dwc2_dma_desc), sizeof(struct dwc2_dma_desc),
&hs_ep->desc_list_dma, GFP_KERNEL); &hs_ep->desc_list_dma, GFP_ATOMIC);
if (!hs_ep->desc_list) { if (!hs_ep->desc_list) {
ret = -ENOMEM; ret = -ENOMEM;
goto error2; goto error2;

View File

@@ -247,8 +247,6 @@ MODULE_DEVICE_TABLE(of, dwc2_of_match_table);
static void dwc2_get_device_property(struct dwc2_hsotg *hsotg, static void dwc2_get_device_property(struct dwc2_hsotg *hsotg,
char *property, u8 size, u64 *value) char *property, u8 size, u64 *value)
{ {
u8 val8;
u16 val16;
u32 val32; u32 val32;
switch (size) { switch (size) {
@@ -256,17 +254,7 @@ static void dwc2_get_device_property(struct dwc2_hsotg *hsotg,
*value = device_property_read_bool(hsotg->dev, property); *value = device_property_read_bool(hsotg->dev, property);
break; break;
case 1: case 1:
if (device_property_read_u8(hsotg->dev, property, &val8))
return;
*value = val8;
break;
case 2: case 2:
if (device_property_read_u16(hsotg->dev, property, &val16))
return;
*value = val16;
break;
case 4: case 4:
if (device_property_read_u32(hsotg->dev, property, &val32)) if (device_property_read_u32(hsotg->dev, property, &val32))
return; return;
@@ -1100,13 +1088,13 @@ static void dwc2_set_gadget_dma(struct dwc2_hsotg *hsotg)
/* Buffer DMA */ /* Buffer DMA */
dwc2_set_param_bool(hsotg, &p->g_dma, dwc2_set_param_bool(hsotg, &p->g_dma,
false, "gadget-dma", false, "gadget-dma",
true, false, dma_capable, false,
dma_capable); dma_capable);
/* DMA Descriptor */ /* DMA Descriptor */
dwc2_set_param_bool(hsotg, &p->g_dma_desc, false, dwc2_set_param_bool(hsotg, &p->g_dma_desc, false,
"gadget-dma-desc", "gadget-dma-desc",
p->g_dma, false, !!hw->dma_desc_enable, false,
!!hw->dma_desc_enable); !!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, dwc2_set_param_bool(hsotg, &p->host_dma,
false, "host-dma", false, "host-dma",
true, false, dma_capable, false,
dma_capable); 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_enable(hsotg, params->dma_desc_enable);
dwc2_set_param_dma_desc_fs_enable(hsotg, params->dma_desc_fs_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); params->host_support_fs_ls_low_power);
dwc2_set_param_enable_dynamic_fifo(hsotg, dwc2_set_param_enable_dynamic_fifo(hsotg,
params->enable_dynamic_fifo); 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, dwc2_set_param_max_transfer_size(hsotg,
params->max_transfer_size); params->max_transfer_size);
dwc2_set_param_max_packet_count(hsotg, dwc2_set_param_max_packet_count(hsotg,

View File

@@ -45,9 +45,7 @@
#define DWC3_XHCI_RESOURCES_NUM 2 #define DWC3_XHCI_RESOURCES_NUM 2
#define DWC3_SCRATCHBUF_SIZE 4096 /* each buffer is assumed to be 4KiB */ #define DWC3_SCRATCHBUF_SIZE 4096 /* each buffer is assumed to be 4KiB */
#define DWC3_EVENT_SIZE 4 /* bytes */ #define DWC3_EVENT_BUFFERS_SIZE 4096
#define DWC3_EVENT_MAX_NUM 64 /* 2 events/endpoint */
#define DWC3_EVENT_BUFFERS_SIZE (DWC3_EVENT_SIZE * DWC3_EVENT_MAX_NUM)
#define DWC3_EVENT_TYPE_MASK 0xfe #define DWC3_EVENT_TYPE_MASK 0xfe
#define DWC3_EVENT_TYPE_DEV 0 #define DWC3_EVENT_TYPE_DEV 0
@@ -311,9 +309,8 @@
#define DWC3_DCFG_SUPERSPEED_PLUS (5 << 0) /* DWC_usb31 only */ #define DWC3_DCFG_SUPERSPEED_PLUS (5 << 0) /* DWC_usb31 only */
#define DWC3_DCFG_SUPERSPEED (4 << 0) #define DWC3_DCFG_SUPERSPEED (4 << 0)
#define DWC3_DCFG_HIGHSPEED (0 << 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_LOWSPEED (2 << 0)
#define DWC3_DCFG_FULLSPEED1 (3 << 0)
#define DWC3_DCFG_NUMP_SHIFT 17 #define DWC3_DCFG_NUMP_SHIFT 17
#define DWC3_DCFG_NUMP(n) (((n) >> DWC3_DCFG_NUMP_SHIFT) & 0x1f) #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_PLUS (5 << 0) /* DWC_usb31 only */
#define DWC3_DSTS_SUPERSPEED (4 << 0) #define DWC3_DSTS_SUPERSPEED (4 << 0)
#define DWC3_DSTS_HIGHSPEED (0 << 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_LOWSPEED (2 << 0)
#define DWC3_DSTS_FULLSPEED1 (3 << 0)
/* Device Generic Command Register */ /* Device Generic Command Register */
#define DWC3_DGCMD_SET_LMP 0x01 #define DWC3_DGCMD_SET_LMP 0x01

View File

@@ -19,6 +19,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/irq.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/platform_data/dwc3-omap.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 */ /* check the DMA Status */
reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG); 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, ret = devm_request_threaded_irq(dev, omap->irq, dwc3_omap_interrupt,
dwc3_omap_interrupt_thread, IRQF_SHARED, dwc3_omap_interrupt_thread, IRQF_SHARED,
"dwc3-omap", omap); "dwc3-omap", omap);
@@ -531,7 +532,7 @@ static int dwc3_omap_probe(struct platform_device *pdev)
} }
dwc3_omap_enable_irqs(omap); dwc3_omap_enable_irqs(omap);
enable_irq(omap->irq);
return 0; return 0;
err2: 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, &omap->vbus_nb);
extcon_unregister_notifier(omap->edev, EXTCON_USB_HOST, &omap->id_nb); extcon_unregister_notifier(omap->edev, EXTCON_USB_HOST, &omap->id_nb);
dwc3_omap_disable_irqs(omap); dwc3_omap_disable_irqs(omap);
disable_irq(omap->irq);
of_platform_depopulate(omap->dev); of_platform_depopulate(omap->dev);
pm_runtime_put_sync(&pdev->dev); pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);

View File

@@ -38,6 +38,7 @@
#define PCI_DEVICE_ID_INTEL_BXT_M 0x1aaa #define PCI_DEVICE_ID_INTEL_BXT_M 0x1aaa
#define PCI_DEVICE_ID_INTEL_APL 0x5aaa #define PCI_DEVICE_ID_INTEL_APL 0x5aaa
#define PCI_DEVICE_ID_INTEL_KBP 0xa2b0 #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_DSM_UUID "732b85d5-b7a7-4a1b-9ba0-4bbd00ffd511"
#define PCI_INTEL_BXT_FUNC_PMU_PWR 4 #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 platform_device *dwc3 = dwc->dwc3;
struct pci_dev *pdev = dwc->pci; 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 && if (pdev->vendor == PCI_VENDOR_ID_AMD &&
pdev->device == PCI_DEVICE_ID_AMD_NL_USB) { 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,disable_scramble_quirk"),
PROPERTY_ENTRY_BOOL("snps,dis_u3_susphy_quirk"), PROPERTY_ENTRY_BOOL("snps,dis_u3_susphy_quirk"),
PROPERTY_ENTRY_BOOL("snps,dis_u2_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; int ret;
struct property_entry properties[] = { 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,usb3_lpm_capable"),
PROPERTY_ENTRY_BOOL("snps,has-lpm-erratum"), PROPERTY_ENTRY_BOOL("snps,has-lpm-erratum"),
PROPERTY_ENTRY_BOOL("snps,dis_enblslpm_quirk"), 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_BXT_M), },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_APL), }, { 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_KBP), },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GLK), },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB), }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB), },
{ } /* Terminating Entry */ { } /* Terminating Entry */
}; };

View File

@@ -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, static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
struct dwc3_ep *dep, struct dwc3_request *req); struct dwc3_ep *dep, struct dwc3_request *req);
static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma, static void dwc3_ep0_prepare_one_trb(struct dwc3 *dwc, u8 epnum,
u32 len, u32 type, bool chain) dma_addr_t buf_dma, u32 len, u32 type, bool chain)
{ {
struct dwc3_gadget_ep_cmd_params params;
struct dwc3_trb *trb; struct dwc3_trb *trb;
struct dwc3_ep *dep; struct dwc3_ep *dep;
int ret;
dep = dwc->eps[epnum]; dep = dwc->eps[epnum];
if (dep->flags & DWC3_EP_BUSY)
return 0;
trb = &dwc->ep0_trb[dep->trb_enqueue]; 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 trb->ctrl |= (DWC3_TRB_CTRL_IOC
| DWC3_TRB_CTRL_LST); | 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; return 0;
memset(&params, 0, sizeof(params)); memset(&params, 0, sizeof(params));
params.param0 = upper_32_bits(dwc->ep0_trb_addr); params.param0 = upper_32_bits(dwc->ep0_trb_addr);
params.param1 = lower_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, &params); ret = dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_STARTTRANSFER, &params);
if (ret < 0) if (ret < 0)
return ret; return ret;
@@ -280,8 +283,9 @@ void dwc3_ep0_out_start(struct dwc3 *dwc)
complete(&dwc->ep0_in_setup); 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); DWC3_TRBCTL_CONTROL_SETUP, false);
ret = dwc3_ep0_start_trans(dwc, 0);
WARN_ON(ret < 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; dwc->ep0_next_event = DWC3_EP0_COMPLETE;
ret = dwc3_ep0_start_trans(dwc, epnum, dwc3_ep0_prepare_one_trb(dwc, epnum, dwc->ctrl_req_addr,
dwc->ctrl_req_addr, 0, 0, DWC3_TRBCTL_CONTROL_DATA, false);
DWC3_TRBCTL_CONTROL_DATA, false); ret = dwc3_ep0_start_trans(dwc, epnum);
WARN_ON(ret < 0); WARN_ON(ret < 0);
} }
} }
@@ -993,9 +997,10 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
req->direction = !!dep->number; req->direction = !!dep->number;
if (req->request.length == 0) { 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, dwc->ctrl_req_addr, 0,
DWC3_TRBCTL_CONTROL_DATA, false); DWC3_TRBCTL_CONTROL_DATA, false);
ret = dwc3_ep0_start_trans(dwc, dep->number);
} else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket) } else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket)
&& (dep->number == 0)) { && (dep->number == 0)) {
u32 transfer_size = 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) { if (req->request.length > DWC3_EP0_BOUNCE_SIZE) {
transfer_size = ALIGN(req->request.length - maxpacket, transfer_size = ALIGN(req->request.length - maxpacket,
maxpacket); maxpacket);
ret = dwc3_ep0_start_trans(dwc, dep->number, dwc3_ep0_prepare_one_trb(dwc, dep->number,
req->request.dma, req->request.dma,
transfer_size, transfer_size,
DWC3_TRBCTL_CONTROL_DATA, DWC3_TRBCTL_CONTROL_DATA,
@@ -1023,18 +1028,20 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
dwc->ep0_bounced = true; 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, dwc->ep0_bounce_addr, transfer_size,
DWC3_TRBCTL_CONTROL_DATA, false); DWC3_TRBCTL_CONTROL_DATA, false);
ret = dwc3_ep0_start_trans(dwc, dep->number);
} else { } else {
ret = usb_gadget_map_request_by_dev(dwc->sysdev, ret = usb_gadget_map_request_by_dev(dwc->sysdev,
&req->request, dep->number); &req->request, dep->number);
if (ret) if (ret)
return; 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, req->request.length, DWC3_TRBCTL_CONTROL_DATA,
false); false);
ret = dwc3_ep0_start_trans(dwc, dep->number);
} }
WARN_ON(ret < 0); 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 type = dwc->three_stage_setup ? DWC3_TRBCTL_CONTROL_STATUS3
: DWC3_TRBCTL_CONTROL_STATUS2; : 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); 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) static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep)

View File

@@ -180,11 +180,11 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
if (req->request.status == -EINPROGRESS) if (req->request.status == -EINPROGRESS)
req->request.status = status; req->request.status = status;
if (dwc->ep0_bounced && dep->number == 0) if (dwc->ep0_bounced && dep->number <= 1)
dwc->ep0_bounced = false; dwc->ep0_bounced = false;
else
usb_gadget_unmap_request_by_dev(dwc->sysdev, usb_gadget_unmap_request_by_dev(dwc->sysdev,
&req->request, req->direction); &req->request, req->direction);
trace_dwc3_gadget_giveback(req); trace_dwc3_gadget_giveback(req);
@@ -1720,7 +1720,7 @@ static int __dwc3_gadget_start(struct dwc3 *dwc)
reg |= DWC3_DCFG_LOWSPEED; reg |= DWC3_DCFG_LOWSPEED;
break; break;
case USB_SPEED_FULL: case USB_SPEED_FULL:
reg |= DWC3_DCFG_FULLSPEED1; reg |= DWC3_DCFG_FULLSPEED;
break; break;
case USB_SPEED_HIGH: case USB_SPEED_HIGH:
reg |= DWC3_DCFG_HIGHSPEED; reg |= DWC3_DCFG_HIGHSPEED;
@@ -2232,9 +2232,14 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
dep = dwc->eps[epnum]; dep = dwc->eps[epnum];
if (!(dep->flags & DWC3_EP_ENABLED) && if (!(dep->flags & DWC3_EP_ENABLED)) {
!(dep->flags & DWC3_EP_END_TRANSFER_PENDING)) if (!(dep->flags & DWC3_EP_END_TRANSFER_PENDING))
return; return;
/* Handle only EPCMDCMPLT when EP disabled */
if (event->endpoint_event != DWC3_DEPEVT_EPCMDCMPLT)
return;
}
if (epnum == 0 || epnum == 1) { if (epnum == 0 || epnum == 1) {
dwc3_ep0_interrupt(dwc, event); 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.ep0->maxpacket = 64;
dwc->gadget.speed = USB_SPEED_HIGH; dwc->gadget.speed = USB_SPEED_HIGH;
break; break;
case DWC3_DSTS_FULLSPEED2: case DWC3_DSTS_FULLSPEED:
case DWC3_DSTS_FULLSPEED1:
dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64); dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
dwc->gadget.ep0->maxpacket = 64; dwc->gadget.ep0->maxpacket = 64;
dwc->gadget.speed = USB_SPEED_FULL; dwc->gadget.speed = USB_SPEED_FULL;

View File

@@ -1694,9 +1694,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
value = min(w_length, (u16) 1); value = min(w_length, (u16) 1);
break; break;
/* function drivers must handle get/set altsetting; if there's /* function drivers must handle get/set altsetting */
* no get() method, we know only altsetting zero works.
*/
case USB_REQ_SET_INTERFACE: case USB_REQ_SET_INTERFACE:
if (ctrl->bRequestType != USB_RECIP_INTERFACE) if (ctrl->bRequestType != USB_RECIP_INTERFACE)
goto unknown; goto unknown;
@@ -1705,7 +1703,13 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
f = cdev->config->interface[intf]; f = cdev->config->interface[intf];
if (!f) if (!f)
break; 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; break;
value = f->set_alt(f, w_index, w_value); value = f->set_alt(f, w_index, w_value);
if (value == USB_GADGET_DELAYED_STATUS) { if (value == USB_GADGET_DELAYED_STATUS) {

View File

@@ -2091,8 +2091,8 @@ static int __ffs_data_do_entity(enum ffs_entity_type type,
case FFS_STRING: case FFS_STRING:
/* /*
* Strings are indexed from 1 (0 is magic ;) reserved * Strings are indexed from 1 (0 is reserved
* for languages list or some such) * for languages list)
*/ */
if (*valuep > helper->ffs->strings_count) if (*valuep > helper->ffs->strings_count)
helper->ffs->strings_count = *valuep; 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) || if (len < sizeof(*d) ||
d->bFirstInterfaceNumber >= ffs->interfaces_count || d->bFirstInterfaceNumber >= ffs->interfaces_count ||
!d->Reserved1) d->Reserved1)
return -EINVAL; return -EINVAL;
for (i = 0; i < ARRAY_SIZE(d->Reserved2); ++i) for (i = 0; i < ARRAY_SIZE(d->Reserved2); ++i)
if (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 ffs_dev *ffs_obj;
struct f_fs_opts *opts; struct f_fs_opts *opts;
struct config_item *ci;
ENTER(); ENTER();
ffs_dev_lock(); 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)) || !atomic_read(&opts->func_inst.group.cg_item.ci_kref.refcount))
goto done; goto done;
unregister_gadget_item(ffs_obj->opts-> ci = opts->func_inst.group.cg_item.ci_parent->ci_parent;
func_inst.group.cg_item.ci_parent->ci_parent); ffs_dev_unlock();
unregister_gadget_item(ci);
return;
done: done:
ffs_dev_unlock(); ffs_dev_unlock();
} }

View File

@@ -593,7 +593,7 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
} }
status = usb_ep_enable(hidg->out_ep); status = usb_ep_enable(hidg->out_ep);
if (status < 0) { if (status < 0) {
ERROR(cdev, "Enable IN endpoint FAILED!\n"); ERROR(cdev, "Enable OUT endpoint FAILED!\n");
goto fail; goto fail;
} }
hidg->out_ep->driver_data = hidg; hidg->out_ep->driver_data = hidg;

View File

@@ -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 */ /* data and/or status stage for control request */
} else if (dev->state == STATE_DEV_SETUP) { } 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) { if (dev->setup_in) {
retval = setup_req (dev->gadget->ep0, dev->req, len); retval = setup_req (dev->gadget->ep0, dev->req, len);
if (retval == 0) { if (retval == 0) {
@@ -1734,10 +1734,12 @@ static struct usb_gadget_driver gadgetfs_driver = {
* such as configuration notifications. * 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 return config->bDescriptorType == USB_DT_CONFIG
&& config->bLength == USB_DT_CONFIG_SIZE && config->bLength == USB_DT_CONFIG_SIZE
&& total >= USB_DT_CONFIG_SIZE
&& config->bConfigurationValue != 0 && config->bConfigurationValue != 0
&& (config->bmAttributes & USB_CONFIG_ATT_ONE) != 0 && (config->bmAttributes & USB_CONFIG_ATT_ONE) != 0
&& (config->bmAttributes & USB_CONFIG_ATT_WAKEUP) == 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); 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; return -EINVAL;
/* we might need to change message format someday */ /* 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 */ /* full or low speed config */
dev->config = (void *) kbuf; dev->config = (void *) kbuf;
total = le16_to_cpu(dev->config->wTotalLength); 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; goto fail;
kbuf += total; kbuf += total;
length -= 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) { if (kbuf [1] == USB_DT_CONFIG) {
dev->hs_config = (void *) kbuf; dev->hs_config = (void *) kbuf;
total = le16_to_cpu(dev->hs_config->wTotalLength); 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; goto fail;
kbuf += total; kbuf += total;
length -= total; length -= total;
} else {
dev->hs_config = NULL;
} }
/* could support multiple configs, using another encoding! */ /* 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->bDescriptorType != USB_DT_DEVICE
|| dev->dev->bNumConfigurations != 1) || dev->dev->bNumConfigurations != 1)
goto fail; goto fail;
dev->dev->bNumConfigurations = 1;
dev->dev->bcdUSB = cpu_to_le16 (0x0200); dev->dev->bcdUSB = cpu_to_le16 (0x0200);
/* triggers gadgetfs_bind(); then we can enumerate. */ /* triggers gadgetfs_bind(); then we can enumerate. */

View File

@@ -1317,7 +1317,11 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
if (!ret) if (!ret)
break; break;
} }
if (!ret && !udc->driver) if (ret)
ret = -ENODEV;
else if (udc->driver)
ret = -EBUSY;
else
goto found; goto found;
} else { } else {
list_for_each_entry(udc, &udc_list, list) { list_for_each_entry(udc, &udc_list, list) {

View File

@@ -330,7 +330,7 @@ static void nuke(struct dummy *dum, struct dummy_ep *ep)
/* caller must hold lock */ /* caller must hold lock */
static void stop_activity(struct dummy *dum) static void stop_activity(struct dummy *dum)
{ {
struct dummy_ep *ep; int i;
/* prevent any more requests */ /* prevent any more requests */
dum->address = 0; 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 */ /* The timer is left running so that outstanding URBs can fail */
/* nuke any pending requests first, so driver i/o is quiesced */ /* nuke any pending requests first, so driver i/o is quiesced */
list_for_each_entry(ep, &dum->gadget.ep_list, ep.ep_list) for (i = 0; i < DUMMY_ENDPOINTS; ++i)
nuke(dum, ep); nuke(dum, &dum->ep[i]);
/* driver now does any non-usb quiescing necessary */ /* driver now does any non-usb quiescing necessary */
} }

View File

@@ -43,7 +43,6 @@ struct at91_usbh_data {
struct gpio_desc *overcurrent_pin[AT91_MAX_USBH_PORTS]; struct gpio_desc *overcurrent_pin[AT91_MAX_USBH_PORTS];
u8 ports; /* number of ports on root hub */ u8 ports; /* number of ports on root hub */
u8 overcurrent_supported; u8 overcurrent_supported;
u8 vbus_pin_active_low[AT91_MAX_USBH_PORTS];
u8 overcurrent_status[AT91_MAX_USBH_PORTS]; u8 overcurrent_status[AT91_MAX_USBH_PORTS];
u8 overcurrent_changed[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)) if (!valid_port(port))
return; return;
gpiod_set_value(pdata->vbus_pin[port], gpiod_set_value(pdata->vbus_pin[port], enable);
pdata->vbus_pin_active_low[port] ^ enable);
} }
static int ohci_at91_usb_get_power(struct at91_usbh_data *pdata, int port) 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)) if (!valid_port(port))
return -EINVAL; return -EINVAL;
return gpiod_get_value(pdata->vbus_pin[port]) ^ return gpiod_get_value(pdata->vbus_pin[port]);
pdata->vbus_pin_active_low[port];
} }
/* /*
@@ -533,18 +530,17 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev)
pdata->ports = ports; pdata->ports = ports;
at91_for_each_port(i) { at91_for_each_port(i) {
pdata->vbus_pin[i] = devm_gpiod_get_optional(&pdev->dev, if (i >= pdata->ports)
"atmel,vbus-gpio", break;
GPIOD_IN);
pdata->vbus_pin[i] =
devm_gpiod_get_index_optional(&pdev->dev, "atmel,vbus",
i, GPIOD_OUT_HIGH);
if (IS_ERR(pdata->vbus_pin[i])) { if (IS_ERR(pdata->vbus_pin[i])) {
err = PTR_ERR(pdata->vbus_pin[i]); err = PTR_ERR(pdata->vbus_pin[i]);
dev_err(&pdev->dev, "unable to claim gpio \"vbus\": %d\n", err); dev_err(&pdev->dev, "unable to claim gpio \"vbus\": %d\n", err);
continue; 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) { at91_for_each_port(i) {
@@ -552,8 +548,8 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev)
break; break;
pdata->overcurrent_pin[i] = pdata->overcurrent_pin[i] =
devm_gpiod_get_optional(&pdev->dev, devm_gpiod_get_index_optional(&pdev->dev, "atmel,oc",
"atmel,oc-gpio", GPIOD_IN); i, GPIOD_IN);
if (IS_ERR(pdata->overcurrent_pin[i])) { if (IS_ERR(pdata->overcurrent_pin[i])) {
err = PTR_ERR(pdata->overcurrent_pin[i]); err = PTR_ERR(pdata->overcurrent_pin[i]);
dev_err(&pdev->dev, "unable to claim gpio \"overcurrent\": %d\n", err); dev_err(&pdev->dev, "unable to claim gpio \"overcurrent\": %d\n", err);

View File

@@ -979,6 +979,40 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id)
xhci->devs[slot_id] = NULL; 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, int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
struct usb_device *udev, gfp_t flags) struct usb_device *udev, gfp_t flags)
{ {
@@ -1795,7 +1829,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
int size; int size;
int i, j, num_ports; 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 */ /* Free the Event Ring Segment Table and the actual Event Ring */
size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries); 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) for (i = HCS_MAX_SLOTS(xhci->hcs_params1); i > 0; i--)
xhci_free_virt_device(xhci, i); xhci_free_virt_devices_depth_first(xhci, i);
dma_pool_destroy(xhci->segment_pool); dma_pool_destroy(xhci->segment_pool);
xhci->segment_pool = NULL; 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_LIST_HEAD(&xhci->cmd_list);
/* init command timeout timer */ /* init command timeout work */
setup_timer(&xhci->cmd_timer, xhci_handle_command_timeout, INIT_DELAYED_WORK(&xhci->cmd_timer, xhci_handle_command_timeout);
(unsigned long)xhci); init_completion(&xhci->cmd_ring_stop_completion);
page_size = readl(&xhci->op_regs->page_size); page_size = readl(&xhci->op_regs->page_size);
xhci_dbg_trace(xhci, trace_xhci_dbg_init, xhci_dbg_trace(xhci, trace_xhci_dbg_init,

View File

@@ -579,8 +579,10 @@ static int xhci_mtk_probe(struct platform_device *pdev)
goto disable_ldos; goto disable_ldos;
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0) if (irq < 0) {
ret = irq;
goto disable_clk; goto disable_clk;
}
/* Initialize dma_mask and coherent_dma_mask to 32-bits */ /* Initialize dma_mask and coherent_dma_mask to 32-bits */
ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));

View File

@@ -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_SUNRISEPOINT_H_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_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_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; xhci->quirks |= XHCI_PME_STUCK_QUIRK;
} }
if (pdev->vendor == PCI_VENDOR_ID_INTEL && if (pdev->vendor == PCI_VENDOR_ID_INTEL &&

View File

@@ -279,23 +279,76 @@ void xhci_ring_cmd_db(struct xhci_hcd *xhci)
readl(&xhci->dba->doorbell[0]); 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; u64 temp_64;
int ret; int ret;
xhci_dbg(xhci, "Abort command ring\n"); xhci_dbg(xhci, "Abort command ring\n");
temp_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); reinit_completion(&xhci->cmd_ring_stop_completion);
xhci->cmd_ring_state = CMD_RING_STATE_ABORTED;
/* temp_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
* 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));
xhci_write_64(xhci, temp_64 | CMD_RING_ABORT, xhci_write_64(xhci, temp_64 | CMD_RING_ABORT,
&xhci->op_regs->cmd_ring); &xhci->op_regs->cmd_ring);
@@ -315,17 +368,30 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci)
udelay(1000); udelay(1000);
ret = xhci_handshake(&xhci->op_regs->cmd_ring, ret = xhci_handshake(&xhci->op_regs->cmd_ring,
CMD_RING_RUNNING, 0, 3 * 1000 * 1000); CMD_RING_RUNNING, 0, 3 * 1000 * 1000);
if (ret == 0) if (ret < 0) {
return 0; xhci_err(xhci, "Stopped the command ring failed, "
"maybe the host is dead\n");
xhci_err(xhci, "Stopped the command ring failed, " xhci->xhc_state |= XHCI_STATE_DYING;
"maybe the host is dead\n"); xhci_halt(xhci);
del_timer(&xhci->cmd_timer); return -ESHUTDOWN;
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; 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); xhci_complete_del_and_free_cmd(cur_cmd, COMP_CMD_ABORT);
} }
/* void xhci_handle_command_timeout(struct work_struct *work)
* 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)
{ {
struct xhci_hcd *xhci; struct xhci_hcd *xhci;
int ret; int ret;
unsigned long flags; unsigned long flags;
u64 hw_ring_state; 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); spin_lock_irqsave(&xhci->lock, flags);
if (xhci->current_cmd) {
if (xhci->current_cmd->status == COMP_CMD_ABORT) /*
second_timeout = true; * If timeout work is pending, or current_cmd is NULL, it means we
xhci->current_cmd->status = COMP_CMD_ABORT; * 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 */ /* Make sure command ring is running before aborting it */
hw_ring_state = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); hw_ring_state = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
if ((xhci->cmd_ring_state & CMD_RING_STATE_RUNNING) && if ((xhci->cmd_ring_state & CMD_RING_STATE_RUNNING) &&
(hw_ring_state & CMD_RING_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"); xhci_dbg(xhci, "Command timeout\n");
ret = xhci_abort_cmd_ring(xhci); ret = xhci_abort_cmd_ring(xhci, flags);
if (unlikely(ret == -ESHUTDOWN)) { if (unlikely(ret == -ESHUTDOWN)) {
xhci_err(xhci, "Abort command ring failed\n"); xhci_err(xhci, "Abort command ring failed\n");
xhci_cleanup_command_queue(xhci); xhci_cleanup_command_queue(xhci);
spin_unlock_irqrestore(&xhci->lock, flags);
usb_hc_died(xhci_to_hcd(xhci)->primary_hcd); usb_hc_died(xhci_to_hcd(xhci)->primary_hcd);
xhci_dbg(xhci, "xHCI host controller is dead.\n"); 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 */ /* host removed. Bail out */
if (second_timeout || xhci->xhc_state & XHCI_STATE_REMOVING) { if (xhci->xhc_state & XHCI_STATE_REMOVING) {
spin_unlock_irqrestore(&xhci->lock, flags); xhci_dbg(xhci, "host removed, ring start fail?\n");
xhci_dbg(xhci, "command timed out twice, ring start fail?\n");
xhci_cleanup_command_queue(xhci); xhci_cleanup_command_queue(xhci);
return;
goto time_out_completed;
} }
/* command timeout on stopped ring, ring can't be aborted */ /* command timeout on stopped ring, ring can't be aborted */
xhci_dbg(xhci, "Command timeout on stopped ring\n"); xhci_dbg(xhci, "Command timeout on stopped ring\n");
xhci_handle_stopped_cmd_ring(xhci, xhci->current_cmd); xhci_handle_stopped_cmd_ring(xhci, xhci->current_cmd);
time_out_completed:
spin_unlock_irqrestore(&xhci->lock, flags); spin_unlock_irqrestore(&xhci->lock, flags);
return; 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); 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); 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 ring stopped we own the trbs between enqueue and dequeue */
if (cmd_comp_code == COMP_CMD_STOP) { if (cmd_comp_code == COMP_CMD_STOP) {
xhci_handle_stopped_cmd_ring(xhci, cmd); complete_all(&xhci->cmd_ring_stop_completion);
return; return;
} }
@@ -1359,8 +1386,11 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
*/ */
if (cmd_comp_code == COMP_CMD_ABORT) { if (cmd_comp_code == COMP_CMD_ABORT) {
xhci->cmd_ring_state = CMD_RING_STATE_STOPPED; 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; goto event_handled;
}
} }
cmd_type = TRB_FIELD_TO_TYPE(le32_to_cpu(cmd_trb->generic.field[3])); 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) { if (cmd->cmd_list.next != &xhci->cmd_list) {
xhci->current_cmd = list_entry(cmd->cmd_list.next, xhci->current_cmd = list_entry(cmd->cmd_list.next,
struct xhci_command, cmd_list); 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: 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; struct xhci_ep_ctx *ep_ctx;
u32 trb_comp_code; u32 trb_comp_code;
u32 remaining, requested; 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)); slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags));
xdev = xhci->devs[slot_id]; xdev = xhci->devs[slot_id];
ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1; 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; requested = td->urb->transfer_buffer_length;
remaining = EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); 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) { switch (trb_comp_code) {
case COMP_SUCCESS: 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", 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; *status = -ESHUTDOWN;
break; break;
} }
@@ -1967,15 +1997,25 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
*status = 0; *status = 0;
break; break;
case COMP_STOP_SHORT: case COMP_STOP_SHORT:
if (on_data_stage) if (trb_type == TRB_DATA || trb_type == TRB_NORMAL)
td->urb->actual_length = remaining; td->urb->actual_length = remaining;
else else
xhci_warn(xhci, "WARN: Stopped Short Packet on ctrl setup or status TRB\n"); xhci_warn(xhci, "WARN: Stopped Short Packet on ctrl setup or status TRB\n");
goto finish_td; goto finish_td;
case COMP_STOP: 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; 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: case COMP_STOP_INVAL:
goto finish_td; goto finish_td;
default: default:
@@ -1987,7 +2027,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
/* else fall through */ /* else fall through */
case COMP_STALL: case COMP_STALL:
/* Did we transfer part of the data (middle) phase? */ /* 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; td->urb->actual_length = requested - remaining;
else if (!td->urb_length_set) else if (!td->urb_length_set)
td->urb->actual_length = 0; 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 */ /* stopped at setup stage, no data transferred */
if (ep_trb == ep_ring->dequeue) if (trb_type == TRB_SETUP)
goto finish_td; goto finish_td;
/* /*
* if on data stage then update the actual_length of the URB and flag it * 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. * 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_length_set = true;
td->urb->actual_length = requested - remaining; td->urb->actual_length = requested - remaining;
xhci_dbg(xhci, "Waiting for status stage event\n"); 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 there are no other commands queued we start the timeout timer */
if (xhci->cmd_list.next == &cmd->cmd_list && if (xhci->cmd_list.next == &cmd->cmd_list &&
!timer_pending(&xhci->cmd_timer)) { !delayed_work_pending(&xhci->cmd_timer)) {
xhci->current_cmd = cmd; 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, queue_trb(xhci, xhci->cmd_ring, false, field1, field2, field3,

View File

@@ -3787,8 +3787,10 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
mutex_lock(&xhci->mutex); mutex_lock(&xhci->mutex);
if (xhci->xhc_state) /* dying, removing or halted */ if (xhci->xhc_state) { /* dying, removing or halted */
ret = -ESHUTDOWN;
goto out; goto out;
}
if (!udev->slot_id) { if (!udev->slot_id) {
xhci_dbg_trace(xhci, trace_xhci_dbg_address, xhci_dbg_trace(xhci, trace_xhci_dbg_address,

View File

@@ -1568,7 +1568,8 @@ struct xhci_hcd {
#define CMD_RING_STATE_STOPPED (1 << 2) #define CMD_RING_STATE_STOPPED (1 << 2)
struct list_head cmd_list; struct list_head cmd_list;
unsigned int cmd_ring_reserved_trbs; 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_command *current_cmd;
struct xhci_ring *event_ring; struct xhci_ring *event_ring;
struct xhci_erst erst; 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, unsigned int slot_id, unsigned int ep_index,
struct xhci_dequeue_state *deq_state); struct xhci_dequeue_state *deq_state);
void xhci_stop_endpoint_command_watchdog(unsigned long arg); 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, void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id,
unsigned int ep_index, unsigned int stream_id); unsigned int ep_index, unsigned int stream_id);

View File

@@ -469,6 +469,7 @@ static const struct musb_platform_ops bfin_ops = {
.init = bfin_musb_init, .init = bfin_musb_init,
.exit = bfin_musb_exit, .exit = bfin_musb_exit,
.fifo_offset = bfin_fifo_offset,
.readb = bfin_readb, .readb = bfin_readb,
.writeb = bfin_writeb, .writeb = bfin_writeb,
.readw = bfin_readw, .readw = bfin_readw,

View File

@@ -2050,6 +2050,7 @@ struct musb_pending_work {
struct list_head node; struct list_head node;
}; };
#ifdef CONFIG_PM
/* /*
* Called from musb_runtime_resume(), musb_resume(), and * Called from musb_runtime_resume(), musb_resume(), and
* musb_queue_resume_work(). Callers must take musb->lock. * musb_queue_resume_work(). Callers must take musb->lock.
@@ -2077,6 +2078,7 @@ static int musb_run_resume_work(struct musb *musb)
return error; return error;
} }
#endif
/* /*
* Called to run work if device is active or else queue the work to happen * Called to run work if device is active or else queue the work to happen

View File

@@ -216,6 +216,7 @@ struct musb_platform_ops {
void (*pre_root_reset_end)(struct musb *musb); void (*pre_root_reset_end)(struct musb *musb);
void (*post_root_reset_end)(struct musb *musb); void (*post_root_reset_end)(struct musb *musb);
int (*phy_callback)(enum musb_vbus_id_status status); 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); 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 * 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 * if the property is not found or not recognized returns MUSB_OTG

View File

@@ -267,6 +267,17 @@ static void otg_timer(unsigned long _musb)
pm_runtime_put_autosuspend(dev); 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) static irqreturn_t dsps_interrupt(int irq, void *hci)
{ {
struct musb *musb = hci; struct musb *musb = hci;
@@ -622,6 +633,7 @@ static struct musb_platform_ops dsps_ops = {
.set_mode = dsps_musb_set_mode, .set_mode = dsps_musb_set_mode,
.recover = dsps_musb_recover, .recover = dsps_musb_recover,
.clear_ep_rxintr = dsps_musb_clear_ep_rxintr,
}; };
static u64 musb_dmamask = DMA_BIT_MASK(32); static u64 musb_dmamask = DMA_BIT_MASK(32);

View File

@@ -2374,12 +2374,11 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh)
int is_in = usb_pipein(urb->pipe); int is_in = usb_pipein(urb->pipe);
int status = 0; int status = 0;
u16 csr; u16 csr;
struct dma_channel *dma = NULL;
musb_ep_select(regs, hw_end); musb_ep_select(regs, hw_end);
if (is_dma_capable()) { if (is_dma_capable()) {
struct dma_channel *dma;
dma = is_in ? ep->rx_channel : ep->tx_channel; dma = is_in ? ep->rx_channel : ep->tx_channel;
if (dma) { if (dma) {
status = ep->musb->dma_controller->channel_abort(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 */ /* giveback saves bulk toggle */
csr = musb_h_flush_rxfifo(ep, 0); csr = musb_h_flush_rxfifo(ep, 0);
/* REVISIT we still get an irq; should likely clear the /* clear the endpoint's irq status here to avoid bogus irqs */
* endpoint's irq status here to avoid bogus irqs. if (is_dma_capable() && dma)
* clearing that status is platform-specific... musb_platform_clear_ep_rxintr(musb, ep->epnum);
*/
} else if (ep->epnum) { } else if (ep->epnum) {
musb_h_tx_flush_fifo(ep); musb_h_tx_flush_fifo(ep);
csr = musb_readw(epio, MUSB_TXCSR); csr = musb_readw(epio, MUSB_TXCSR);

View File

@@ -157,5 +157,5 @@ struct musb_dma_controller {
void __iomem *base; void __iomem *base;
u8 channel_count; u8 channel_count;
u8 used_channels; u8 used_channels;
u8 irq; int irq;
}; };

View File

@@ -50,6 +50,7 @@
#define CYBERJACK_PRODUCT_ID 0x0100 #define CYBERJACK_PRODUCT_ID 0x0100
/* Function prototypes */ /* Function prototypes */
static int cyberjack_attach(struct usb_serial *serial);
static int cyberjack_port_probe(struct usb_serial_port *port); static int cyberjack_port_probe(struct usb_serial_port *port);
static int cyberjack_port_remove(struct usb_serial_port *port); static int cyberjack_port_remove(struct usb_serial_port *port);
static int cyberjack_open(struct tty_struct *tty, 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", .description = "Reiner SCT Cyberjack USB card reader",
.id_table = id_table, .id_table = id_table,
.num_ports = 1, .num_ports = 1,
.attach = cyberjack_attach,
.port_probe = cyberjack_port_probe, .port_probe = cyberjack_port_probe,
.port_remove = cyberjack_port_remove, .port_remove = cyberjack_port_remove,
.open = cyberjack_open, .open = cyberjack_open,
@@ -100,6 +102,14 @@ struct cyberjack_private {
short wrsent; /* Data already sent */ 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) static int cyberjack_port_probe(struct usb_serial_port *port)
{ {
struct cyberjack_private *priv; struct cyberjack_private *priv;

View File

@@ -1237,6 +1237,7 @@ static int f81534_attach(struct usb_serial *serial)
static int f81534_port_probe(struct usb_serial_port *port) static int f81534_port_probe(struct usb_serial_port *port)
{ {
struct f81534_port_private *port_priv; struct f81534_port_private *port_priv;
int ret;
port_priv = devm_kzalloc(&port->dev, sizeof(*port_priv), GFP_KERNEL); port_priv = devm_kzalloc(&port->dev, sizeof(*port_priv), GFP_KERNEL);
if (!port_priv) if (!port_priv)
@@ -1246,10 +1247,11 @@ static int f81534_port_probe(struct usb_serial_port *port)
mutex_init(&port_priv->mcr_mutex); mutex_init(&port_priv->mcr_mutex);
/* Assign logic-to-phy mapping */ /* Assign logic-to-phy mapping */
port_priv->phy_num = f81534_logic_to_phy_port(port->serial, port); ret = f81534_logic_to_phy_port(port->serial, port);
if (port_priv->phy_num < 0 || port_priv->phy_num >= F81534_NUM_PORT) if (ret < 0)
return -ENODEV; return ret;
port_priv->phy_num = ret;
usb_set_serial_port_data(port, port_priv); usb_set_serial_port_data(port, port_priv);
dev_dbg(&port->dev, "%s: port_number: %d, phy_num: %d\n", __func__, dev_dbg(&port->dev, "%s: port_number: %d, phy_num: %d\n", __func__,
port->port_number, port_priv->phy_num); port->port_number, port_priv->phy_num);

View File

@@ -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", "%s - usb_submit_urb(write bulk) failed with status = %d\n",
__func__, status); __func__, status);
count = status; count = status;
kfree(buffer);
} }
/* we are done with this urb, so let the host driver /* we are done with this urb, so let the host driver

View File

@@ -2751,6 +2751,11 @@ static int edge_startup(struct usb_serial *serial)
EDGE_COMPATIBILITY_MASK1, EDGE_COMPATIBILITY_MASK1,
EDGE_COMPATIBILITY_MASK2 }; 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; dev = serial->dev;
/* create our private serial structure */ /* create our private serial structure */

View File

@@ -1499,8 +1499,7 @@ static int do_boot_mode(struct edgeport_serial *serial,
dev_dbg(dev, "%s - Download successful -- Device rebooting...\n", __func__); dev_dbg(dev, "%s - Download successful -- Device rebooting...\n", __func__);
/* return an error on purpose */ return 1;
return -ENODEV;
} }
stayinbootmode: stayinbootmode:
@@ -1508,7 +1507,7 @@ stayinbootmode:
dev_dbg(dev, "%s - STAYING IN BOOT MODE\n", __func__); dev_dbg(dev, "%s - STAYING IN BOOT MODE\n", __func__);
serial->product_info.TiMode = TI_MODE_BOOT; serial->product_info.TiMode = TI_MODE_BOOT;
return 0; return 1;
} }
static int ti_do_config(struct edgeport_port *port, int feature, int on) 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; int status;
u16 product_id; 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 */ /* create our private serial structure */
edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL); edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL);
if (!edge_serial) if (!edge_serial)
@@ -2553,14 +2559,18 @@ static int edge_startup(struct usb_serial *serial)
mutex_init(&edge_serial->es_lock); mutex_init(&edge_serial->es_lock);
edge_serial->serial = serial; edge_serial->serial = serial;
INIT_DELAYED_WORK(&edge_serial->heartbeat_work, edge_heartbeat_work);
usb_set_serial_data(serial, edge_serial); usb_set_serial_data(serial, edge_serial);
status = download_fw(edge_serial); status = download_fw(edge_serial);
if (status) { if (status < 0) {
kfree(edge_serial); kfree(edge_serial);
return status; return status;
} }
if (status > 0)
return 1; /* bind but do not register any ports */
product_id = le16_to_cpu( product_id = le16_to_cpu(
edge_serial->serial->dev->descriptor.idProduct); 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); edge_heartbeat_schedule(edge_serial);
return 0; return 0;
@@ -2580,6 +2589,9 @@ static int edge_startup(struct usb_serial *serial)
static void edge_disconnect(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) static void edge_release(struct usb_serial *serial)

View File

@@ -68,6 +68,16 @@ struct iuu_private {
u32 clk; 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) static int iuu_port_probe(struct usb_serial_port *port)
{ {
struct iuu_private *priv; struct iuu_private *priv;
@@ -1196,6 +1206,7 @@ static struct usb_serial_driver iuu_device = {
.tiocmset = iuu_tiocmset, .tiocmset = iuu_tiocmset,
.set_termios = iuu_set_termios, .set_termios = iuu_set_termios,
.init_termios = iuu_init_termios, .init_termios = iuu_init_termios,
.attach = iuu_attach,
.port_probe = iuu_port_probe, .port_probe = iuu_port_probe,
.port_remove = iuu_port_remove, .port_remove = iuu_port_remove,
}; };

View File

@@ -699,6 +699,19 @@ MODULE_FIRMWARE("keyspan_pda/keyspan_pda.fw");
MODULE_FIRMWARE("keyspan_pda/xircom_pgs.fw"); MODULE_FIRMWARE("keyspan_pda/xircom_pgs.fw");
#endif #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) 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, .break_ctl = keyspan_pda_break_ctl,
.tiocmget = keyspan_pda_tiocmget, .tiocmget = keyspan_pda_tiocmget,
.tiocmset = keyspan_pda_tiocmset, .tiocmset = keyspan_pda_tiocmset,
.attach = keyspan_pda_attach,
.port_probe = keyspan_pda_port_probe, .port_probe = keyspan_pda_port_probe,
.port_remove = keyspan_pda_port_remove, .port_remove = keyspan_pda_port_remove,
}; };

View File

@@ -51,6 +51,7 @@
/* Function prototypes */ /* Function prototypes */
static int kobil_attach(struct usb_serial *serial);
static int kobil_port_probe(struct usb_serial_port *probe); static int kobil_port_probe(struct usb_serial_port *probe);
static int kobil_port_remove(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); 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", .description = "KOBIL USB smart card terminal",
.id_table = id_table, .id_table = id_table,
.num_ports = 1, .num_ports = 1,
.attach = kobil_attach,
.port_probe = kobil_port_probe, .port_probe = kobil_port_probe,
.port_remove = kobil_port_remove, .port_remove = kobil_port_remove,
.ioctl = kobil_ioctl, .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) static int kobil_port_probe(struct usb_serial_port *port)
{ {
struct usb_serial *serial = port->serial; struct usb_serial *serial = port->serial;

View File

@@ -65,8 +65,6 @@ struct moschip_port {
struct urb *write_urb_pool[NUM_URBS]; struct urb *write_urb_pool[NUM_URBS];
}; };
static struct usb_serial_driver moschip7720_2port_driver;
#define USB_VENDOR_ID_MOSCHIP 0x9710 #define USB_VENDOR_ID_MOSCHIP 0x9710
#define MOSCHIP_DEVICE_ID_7720 0x7720 #define MOSCHIP_DEVICE_ID_7720 0x7720
#define MOSCHIP_DEVICE_ID_7715 0x7715 #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); 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) static int mos77xx_calc_num_ports(struct usb_serial *serial)
{ {
u16 product = le16_to_cpu(serial->dev->descriptor.idProduct); u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);
@@ -1917,6 +1896,11 @@ static int mos7720_startup(struct usb_serial *serial)
u16 product; u16 product;
int ret_val; 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); product = le16_to_cpu(serial->dev->descriptor.idProduct);
dev = serial->dev; dev = serial->dev;
@@ -1941,19 +1925,18 @@ static int mos7720_startup(struct usb_serial *serial)
tmp->interrupt_in_endpointAddress; tmp->interrupt_in_endpointAddress;
serial->port[1]->interrupt_in_urb = NULL; serial->port[1]->interrupt_in_urb = NULL;
serial->port[1]->interrupt_in_buffer = 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 */ /* setting configuration feature to one */
usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
(__u8)0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5000); (__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 #ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT
if (product == MOSCHIP_DEVICE_ID_7715) { if (product == MOSCHIP_DEVICE_ID_7715) {
ret_val = mos7715_parport_init(serial); ret_val = mos7715_parport_init(serial);
@@ -1961,6 +1944,13 @@ static int mos7720_startup(struct usb_serial *serial)
return ret_val; return ret_val;
} }
#endif #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 */ /* LSR For Port 1 */
read_mos_reg(serial, 0, MOS7720_LSR, &data); read_mos_reg(serial, 0, MOS7720_LSR, &data);
dev_dbg(&dev->dev, "LSR:%x\n", 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) static void mos7720_release(struct usb_serial *serial)
{ {
usb_kill_urb(serial->port[0]->interrupt_in_urb);
#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT #ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT
/* close the parallel port */ /* close the parallel port */
@@ -2019,11 +2011,6 @@ static int mos7720_port_probe(struct usb_serial_port *port)
if (!mos7720_port) if (!mos7720_port)
return -ENOMEM; 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; mos7720_port->port = port;
usb_set_serial_port_data(port, mos7720_port); usb_set_serial_port_data(port, mos7720_port);
@@ -2053,7 +2040,6 @@ static struct usb_serial_driver moschip7720_2port_driver = {
.close = mos7720_close, .close = mos7720_close,
.throttle = mos7720_throttle, .throttle = mos7720_throttle,
.unthrottle = mos7720_unthrottle, .unthrottle = mos7720_unthrottle,
.probe = mos77xx_probe,
.attach = mos7720_startup, .attach = mos7720_startup,
.release = mos7720_release, .release = mos7720_release,
.port_probe = mos7720_port_probe, .port_probe = mos7720_port_probe,
@@ -2067,7 +2053,7 @@ static struct usb_serial_driver moschip7720_2port_driver = {
.chars_in_buffer = mos7720_chars_in_buffer, .chars_in_buffer = mos7720_chars_in_buffer,
.break_ctl = mos7720_break, .break_ctl = mos7720_break,
.read_bulk_callback = mos7720_bulk_in_callback, .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[] = { static struct usb_serial_driver * const serial_drivers[] = {

View File

@@ -214,7 +214,6 @@ MODULE_DEVICE_TABLE(usb, id_table);
struct moschip_port { struct moschip_port {
int port_num; /*Actual port number in the device(1,2,etc) */ 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 */ struct urb *read_urb; /* read URB for this port */
__u8 shadowLCR; /* last LCR value received */ __u8 shadowLCR; /* last LCR value received */
__u8 shadowMCR; /* last MCR 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,
serial->port[0]->interrupt_in_urb->interval); serial->port[0]->interrupt_in_urb->interval);
/* start interrupt read for mos7840 * /* start interrupt read for mos7840 */
* will continue as long as mos7840 is connected */
response = response =
usb_submit_urb(serial->port[0]->interrupt_in_urb, usb_submit_urb(serial->port[0]->interrupt_in_urb,
GFP_KERNEL); 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); usb_kill_urb(mos7840_port->read_urb);
mos7840_port->read_urb_busy = false; 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; Data = 0x0;
mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data); 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; 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) static int mos7840_port_probe(struct usb_serial_port *port)
{ {
struct usb_serial *serial = port->serial; struct usb_serial *serial = port->serial;
@@ -2388,6 +2389,7 @@ static struct usb_serial_driver moschip7840_4port_device = {
.tiocmset = mos7840_tiocmset, .tiocmset = mos7840_tiocmset,
.tiocmiwait = usb_serial_generic_tiocmiwait, .tiocmiwait = usb_serial_generic_tiocmiwait,
.get_icount = usb_serial_generic_get_icount, .get_icount = usb_serial_generic_get_icount,
.attach = mos7840_attach,
.port_probe = mos7840_port_probe, .port_probe = mos7840_port_probe,
.port_remove = mos7840_port_remove, .port_remove = mos7840_port_remove,
.read_bulk_callback = mos7840_bulk_in_callback, .read_bulk_callback = mos7840_bulk_in_callback,

View File

@@ -38,6 +38,7 @@ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count); const unsigned char *buf, int count);
static int omninet_write_room(struct tty_struct *tty); static int omninet_write_room(struct tty_struct *tty);
static void omninet_disconnect(struct usb_serial *serial); 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_probe(struct usb_serial_port *port);
static int omninet_port_remove(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", .description = "ZyXEL - omni.net lcd plus usb",
.id_table = id_table, .id_table = id_table,
.num_ports = 1, .num_ports = 1,
.attach = omninet_attach,
.port_probe = omninet_port_probe, .port_probe = omninet_port_probe,
.port_remove = omninet_port_remove, .port_remove = omninet_port_remove,
.open = omninet_open, .open = omninet_open,
@@ -104,6 +106,17 @@ struct omninet_data {
__u8 od_outseq; /* Sequence number for bulk_out URBs */ __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) static int omninet_port_probe(struct usb_serial_port *port)
{ {
struct omninet_data *od; struct omninet_data *od;

View File

@@ -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_tiocmget(struct tty_struct *tty);
static int oti6858_tiocmset(struct tty_struct *tty, static int oti6858_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear); 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_probe(struct usb_serial_port *port);
static int oti6858_port_remove(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_bulk_callback = oti6858_write_bulk_callback,
.write_room = oti6858_write_room, .write_room = oti6858_write_room,
.chars_in_buffer = oti6858_chars_in_buffer, .chars_in_buffer = oti6858_chars_in_buffer,
.attach = oti6858_attach,
.port_probe = oti6858_port_probe, .port_probe = oti6858_port_probe,
.port_remove = oti6858_port_remove, .port_remove = oti6858_port_remove,
}; };
@@ -324,6 +326,20 @@ static void send_data(struct work_struct *work)
usb_serial_port_softint(port); 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) static int oti6858_port_probe(struct usb_serial_port *port)
{ {
struct oti6858_private *priv; struct oti6858_private *priv;

View File

@@ -220,9 +220,17 @@ static int pl2303_probe(struct usb_serial *serial,
static int pl2303_startup(struct usb_serial *serial) static int pl2303_startup(struct usb_serial *serial)
{ {
struct pl2303_serial_private *spriv; struct pl2303_serial_private *spriv;
unsigned char num_ports = serial->num_ports;
enum pl2303_type type = TYPE_01; enum pl2303_type type = TYPE_01;
unsigned char *buf; 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); spriv = kzalloc(sizeof(*spriv), GFP_KERNEL);
if (!spriv) if (!spriv)
return -ENOMEM; return -ENOMEM;

View File

@@ -408,16 +408,12 @@ static void qt2_close(struct usb_serial_port *port)
{ {
struct usb_serial *serial; struct usb_serial *serial;
struct qt2_port_private *port_priv; struct qt2_port_private *port_priv;
unsigned long flags;
int i; int i;
serial = port->serial; serial = port->serial;
port_priv = usb_get_serial_port_data(port); port_priv = usb_get_serial_port_data(port);
spin_lock_irqsave(&port_priv->urb_lock, flags);
usb_kill_urb(port_priv->write_urb); 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 */ /* flush the port transmit buffer */
i = usb_control_msg(serial->dev, i = usb_control_msg(serial->dev,

View File

@@ -154,6 +154,19 @@ static int spcp8x5_probe(struct usb_serial *serial,
return 0; 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) static int spcp8x5_port_probe(struct usb_serial_port *port)
{ {
const struct usb_device_id *id = usb_get_serial_data(port->serial); 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, .tiocmget = spcp8x5_tiocmget,
.tiocmset = spcp8x5_tiocmset, .tiocmset = spcp8x5_tiocmset,
.probe = spcp8x5_probe, .probe = spcp8x5_probe,
.attach = spcp8x5_attach,
.port_probe = spcp8x5_port_probe, .port_probe = spcp8x5_port_probe,
.port_remove = spcp8x5_port_remove, .port_remove = spcp8x5_port_remove,
}; };

View File

@@ -579,6 +579,13 @@ static int ti_startup(struct usb_serial *serial)
goto free_tdev; 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; return 0;
free_tdev: free_tdev:

View File

@@ -2109,6 +2109,13 @@ UNUSUAL_DEV( 0x152d, 0x2566, 0x0114, 0x0114,
USB_SC_DEVICE, USB_PR_DEVICE, NULL, USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_BROKEN_FUA ), 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) * Entrega Technologies U1-SC25 (later Xircom PortGear PGSCSI)
* and Mac USB Dock USB-SCSI */ * and Mac USB Dock USB-SCSI */

View File

@@ -93,6 +93,7 @@ struct usb_ext_prop_desc {
* | 0 | magic | LE32 | FUNCTIONFS_DESCRIPTORS_MAGIC_V2 | * | 0 | magic | LE32 | FUNCTIONFS_DESCRIPTORS_MAGIC_V2 |
* | 4 | length | LE32 | length of the whole data chunk | * | 4 | length | LE32 | length of the whole data chunk |
* | 8 | flags | LE32 | combination of functionfs_flags | * | 8 | flags | LE32 | combination of functionfs_flags |
* | | eventfd | LE32 | eventfd file descriptor |
* | | fs_count | LE32 | number of full-speed descriptors | * | | fs_count | LE32 | number of full-speed descriptors |
* | | hs_count | LE32 | number of high-speed descriptors | * | | hs_count | LE32 | number of high-speed descriptors |
* | | ss_count | LE32 | number of super-speed descriptors | * | | ss_count | LE32 | number of super-speed descriptors |