diff options
author | Sarah Sharp <sarah.a.sharp@linux.intel.com> | 2009-04-27 19:57:12 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-06-15 21:44:48 -0700 |
commit | 0f2a79300a1471cf92ab43af165ea13555c8b0a5 (patch) | |
tree | a46c63777a6040708500aefdbc31e0a0404d2e4a /drivers/usb/host/xhci-ring.c | |
parent | 7206b00164a1c3ca533e01db285955617e1019f8 (diff) | |
download | kernel_samsung_smdk4412-0f2a79300a1471cf92ab43af165ea13555c8b0a5.zip kernel_samsung_smdk4412-0f2a79300a1471cf92ab43af165ea13555c8b0a5.tar.gz kernel_samsung_smdk4412-0f2a79300a1471cf92ab43af165ea13555c8b0a5.tar.bz2 |
USB: xhci: Root hub support.
Add functionality for getting port status and hub descriptor for xHCI root
hubs. This is WIP because the USB 3.0 hub descriptor is different from
the USB 2.0 hub descriptor. For now, we lie about the root hub descriptor
because the changes won't effect how the core talks to the root hub.
Later we will need to add the USB 3.0 hub descriptor for real hubs, and
this code might change.
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/xhci-ring.c')
-rw-r--r-- | drivers/usb/host/xhci-ring.c | 43 |
1 files changed, 39 insertions, 4 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index c7e3c71..9d6bb3d 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -284,9 +284,38 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, inc_deq(xhci, xhci->cmd_ring, false); } +static void handle_port_status(struct xhci_hcd *xhci, + union xhci_trb *event) +{ + u32 port_id; + + /* Port status change events always have a successful completion code */ + if (GET_COMP_CODE(event->generic.field[2]) != COMP_SUCCESS) { + xhci_warn(xhci, "WARN: xHC returned failed port status event\n"); + xhci->error_bitmask |= 1 << 8; + } + /* FIXME: core doesn't care about all port link state changes yet */ + port_id = GET_PORT_ID(event->generic.field[0]); + xhci_dbg(xhci, "Port Status Change Event for port %d\n", port_id); + + /* Update event ring dequeue pointer before dropping the lock */ + inc_deq(xhci, xhci->event_ring, true); + set_hc_event_deq(xhci); + + spin_unlock(&xhci->lock); + /* Pass this up to the core */ + usb_hcd_poll_rh_status(xhci_to_hcd(xhci)); + spin_lock(&xhci->lock); +} + +/* + * This function handles all OS-owned events on the event ring. It may drop + * xhci->lock between event processing (e.g. to pass up port status changes). + */ void handle_event(struct xhci_hcd *xhci) { union xhci_trb *event; + int update_ptrs = 1; if (!xhci->event_ring || !xhci->event_ring->dequeue) { xhci->error_bitmask |= 1 << 1; @@ -301,18 +330,24 @@ void handle_event(struct xhci_hcd *xhci) return; } - /* FIXME: Only handles command completion events. */ + /* FIXME: Handle more event types. */ switch ((event->event_cmd.flags & TRB_TYPE_BITMASK)) { case TRB_TYPE(TRB_COMPLETION): handle_cmd_completion(xhci, &event->event_cmd); break; + case TRB_TYPE(TRB_PORT_STATUS): + handle_port_status(xhci, event); + update_ptrs = 0; + break; default: xhci->error_bitmask |= 1 << 3; } - /* Update SW and HC event ring dequeue pointer */ - inc_deq(xhci, xhci->event_ring, true); - set_hc_event_deq(xhci); + if (update_ptrs) { + /* Update SW and HC event ring dequeue pointer */ + inc_deq(xhci, xhci->event_ring, true); + set_hc_event_deq(xhci); + } /* Are there more items on the event ring? */ handle_event(xhci); } |