Commit bcba282a authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'usb-4.3-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

Pull USB fixes from Greg KH:
 "Here are some USB driver fixes for 4.3-rc3.

  There's the usual assortment of new device ids, combined with xhci and
  gadget driver fixes.  Full details in the shortlog.  All of these have
  been in linux-next with no reported problems"

* tag 'usb-4.3-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (34 commits)
  MAINTAINERS: remove amd5536udc USB gadget driver maintainer
  USB: whiteheat: fix potential null-deref at probe
  xhci: init command timeout timer earlier to avoid deleting it uninitialized
  xhci: change xhci 1.0 only restrictions to support xhci 1.1
  usb: xhci: exit early in xhci_setup_device() if we're halted or dying
  usb: xhci: stop everything on the first call to xhci_stop
  usb: xhci: Clear XHCI_STATE_DYING on start
  usb: xhci: lock mutex on xhci_stop
  xhci: Move xhci_pme_quirk() behind #ifdef CONFIG_PM
  xhci: give command abortion one more chance before killing xhci
  usb: Use the USB_SS_MULT() macro to get the burst multiplier.
  usb: dwc3: gadget: Fix BUG in RT config
  usb: musb: fix cppi channel teardown for isoch transfer
  usb: phy: isp1301: Export I2C module alias information
  usb: gadget: drop null test before destroy functions
  usb: gadget: dummy_hcd: in transfer(), return data sent, not limit
  usb: gadget: dummy_hcd: fix rescan logic for transfer
  usb: gadget: dummy_hcd: fix unneeded else-if condition
  usb: gadget: dummy_hcd: emulate sending zlp in packet logic
  usb: musb: dsps: fix polling in device-only mode
  ...
parents fb740f9b b4731977
...@@ -6,6 +6,7 @@ Required properties: ...@@ -6,6 +6,7 @@ Required properties:
"lsi,zevio-usb" "lsi,zevio-usb"
"qcom,ci-hdrc" "qcom,ci-hdrc"
"chipidea,usb2" "chipidea,usb2"
"xlnx,zynq-usb-2.20a"
- reg: base address and length of the registers - reg: base address and length of the registers
- interrupts: interrupt for the USB controller - interrupts: interrupt for the USB controller
......
...@@ -615,9 +615,8 @@ F: Documentation/hwmon/fam15h_power ...@@ -615,9 +615,8 @@ F: Documentation/hwmon/fam15h_power
F: drivers/hwmon/fam15h_power.c F: drivers/hwmon/fam15h_power.c
AMD GEODE CS5536 USB DEVICE CONTROLLER DRIVER AMD GEODE CS5536 USB DEVICE CONTROLLER DRIVER
M: Thomas Dahlmann <dahlmann.thomas@arcor.de>
L: linux-geode@lists.infradead.org (moderated for non-subscribers) L: linux-geode@lists.infradead.org (moderated for non-subscribers)
S: Supported S: Orphan
F: drivers/usb/gadget/udc/amd5536udc.* F: drivers/usb/gadget/udc/amd5536udc.*
AMD GEODE PROCESSOR/CHIPSET SUPPORT AMD GEODE PROCESSOR/CHIPSET SUPPORT
......
...@@ -61,7 +61,7 @@ static const struct of_device_id ci_hdrc_imx_dt_ids[] = { ...@@ -61,7 +61,7 @@ static const struct of_device_id ci_hdrc_imx_dt_ids[] = {
{ .compatible = "fsl,imx27-usb", .data = &imx27_usb_data}, { .compatible = "fsl,imx27-usb", .data = &imx27_usb_data},
{ .compatible = "fsl,imx6q-usb", .data = &imx6q_usb_data}, { .compatible = "fsl,imx6q-usb", .data = &imx6q_usb_data},
{ .compatible = "fsl,imx6sl-usb", .data = &imx6sl_usb_data}, { .compatible = "fsl,imx6sl-usb", .data = &imx6sl_usb_data},
{ .compatible = "fsl,imx6sx-usb", .data = &imx6sl_usb_data}, { .compatible = "fsl,imx6sx-usb", .data = &imx6sx_usb_data},
{ /* sentinel */ } { /* sentinel */ }
}; };
MODULE_DEVICE_TABLE(of, ci_hdrc_imx_dt_ids); MODULE_DEVICE_TABLE(of, ci_hdrc_imx_dt_ids);
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/usb/chipidea.h> #include <linux/usb/chipidea.h>
...@@ -30,18 +31,36 @@ static const struct ci_hdrc_platform_data ci_default_pdata = { ...@@ -30,18 +31,36 @@ static const struct ci_hdrc_platform_data ci_default_pdata = {
.flags = CI_HDRC_DISABLE_STREAMING, .flags = CI_HDRC_DISABLE_STREAMING,
}; };
static struct ci_hdrc_platform_data ci_zynq_pdata = {
.capoffset = DEF_CAPOFFSET,
};
static const struct of_device_id ci_hdrc_usb2_of_match[] = {
{ .compatible = "chipidea,usb2"},
{ .compatible = "xlnx,zynq-usb-2.20a", .data = &ci_zynq_pdata},
{ }
};
MODULE_DEVICE_TABLE(of, ci_hdrc_usb2_of_match);
static int ci_hdrc_usb2_probe(struct platform_device *pdev) static int ci_hdrc_usb2_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct ci_hdrc_usb2_priv *priv; struct ci_hdrc_usb2_priv *priv;
struct ci_hdrc_platform_data *ci_pdata = dev_get_platdata(dev); struct ci_hdrc_platform_data *ci_pdata = dev_get_platdata(dev);
int ret; int ret;
const struct of_device_id *match;
if (!ci_pdata) { if (!ci_pdata) {
ci_pdata = devm_kmalloc(dev, sizeof(*ci_pdata), GFP_KERNEL); ci_pdata = devm_kmalloc(dev, sizeof(*ci_pdata), GFP_KERNEL);
*ci_pdata = ci_default_pdata; /* struct copy */ *ci_pdata = ci_default_pdata; /* struct copy */
} }
match = of_match_device(ci_hdrc_usb2_of_match, &pdev->dev);
if (match && match->data) {
/* struct copy */
*ci_pdata = *(struct ci_hdrc_platform_data *)match->data;
}
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv) if (!priv)
return -ENOMEM; return -ENOMEM;
...@@ -96,12 +115,6 @@ static int ci_hdrc_usb2_remove(struct platform_device *pdev) ...@@ -96,12 +115,6 @@ static int ci_hdrc_usb2_remove(struct platform_device *pdev)
return 0; return 0;
} }
static const struct of_device_id ci_hdrc_usb2_of_match[] = {
{ .compatible = "chipidea,usb2" },
{ }
};
MODULE_DEVICE_TABLE(of, ci_hdrc_usb2_of_match);
static struct platform_driver ci_hdrc_usb2_driver = { static struct platform_driver ci_hdrc_usb2_driver = {
.probe = ci_hdrc_usb2_probe, .probe = ci_hdrc_usb2_probe,
.remove = ci_hdrc_usb2_remove, .remove = ci_hdrc_usb2_remove,
......
...@@ -656,6 +656,44 @@ __acquires(hwep->lock) ...@@ -656,6 +656,44 @@ __acquires(hwep->lock)
return 0; return 0;
} }
static int _ep_set_halt(struct usb_ep *ep, int value, bool check_transfer)
{
struct ci_hw_ep *hwep = container_of(ep, struct ci_hw_ep, ep);
int direction, retval = 0;
unsigned long flags;
if (ep == NULL || hwep->ep.desc == NULL)
return -EINVAL;
if (usb_endpoint_xfer_isoc(hwep->ep.desc))
return -EOPNOTSUPP;
spin_lock_irqsave(hwep->lock, flags);
if (value && hwep->dir == TX && check_transfer &&
!list_empty(&hwep->qh.queue) &&
!usb_endpoint_xfer_control(hwep->ep.desc)) {
spin_unlock_irqrestore(hwep->lock, flags);
return -EAGAIN;
}
direction = hwep->dir;
do {
retval |= hw_ep_set_halt(hwep->ci, hwep->num, hwep->dir, value);
if (!value)
hwep->wedge = 0;
if (hwep->type == USB_ENDPOINT_XFER_CONTROL)
hwep->dir = (hwep->dir == TX) ? RX : TX;
} while (hwep->dir != direction);
spin_unlock_irqrestore(hwep->lock, flags);
return retval;
}
/** /**
* _gadget_stop_activity: stops all USB activity, flushes & disables all endpts * _gadget_stop_activity: stops all USB activity, flushes & disables all endpts
* @gadget: gadget * @gadget: gadget
...@@ -1051,7 +1089,7 @@ __acquires(ci->lock) ...@@ -1051,7 +1089,7 @@ __acquires(ci->lock)
num += ci->hw_ep_max / 2; num += ci->hw_ep_max / 2;
spin_unlock(&ci->lock); spin_unlock(&ci->lock);
err = usb_ep_set_halt(&ci->ci_hw_ep[num].ep); err = _ep_set_halt(&ci->ci_hw_ep[num].ep, 1, false);
spin_lock(&ci->lock); spin_lock(&ci->lock);
if (!err) if (!err)
isr_setup_status_phase(ci); isr_setup_status_phase(ci);
...@@ -1117,8 +1155,8 @@ __acquires(ci->lock) ...@@ -1117,8 +1155,8 @@ __acquires(ci->lock)
if (err < 0) { if (err < 0) {
spin_unlock(&ci->lock); spin_unlock(&ci->lock);
if (usb_ep_set_halt(&hwep->ep)) if (_ep_set_halt(&hwep->ep, 1, false))
dev_err(ci->dev, "error: ep_set_halt\n"); dev_err(ci->dev, "error: _ep_set_halt\n");
spin_lock(&ci->lock); spin_lock(&ci->lock);
} }
} }
...@@ -1149,9 +1187,9 @@ __acquires(ci->lock) ...@@ -1149,9 +1187,9 @@ __acquires(ci->lock)
err = isr_setup_status_phase(ci); err = isr_setup_status_phase(ci);
if (err < 0) { if (err < 0) {
spin_unlock(&ci->lock); spin_unlock(&ci->lock);
if (usb_ep_set_halt(&hwep->ep)) if (_ep_set_halt(&hwep->ep, 1, false))
dev_err(ci->dev, dev_err(ci->dev,
"error: ep_set_halt\n"); "error: _ep_set_halt\n");
spin_lock(&ci->lock); spin_lock(&ci->lock);
} }
} }
...@@ -1397,41 +1435,7 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *req) ...@@ -1397,41 +1435,7 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)
*/ */
static int ep_set_halt(struct usb_ep *ep, int value) static int ep_set_halt(struct usb_ep *ep, int value)
{ {
struct ci_hw_ep *hwep = container_of(ep, struct ci_hw_ep, ep); return _ep_set_halt(ep, value, true);
int direction, retval = 0;
unsigned long flags;
if (ep == NULL || hwep->ep.desc == NULL)
return -EINVAL;
if (usb_endpoint_xfer_isoc(hwep->ep.desc))
return -EOPNOTSUPP;
spin_lock_irqsave(hwep->lock, flags);
#ifndef STALL_IN
/* g_file_storage MS compliant but g_zero fails chapter 9 compliance */
if (value && hwep->type == USB_ENDPOINT_XFER_BULK && hwep->dir == TX &&
!list_empty(&hwep->qh.queue)) {
spin_unlock_irqrestore(hwep->lock, flags);
return -EAGAIN;
}
#endif
direction = hwep->dir;
do {
retval |= hw_ep_set_halt(hwep->ci, hwep->num, hwep->dir, value);
if (!value)
hwep->wedge = 0;
if (hwep->type == USB_ENDPOINT_XFER_CONTROL)
hwep->dir = (hwep->dir == TX) ? RX : TX;
} while (hwep->dir != direction);
spin_unlock_irqrestore(hwep->lock, flags);
return retval;
} }
/** /**
......
...@@ -112,7 +112,7 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno, ...@@ -112,7 +112,7 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
cfgno, inum, asnum, ep->desc.bEndpointAddress); cfgno, inum, asnum, ep->desc.bEndpointAddress);
ep->ss_ep_comp.bmAttributes = 16; ep->ss_ep_comp.bmAttributes = 16;
} else if (usb_endpoint_xfer_isoc(&ep->desc) && } else if (usb_endpoint_xfer_isoc(&ep->desc) &&
desc->bmAttributes > 2) { USB_SS_MULT(desc->bmAttributes) > 3) {
dev_warn(ddev, "Isoc endpoint has Mult of %d in " dev_warn(ddev, "Isoc endpoint has Mult of %d in "
"config %d interface %d altsetting %d ep %d: " "config %d interface %d altsetting %d ep %d: "
"setting to 3\n", desc->bmAttributes + 1, "setting to 3\n", desc->bmAttributes + 1,
...@@ -121,7 +121,8 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno, ...@@ -121,7 +121,8 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
} }
if (usb_endpoint_xfer_isoc(&ep->desc)) if (usb_endpoint_xfer_isoc(&ep->desc))
max_tx = (desc->bMaxBurst + 1) * (desc->bmAttributes + 1) * max_tx = (desc->bMaxBurst + 1) *
(USB_SS_MULT(desc->bmAttributes)) *
usb_endpoint_maxp(&ep->desc); usb_endpoint_maxp(&ep->desc);
else if (usb_endpoint_xfer_int(&ep->desc)) else if (usb_endpoint_xfer_int(&ep->desc))
max_tx = usb_endpoint_maxp(&ep->desc) * max_tx = usb_endpoint_maxp(&ep->desc) *
......
...@@ -514,8 +514,6 @@ static int dwc3_omap_probe(struct platform_device *pdev) ...@@ -514,8 +514,6 @@ static int dwc3_omap_probe(struct platform_device *pdev)
goto err1; goto err1;
} }
dwc3_omap_enable_irqs(omap);
ret = dwc3_omap_extcon_register(omap); ret = dwc3_omap_extcon_register(omap);
if (ret < 0) if (ret < 0)
goto err2; goto err2;
...@@ -526,6 +524,8 @@ static int dwc3_omap_probe(struct platform_device *pdev) ...@@ -526,6 +524,8 @@ static int dwc3_omap_probe(struct platform_device *pdev)
goto err3; goto err3;
} }
dwc3_omap_enable_irqs(omap);
return 0; return 0;
err3: err3:
......
...@@ -2665,8 +2665,6 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc) ...@@ -2665,8 +2665,6 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
int i; int i;
irqreturn_t ret = IRQ_NONE; irqreturn_t ret = IRQ_NONE;
spin_lock(&dwc->lock);
for (i = 0; i < dwc->num_event_buffers; i++) { for (i = 0; i < dwc->num_event_buffers; i++) {
irqreturn_t status; irqreturn_t status;
...@@ -2675,8 +2673,6 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc) ...@@ -2675,8 +2673,6 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
ret = status; ret = status;
} }
spin_unlock(&dwc->lock);
return ret; return ret;
} }
......
...@@ -186,6 +186,7 @@ void usb_ep_autoconfig_reset (struct usb_gadget *gadget) ...@@ -186,6 +186,7 @@ void usb_ep_autoconfig_reset (struct usb_gadget *gadget)
list_for_each_entry (ep, &gadget->ep_list, ep_list) { list_for_each_entry (ep, &gadget->ep_list, ep_list) {
ep->claimed = false; ep->claimed = false;
ep->driver_data = NULL;
} }
gadget->in_epnum = 0; gadget->in_epnum = 0;
gadget->out_epnum = 0; gadget->out_epnum = 0;
......
...@@ -3138,8 +3138,8 @@ static void udc_pci_remove(struct pci_dev *pdev) ...@@ -3138,8 +3138,8 @@ static void udc_pci_remove(struct pci_dev *pdev)
writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg); writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
if (dev->irq_registered) if (dev->irq_registered)
free_irq(pdev->irq, dev); free_irq(pdev->irq, dev);
if (dev->regs) if (dev->virt_addr)
iounmap(dev->regs); iounmap(dev->virt_addr);
if (dev->mem_region) if (dev->mem_region)
release_mem_region(pci_resource_start(pdev, 0), release_mem_region(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0)); pci_resource_len(pdev, 0));
...@@ -3226,17 +3226,13 @@ static int udc_pci_probe( ...@@ -3226,17 +3226,13 @@ static int udc_pci_probe(
/* init */ /* init */
dev = kzalloc(sizeof(struct udc), GFP_KERNEL); dev = kzalloc(sizeof(struct udc), GFP_KERNEL);
if (!dev) { if (!dev)
retval = -ENOMEM; return -ENOMEM;
goto finished;
}
/* pci setup */ /* pci setup */
if (pci_enable_device(pdev) < 0) { if (pci_enable_device(pdev) < 0) {
kfree(dev);
dev = NULL;
retval = -ENODEV; retval = -ENODEV;
goto finished; goto err_pcidev;
} }
dev->active = 1; dev->active = 1;
...@@ -3246,28 +3242,22 @@ static int udc_pci_probe( ...@@ -3246,28 +3242,22 @@ static int udc_pci_probe(
if (!request_mem_region(resource, len, name)) { if (!request_mem_region(resource, len, name)) {
dev_dbg(&pdev->dev, "pci device used already\n"); dev_dbg(&pdev->dev, "pci device used already\n");
kfree(dev);
dev = NULL;
retval = -EBUSY; retval = -EBUSY;
goto finished; goto err_memreg;
} }
dev->mem_region = 1; dev->mem_region = 1;
dev->virt_addr = ioremap_nocache(resource, len); dev->virt_addr = ioremap_nocache(resource, len);
if (dev->virt_addr == NULL) { if (dev->virt_addr == NULL) {
dev_dbg(&pdev->dev, "start address cannot be mapped\n"); dev_dbg(&pdev->dev, "start address cannot be mapped\n");
kfree(dev);
dev = NULL;
retval = -EFAULT; retval = -EFAULT;
goto finished; goto err_ioremap;
} }
if (!pdev->irq) { if (!pdev->irq) {
dev_err(&pdev->dev, "irq not set\n"); dev_err(&pdev->dev, "irq not set\n");
kfree(dev);
dev = NULL;
retval = -ENODEV; retval = -ENODEV;
goto finished; goto err_irq;
} }
spin_lock_init(&dev->lock); spin_lock_init(&dev->lock);
...@@ -3283,10 +3273,8 @@ static int udc_pci_probe( ...@@ -3283,10 +3273,8 @@ static int udc_pci_probe(
if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) { if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) {
dev_dbg(&pdev->dev, "request_irq(%d) fail\n", pdev->irq); dev_dbg(&pdev->dev, "request_irq(%d) fail\n", pdev->irq);
kfree(dev);
dev = NULL;
retval = -EBUSY; retval = -EBUSY;
goto finished; goto err_irq;
} }
dev->irq_registered = 1; dev->irq_registered = 1;
...@@ -3314,8 +3302,17 @@ static int udc_pci_probe( ...@@ -3314,8 +3302,17 @@ static int udc_pci_probe(
return 0; return 0;
finished: finished:
if (dev) udc_pci_remove(pdev);
udc_pci_remove(pdev); return retval;
err_irq:
iounmap(dev->virt_addr);
err_ioremap:
release_mem_region(resource, len);
err_memreg:
pci_disable_device(pdev);
err_pcidev:
kfree(dev);
return retval; return retval;
} }
......
...@@ -2002,6 +2002,17 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, ...@@ -2002,6 +2002,17 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
ep->udc = udc; ep->udc = udc;
INIT_LIST_HEAD(&ep->queue); INIT_LIST_HEAD(&ep->queue);
if (ep->index == 0) {
ep->ep.caps.type_control = true;
} else {
ep->ep.caps.type_iso = ep->can_isoc;
ep->ep.caps.type_bulk = true;
ep->ep.caps.type_int = true;
}
ep->ep.caps.dir_in = true;
ep->ep.caps.dir_out = true;
if (i) if (i)
list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
......
...@@ -324,8 +324,7 @@ static void bdc_mem_free(struct bdc *bdc) ...@@ -324,8 +324,7 @@ static void bdc_mem_free(struct bdc *bdc)
bdc->scratchpad.buff, bdc->scratchpad.sp_dma); bdc->scratchpad.buff, bdc->scratchpad.sp_dma);
/* Destroy the dma pools */ /* Destroy the dma pools */
if (bdc->bd_table_pool) dma_pool_destroy(bdc->bd_table_pool);
dma_pool_destroy(bdc->bd_table_pool);
/* Free the bdc_ep array */ /* Free the bdc_ep array */
kfree(bdc->bdc_ep_array); kfree(bdc->bdc_ep_array);
......
...@@ -1348,6 +1348,7 @@ static int transfer(struct dummy_hcd *dum_hcd, struct urb *urb, ...@@ -1348,6 +1348,7 @@ static int transfer(struct dummy_hcd *dum_hcd, struct urb *urb,
{ {
struct dummy *dum = dum_hcd->dum; struct dummy *dum = dum_hcd->dum;
struct dummy_request *req; struct dummy_request *req;
int sent = 0;
top: top:
/* if there's no request queued, the device is NAKing; return */ /* if there's no request queued, the device is NAKing; return */
...@@ -1385,12 +1386,15 @@ static int transfer(struct dummy_hcd *dum_hcd, struct urb *urb, ...@@ -1385,12 +1386,15 @@ static int transfer(struct dummy_hcd *dum_hcd, struct urb *urb,
if (len == 0) if (len == 0)
break; break;
/* use an extra pass for the final short packet */ /* send multiple of maxpacket first, then remainder */
if (len > ep->ep.maxpacket) { if (len >= ep->ep.maxpacket) {
rescan = 1; is_short = 0;
len -= (len % ep->ep.maxpacket); if (len % ep->ep.maxpacket)
rescan = 1;
len -= len % ep->ep.maxpacket;
} else {
is_short = 1;
} }
is_short = (len % ep->ep.maxpacket) != 0;
len = dummy_perform_transfer(urb, req, len); len = dummy_perform_transfer(urb, req, len);
...@@ -1399,6 +1403,7 @@ static int transfer(struct dummy_hcd *dum_hcd, struct urb *urb, ...@@ -1399,6 +1403,7 @@ static int transfer(struct dummy_hcd *dum_hcd, struct urb *urb,
req->req.status = len; req->req.status = len;
} else { } else {
limit -= len; limit -= len;
sent += len;
urb->actual_length += len; urb->actual_length += len;
req->req.actual += len; req->req.actual += len;
} }
...@@ -1421,7 +1426,7 @@ static int transfer(struct dummy_hcd *dum_hcd, struct urb *urb, ...@@ -1421,7 +1426,7 @@ static int transfer(struct dummy_hcd *dum_hcd, struct urb *urb,
*status = -EOVERFLOW; *status = -EOVERFLOW;
else else
*status = 0; *status = 0;
} else if (!to_host) { } else {
*status = 0; *status = 0;
if (host_len > dev_len) if (host_len > dev_len)
req->req.status = -EOVERFLOW; req->req.status = -EOVERFLOW;
...@@ -1429,15 +1434,24 @@ static int transfer(struct dummy_hcd *dum_hcd, struct urb *urb, ...@@ -1429,15 +1434,24 @@ static int transfer(struct dummy_hcd *dum_hcd, struct urb *urb,
req->req.status = 0; req->req.status = 0;
} }
/* many requests terminate without a short packet */ /*
* many requests terminate without a short packet.
* send a zlp if demanded by flags.
*/
} else { } else {
if (req->req.length == req->req.actual if (req->req.length == req->req.actual) {
&& !req->req.zero) if (req->req.zero && to_host)
req->req.status = 0; rescan = 1;
if (urb->transfer_buffer_length == urb->actual_length else
&& !(urb->transfer_flags req->req.status = 0;
& URB_ZERO_PACKET)) }
*status = 0; if (urb->transfer_buffer_length == urb->actual_length) {
if (urb->transfer_flags & URB_ZERO_PACKET &&
!to_host)
rescan = 1;
else
*status = 0;
}
} }
/* device side completion --> continuable */ /* device side completion --> continuable */
...@@ -1460,7 +1474,7 @@ static int transfer(struct dummy_hcd *dum_hcd, struct urb *urb, ...@@ -1460,7 +1474,7 @@ static int transfer(struct dummy_hcd *dum_hcd, struct urb *urb,
if (rescan) if (rescan)
goto top; goto top;
} }
return limit; return sent;
} }
static int periodic_bytes(struct dummy *dum, struct dummy_ep *ep) static int periodic_bytes(struct dummy *dum, struct dummy_ep *ep)
...@@ -1890,7 +1904,7 @@ static void dummy_timer(unsigned long _dum_hcd) ...@@ -1890,7 +1904,7 @@ static void dummy_timer(unsigned long _dum_hcd)
default: default:
treat_control_like_bulk: treat_control_like_bulk:
ep->last_io = jiffies; ep->last_io = jiffies;
total = transfer(dum_hcd, urb, ep, limit, &status); total -= transfer(dum_hcd, urb, ep, limit, &status);
break; break;
} }
......
...@@ -2117,8 +2117,7 @@ static int gr_remove(struct platform_device *pdev) ...@@ -2117,8 +2117,7 @@ static int gr_remove(struct platform_device *pdev)
return -EBUSY; return -EBUSY;
gr_dfs_delete(dev); gr_dfs_delete(dev);
if (dev->desc_pool) dma_pool_destroy(dev->desc_pool);
dma_pool_destroy(dev->desc_pool);
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
gr_free_request(&dev->epi[0].ep, &dev->ep0reqi->req); gr_free_request(&dev->epi[0].ep, &dev->ep0reqi->req);
......
...@@ -1767,8 +1767,7 @@ static int mv_u3d_remove(struct platform_device *dev) ...@@ -1767,8 +1767,7 @@ static int mv_u3d_remove(struct platform_device *dev)
usb_del_gadget_udc(&u3d->gadget); usb_del_gadget_udc(&u3d->gadget);
/* free memory allocated in probe */ /* free memory allocated in probe */
if (u3d->trb_pool) dma_pool_destroy(u3d->trb_pool);
dma_pool_destroy(u3d->trb_pool);
if (u3d->ep_context) if (u3d->ep_context)
dma_free_coherent(&dev->dev, u3d->ep_context_size, dma_free_coherent(&dev->dev, u3d->ep_context_size,
......
...@@ -2100,8 +2100,7 @@ static int mv_udc_remove(struct platform_device *pdev) ...@@ -2100,8 +2100,7 @@ static int mv_udc_remove(struct platform_device *pdev)
} }
/* free memory allocated in probe */ /* free memory allocated in probe */
if (udc->dtd_pool) dma_pool_destroy(udc->dtd_pool);
dma_pool_destroy(udc->dtd_pool);
if (udc->ep_dqh) if (udc->ep_dqh)
dma_free_coherent(&pdev->dev, udc->ep_dqh_size, dma_free_coherent(&pdev->dev, udc->ep_dqh_size,
......
...@@ -1498,10 +1498,10 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, ...@@ -1498,10 +1498,10 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
* use Event Data TRBs, and we don't chain in a link TRB on short * use Event Data TRBs, and we don't chain in a link TRB on short
* transfers, we're basically dividing by 1. * transfers, we're basically dividing by 1.
* *
* xHCI 1.0 specification indicates that the Average TRB Length should * xHCI 1.0 and 1.1 specification indicates that the Average TRB Length
* be set to 8 for control endpoints. * should be set to 8 for control endpoints.
*/ */
if (usb_endpoint_xfer_control(&ep->desc) && xhci->hci_version == 0x100) if (usb_endpoint_xfer_control(&ep->desc) && xhci->hci_version >= 0x100)
ep_ctx->tx_info |= cpu_to_le32(AVG_TRB_LENGTH_FOR_EP(8)); ep_ctx->tx_info |= cpu_to_le32(AVG_TRB_LENGTH_FOR_EP(8));
else else
ep_ctx->tx_info |= ep_ctx->tx_info |=
...@@ -1792,8 +1792,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) ...@@ -1792,8 +1792,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
int size; int size;
int i, j, num_ports; int i, j, num_ports;
if (timer_pending(&xhci->cmd_timer)) del_timer_sync(&xhci->cmd_timer);
del_timer_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);
...@@ -2321,6 +2320,10 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) ...@@ -2321,6 +2320,10 @@ 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 */
setup_timer(&xhci->cmd_timer, xhci_handle_command_timeout,
(unsigned long)xhci);
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,
"Supported page size register = 0x%x", page_size); "Supported page size register = 0x%x", page_size);
...@@ -2505,10 +2508,6 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) ...@@ -2505,10 +2508,6 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
"Wrote ERST address to ir_set 0."); "Wrote ERST address to ir_set 0.");
xhci_print_ir_set(xhci, 0); xhci_print_ir_set(xhci, 0);
/* init command timeout timer */
setup_timer(&xhci->cmd_timer, xhci_handle_command_timeout,
(unsigned long)xhci);
/* /*
* XXX: Might need to set the Interrupter Moderation Register to * XXX: Might need to set the Interrupter Moderation Register to
* something other than the default (~1ms minimum between interrupts). * something other than the default (~1ms minimum between interrupts).
......
...@@ -180,51 +180,6 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) ...@@ -180,51 +180,6 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
"QUIRK: Resetting on resume"); "QUIRK: Resetting on resume");
} }
/*
* In some Intel xHCI controllers, in order to get D3 working,
* through a vendor specific SSIC CONFIG register at offset 0x883c,
* SSIC PORT need to be marked as "unused" before putting xHCI
* into D3. After D3 exit, the SSIC port need to be marked as "used".
* Without this change, xHCI might not enter D3 state.
* Make sure PME works on some Intel xHCI controllers by writing 1 to clear
* the Internal PME flag bit in vendor specific PMCTRL register at offset 0x80a4
*/
static void xhci_pme_quirk(struct usb_hcd *hcd, bool suspend)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
u32 val;
void __iomem *reg;
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) {
reg = (void __iomem *) xhci->cap_regs + PORT2_SSIC_CONFIG_REG2;
/* Notify SSIC that SSIC profile programming is not done */
val = readl(reg) & ~PROG_DONE;
writel(val, reg);
/* Mark SSIC port as unused(suspend) or used(resume) */
val = readl(reg);
if (suspend)
val |= SSIC_PORT_UNUSED;
else
val &= ~SSIC_PORT_UNUSED;
writel(val, reg);
/* Notify SSIC that SSIC profile programming is done */
val = readl(reg) | PROG_DONE;
writel(val, reg);
readl(reg);
}
reg = (void __iomem *) xhci->cap_regs + 0x80a4;
val = readl(reg);
writel(val | BIT(28), reg);
readl(reg);
}
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev) static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev)
{ {
...@@ -345,6 +300,51 @@ static void xhci_pci_remove(struct pci_dev *dev) ...@@ -345,6 +300,51 @@ static void xhci_pci_remove(struct pci_dev *dev)
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
/*
* In some Intel xHCI controllers, in order to get D3 working,
* through a vendor specific SSIC CONFIG register at offset 0x883c,
* SSIC PORT need to be marked as "unused" before putting xHCI
* into D3. After D3 exit, the SSIC port need to be marked as "used".
* Without this change, xHCI might not enter D3 state.
* Make sure PME works on some Intel xHCI controllers by writing 1 to clear
* the Internal PME flag bit in vendor specific PMCTRL register at offset 0x80a4
*/
static void xhci_pme_quirk(struct usb_hcd *hcd, bool suspend)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
u32 val;
void __iomem *reg;
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) {
reg = (void __iomem *) xhci->cap_regs + PORT2_SSIC_CONFIG_REG2;
/* Notify SSIC that SSIC profile programming is not done */
val = readl(reg) & ~PROG_DONE;
writel(val, reg);
/* Mark SSIC port as unused(suspend) or used(resume) */
val = readl(reg);
if (suspend)
val |= SSIC_PORT_UNUSED;
else
val &= ~SSIC_PORT_UNUSED;
writel(val, reg);
/* Notify SSIC that SSIC profile programming is done */
val = readl(reg) | PROG_DONE;
writel(val, reg);
readl(reg);
}
reg = (void __iomem *) xhci->cap_regs + 0x80a4;
val = readl(reg);
writel(val | BIT(28), reg);
readl(reg);
}
static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
{ {
struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct xhci_hcd *xhci = hcd_to_xhci(hcd);
......
...@@ -302,6 +302,15 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci) ...@@ -302,6 +302,15 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci)
ret = xhci_handshake(&xhci->op_regs->cmd_ring, ret = xhci_handshake(&xhci->op_regs->cmd_ring,
CMD_RING_RUNNING, 0, 5 * 1000 * 1000); CMD_RING_RUNNING, 0, 5 * 1000 * 1000);
if (ret < 0) { if (ret < 0) {
/* we are about to kill xhci, give it one more chance */
xhci_write_64(xhci, temp_64 | CMD_RING_ABORT,
&xhci->op_regs->cmd_ring);
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, " xhci_err(xhci, "Stopped the command ring failed, "
"maybe the host is dead\n"); "maybe the host is dead\n");
xhci->xhc_state |= XHCI_STATE_DYING; xhci->xhc_state |= XHCI_STATE_DYING;
...@@ -3461,8 +3470,8 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, ...@@ -3461,8 +3470,8 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
if (start_cycle == 0) if (start_cycle == 0)
field |= 0x1; field |= 0x1;
/* xHCI 1.0 6.4.1.2.1: Transfer Type field */ /* xHCI 1.0/1.1 6.4.1.2.1: Transfer Type field */
if (xhci->hci_version == 0x100) { if (xhci->hci_version >= 0x100) {
if (urb->transfer_buffer_length > 0) { if (urb->transfer_buffer_length > 0) {
if (setup->bRequestType & USB_DIR_IN) if (setup->bRequestType & USB_DIR_IN)
field |= TRB_TX_TYPE(TRB_DATA_IN); field |= TRB_TX_TYPE(TRB_DATA_IN);
......
...@@ -146,7 +146,8 @@ static int xhci_start(struct xhci_hcd *xhci) ...@@ -146,7 +146,8 @@ static int xhci_start(struct xhci_hcd *xhci)
"waited %u microseconds.\n", "waited %u microseconds.\n",
XHCI_MAX_HALT_USEC); XHCI_MAX_HALT_USEC);
if (!ret) if (!ret)
xhci->xhc_state &= ~XHCI_STATE_HALTED; xhci->xhc_state &= ~(XHCI_STATE_HALTED | XHCI_STATE_DYING);
return ret; return ret;
} }
...@@ -654,15 +655,6 @@ int xhci_run(struct usb_hcd *hcd) ...@@ -654,15 +655,6 @@ int xhci_run(struct usb_hcd *hcd)
} }
EXPORT_SYMBOL_GPL(xhci_run); EXPORT_SYMBOL_GPL(xhci_run);
static void xhci_only_stop_hcd(struct usb_hcd *hcd)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
spin_lock_irq(&xhci->lock);
xhci_halt(xhci);
spin_unlock_irq(&xhci->lock);
}
/* /*
* Stop xHCI driver. * Stop xHCI driver.
* *
...@@ -677,12 +669,14 @@ void xhci_stop(struct usb_hcd *hcd) ...@@ -677,12 +669,14 @@ void xhci_stop(struct usb_hcd *hcd)
u32 temp; u32 temp;
struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct xhci_hcd *xhci = hcd_to_xhci(hcd);
if (!usb_hcd_is_primary_hcd(hcd)) { if (xhci->xhc_state & XHCI_STATE_HALTED)
xhci_only_stop_hcd(xhci->shared_hcd);
return; return;
}
mutex_lock(&xhci->mutex);
spin_lock_irq(&xhci->lock); spin_lock_irq(&xhci->lock);
xhci->xhc_state |= XHCI_STATE_HALTED;
xhci->cmd_ring_state = CMD_RING_STATE_STOPPED;
/* Make sure the xHC is halted for a USB3 roothub /* Make sure the xHC is halted for a USB3 roothub
* (xhci_stop() could be called as part of failed init). * (xhci_stop() could be called as part of failed init).
*/ */
...@@ -717,6 +711,7 @@ void xhci_stop(struct usb_hcd *hcd) ...@@ -717,6 +711,7 @@ void xhci_stop(struct usb_hcd *hcd)
xhci_dbg_trace(xhci, trace_xhci_dbg_init, xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"xhci_stop completed - status = %x", "xhci_stop completed - status = %x",
readl(&xhci->op_regs->status)); readl(&xhci->op_regs->status));
mutex_unlock(&xhci->mutex);
} }
/* /*
...@@ -3793,6 +3788,9 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev, ...@@ -3793,6 +3788,9 @@ 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 or halted */
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,
"Bad Slot ID %d", udev->slot_id); "Bad Slot ID %d", udev->slot_id);
......
...@@ -1051,6 +1051,7 @@ void musb_start(struct musb *musb) ...@@ -1051,6 +1051,7 @@ void musb_start(struct musb *musb)
* (c) peripheral initiates, using SRP * (c) peripheral initiates, using SRP
*/ */
if (musb->port_mode != MUSB_PORT_MODE_HOST && if (musb->port_mode != MUSB_PORT_MODE_HOST &&
musb->xceiv->otg->state != OTG_STATE_A_WAIT_BCON &&
(devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) { (devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) {
musb->is_active = 1; musb->is_active = 1;
} else { } else {
...@@ -2448,6 +2449,9 @@ static int musb_suspend(struct device *dev) ...@@ -2448,6 +2449,9 @@ static int musb_suspend(struct device *dev)
struct musb *musb = dev_to_musb(dev); struct musb *musb = dev_to_musb(dev);
unsigned long flags; unsigned long flags;
musb_platform_disable(musb);
musb_generic_disable(musb);
spin_lock_irqsave(&musb->lock, flags); spin_lock_irqsave(&musb->lock, flags);
if (is_peripheral_active(musb)) { if (is_peripheral_active(musb)) {
...@@ -2501,6 +2505,9 @@ static int musb_resume(struct device *dev) ...@@ -2501,6 +2505,9 @@ static int musb_resume(struct device *dev)
pm_runtime_disable(dev); pm_runtime_disable(dev);
pm_runtime_set_active(dev); pm_runtime_set_active(dev);
pm_runtime_enable(dev); pm_runtime_enable(dev);
musb_start(musb);
return 0; return 0;
} }
......
...@@ -551,6 +551,9 @@ static int cppi41_dma_channel_abort(struct dma_channel *channel) ...@@ -551,6 +551,9 @@ static int cppi41_dma_channel_abort(struct dma_channel *channel)
} else { } else {
cppi41_set_autoreq_mode(cppi41_channel, EP_MODE_AUTOREQ_NONE); cppi41_set_autoreq_mode(cppi41_channel, EP_MODE_AUTOREQ_NONE);
/* delay to drain to cppi dma pipeline for isoch */
udelay(250);
csr = musb_readw(epio, MUSB_RXCSR); csr = musb_readw(epio, MUSB_RXCSR);
csr &= ~(MUSB_RXCSR_H_REQPKT | MUSB_RXCSR_DMAENAB); csr &= ~(MUSB_RXCSR_H_REQPKT | MUSB_RXCSR_DMAENAB);
musb_writew(epio, MUSB_RXCSR, csr); musb_writew(epio, MUSB_RXCSR, csr);
......
...@@ -225,8 +225,11 @@ static void dsps_musb_enable(struct musb *musb) ...@@ -225,8 +225,11 @@ static void dsps_musb_enable(struct musb *musb)
dsps_writel(reg_base, wrp->epintr_set, epmask); dsps_writel(reg_base, wrp->epintr_set, epmask);
dsps_writel(reg_base, wrp->coreintr_set, coremask); dsps_writel(reg_base, wrp->coreintr_set, coremask);
/* start polling for ID change. */ /* start polling for ID change in dual-role idle mode */
mod_timer(&glue->timer, jiffies + msecs_to_jiffies(wrp->poll_timeout)); if (musb->xceiv->otg->state == OTG_STATE_B_IDLE &&
musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE)
mod_timer(&glue->timer, jiffies +
msecs_to_jiffies(wrp->poll_timeout));
dsps_musb_try_idle(musb, 0); dsps_musb_try_idle(musb, 0);
} }
......
...@@ -379,6 +379,8 @@ static const struct of_device_id ux500_match[] = { ...@@ -379,6 +379,8 @@ static const struct of_device_id ux500_match[] = {
{} {}
}; };
MODULE_DEVICE_TABLE(of, ux500_match);
static struct platform_driver ux500_driver = { static struct platform_driver ux500_driver = {
.probe = ux500_probe, .probe = ux500_probe,
.remove = ux500_remove, .remove = ux500_remove,
......
...@@ -155,7 +155,7 @@ config USB_MSM_OTG ...@@ -155,7 +155,7 @@ config USB_MSM_OTG
config USB_QCOM_8X16_PHY config USB_QCOM_8X16_PHY
tristate "Qualcomm APQ8016/MSM8916 on-chip USB PHY controller support" tristate "Qualcomm APQ8016/MSM8916 on-chip USB PHY controller support"
depends on ARCH_QCOM || COMPILE_TEST depends on ARCH_QCOM || COMPILE_TEST
depends on RESET_CONTROLLER depends on RESET_CONTROLLER && EXTCON
select USB_PHY select USB_PHY
select USB_ULPI_VIEWPORT select USB_ULPI_VIEWPORT
help help
......
...@@ -232,7 +232,8 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop, ...@@ -232,7 +232,8 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop,
clk_rate = pdata->clk_rate; clk_rate = pdata->clk_rate;
needs_vcc = pdata->needs_vcc; needs_vcc = pdata->needs_vcc;
if (gpio_is_valid(pdata->gpio_reset)) { if (gpio_is_valid(pdata->gpio_reset)) {
err = devm_gpio_request_one(dev, pdata->gpio_reset, 0, err = devm_gpio_request_one(dev, pdata->gpio_reset,
GPIOF_ACTIVE_LOW,
dev_name(dev)); dev_name(dev));
if (!err) if (!err)
nop->gpiod_reset = nop->gpiod_reset =
......
...@@ -31,6 +31,7 @@ static const struct i2c_device_id isp1301_id[] = { ...@@ -31,6 +31,7 @@ static const struct i2c_device_id isp1301_id[] = {
{ "isp1301", 0 }, { "isp1301", 0 },
{ } { }
}; };
MODULE_DEVICE_TABLE(i2c, isp1301_id);
static struct i2c_client *isp1301_i2c_client; static struct i2c_client *isp1301_i2c_client;
......
...@@ -278,6 +278,10 @@ static void option_instat_callback(struct urb *urb); ...@@ -278,6 +278,10 @@ static void option_instat_callback(struct urb *urb);
#define ZTE_PRODUCT_MF622 0x0001 #define ZTE_PRODUCT_MF622 0x0001
#define ZTE_PRODUCT_MF628 0x0015 #define ZTE_PRODUCT_MF628 0x0015
#define ZTE_PRODUCT_MF626 0x0031 #define ZTE_PRODUCT_MF626 0x0031
#define ZTE_PRODUCT_ZM8620_X 0x0396
#define ZTE_PRODUCT_ME3620_MBIM 0x0426
#define ZTE_PRODUCT_ME3620_X 0x1432
#define ZTE_PRODUCT_ME3620_L 0x1433
#define ZTE_PRODUCT_AC2726 0xfff1 #define ZTE_PRODUCT_AC2726 0xfff1
#define ZTE_PRODUCT_MG880 0xfffd #define ZTE_PRODUCT_MG880 0xfffd
#define ZTE_PRODUCT_CDMA_TECH 0xfffe #define ZTE_PRODUCT_CDMA_TECH 0xfffe
...@@ -544,6 +548,18 @@ static const struct option_blacklist_info zte_mc2716_z_blacklist = { ...@@ -544,6 +548,18 @@ static const struct option_blacklist_info zte_mc2716_z_blacklist = {
.sendsetup = BIT(1) | BIT(2) | BIT(3), .sendsetup = BIT(1) | BIT(2) | BIT(3),
}; };
static const struct option_blacklist_info zte_me3620_mbim_blacklist = {
.reserved = BIT(2) | BIT(3) | BIT(4),
};
static const struct option_blacklist_info zte_me3620_xl_blacklist = {
.reserved = BIT(3) | BIT(4) | BIT(5),
};
static const struct option_blacklist_info zte_zm8620_x_blacklist = {
.reserved = BIT(3) | BIT(4) | BIT(5),
};
static const struct option_blacklist_info huawei_cdc12_blacklist = { static const struct option_blacklist_info huawei_cdc12_blacklist = {
.reserved = BIT(1) | BIT(2), .reserved = BIT(1) | BIT(2),
}; };
...@@ -1591,6 +1607,14 @@ static const struct usb_device_id option_ids[] = { ...@@ -1591,6 +1607,14 @@ static const struct usb_device_id option_ids[] = {
.driver_info = (kernel_ulong_t)&zte_ad3812_z_blacklist }, .driver_info = (kernel_ulong_t)&zte_ad3812_z_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2716, 0xff, 0xff, 0xff), { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2716, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&zte_mc2716_z_blacklist }, .driver_info = (kernel_ulong_t)&zte_mc2716_z_blacklist },
{ USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_ME3620_L),
.driver_info = (kernel_ulong_t)&zte_me3620_xl_blacklist },
{ USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_ME3620_MBIM),
.driver_info = (kernel_ulong_t)&zte_me3620_mbim_blacklist },
{ USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_ME3620_X),
.driver_info = (kernel_ulong_t)&zte_me3620_xl_blacklist },
{ USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_ZM8620_X),
.driver_info = (kernel_ulong_t)&zte_zm8620_x_blacklist },
{ USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x02, 0x01) }, { USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x02, 0x01) },
{ USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x02, 0x05) }, { USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x02, 0x05) },
{ USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x86, 0x10) }, { USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x86, 0x10) },
......
...@@ -80,6 +80,8 @@ static int whiteheat_firmware_download(struct usb_serial *serial, ...@@ -80,6 +80,8 @@ static int whiteheat_firmware_download(struct usb_serial *serial,
static int whiteheat_firmware_attach(struct usb_serial *serial); static int whiteheat_firmware_attach(struct usb_serial *serial);
/* function prototypes for the Connect Tech WhiteHEAT serial converter */ /* function prototypes for the Connect Tech WhiteHEAT serial converter */
static int whiteheat_probe(struct usb_serial *serial,
const struct usb_device_id *id);
static int whiteheat_attach(struct usb_serial *serial); static int whiteheat_attach(struct usb_serial *serial);
static void whiteheat_release(struct usb_serial *serial); static void whiteheat_release(struct usb_serial *serial);
static int whiteheat_port_probe(struct usb_serial_port *port); static int whiteheat_port_probe(struct usb_serial_port *port);
...@@ -116,6 +118,7 @@ static struct usb_serial_driver whiteheat_device = { ...@@ -116,6 +118,7 @@ static struct usb_serial_driver whiteheat_device = {
.description = "Connect Tech - WhiteHEAT", .description = "Connect Tech - WhiteHEAT",
.id_table = id_table_std, .id_table = id_table_std,
.num_ports = 4, .num_ports = 4,
.probe = whiteheat_probe,
.attach = whiteheat_attach, .attach = whiteheat_attach,
.release = whiteheat_release, .release = whiteheat_release,
.port_probe = whiteheat_port_probe, .port_probe = whiteheat_port_probe,
...@@ -217,6 +220,34 @@ static int whiteheat_firmware_attach(struct usb_serial *serial) ...@@ -217,6 +220,34 @@ static int whiteheat_firmware_attach(struct usb_serial *serial)
/***************************************************************************** /*****************************************************************************
* Connect Tech's White Heat serial driver functions * Connect Tech's White Heat serial driver functions
*****************************************************************************/ *****************************************************************************/
static int whiteheat_probe(struct usb_serial *serial,
const struct usb_device_id *id)
{
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint;
size_t num_bulk_in = 0;
size_t num_bulk_out = 0;
size_t min_num_bulk;
unsigned int i;
iface_desc = serial->interface->cur_altsetting;
for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
endpoint = &iface_desc->endpoint[i].desc;
if (usb_endpoint_is_bulk_in(endpoint))
++num_bulk_in;
if (usb_endpoint_is_bulk_out(endpoint))
++num_bulk_out;
}
min_num_bulk = COMMAND_PORT + 1;
if (num_bulk_in < min_num_bulk || num_bulk_out < min_num_bulk)
return -ENODEV;
return 0;
}
static int whiteheat_attach(struct usb_serial *serial) static int whiteheat_attach(struct usb_serial *serial)
{ {
struct usb_serial_port *command_port; struct usb_serial_port *command_port;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment