Merge branch 'for-usb-linus' of git+ssh://master.kernel.org/pub/scm/linux/kernel/git/sarah/xhci into usb-linus
* 'for-usb-linus' of git+ssh://master.kernel.org/pub/scm/linux/kernel/git/sarah/xhci: 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 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.
This commit is contained in:
@@ -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
|
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.
|
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
|
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.
|
device removal events immediately.
|
||||||
|
|
||||||
-EXDEV ISO transfer only partially completed
|
-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
|
-EINVAL ISO madness, if this happens: Log off and go home
|
||||||
|
|
||||||
|
@@ -1634,6 +1634,7 @@ void usb_disconnect(struct usb_device **pdev)
|
|||||||
{
|
{
|
||||||
struct usb_device *udev = *pdev;
|
struct usb_device *udev = *pdev;
|
||||||
int i;
|
int i;
|
||||||
|
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
|
||||||
|
|
||||||
if (!udev) {
|
if (!udev) {
|
||||||
pr_debug ("%s nodev\n", __func__);
|
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.
|
* so that the hardware is now fully quiesced.
|
||||||
*/
|
*/
|
||||||
dev_dbg (&udev->dev, "unregistering device\n");
|
dev_dbg (&udev->dev, "unregistering device\n");
|
||||||
|
mutex_lock(hcd->bandwidth_mutex);
|
||||||
usb_disable_device(udev, 0);
|
usb_disable_device(udev, 0);
|
||||||
|
mutex_unlock(hcd->bandwidth_mutex);
|
||||||
usb_hcd_synchronize_unlinks(udev);
|
usb_hcd_synchronize_unlinks(udev);
|
||||||
|
|
||||||
usb_remove_ep_devs(&udev->ep0);
|
usb_remove_ep_devs(&udev->ep0);
|
||||||
|
@@ -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
|
* Deallocates hcd/hardware state for the endpoints (nuking all or most
|
||||||
* pending urbs) and usbcore state for the interfaces, so that usbcore
|
* pending urbs) and usbcore state for the interfaces, so that usbcore
|
||||||
* must usb_set_configuration() before any interfaces could be used.
|
* 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)
|
void usb_disable_device(struct usb_device *dev, int skip_ep0)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
struct usb_hcd *hcd = bus_to_hcd(dev->bus);
|
||||||
|
|
||||||
/* getting rid of interfaces will disconnect
|
/* getting rid of interfaces will disconnect
|
||||||
* any drivers bound to them (a key side effect)
|
* 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__,
|
dev_dbg(&dev->dev, "%s nuking %s URBs\n", __func__,
|
||||||
skip_ep0 ? "non-ep0" : "all");
|
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) {
|
for (i = skip_ep0; i < 16; ++i) {
|
||||||
usb_disable_endpoint(dev, i, true);
|
usb_disable_endpoint(dev, i, true);
|
||||||
usb_disable_endpoint(dev, i + USB_DIR_IN, true);
|
usb_disable_endpoint(dev, i + USB_DIR_IN, true);
|
||||||
@@ -1727,6 +1740,7 @@ free_interfaces:
|
|||||||
/* if it's already configured, clear out old state first.
|
/* if it's already configured, clear out old state first.
|
||||||
* getting rid of old interfaces means unbinding their drivers.
|
* getting rid of old interfaces means unbinding their drivers.
|
||||||
*/
|
*/
|
||||||
|
mutex_lock(hcd->bandwidth_mutex);
|
||||||
if (dev->state != USB_STATE_ADDRESS)
|
if (dev->state != USB_STATE_ADDRESS)
|
||||||
usb_disable_device(dev, 1); /* Skip ep0 */
|
usb_disable_device(dev, 1); /* Skip ep0 */
|
||||||
|
|
||||||
@@ -1739,7 +1753,6 @@ free_interfaces:
|
|||||||
* host controller will not allow submissions to dropped endpoints. If
|
* host controller will not allow submissions to dropped endpoints. If
|
||||||
* this call fails, the device state is unchanged.
|
* this call fails, the device state is unchanged.
|
||||||
*/
|
*/
|
||||||
mutex_lock(hcd->bandwidth_mutex);
|
|
||||||
ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL);
|
ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
mutex_unlock(hcd->bandwidth_mutex);
|
mutex_unlock(hcd->bandwidth_mutex);
|
||||||
|
@@ -1215,8 +1215,6 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
|
|||||||
ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet));
|
ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet));
|
||||||
/* dig out max burst from ep companion desc */
|
/* dig out max burst from ep companion desc */
|
||||||
max_packet = ep->ss_ep_comp.bMaxBurst;
|
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));
|
ep_ctx->ep_info2 |= cpu_to_le32(MAX_BURST(max_packet));
|
||||||
break;
|
break;
|
||||||
case USB_SPEED_HIGH:
|
case USB_SPEED_HIGH:
|
||||||
|
@@ -29,6 +29,9 @@
|
|||||||
#define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73
|
#define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73
|
||||||
#define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000
|
#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";
|
static const char hcd_name[] = "xhci_hcd";
|
||||||
|
|
||||||
/* called after powerup, by probe or system-pm "wakeup" */
|
/* 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->quirks |= XHCI_EP_LIMIT_QUIRK;
|
||||||
xhci->limit_active_eps = 64;
|
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. */
|
/* Make sure the HC is halted. */
|
||||||
retval = xhci_halt(xhci);
|
retval = xhci_halt(xhci);
|
||||||
|
@@ -1733,6 +1733,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
|||||||
frame->status = -EOVERFLOW;
|
frame->status = -EOVERFLOW;
|
||||||
skip_td = true;
|
skip_td = true;
|
||||||
break;
|
break;
|
||||||
|
case COMP_DEV_ERR:
|
||||||
case COMP_STALL:
|
case COMP_STALL:
|
||||||
frame->status = -EPROTO;
|
frame->status = -EPROTO;
|
||||||
skip_td = true;
|
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);
|
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;
|
idx = urb_priv->td_cnt;
|
||||||
frame = &td->urb->iso_frame_desc[idx];
|
frame = &td->urb->iso_frame_desc[idx];
|
||||||
|
|
||||||
/* The transfer is partly done */
|
/* The transfer is partly done. */
|
||||||
*status = -EXDEV;
|
|
||||||
frame->status = -EXDEV;
|
frame->status = -EXDEV;
|
||||||
|
|
||||||
/* calc actual length */
|
/* 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)),
|
TRB_TO_SLOT_ID(le32_to_cpu(event->flags)),
|
||||||
ep_index);
|
ep_index);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
case COMP_DEV_ERR:
|
||||||
|
xhci_warn(xhci, "WARN: detect an incompatible device");
|
||||||
|
status = -EPROTO;
|
||||||
|
break;
|
||||||
case COMP_MISSED_INT:
|
case COMP_MISSED_INT:
|
||||||
/*
|
/*
|
||||||
* When encounter missed service error, one or more isoc tds
|
* 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? */
|
/* Is this a TRB in the currently executing TD? */
|
||||||
event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue,
|
event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue,
|
||||||
td->last_trb, event_dma);
|
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 (!event_seg) {
|
||||||
if (!ep->skip ||
|
if (!ep->skip ||
|
||||||
!usb_endpoint_xfer_isoc(&td->urb->ep->desc)) {
|
!usb_endpoint_xfer_isoc(&td->urb->ep->desc)) {
|
||||||
@@ -2158,6 +2173,11 @@ cleanup:
|
|||||||
urb->transfer_buffer_length,
|
urb->transfer_buffer_length,
|
||||||
status);
|
status);
|
||||||
spin_unlock(&xhci->lock);
|
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);
|
usb_hcd_giveback_urb(bus_to_hcd(urb->dev->bus), urb, status);
|
||||||
spin_lock(&xhci->lock);
|
spin_lock(&xhci->lock);
|
||||||
}
|
}
|
||||||
|
@@ -759,6 +759,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
|
|||||||
msleep(100);
|
msleep(100);
|
||||||
|
|
||||||
spin_lock_irq(&xhci->lock);
|
spin_lock_irq(&xhci->lock);
|
||||||
|
if (xhci->quirks & XHCI_RESET_ON_RESUME)
|
||||||
|
hibernated = true;
|
||||||
|
|
||||||
if (!hibernated) {
|
if (!hibernated) {
|
||||||
/* step 1: restore register */
|
/* step 1: restore register */
|
||||||
@@ -1401,6 +1403,7 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
|
|||||||
u32 added_ctxs;
|
u32 added_ctxs;
|
||||||
unsigned int last_ctx;
|
unsigned int last_ctx;
|
||||||
u32 new_add_flags, new_drop_flags, new_slot_info;
|
u32 new_add_flags, new_drop_flags, new_slot_info;
|
||||||
|
struct xhci_virt_device *virt_dev;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
ret = xhci_check_args(hcd, udev, ep, 1, true, __func__);
|
ret = xhci_check_args(hcd, udev, ep, 1, true, __func__);
|
||||||
@@ -1425,11 +1428,25 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
in_ctx = xhci->devs[udev->slot_id]->in_ctx;
|
virt_dev = xhci->devs[udev->slot_id];
|
||||||
out_ctx = xhci->devs[udev->slot_id]->out_ctx;
|
in_ctx = virt_dev->in_ctx;
|
||||||
|
out_ctx = virt_dev->out_ctx;
|
||||||
ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
|
ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
|
||||||
ep_index = xhci_get_endpoint_index(&ep->desc);
|
ep_index = xhci_get_endpoint_index(&ep->desc);
|
||||||
ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index);
|
ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index);
|
||||||
|
|
||||||
|
/* If this endpoint is already in use, and the upper layers are trying
|
||||||
|
* to add it again without dropping it, reject the addition.
|
||||||
|
*/
|
||||||
|
if (virt_dev->eps[ep_index].ring &&
|
||||||
|
!(le32_to_cpu(ctrl_ctx->drop_flags) &
|
||||||
|
xhci_get_endpoint_flag(&ep->desc))) {
|
||||||
|
xhci_warn(xhci, "Trying to add endpoint 0x%x "
|
||||||
|
"without dropping it.\n",
|
||||||
|
(unsigned int) ep->desc.bEndpointAddress);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
/* If the HCD has already noted the endpoint is enabled,
|
/* If the HCD has already noted the endpoint is enabled,
|
||||||
* ignore this request.
|
* ignore this request.
|
||||||
*/
|
*/
|
||||||
@@ -1445,8 +1462,7 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
|
|||||||
* process context, not interrupt context (or so documenation
|
* process context, not interrupt context (or so documenation
|
||||||
* for usb_set_interface() and usb_set_configuration() claim).
|
* for usb_set_interface() and usb_set_configuration() claim).
|
||||||
*/
|
*/
|
||||||
if (xhci_endpoint_init(xhci, xhci->devs[udev->slot_id],
|
if (xhci_endpoint_init(xhci, virt_dev, udev, ep, GFP_NOIO) < 0) {
|
||||||
udev, ep, GFP_NOIO) < 0) {
|
|
||||||
dev_dbg(&udev->dev, "%s - could not initialize ep %#x\n",
|
dev_dbg(&udev->dev, "%s - could not initialize ep %#x\n",
|
||||||
__func__, ep->desc.bEndpointAddress);
|
__func__, ep->desc.bEndpointAddress);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@@ -1537,6 +1553,11 @@ static int xhci_configure_endpoint_result(struct xhci_hcd *xhci,
|
|||||||
"and endpoint is not disabled.\n");
|
"and endpoint is not disabled.\n");
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
break;
|
break;
|
||||||
|
case COMP_DEV_ERR:
|
||||||
|
dev_warn(&udev->dev, "ERROR: Incompatible device for endpoint "
|
||||||
|
"configure command.\n");
|
||||||
|
ret = -ENODEV;
|
||||||
|
break;
|
||||||
case COMP_SUCCESS:
|
case COMP_SUCCESS:
|
||||||
dev_dbg(&udev->dev, "Successful Endpoint Configure command\n");
|
dev_dbg(&udev->dev, "Successful Endpoint Configure command\n");
|
||||||
ret = 0;
|
ret = 0;
|
||||||
@@ -1571,6 +1592,11 @@ static int xhci_evaluate_context_result(struct xhci_hcd *xhci,
|
|||||||
xhci_dbg_ctx(xhci, virt_dev->out_ctx, 1);
|
xhci_dbg_ctx(xhci, virt_dev->out_ctx, 1);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
break;
|
break;
|
||||||
|
case COMP_DEV_ERR:
|
||||||
|
dev_warn(&udev->dev, "ERROR: Incompatible device for evaluate "
|
||||||
|
"context command.\n");
|
||||||
|
ret = -ENODEV;
|
||||||
|
break;
|
||||||
case COMP_MEL_ERR:
|
case COMP_MEL_ERR:
|
||||||
/* Max Exit Latency too large error */
|
/* Max Exit Latency too large error */
|
||||||
dev_warn(&udev->dev, "WARN: Max Exit Latency too large\n");
|
dev_warn(&udev->dev, "WARN: Max Exit Latency too large\n");
|
||||||
@@ -2853,6 +2879,11 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
|
|||||||
dev_warn(&udev->dev, "Device not responding to set address.\n");
|
dev_warn(&udev->dev, "Device not responding to set address.\n");
|
||||||
ret = -EPROTO;
|
ret = -EPROTO;
|
||||||
break;
|
break;
|
||||||
|
case COMP_DEV_ERR:
|
||||||
|
dev_warn(&udev->dev, "ERROR: Incompatible device for address "
|
||||||
|
"device command.\n");
|
||||||
|
ret = -ENODEV;
|
||||||
|
break;
|
||||||
case COMP_SUCCESS:
|
case COMP_SUCCESS:
|
||||||
xhci_dbg(xhci, "Successful Address Device command\n");
|
xhci_dbg(xhci, "Successful Address Device command\n");
|
||||||
break;
|
break;
|
||||||
|
@@ -874,6 +874,8 @@ struct xhci_transfer_event {
|
|||||||
#define COMP_PING_ERR 20
|
#define COMP_PING_ERR 20
|
||||||
/* Event Ring is full */
|
/* Event Ring is full */
|
||||||
#define COMP_ER_FULL 21
|
#define COMP_ER_FULL 21
|
||||||
|
/* Incompatible Device Error */
|
||||||
|
#define COMP_DEV_ERR 22
|
||||||
/* Missed Service Error - HC couldn't service an isoc ep within interval */
|
/* Missed Service Error - HC couldn't service an isoc ep within interval */
|
||||||
#define COMP_MISSED_INT 23
|
#define COMP_MISSED_INT 23
|
||||||
/* Successfully stopped command ring */
|
/* Successfully stopped command ring */
|
||||||
@@ -1308,6 +1310,7 @@ struct xhci_hcd {
|
|||||||
*/
|
*/
|
||||||
#define XHCI_EP_LIMIT_QUIRK (1 << 5)
|
#define XHCI_EP_LIMIT_QUIRK (1 << 5)
|
||||||
#define XHCI_BROKEN_MSI (1 << 6)
|
#define XHCI_BROKEN_MSI (1 << 6)
|
||||||
|
#define XHCI_RESET_ON_RESUME (1 << 7)
|
||||||
unsigned int num_active_eps;
|
unsigned int num_active_eps;
|
||||||
unsigned int limit_active_eps;
|
unsigned int limit_active_eps;
|
||||||
/* There are two roothubs to keep track of bus suspend info for */
|
/* There are two roothubs to keep track of bus suspend info for */
|
||||||
|
Reference in New Issue
Block a user