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:
  USB: fix autosuspend bug in usb-serial
  USB: ehci: disable LPM and PPCD for nVidia MCP89 chips
  USB: serial: ftdi_sio: Vardaan USB RS422/485 converter PID added
  USB: yurex: add .llseek fop to file_operations
  USB: ftdi_sio: Add ID for RT Systems USB-29B radio cable
  usb: musb: do not use dma for control transfers
  usb: musb: gadget: fix compilation warning
  usb: musb: clear RXCSR_AUTOCLEAR before PIO read
  usb: musb: unmap dma buffer when switching to PIO
  xhci: Don't let the USB core disable SuperSpeed ports.
  xhci: Setup array of USB 2.0 and USB 3.0 ports.
  xhci: Fix reset-device and configure-endpoint commands
  • Loading branch information
Linus Torvalds committed Dec 2, 2010
2 parents 2e5c26d + b7a5100 commit 435a5ae
Show file tree
Hide file tree
Showing 13 changed files with 332 additions and 38 deletions.
2 changes: 2 additions & 0 deletions drivers/usb/core/hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1330,6 +1330,8 @@ static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
*/

if (usb_endpoint_xfer_control(&urb->ep->desc)) {
if (hcd->self.uses_pio_for_control)
return ret;
if (hcd->self.uses_dma) {
urb->setup_dma = dma_map_single(
hcd->self.controller,
Expand Down
12 changes: 12 additions & 0 deletions drivers/usb/host/ehci-pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,18 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
if (pdev->revision < 0xa4)
ehci->no_selective_suspend = 1;
break;

/* MCP89 chips on the MacBookAir3,1 give EPROTO when
* fetching device descriptors unless LPM is disabled.
* There are also intermittent problems enumerating
* devices with PPCD enabled.
*/
case 0x0d9d:
ehci_info(ehci, "disable lpm/ppcd for nvidia mcp89");
ehci->has_lpm = 0;
ehci->has_ppcd = 0;
ehci->command &= ~CMD_PPCEE;
break;
}
break;
case PCI_VENDOR_ID_VIA:
Expand Down
7 changes: 7 additions & 0 deletions drivers/usb/host/xhci-hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,13 @@ void xhci_ring_device(struct xhci_hcd *xhci, int slot_id)
static void xhci_disable_port(struct xhci_hcd *xhci, u16 wIndex,
u32 __iomem *addr, u32 port_status)
{
/* Don't allow the USB core to disable SuperSpeed ports. */
if (xhci->port_array[wIndex] == 0x03) {
xhci_dbg(xhci, "Ignoring request to disable "
"SuperSpeed port.\n");
return;
}

/* Write 1 to disable the port */
xhci_writel(xhci, port_status | PORT_PE, addr);
port_status = xhci_readl(xhci, addr);
Expand Down
164 changes: 164 additions & 0 deletions drivers/usb/host/xhci-mem.c
Original file line number Diff line number Diff line change
Expand Up @@ -1443,6 +1443,13 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
xhci->dcbaa = NULL;

scratchpad_free(xhci);

xhci->num_usb2_ports = 0;
xhci->num_usb3_ports = 0;
kfree(xhci->usb2_ports);
kfree(xhci->usb3_ports);
kfree(xhci->port_array);

xhci->page_size = 0;
xhci->page_shift = 0;
xhci->bus_suspended = 0;
Expand Down Expand Up @@ -1627,6 +1634,161 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci)
&xhci->ir_set->erst_dequeue);
}

static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
u32 __iomem *addr, u8 major_revision)
{
u32 temp, port_offset, port_count;
int i;

if (major_revision > 0x03) {
xhci_warn(xhci, "Ignoring unknown port speed, "
"Ext Cap %p, revision = 0x%x\n",
addr, major_revision);
/* Ignoring port protocol we can't understand. FIXME */
return;
}

/* Port offset and count in the third dword, see section 7.2 */
temp = xhci_readl(xhci, addr + 2);
port_offset = XHCI_EXT_PORT_OFF(temp);
port_count = XHCI_EXT_PORT_COUNT(temp);
xhci_dbg(xhci, "Ext Cap %p, port offset = %u, "
"count = %u, revision = 0x%x\n",
addr, port_offset, port_count, major_revision);
/* Port count includes the current port offset */
if (port_offset == 0 || (port_offset + port_count - 1) > num_ports)
/* WTF? "Valid values are ‘1’ to MaxPorts" */
return;
port_offset--;
for (i = port_offset; i < (port_offset + port_count); i++) {
/* Duplicate entry. Ignore the port if the revisions differ. */
if (xhci->port_array[i] != 0) {
xhci_warn(xhci, "Duplicate port entry, Ext Cap %p,"
" port %u\n", addr, i);
xhci_warn(xhci, "Port was marked as USB %u, "
"duplicated as USB %u\n",
xhci->port_array[i], major_revision);
/* Only adjust the roothub port counts if we haven't
* found a similar duplicate.
*/
if (xhci->port_array[i] != major_revision &&
xhci->port_array[i] != (u8) -1) {
if (xhci->port_array[i] == 0x03)
xhci->num_usb3_ports--;
else
xhci->num_usb2_ports--;
xhci->port_array[i] = (u8) -1;
}
/* FIXME: Should we disable the port? */
}
xhci->port_array[i] = major_revision;
if (major_revision == 0x03)
xhci->num_usb3_ports++;
else
xhci->num_usb2_ports++;
}
/* FIXME: Should we disable ports not in the Extended Capabilities? */
}

/*
* Scan the Extended Capabilities for the "Supported Protocol Capabilities" that
* specify what speeds each port is supposed to be. We can't count on the port
* speed bits in the PORTSC register being correct until a device is connected,
* but we need to set up the two fake roothubs with the correct number of USB
* 3.0 and USB 2.0 ports at host controller initialization time.
*/
static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
{
u32 __iomem *addr;
u32 offset;
unsigned int num_ports;
int i, port_index;

addr = &xhci->cap_regs->hcc_params;
offset = XHCI_HCC_EXT_CAPS(xhci_readl(xhci, addr));
if (offset == 0) {
xhci_err(xhci, "No Extended Capability registers, "
"unable to set up roothub.\n");
return -ENODEV;
}

num_ports = HCS_MAX_PORTS(xhci->hcs_params1);
xhci->port_array = kzalloc(sizeof(*xhci->port_array)*num_ports, flags);
if (!xhci->port_array)
return -ENOMEM;

/*
* For whatever reason, the first capability offset is from the
* capability register base, not from the HCCPARAMS register.
* See section 5.3.6 for offset calculation.
*/
addr = &xhci->cap_regs->hc_capbase + offset;
while (1) {
u32 cap_id;

cap_id = xhci_readl(xhci, addr);
if (XHCI_EXT_CAPS_ID(cap_id) == XHCI_EXT_CAPS_PROTOCOL)
xhci_add_in_port(xhci, num_ports, addr,
(u8) XHCI_EXT_PORT_MAJOR(cap_id));
offset = XHCI_EXT_CAPS_NEXT(cap_id);
if (!offset || (xhci->num_usb2_ports + xhci->num_usb3_ports)
== num_ports)
break;
/*
* Once you're into the Extended Capabilities, the offset is
* always relative to the register holding the offset.
*/
addr += offset;
}

if (xhci->num_usb2_ports == 0 && xhci->num_usb3_ports == 0) {
xhci_warn(xhci, "No ports on the roothubs?\n");
return -ENODEV;
}
xhci_dbg(xhci, "Found %u USB 2.0 ports and %u USB 3.0 ports.\n",
xhci->num_usb2_ports, xhci->num_usb3_ports);
/*
* Note we could have all USB 3.0 ports, or all USB 2.0 ports.
* Not sure how the USB core will handle a hub with no ports...
*/
if (xhci->num_usb2_ports) {
xhci->usb2_ports = kmalloc(sizeof(*xhci->usb2_ports)*
xhci->num_usb2_ports, flags);
if (!xhci->usb2_ports)
return -ENOMEM;

port_index = 0;
for (i = 0; i < num_ports; i++)
if (xhci->port_array[i] != 0x03) {
xhci->usb2_ports[port_index] =
&xhci->op_regs->port_status_base +
NUM_PORT_REGS*i;
xhci_dbg(xhci, "USB 2.0 port at index %u, "
"addr = %p\n", i,
xhci->usb2_ports[port_index]);
port_index++;
}
}
if (xhci->num_usb3_ports) {
xhci->usb3_ports = kmalloc(sizeof(*xhci->usb3_ports)*
xhci->num_usb3_ports, flags);
if (!xhci->usb3_ports)
return -ENOMEM;

port_index = 0;
for (i = 0; i < num_ports; i++)
if (xhci->port_array[i] == 0x03) {
xhci->usb3_ports[port_index] =
&xhci->op_regs->port_status_base +
NUM_PORT_REGS*i;
xhci_dbg(xhci, "USB 3.0 port at index %u, "
"addr = %p\n", i,
xhci->usb3_ports[port_index]);
port_index++;
}
}
return 0;
}

int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
{
Expand Down Expand Up @@ -1809,6 +1971,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)

if (scratchpad_alloc(xhci, flags))
goto fail;
if (xhci_setup_port_arrays(xhci, flags))
goto fail;

return 0;

Expand Down
18 changes: 18 additions & 0 deletions drivers/usb/host/xhci.c
Original file line number Diff line number Diff line change
Expand Up @@ -1549,6 +1549,15 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
cmd_completion = command->completion;
cmd_status = &command->status;
command->command_trb = xhci->cmd_ring->enqueue;

/* Enqueue pointer can be left pointing to the link TRB,
* we must handle that
*/
if ((command->command_trb->link.control & TRB_TYPE_BITMASK)
== TRB_TYPE(TRB_LINK))
command->command_trb =
xhci->cmd_ring->enq_seg->next->trbs;

list_add_tail(&command->cmd_list, &virt_dev->cmd_list);
} else {
in_ctx = virt_dev->in_ctx;
Expand Down Expand Up @@ -2272,6 +2281,15 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
/* Attempt to submit the Reset Device command to the command ring */
spin_lock_irqsave(&xhci->lock, flags);
reset_device_cmd->command_trb = xhci->cmd_ring->enqueue;

/* Enqueue pointer can be left pointing to the link TRB,
* we must handle that
*/
if ((reset_device_cmd->command_trb->link.control & TRB_TYPE_BITMASK)
== TRB_TYPE(TRB_LINK))
reset_device_cmd->command_trb =
xhci->cmd_ring->enq_seg->next->trbs;

list_add_tail(&reset_device_cmd->cmd_list, &virt_dev->cmd_list);
ret = xhci_queue_reset_device(xhci, slot_id);
if (ret) {
Expand Down
26 changes: 26 additions & 0 deletions drivers/usb/host/xhci.h
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,24 @@ struct xhci_doorbell_array {
#define STREAM_ID_TO_DB(p) (((p) & 0xffff) << 16)


/**
* struct xhci_protocol_caps
* @revision: major revision, minor revision, capability ID,
* and next capability pointer.
* @name_string: Four ASCII characters to say which spec this xHC
* follows, typically "USB ".
* @port_info: Port offset, count, and protocol-defined information.
*/
struct xhci_protocol_caps {
u32 revision;
u32 name_string;
u32 port_info;
};

#define XHCI_EXT_PORT_MAJOR(x) (((x) >> 24) & 0xff)
#define XHCI_EXT_PORT_OFF(x) ((x) & 0xff)
#define XHCI_EXT_PORT_COUNT(x) (((x) >> 8) & 0xff)

/**
* struct xhci_container_ctx
* @type: Type of context. Used to calculated offsets to contained contexts.
Expand Down Expand Up @@ -1240,6 +1258,14 @@ struct xhci_hcd {
u32 suspended_ports[8]; /* which ports are
suspended */
unsigned long resume_done[MAX_HC_PORTS];
/* Is each xHCI roothub port a USB 3.0, USB 2.0, or USB 1.1 port? */
u8 *port_array;
/* Array of pointers to USB 3.0 PORTSC registers */
u32 __iomem **usb3_ports;
unsigned int num_usb3_ports;
/* Array of pointers to USB 2.0 PORTSC registers */
u32 __iomem **usb2_ports;
unsigned int num_usb2_ports;
};

/* For testing purposes */
Expand Down
1 change: 1 addition & 0 deletions drivers/usb/misc/yurex.c
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,7 @@ static const struct file_operations yurex_fops = {
.open = yurex_open,
.release = yurex_release,
.fasync = yurex_fasync,
.llseek = default_llseek,
};


Expand Down
3 changes: 3 additions & 0 deletions drivers/usb/musb/musb_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -2116,12 +2116,15 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
* Otherwise, wait till the gadget driver hooks up.
*/
if (!is_otg_enabled(musb) && is_host_enabled(musb)) {
struct usb_hcd *hcd = musb_to_hcd(musb);

MUSB_HST_MODE(musb);
musb->xceiv->default_a = 1;
musb->xceiv->state = OTG_STATE_A_IDLE;

status = usb_add_hcd(musb_to_hcd(musb), -1, 0);

hcd->self.uses_pio_for_control = 1;
DBG(1, "%s mode, status %d, devctl %02x %c\n",
"HOST", status,
musb_readb(musb->mregs, MUSB_DEVCTL),
Expand Down
Loading

0 comments on commit 435a5ae

Please sign in to comment.