Skip to content

Commit

Permalink
Merge branch 'usb-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/gregkh/usb-2.6

* 'usb-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6:
  MAINTAINERS: add myself as maintainer of USB/IP
  usb: r8a66597-hcd: fix cannot detect low/full speed device
  USB: ehci-ath79: fix a NULL pointer dereference
  USB: Add new FT232H chip to drivers/usb/serial/ftdi_sio.c
  usb/isp1760: Fix bug preventing the unlinking of control urbs
  USB: Fix up URB error codes to reflect implementation.
  xhci: Always set urb->status to zero for isoc endpoints.
  xhci: Add reset on resume quirk for asrock p67 host
  xHCI 1.0: Incompatible Device Error
  USB: don't let errors prevent system sleep
  USB: don't let the hub driver prevent system sleep
  USB: change maintainership of ohci-hcd and ehci-hcd
  xHCI 1.0: Force Stopped Event(FSE)
  xhci: Don't warn about zeroed bMaxBurst descriptor field.
  USB: Free bandwidth when usb_disable_device is called.
  xhci: Reject double add of active endpoints.
  USB: TI 3410/5052 USB Serial Driver: Fix mem leak when firmware is too big.
  usb: musb: gadget: clear TXPKTRDY flag when set FLUSHFIFO
  usb: musb: host: compare status for negative error values
  • Loading branch information
torvalds committed Jun 28, 2011
2 parents 04b9059 + 857aab3 commit 2e34b42
Showing 21 changed files with 164 additions and 34 deletions.
9 changes: 8 additions & 1 deletion Documentation/usb/error-codes.txt
Original file line number Diff line number Diff line change
@@ -76,6 +76,13 @@ A transfer's actual_length may be positive even when an error has been
reported. That's because transfers often involve several packets, so that
one or more packets could finish before an error stops further endpoint I/O.

For isochronous URBs, the urb status value is non-zero only if the URB is
unlinked, the device is removed, the host controller is disabled, or the total
transferred length is less than the requested length and the URB_SHORT_NOT_OK
flag is set. Completion handlers for isochronous URBs should only see
urb->status set to zero, -ENOENT, -ECONNRESET, -ESHUTDOWN, or -EREMOTEIO.
Individual frame descriptor status fields may report more status codes.


0 Transfer completed successfully

@@ -132,7 +139,7 @@ one or more packets could finish before an error stops further endpoint I/O.
device removal events immediately.

-EXDEV ISO transfer only partially completed
look at individual frame status for details
(only set in iso_frame_desc[n].status, not urb->status)

-EINVAL ISO madness, if this happens: Log off and go home

12 changes: 10 additions & 2 deletions MAINTAINERS
Original file line number Diff line number Diff line change
@@ -6434,8 +6434,9 @@ S: Maintained
F: drivers/usb/misc/rio500*

USB EHCI DRIVER
M: Alan Stern <[email protected]>
L: [email protected]
S: Orphan
S: Maintained
F: Documentation/usb/ehci.txt
F: drivers/usb/host/ehci*

@@ -6465,6 +6466,12 @@ S: Maintained
F: Documentation/hid/hiddev.txt
F: drivers/hid/usbhid/

USB/IP DRIVERS
M: Matt Mooney <[email protected]>
L: [email protected]
S: Maintained
F: drivers/staging/usbip/

USB ISP116X DRIVER
M: Olav Kongas <[email protected]>
L: [email protected]
@@ -6494,8 +6501,9 @@ S: Maintained
F: sound/usb/midi.*

USB OHCI DRIVER
M: Alan Stern <[email protected]>
L: [email protected]
S: Orphan
S: Maintained
F: Documentation/usb/ohci.txt
F: drivers/usb/host/ohci*

11 changes: 10 additions & 1 deletion drivers/usb/core/driver.c
Original file line number Diff line number Diff line change
@@ -1187,13 +1187,22 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
for (i = n - 1; i >= 0; --i) {
intf = udev->actconfig->interface[i];
status = usb_suspend_interface(udev, intf, msg);

/* Ignore errors during system sleep transitions */
if (!(msg.event & PM_EVENT_AUTO))
status = 0;
if (status != 0)
break;
}
}
if (status == 0)
if (status == 0) {
status = usb_suspend_device(udev, msg);

/* Again, ignore errors during system sleep transitions */
if (!(msg.event & PM_EVENT_AUTO))
status = 0;
}

/* If the suspend failed, resume interfaces that did get suspended */
if (status != 0) {
msg.event ^= (PM_EVENT_SUSPEND | PM_EVENT_RESUME);
16 changes: 11 additions & 5 deletions drivers/usb/core/hub.c
Original file line number Diff line number Diff line change
@@ -1634,6 +1634,7 @@ void usb_disconnect(struct usb_device **pdev)
{
struct usb_device *udev = *pdev;
int i;
struct usb_hcd *hcd = bus_to_hcd(udev->bus);

if (!udev) {
pr_debug ("%s nodev\n", __func__);
@@ -1661,7 +1662,9 @@ void usb_disconnect(struct usb_device **pdev)
* so that the hardware is now fully quiesced.
*/
dev_dbg (&udev->dev, "unregistering device\n");
mutex_lock(hcd->bandwidth_mutex);
usb_disable_device(udev, 0);
mutex_unlock(hcd->bandwidth_mutex);
usb_hcd_synchronize_unlinks(udev);

usb_remove_ep_devs(&udev->ep0);
@@ -2362,6 +2365,10 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
USB_DEVICE_REMOTE_WAKEUP, 0,
NULL, 0,
USB_CTRL_SET_TIMEOUT);

/* System sleep transitions should never fail */
if (!(msg.event & PM_EVENT_AUTO))
status = 0;
} else {
/* device has up to 10 msec to fully suspend */
dev_dbg(&udev->dev, "usb %ssuspend\n",
@@ -2611,16 +2618,15 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
struct usb_device *hdev = hub->hdev;
unsigned port1;

/* fail if children aren't already suspended */
/* Warn if children aren't already suspended */
for (port1 = 1; port1 <= hdev->maxchild; port1++) {
struct usb_device *udev;

udev = hdev->children [port1-1];
if (udev && udev->can_submit) {
if (!(msg.event & PM_EVENT_AUTO))
dev_dbg(&intf->dev, "port %d nyet suspended\n",
port1);
return -EBUSY;
dev_warn(&intf->dev, "port %d nyet suspended\n", port1);
if (msg.event & PM_EVENT_AUTO)
return -EBUSY;
}
}

15 changes: 14 additions & 1 deletion drivers/usb/core/message.c
Original file line number Diff line number Diff line change
@@ -1135,10 +1135,13 @@ void usb_disable_interface(struct usb_device *dev, struct usb_interface *intf,
* Deallocates hcd/hardware state for the endpoints (nuking all or most
* pending urbs) and usbcore state for the interfaces, so that usbcore
* must usb_set_configuration() before any interfaces could be used.
*
* Must be called with hcd->bandwidth_mutex held.
*/
void usb_disable_device(struct usb_device *dev, int skip_ep0)
{
int i;
struct usb_hcd *hcd = bus_to_hcd(dev->bus);

/* getting rid of interfaces will disconnect
* any drivers bound to them (a key side effect)
@@ -1172,6 +1175,16 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)

dev_dbg(&dev->dev, "%s nuking %s URBs\n", __func__,
skip_ep0 ? "non-ep0" : "all");
if (hcd->driver->check_bandwidth) {
/* First pass: Cancel URBs, leave endpoint pointers intact. */
for (i = skip_ep0; i < 16; ++i) {
usb_disable_endpoint(dev, i, false);
usb_disable_endpoint(dev, i + USB_DIR_IN, false);
}
/* Remove endpoints from the host controller internal state */
usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
/* Second pass: remove endpoint pointers */
}
for (i = skip_ep0; i < 16; ++i) {
usb_disable_endpoint(dev, i, true);
usb_disable_endpoint(dev, i + USB_DIR_IN, true);
@@ -1727,6 +1740,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
/* if it's already configured, clear out old state first.
* getting rid of old interfaces means unbinding their drivers.
*/
mutex_lock(hcd->bandwidth_mutex);
if (dev->state != USB_STATE_ADDRESS)
usb_disable_device(dev, 1); /* Skip ep0 */

@@ -1739,7 +1753,6 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
* host controller will not allow submissions to dropped endpoints. If
* this call fails, the device state is unchanged.
*/
mutex_lock(hcd->bandwidth_mutex);
ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL);
if (ret < 0) {
mutex_unlock(hcd->bandwidth_mutex);
10 changes: 6 additions & 4 deletions drivers/usb/host/ehci-ath79.c
Original file line number Diff line number Diff line change
@@ -44,7 +44,6 @@ static int ehci_ath79_init(struct usb_hcd *hcd)
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
struct platform_device *pdev = to_platform_device(hcd->self.controller);
const struct platform_device_id *id;
int hclength;
int ret;

id = platform_get_device_id(pdev);
@@ -53,20 +52,23 @@ static int ehci_ath79_init(struct usb_hcd *hcd)
return -EINVAL;
}

hclength = HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
switch (id->driver_data) {
case EHCI_ATH79_IP_V1:
ehci->has_synopsys_hc_bug = 1;

ehci->caps = hcd->regs;
ehci->regs = hcd->regs + hclength;
ehci->regs = hcd->regs +
HC_LENGTH(ehci,
ehci_readl(ehci, &ehci->caps->hc_capbase));
break;

case EHCI_ATH79_IP_V2:
hcd->has_tt = 1;

ehci->caps = hcd->regs + 0x100;
ehci->regs = hcd->regs + 0x100 + hclength;
ehci->regs = hcd->regs + 0x100 +
HC_LENGTH(ehci,
ehci_readl(ehci, &ehci->caps->hc_capbase));
break;

default:
4 changes: 4 additions & 0 deletions drivers/usb/host/ehci-hcd.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
/*
* Enhanced Host Controller Interface (EHCI) driver for USB.
*
* Maintainer: Alan Stern <[email protected]>
*
* Copyright (c) 2000-2004 by David Brownell
*
* This program is free software; you can redistribute it and/or modify it
2 changes: 1 addition & 1 deletion drivers/usb/host/isp1760-hcd.c
Original file line number Diff line number Diff line change
@@ -1555,7 +1555,7 @@ static void kill_transfer(struct usb_hcd *hcd, struct urb *urb,

/* We need to forcefully reclaim the slot since some transfers never
return, e.g. interrupt transfers and NAKed bulk transfers. */
if (usb_pipebulk(urb->pipe)) {
if (usb_pipecontrol(urb->pipe) || usb_pipebulk(urb->pipe)) {
skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
skip_map |= (1 << qh->slot);
reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map);
4 changes: 3 additions & 1 deletion drivers/usb/host/ohci-hcd.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
/*
* OHCI HCD (Host Controller Driver) for USB.
* Open Host Controller Interface (OHCI) driver for USB.
*
* Maintainer: Alan Stern <[email protected]>
*
* (C) Copyright 1999 Roman Weissgaerber <[email protected]>
* (C) Copyright 2000-2004 David Brownell <[email protected]>
1 change: 1 addition & 0 deletions drivers/usb/host/r8a66597-hcd.c
Original file line number Diff line number Diff line change
@@ -2517,6 +2517,7 @@ static int __devinit r8a66597_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&r8a66597->child_device);

hcd->rsrc_start = res->start;
hcd->has_tt = 1;

ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | irq_trigger);
if (ret != 0) {
2 changes: 0 additions & 2 deletions drivers/usb/host/xhci-mem.c
Original file line number Diff line number Diff line change
@@ -1215,8 +1215,6 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet));
/* dig out max burst from ep companion desc */
max_packet = ep->ss_ep_comp.bMaxBurst;
if (!max_packet)
xhci_warn(xhci, "WARN no SS endpoint bMaxBurst\n");
ep_ctx->ep_info2 |= cpu_to_le32(MAX_BURST(max_packet));
break;
case USB_SPEED_HIGH:
8 changes: 8 additions & 0 deletions drivers/usb/host/xhci-pci.c
Original file line number Diff line number Diff line change
@@ -29,6 +29,9 @@
#define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73
#define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000

#define PCI_VENDOR_ID_ETRON 0x1b6f
#define PCI_DEVICE_ID_ASROCK_P67 0x7023

static const char hcd_name[] = "xhci_hcd";

/* called after powerup, by probe or system-pm "wakeup" */
@@ -134,6 +137,11 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
xhci->quirks |= XHCI_EP_LIMIT_QUIRK;
xhci->limit_active_eps = 64;
}
if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
pdev->device == PCI_DEVICE_ID_ASROCK_P67) {
xhci->quirks |= XHCI_RESET_ON_RESUME;
xhci_dbg(xhci, "QUIRK: Resetting on resume\n");
}

/* Make sure the HC is halted. */
retval = xhci_halt(xhci);
30 changes: 25 additions & 5 deletions drivers/usb/host/xhci-ring.c
Original file line number Diff line number Diff line change
@@ -1733,6 +1733,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
frame->status = -EOVERFLOW;
skip_td = true;
break;
case COMP_DEV_ERR:
case COMP_STALL:
frame->status = -EPROTO;
skip_td = true;
@@ -1767,9 +1768,6 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
}
}

if ((idx == urb_priv->length - 1) && *status == -EINPROGRESS)
*status = 0;

return finish_td(xhci, td, event_trb, event, ep, status, false);
}

@@ -1787,8 +1785,7 @@ static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
idx = urb_priv->td_cnt;
frame = &td->urb->iso_frame_desc[idx];

/* The transfer is partly done */
*status = -EXDEV;
/* The transfer is partly done. */
frame->status = -EXDEV;

/* calc actual length */
@@ -2016,6 +2013,10 @@ static int handle_tx_event(struct xhci_hcd *xhci,
TRB_TO_SLOT_ID(le32_to_cpu(event->flags)),
ep_index);
goto cleanup;
case COMP_DEV_ERR:
xhci_warn(xhci, "WARN: detect an incompatible device");
status = -EPROTO;
break;
case COMP_MISSED_INT:
/*
* When encounter missed service error, one or more isoc tds
@@ -2063,6 +2064,20 @@ static int handle_tx_event(struct xhci_hcd *xhci,
/* Is this a TRB in the currently executing TD? */
event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue,
td->last_trb, event_dma);

/*
* Skip the Force Stopped Event. The event_trb(event_dma) of FSE
* is not in the current TD pointed by ep_ring->dequeue because
* that the hardware dequeue pointer still at the previous TRB
* of the current TD. The previous TRB maybe a Link TD or the
* last TRB of the previous TD. The command completion handle
* will take care the rest.
*/
if (!event_seg && trb_comp_code == COMP_STOP_INVAL) {
ret = 0;
goto cleanup;
}

if (!event_seg) {
if (!ep->skip ||
!usb_endpoint_xfer_isoc(&td->urb->ep->desc)) {
@@ -2158,6 +2173,11 @@ static int handle_tx_event(struct xhci_hcd *xhci,
urb->transfer_buffer_length,
status);
spin_unlock(&xhci->lock);
/* EHCI, UHCI, and OHCI always unconditionally set the
* urb->status of an isochronous endpoint to 0.
*/
if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
status = 0;
usb_hcd_giveback_urb(bus_to_hcd(urb->dev->bus), urb, status);
spin_lock(&xhci->lock);
}
Loading

0 comments on commit 2e34b42

Please sign in to comment.