Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (143 commits) USB: xhci depends on PCI. USB: xhci: Add Makefile, MAINTAINERS, and Kconfig entries. USB: xhci: Respect critical sections. USB: xHCI: Fix interrupt moderation. USB: xhci: Remove packed attribute from structures. usb; xhci: Fix TRB offset calculations. USB: xhci: replace if-elseif-else with switch-case USB: xhci: Make xhci-mem.c include linux/dmapool.h USB: xhci: drop spinlock in xhci_urb_enqueue() error path. USB: Change names of SuperSpeed ep companion descriptor structs. USB: xhci: Avoid compiler reordering in Link TRB giveback. USB: xhci: Clean up xhci_irq() function. USB: xhci: Avoid global namespace pollution. USB: xhci: Fix Link TRB handoff bit twiddling. USB: xhci: Fix register write order. USB: xhci: fix some compiler warnings in xhci.h USB: xhci: fix lots of compiler warnings. USB: xhci: use xhci_handle_event instead of handle_event USB: xhci: URB cancellation support. USB: xhci: Scatter gather list support for bulk transfers. ...
This commit is contained in:
@@ -28,7 +28,7 @@ comment "Miscellaneous USB options"
|
||||
depends on USB
|
||||
|
||||
config USB_DEVICEFS
|
||||
bool "USB device filesystem"
|
||||
bool "USB device filesystem (DEPRECATED)" if EMBEDDED
|
||||
depends on USB
|
||||
---help---
|
||||
If you say Y here (and to "/proc file system support" in the "File
|
||||
@@ -46,11 +46,15 @@ config USB_DEVICEFS
|
||||
For the format of the various /proc/bus/usb/ files, please read
|
||||
<file:Documentation/usb/proc_usb_info.txt>.
|
||||
|
||||
Usbfs files can't handle Access Control Lists (ACL), which are the
|
||||
default way to grant access to USB devices for untrusted users of a
|
||||
desktop system. The usbfs functionality is replaced by real
|
||||
device-nodes managed by udev. These nodes live in /dev/bus/usb and
|
||||
are used by libusb.
|
||||
Modern Linux systems do not use this.
|
||||
|
||||
Usbfs entries are files and not character devices; usbfs can't
|
||||
handle Access Control Lists (ACL) which are the default way to
|
||||
grant access to USB devices for untrusted users of a desktop
|
||||
system.
|
||||
|
||||
The usbfs functionality is replaced by real device-nodes managed by
|
||||
udev. These nodes lived in /dev/bus/usb and are used by libusb.
|
||||
|
||||
config USB_DEVICE_CLASS
|
||||
bool "USB device class-devices (DEPRECATED)"
|
||||
|
@@ -4,14 +4,14 @@
|
||||
|
||||
usbcore-objs := usb.o hub.o hcd.o urb.o message.o driver.o \
|
||||
config.o file.o buffer.o sysfs.o endpoint.o \
|
||||
devio.o notify.o generic.o quirks.o
|
||||
devio.o notify.o generic.o quirks.o devices.o
|
||||
|
||||
ifeq ($(CONFIG_PCI),y)
|
||||
usbcore-objs += hcd-pci.o
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_USB_DEVICEFS),y)
|
||||
usbcore-objs += inode.o devices.o
|
||||
usbcore-objs += inode.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_USB) += usbcore.o
|
||||
|
@@ -19,6 +19,32 @@ static inline const char *plural(int n)
|
||||
return (n == 1 ? "" : "s");
|
||||
}
|
||||
|
||||
/* FIXME: this is a kludge */
|
||||
static int find_next_descriptor_more(unsigned char *buffer, int size,
|
||||
int dt1, int dt2, int dt3, int *num_skipped)
|
||||
{
|
||||
struct usb_descriptor_header *h;
|
||||
int n = 0;
|
||||
unsigned char *buffer0 = buffer;
|
||||
|
||||
/* Find the next descriptor of type dt1 or dt2 or dt3 */
|
||||
while (size > 0) {
|
||||
h = (struct usb_descriptor_header *) buffer;
|
||||
if (h->bDescriptorType == dt1 || h->bDescriptorType == dt2 ||
|
||||
h->bDescriptorType == dt3)
|
||||
break;
|
||||
buffer += h->bLength;
|
||||
size -= h->bLength;
|
||||
++n;
|
||||
}
|
||||
|
||||
/* Store the number of descriptors skipped and return the
|
||||
* number of bytes skipped */
|
||||
if (num_skipped)
|
||||
*num_skipped = n;
|
||||
return buffer - buffer0;
|
||||
}
|
||||
|
||||
static int find_next_descriptor(unsigned char *buffer, int size,
|
||||
int dt1, int dt2, int *num_skipped)
|
||||
{
|
||||
@@ -43,6 +69,129 @@ static int find_next_descriptor(unsigned char *buffer, int size,
|
||||
return buffer - buffer0;
|
||||
}
|
||||
|
||||
static int usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
|
||||
int inum, int asnum, struct usb_host_endpoint *ep,
|
||||
int num_ep, unsigned char *buffer, int size)
|
||||
{
|
||||
unsigned char *buffer_start = buffer;
|
||||
struct usb_ss_ep_comp_descriptor *desc;
|
||||
int retval;
|
||||
int num_skipped;
|
||||
int max_tx;
|
||||
int i;
|
||||
|
||||
/* Allocate space for the SS endpoint companion descriptor */
|
||||
ep->ss_ep_comp = kzalloc(sizeof(struct usb_host_ss_ep_comp),
|
||||
GFP_KERNEL);
|
||||
if (!ep->ss_ep_comp)
|
||||
return -ENOMEM;
|
||||
desc = (struct usb_ss_ep_comp_descriptor *) buffer;
|
||||
if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP) {
|
||||
dev_warn(ddev, "No SuperSpeed endpoint companion for config %d "
|
||||
" interface %d altsetting %d ep %d: "
|
||||
"using minimum values\n",
|
||||
cfgno, inum, asnum, ep->desc.bEndpointAddress);
|
||||
ep->ss_ep_comp->desc.bLength = USB_DT_SS_EP_COMP_SIZE;
|
||||
ep->ss_ep_comp->desc.bDescriptorType = USB_DT_SS_ENDPOINT_COMP;
|
||||
ep->ss_ep_comp->desc.bMaxBurst = 0;
|
||||
/*
|
||||
* Leave bmAttributes as zero, which will mean no streams for
|
||||
* bulk, and isoc won't support multiple bursts of packets.
|
||||
* With bursts of only one packet, and a Mult of 1, the max
|
||||
* amount of data moved per endpoint service interval is one
|
||||
* packet.
|
||||
*/
|
||||
if (usb_endpoint_xfer_isoc(&ep->desc) ||
|
||||
usb_endpoint_xfer_int(&ep->desc))
|
||||
ep->ss_ep_comp->desc.wBytesPerInterval =
|
||||
ep->desc.wMaxPacketSize;
|
||||
/*
|
||||
* The next descriptor is for an Endpoint or Interface,
|
||||
* no extra descriptors to copy into the companion structure,
|
||||
* and we didn't eat up any of the buffer.
|
||||
*/
|
||||
retval = 0;
|
||||
goto valid;
|
||||
}
|
||||
memcpy(&ep->ss_ep_comp->desc, desc, USB_DT_SS_EP_COMP_SIZE);
|
||||
desc = &ep->ss_ep_comp->desc;
|
||||
buffer += desc->bLength;
|
||||
size -= desc->bLength;
|
||||
|
||||
/* Eat up the other descriptors we don't care about */
|
||||
ep->ss_ep_comp->extra = buffer;
|
||||
i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
|
||||
USB_DT_INTERFACE, &num_skipped);
|
||||
ep->ss_ep_comp->extralen = i;
|
||||
buffer += i;
|
||||
size -= i;
|
||||
retval = buffer - buffer_start + i;
|
||||
if (num_skipped > 0)
|
||||
dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
|
||||
num_skipped, plural(num_skipped),
|
||||
"SuperSpeed endpoint companion");
|
||||
|
||||
/* Check the various values */
|
||||
if (usb_endpoint_xfer_control(&ep->desc) && desc->bMaxBurst != 0) {
|
||||
dev_warn(ddev, "Control endpoint with bMaxBurst = %d in "
|
||||
"config %d interface %d altsetting %d ep %d: "
|
||||
"setting to zero\n", desc->bMaxBurst,
|
||||
cfgno, inum, asnum, ep->desc.bEndpointAddress);
|
||||
desc->bMaxBurst = 0;
|
||||
}
|
||||
if (desc->bMaxBurst > 15) {
|
||||
dev_warn(ddev, "Endpoint with bMaxBurst = %d in "
|
||||
"config %d interface %d altsetting %d ep %d: "
|
||||
"setting to 15\n", desc->bMaxBurst,
|
||||
cfgno, inum, asnum, ep->desc.bEndpointAddress);
|
||||
desc->bMaxBurst = 15;
|
||||
}
|
||||
if ((usb_endpoint_xfer_control(&ep->desc) || usb_endpoint_xfer_int(&ep->desc))
|
||||
&& desc->bmAttributes != 0) {
|
||||
dev_warn(ddev, "%s endpoint with bmAttributes = %d in "
|
||||
"config %d interface %d altsetting %d ep %d: "
|
||||
"setting to zero\n",
|
||||
usb_endpoint_xfer_control(&ep->desc) ? "Control" : "Bulk",
|
||||
desc->bmAttributes,
|
||||
cfgno, inum, asnum, ep->desc.bEndpointAddress);
|
||||
desc->bmAttributes = 0;
|
||||
}
|
||||
if (usb_endpoint_xfer_bulk(&ep->desc) && desc->bmAttributes > 16) {
|
||||
dev_warn(ddev, "Bulk endpoint with more than 65536 streams in "
|
||||
"config %d interface %d altsetting %d ep %d: "
|
||||
"setting to max\n",
|
||||
cfgno, inum, asnum, ep->desc.bEndpointAddress);
|
||||
desc->bmAttributes = 16;
|
||||
}
|
||||
if (usb_endpoint_xfer_isoc(&ep->desc) && desc->bmAttributes > 2) {
|
||||
dev_warn(ddev, "Isoc endpoint has Mult of %d in "
|
||||
"config %d interface %d altsetting %d ep %d: "
|
||||
"setting to 3\n", desc->bmAttributes + 1,
|
||||
cfgno, inum, asnum, ep->desc.bEndpointAddress);
|
||||
desc->bmAttributes = 2;
|
||||
}
|
||||
if (usb_endpoint_xfer_isoc(&ep->desc)) {
|
||||
max_tx = ep->desc.wMaxPacketSize * (desc->bMaxBurst + 1) *
|
||||
(desc->bmAttributes + 1);
|
||||
} else if (usb_endpoint_xfer_int(&ep->desc)) {
|
||||
max_tx = ep->desc.wMaxPacketSize * (desc->bMaxBurst + 1);
|
||||
} else {
|
||||
goto valid;
|
||||
}
|
||||
if (desc->wBytesPerInterval > max_tx) {
|
||||
dev_warn(ddev, "%s endpoint with wBytesPerInterval of %d in "
|
||||
"config %d interface %d altsetting %d ep %d: "
|
||||
"setting to %d\n",
|
||||
usb_endpoint_xfer_isoc(&ep->desc) ? "Isoc" : "Int",
|
||||
desc->wBytesPerInterval,
|
||||
cfgno, inum, asnum, ep->desc.bEndpointAddress,
|
||||
max_tx);
|
||||
desc->wBytesPerInterval = max_tx;
|
||||
}
|
||||
valid:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
|
||||
int asnum, struct usb_host_interface *ifp, int num_ep,
|
||||
unsigned char *buffer, int size)
|
||||
@@ -50,7 +199,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
|
||||
unsigned char *buffer0 = buffer;
|
||||
struct usb_endpoint_descriptor *d;
|
||||
struct usb_host_endpoint *endpoint;
|
||||
int n, i, j;
|
||||
int n, i, j, retval;
|
||||
|
||||
d = (struct usb_endpoint_descriptor *) buffer;
|
||||
buffer += d->bLength;
|
||||
@@ -92,6 +241,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
|
||||
if (usb_endpoint_xfer_int(d)) {
|
||||
i = 1;
|
||||
switch (to_usb_device(ddev)->speed) {
|
||||
case USB_SPEED_SUPER:
|
||||
case USB_SPEED_HIGH:
|
||||
/* Many device manufacturers are using full-speed
|
||||
* bInterval values in high-speed interrupt endpoint
|
||||
@@ -161,17 +311,39 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
|
||||
cfgno, inum, asnum, d->bEndpointAddress,
|
||||
maxp);
|
||||
}
|
||||
/* Allocate room for and parse any SS endpoint companion descriptors */
|
||||
if (to_usb_device(ddev)->speed == USB_SPEED_SUPER) {
|
||||
endpoint->extra = buffer;
|
||||
i = find_next_descriptor_more(buffer, size, USB_DT_SS_ENDPOINT_COMP,
|
||||
USB_DT_ENDPOINT, USB_DT_INTERFACE, &n);
|
||||
endpoint->extralen = i;
|
||||
buffer += i;
|
||||
size -= i;
|
||||
|
||||
/* Skip over any Class Specific or Vendor Specific descriptors;
|
||||
* find the next endpoint or interface descriptor */
|
||||
endpoint->extra = buffer;
|
||||
i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
|
||||
USB_DT_INTERFACE, &n);
|
||||
endpoint->extralen = i;
|
||||
if (size > 0) {
|
||||
retval = usb_parse_ss_endpoint_companion(ddev, cfgno,
|
||||
inum, asnum, endpoint, num_ep, buffer,
|
||||
size);
|
||||
if (retval >= 0) {
|
||||
buffer += retval;
|
||||
retval = buffer - buffer0;
|
||||
}
|
||||
} else {
|
||||
retval = buffer - buffer0;
|
||||
}
|
||||
} else {
|
||||
/* Skip over any Class Specific or Vendor Specific descriptors;
|
||||
* find the next endpoint or interface descriptor */
|
||||
endpoint->extra = buffer;
|
||||
i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
|
||||
USB_DT_INTERFACE, &n);
|
||||
endpoint->extralen = i;
|
||||
retval = buffer - buffer0 + i;
|
||||
}
|
||||
if (n > 0)
|
||||
dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
|
||||
n, plural(n), "endpoint");
|
||||
return buffer - buffer0 + i;
|
||||
return retval;
|
||||
|
||||
skip_to_next_endpoint_or_interface_descriptor:
|
||||
i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
|
||||
@@ -452,6 +624,8 @@ static int usb_parse_configuration(struct device *ddev, int cfgidx,
|
||||
kref_init(&intfc->ref);
|
||||
}
|
||||
|
||||
/* FIXME: parse the BOS descriptor */
|
||||
|
||||
/* Skip over any Class Specific or Vendor Specific descriptors;
|
||||
* find the first interface descriptor */
|
||||
config->extra = buffer;
|
||||
|
@@ -154,16 +154,11 @@ static const struct usb_device_id *usb_match_dynamic_id(struct usb_interface *in
|
||||
static int usb_probe_device(struct device *dev)
|
||||
{
|
||||
struct usb_device_driver *udriver = to_usb_device_driver(dev->driver);
|
||||
struct usb_device *udev;
|
||||
struct usb_device *udev = to_usb_device(dev);
|
||||
int error = -ENODEV;
|
||||
|
||||
dev_dbg(dev, "%s\n", __func__);
|
||||
|
||||
if (!is_usb_device(dev)) /* Sanity check */
|
||||
return error;
|
||||
|
||||
udev = to_usb_device(dev);
|
||||
|
||||
/* TODO: Add real matching code */
|
||||
|
||||
/* The device should always appear to be in use
|
||||
@@ -203,18 +198,13 @@ static void usb_cancel_queued_reset(struct usb_interface *iface)
|
||||
static int usb_probe_interface(struct device *dev)
|
||||
{
|
||||
struct usb_driver *driver = to_usb_driver(dev->driver);
|
||||
struct usb_interface *intf;
|
||||
struct usb_device *udev;
|
||||
struct usb_interface *intf = to_usb_interface(dev);
|
||||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
const struct usb_device_id *id;
|
||||
int error = -ENODEV;
|
||||
|
||||
dev_dbg(dev, "%s\n", __func__);
|
||||
|
||||
if (is_usb_device(dev)) /* Sanity check */
|
||||
return error;
|
||||
|
||||
intf = to_usb_interface(dev);
|
||||
udev = interface_to_usbdev(intf);
|
||||
intf->needs_binding = 0;
|
||||
|
||||
if (udev->authorized == 0) {
|
||||
@@ -385,7 +375,6 @@ void usb_driver_release_interface(struct usb_driver *driver,
|
||||
struct usb_interface *iface)
|
||||
{
|
||||
struct device *dev = &iface->dev;
|
||||
struct usb_device *udev = interface_to_usbdev(iface);
|
||||
|
||||
/* this should never happen, don't release something that's not ours */
|
||||
if (!dev->driver || dev->driver != &driver->drvwrap.driver)
|
||||
@@ -394,23 +383,19 @@ void usb_driver_release_interface(struct usb_driver *driver,
|
||||
/* don't release from within disconnect() */
|
||||
if (iface->condition != USB_INTERFACE_BOUND)
|
||||
return;
|
||||
iface->condition = USB_INTERFACE_UNBINDING;
|
||||
|
||||
/* don't release if the interface hasn't been added yet */
|
||||
/* Release via the driver core only if the interface
|
||||
* has already been registered
|
||||
*/
|
||||
if (device_is_registered(dev)) {
|
||||
iface->condition = USB_INTERFACE_UNBINDING;
|
||||
device_release_driver(dev);
|
||||
} else {
|
||||
iface->condition = USB_INTERFACE_UNBOUND;
|
||||
usb_cancel_queued_reset(iface);
|
||||
down(&dev->sem);
|
||||
usb_unbind_interface(dev);
|
||||
dev->driver = NULL;
|
||||
up(&dev->sem);
|
||||
}
|
||||
dev->driver = NULL;
|
||||
usb_set_intfdata(iface, NULL);
|
||||
|
||||
usb_pm_lock(udev);
|
||||
iface->condition = USB_INTERFACE_UNBOUND;
|
||||
mark_quiesced(iface);
|
||||
iface->needs_remote_wakeup = 0;
|
||||
usb_pm_unlock(udev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_driver_release_interface);
|
||||
|
||||
@@ -598,7 +583,7 @@ static int usb_device_match(struct device *dev, struct device_driver *drv)
|
||||
/* TODO: Add real matching code */
|
||||
return 1;
|
||||
|
||||
} else {
|
||||
} else if (is_usb_interface(dev)) {
|
||||
struct usb_interface *intf;
|
||||
struct usb_driver *usb_drv;
|
||||
const struct usb_device_id *id;
|
||||
@@ -630,11 +615,14 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
/* driver is often null here; dev_dbg() would oops */
|
||||
pr_debug("usb %s: uevent\n", dev_name(dev));
|
||||
|
||||
if (is_usb_device(dev))
|
||||
if (is_usb_device(dev)) {
|
||||
usb_dev = to_usb_device(dev);
|
||||
else {
|
||||
} else if (is_usb_interface(dev)) {
|
||||
struct usb_interface *intf = to_usb_interface(dev);
|
||||
|
||||
usb_dev = interface_to_usbdev(intf);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (usb_dev->devnum < 0) {
|
||||
@@ -1762,6 +1750,7 @@ int usb_suspend(struct device *dev, pm_message_t msg)
|
||||
int usb_resume(struct device *dev, pm_message_t msg)
|
||||
{
|
||||
struct usb_device *udev;
|
||||
int status;
|
||||
|
||||
udev = to_usb_device(dev);
|
||||
|
||||
@@ -1771,7 +1760,14 @@ int usb_resume(struct device *dev, pm_message_t msg)
|
||||
*/
|
||||
if (udev->skip_sys_resume)
|
||||
return 0;
|
||||
return usb_external_resume_device(udev, msg);
|
||||
status = usb_external_resume_device(udev, msg);
|
||||
|
||||
/* Avoid PM error messages for devices disconnected while suspended
|
||||
* as we'll display regular disconnect messages just a bit later.
|
||||
*/
|
||||
if (status == -ENODEV)
|
||||
return 0;
|
||||
return status;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PM */
|
||||
|
@@ -15,19 +15,18 @@
|
||||
#include <linux/usb.h>
|
||||
#include "usb.h"
|
||||
|
||||
#define MAX_ENDPOINT_MINORS (64*128*32)
|
||||
static int usb_endpoint_major;
|
||||
static DEFINE_IDR(endpoint_idr);
|
||||
|
||||
struct ep_device {
|
||||
struct usb_endpoint_descriptor *desc;
|
||||
struct usb_device *udev;
|
||||
struct device dev;
|
||||
int minor;
|
||||
};
|
||||
#define to_ep_device(_dev) \
|
||||
container_of(_dev, struct ep_device, dev)
|
||||
|
||||
struct device_type usb_ep_device_type = {
|
||||
.name = "usb_endpoint",
|
||||
};
|
||||
|
||||
struct ep_attribute {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct usb_device *,
|
||||
@@ -160,118 +159,10 @@ static struct attribute_group *ep_dev_groups[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static int usb_endpoint_major_init(void)
|
||||
{
|
||||
dev_t dev;
|
||||
int error;
|
||||
|
||||
error = alloc_chrdev_region(&dev, 0, MAX_ENDPOINT_MINORS,
|
||||
"usb_endpoint");
|
||||
if (error) {
|
||||
printk(KERN_ERR "Unable to get a dynamic major for "
|
||||
"usb endpoints.\n");
|
||||
return error;
|
||||
}
|
||||
usb_endpoint_major = MAJOR(dev);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static void usb_endpoint_major_cleanup(void)
|
||||
{
|
||||
unregister_chrdev_region(MKDEV(usb_endpoint_major, 0),
|
||||
MAX_ENDPOINT_MINORS);
|
||||
}
|
||||
|
||||
static int endpoint_get_minor(struct ep_device *ep_dev)
|
||||
{
|
||||
static DEFINE_MUTEX(minor_lock);
|
||||
int retval = -ENOMEM;
|
||||
int id;
|
||||
|
||||
mutex_lock(&minor_lock);
|
||||
if (idr_pre_get(&endpoint_idr, GFP_KERNEL) == 0)
|
||||
goto exit;
|
||||
|
||||
retval = idr_get_new(&endpoint_idr, ep_dev, &id);
|
||||
if (retval < 0) {
|
||||
if (retval == -EAGAIN)
|
||||
retval = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
ep_dev->minor = id & MAX_ID_MASK;
|
||||
exit:
|
||||
mutex_unlock(&minor_lock);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void endpoint_free_minor(struct ep_device *ep_dev)
|
||||
{
|
||||
idr_remove(&endpoint_idr, ep_dev->minor);
|
||||
}
|
||||
|
||||
static struct endpoint_class {
|
||||
struct kref kref;
|
||||
struct class *class;
|
||||
} *ep_class;
|
||||
|
||||
static int init_endpoint_class(void)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
if (ep_class != NULL) {
|
||||
kref_get(&ep_class->kref);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ep_class = kmalloc(sizeof(*ep_class), GFP_KERNEL);
|
||||
if (!ep_class) {
|
||||
result = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
kref_init(&ep_class->kref);
|
||||
ep_class->class = class_create(THIS_MODULE, "usb_endpoint");
|
||||
if (IS_ERR(ep_class->class)) {
|
||||
result = PTR_ERR(ep_class->class);
|
||||
goto class_create_error;
|
||||
}
|
||||
|
||||
result = usb_endpoint_major_init();
|
||||
if (result)
|
||||
goto endpoint_major_error;
|
||||
|
||||
goto exit;
|
||||
|
||||
endpoint_major_error:
|
||||
class_destroy(ep_class->class);
|
||||
class_create_error:
|
||||
kfree(ep_class);
|
||||
ep_class = NULL;
|
||||
exit:
|
||||
return result;
|
||||
}
|
||||
|
||||
static void release_endpoint_class(struct kref *kref)
|
||||
{
|
||||
/* Ok, we cheat as we know we only have one ep_class */
|
||||
class_destroy(ep_class->class);
|
||||
kfree(ep_class);
|
||||
ep_class = NULL;
|
||||
usb_endpoint_major_cleanup();
|
||||
}
|
||||
|
||||
static void destroy_endpoint_class(void)
|
||||
{
|
||||
if (ep_class)
|
||||
kref_put(&ep_class->kref, release_endpoint_class);
|
||||
}
|
||||
|
||||
static void ep_device_release(struct device *dev)
|
||||
{
|
||||
struct ep_device *ep_dev = to_ep_device(dev);
|
||||
|
||||
endpoint_free_minor(ep_dev);
|
||||
kfree(ep_dev);
|
||||
}
|
||||
|
||||
@@ -279,62 +170,32 @@ int usb_create_ep_devs(struct device *parent,
|
||||
struct usb_host_endpoint *endpoint,
|
||||
struct usb_device *udev)
|
||||
{
|
||||
char name[8];
|
||||
struct ep_device *ep_dev;
|
||||
int retval;
|
||||
|
||||
retval = init_endpoint_class();
|
||||
if (retval)
|
||||
goto exit;
|
||||
|
||||
ep_dev = kzalloc(sizeof(*ep_dev), GFP_KERNEL);
|
||||
if (!ep_dev) {
|
||||
retval = -ENOMEM;
|
||||
goto error_alloc;
|
||||
}
|
||||
|
||||
retval = endpoint_get_minor(ep_dev);
|
||||
if (retval) {
|
||||
dev_err(parent, "can not allocate minor number for %s\n",
|
||||
dev_name(&ep_dev->dev));
|
||||
goto error_register;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ep_dev->desc = &endpoint->desc;
|
||||
ep_dev->udev = udev;
|
||||
ep_dev->dev.groups = ep_dev_groups;
|
||||
ep_dev->dev.devt = MKDEV(usb_endpoint_major, ep_dev->minor);
|
||||
ep_dev->dev.class = ep_class->class;
|
||||
ep_dev->dev.type = &usb_ep_device_type;
|
||||
ep_dev->dev.parent = parent;
|
||||
ep_dev->dev.release = ep_device_release;
|
||||
dev_set_name(&ep_dev->dev, "usbdev%d.%d_ep%02x",
|
||||
udev->bus->busnum, udev->devnum,
|
||||
endpoint->desc.bEndpointAddress);
|
||||
dev_set_name(&ep_dev->dev, "ep_%02x", endpoint->desc.bEndpointAddress);
|
||||
|
||||
retval = device_register(&ep_dev->dev);
|
||||
if (retval)
|
||||
goto error_chrdev;
|
||||
goto error_register;
|
||||
|
||||
/* create the symlink to the old-style "ep_XX" directory */
|
||||
sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress);
|
||||
retval = sysfs_create_link(&parent->kobj, &ep_dev->dev.kobj, name);
|
||||
if (retval)
|
||||
goto error_link;
|
||||
endpoint->ep_dev = ep_dev;
|
||||
return retval;
|
||||
|
||||
error_link:
|
||||
device_unregister(&ep_dev->dev);
|
||||
destroy_endpoint_class();
|
||||
return retval;
|
||||
|
||||
error_chrdev:
|
||||
endpoint_free_minor(ep_dev);
|
||||
|
||||
error_register:
|
||||
kfree(ep_dev);
|
||||
error_alloc:
|
||||
destroy_endpoint_class();
|
||||
exit:
|
||||
return retval;
|
||||
}
|
||||
@@ -344,12 +205,7 @@ void usb_remove_ep_devs(struct usb_host_endpoint *endpoint)
|
||||
struct ep_device *ep_dev = endpoint->ep_dev;
|
||||
|
||||
if (ep_dev) {
|
||||
char name[8];
|
||||
|
||||
sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress);
|
||||
sysfs_remove_link(&ep_dev->dev.parent->kobj, name);
|
||||
device_unregister(&ep_dev->dev);
|
||||
endpoint->ep_dev = NULL;
|
||||
destroy_endpoint_class();
|
||||
}
|
||||
}
|
||||
|
@@ -185,180 +185,6 @@ void usb_hcd_pci_remove(struct pci_dev *dev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_hcd_pci_remove);
|
||||
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
/**
|
||||
* usb_hcd_pci_suspend - power management suspend of a PCI-based HCD
|
||||
* @dev: USB Host Controller being suspended
|
||||
* @message: Power Management message describing this state transition
|
||||
*
|
||||
* Store this function in the HCD's struct pci_driver as .suspend.
|
||||
*/
|
||||
int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t message)
|
||||
{
|
||||
struct usb_hcd *hcd = pci_get_drvdata(dev);
|
||||
int retval = 0;
|
||||
int wake, w;
|
||||
int has_pci_pm;
|
||||
|
||||
/* Root hub suspend should have stopped all downstream traffic,
|
||||
* and all bus master traffic. And done so for both the interface
|
||||
* and the stub usb_device (which we check here). But maybe it
|
||||
* didn't; writing sysfs power/state files ignores such rules...
|
||||
*
|
||||
* We must ignore the FREEZE vs SUSPEND distinction here, because
|
||||
* otherwise the swsusp will save (and restore) garbage state.
|
||||
*/
|
||||
if (!(hcd->state == HC_STATE_SUSPENDED ||
|
||||
hcd->state == HC_STATE_HALT)) {
|
||||
dev_warn(&dev->dev, "Root hub is not suspended\n");
|
||||
retval = -EBUSY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* We might already be suspended (runtime PM -- not yet written) */
|
||||
if (dev->current_state != PCI_D0)
|
||||
goto done;
|
||||
|
||||
if (hcd->driver->pci_suspend) {
|
||||
retval = hcd->driver->pci_suspend(hcd, message);
|
||||
suspend_report_result(hcd->driver->pci_suspend, retval);
|
||||
if (retval)
|
||||
goto done;
|
||||
}
|
||||
|
||||
synchronize_irq(dev->irq);
|
||||
|
||||
/* Downstream ports from this root hub should already be quiesced, so
|
||||
* there will be no DMA activity. Now we can shut down the upstream
|
||||
* link (except maybe for PME# resume signaling) and enter some PCI
|
||||
* low power state, if the hardware allows.
|
||||
*/
|
||||
pci_disable_device(dev);
|
||||
|
||||
pci_save_state(dev);
|
||||
|
||||
/* Don't fail on error to enable wakeup. We rely on pci code
|
||||
* to reject requests the hardware can't implement, rather
|
||||
* than coding the same thing.
|
||||
*/
|
||||
wake = (hcd->state == HC_STATE_SUSPENDED &&
|
||||
device_may_wakeup(&dev->dev));
|
||||
w = pci_wake_from_d3(dev, wake);
|
||||
if (w < 0)
|
||||
wake = w;
|
||||
dev_dbg(&dev->dev, "wakeup: %d\n", wake);
|
||||
|
||||
/* Don't change state if we don't need to */
|
||||
if (message.event == PM_EVENT_FREEZE ||
|
||||
message.event == PM_EVENT_PRETHAW) {
|
||||
dev_dbg(&dev->dev, "--> no state change\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM);
|
||||
if (!has_pci_pm) {
|
||||
dev_dbg(&dev->dev, "--> PCI D0 legacy\n");
|
||||
} else {
|
||||
|
||||
/* NOTE: dev->current_state becomes nonzero only here, and
|
||||
* only for devices that support PCI PM. Also, exiting
|
||||
* PCI_D3 (but not PCI_D1 or PCI_D2) is allowed to reset
|
||||
* some device state (e.g. as part of clock reinit).
|
||||
*/
|
||||
retval = pci_set_power_state(dev, PCI_D3hot);
|
||||
suspend_report_result(pci_set_power_state, retval);
|
||||
if (retval == 0) {
|
||||
dev_dbg(&dev->dev, "--> PCI D3\n");
|
||||
} else {
|
||||
dev_dbg(&dev->dev, "PCI D3 suspend fail, %d\n",
|
||||
retval);
|
||||
pci_restore_state(dev);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PPC_PMAC
|
||||
if (retval == 0) {
|
||||
/* Disable ASIC clocks for USB */
|
||||
if (machine_is(powermac)) {
|
||||
struct device_node *of_node;
|
||||
|
||||
of_node = pci_device_to_OF_node(dev);
|
||||
if (of_node)
|
||||
pmac_call_feature(PMAC_FTR_USB_ENABLE,
|
||||
of_node, 0, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_hcd_pci_suspend);
|
||||
|
||||
/**
|
||||
* usb_hcd_pci_resume - power management resume of a PCI-based HCD
|
||||
* @dev: USB Host Controller being resumed
|
||||
*
|
||||
* Store this function in the HCD's struct pci_driver as .resume.
|
||||
*/
|
||||
int usb_hcd_pci_resume(struct pci_dev *dev)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
int retval;
|
||||
|
||||
#ifdef CONFIG_PPC_PMAC
|
||||
/* Reenable ASIC clocks for USB */
|
||||
if (machine_is(powermac)) {
|
||||
struct device_node *of_node;
|
||||
|
||||
of_node = pci_device_to_OF_node(dev);
|
||||
if (of_node)
|
||||
pmac_call_feature(PMAC_FTR_USB_ENABLE,
|
||||
of_node, 0, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
pci_restore_state(dev);
|
||||
|
||||
hcd = pci_get_drvdata(dev);
|
||||
if (hcd->state != HC_STATE_SUSPENDED) {
|
||||
dev_dbg(hcd->self.controller,
|
||||
"can't resume, not suspended!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pci_enable_wake(dev, PCI_D0, false);
|
||||
|
||||
retval = pci_enable_device(dev);
|
||||
if (retval < 0) {
|
||||
dev_err(&dev->dev, "can't re-enable after resume, %d!\n",
|
||||
retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
pci_set_master(dev);
|
||||
|
||||
/* yes, ignore this result too... */
|
||||
(void) pci_wake_from_d3(dev, 0);
|
||||
|
||||
clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
|
||||
|
||||
if (hcd->driver->pci_resume) {
|
||||
retval = hcd->driver->pci_resume(hcd);
|
||||
if (retval) {
|
||||
dev_err(hcd->self.controller,
|
||||
"PCI post-resume error %d!\n", retval);
|
||||
usb_hc_died(hcd);
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_hcd_pci_resume);
|
||||
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
/**
|
||||
* usb_hcd_pci_shutdown - shutdown host controller
|
||||
* @dev: USB Host Controller being shutdown
|
||||
@@ -376,3 +202,181 @@ void usb_hcd_pci_shutdown(struct pci_dev *dev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_hcd_pci_shutdown);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
||||
static int check_root_hub_suspended(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pci_dev = to_pci_dev(dev);
|
||||
struct usb_hcd *hcd = pci_get_drvdata(pci_dev);
|
||||
|
||||
if (!(hcd->state == HC_STATE_SUSPENDED ||
|
||||
hcd->state == HC_STATE_HALT)) {
|
||||
dev_warn(dev, "Root hub is not suspended\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hcd_pci_suspend(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pci_dev = to_pci_dev(dev);
|
||||
struct usb_hcd *hcd = pci_get_drvdata(pci_dev);
|
||||
int retval;
|
||||
|
||||
/* Root hub suspend should have stopped all downstream traffic,
|
||||
* and all bus master traffic. And done so for both the interface
|
||||
* and the stub usb_device (which we check here). But maybe it
|
||||
* didn't; writing sysfs power/state files ignores such rules...
|
||||
*/
|
||||
retval = check_root_hub_suspended(dev);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/* We might already be suspended (runtime PM -- not yet written) */
|
||||
if (pci_dev->current_state != PCI_D0)
|
||||
return retval;
|
||||
|
||||
if (hcd->driver->pci_suspend) {
|
||||
retval = hcd->driver->pci_suspend(hcd);
|
||||
suspend_report_result(hcd->driver->pci_suspend, retval);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
|
||||
synchronize_irq(pci_dev->irq);
|
||||
|
||||
/* Downstream ports from this root hub should already be quiesced, so
|
||||
* there will be no DMA activity. Now we can shut down the upstream
|
||||
* link (except maybe for PME# resume signaling). We'll enter a
|
||||
* low power state during suspend_noirq, if the hardware allows.
|
||||
*/
|
||||
pci_disable_device(pci_dev);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int hcd_pci_suspend_noirq(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pci_dev = to_pci_dev(dev);
|
||||
struct usb_hcd *hcd = pci_get_drvdata(pci_dev);
|
||||
int retval;
|
||||
|
||||
retval = check_root_hub_suspended(dev);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
pci_save_state(pci_dev);
|
||||
|
||||
/* If the root hub is HALTed rather than SUSPENDed,
|
||||
* disallow remote wakeup.
|
||||
*/
|
||||
if (hcd->state == HC_STATE_HALT)
|
||||
device_set_wakeup_enable(dev, 0);
|
||||
dev_dbg(dev, "wakeup: %d\n", device_may_wakeup(dev));
|
||||
|
||||
/* Possibly enable remote wakeup,
|
||||
* choose the appropriate low-power state, and go to that state.
|
||||
*/
|
||||
retval = pci_prepare_to_sleep(pci_dev);
|
||||
if (retval == -EIO) { /* Low-power not supported */
|
||||
dev_dbg(dev, "--> PCI D0 legacy\n");
|
||||
retval = 0;
|
||||
} else if (retval == 0) {
|
||||
dev_dbg(dev, "--> PCI %s\n",
|
||||
pci_power_name(pci_dev->current_state));
|
||||
} else {
|
||||
suspend_report_result(pci_prepare_to_sleep, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PPC_PMAC
|
||||
/* Disable ASIC clocks for USB */
|
||||
if (machine_is(powermac)) {
|
||||
struct device_node *of_node;
|
||||
|
||||
of_node = pci_device_to_OF_node(pci_dev);
|
||||
if (of_node)
|
||||
pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0);
|
||||
}
|
||||
#endif
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int hcd_pci_resume_noirq(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pci_dev = to_pci_dev(dev);
|
||||
|
||||
#ifdef CONFIG_PPC_PMAC
|
||||
/* Reenable ASIC clocks for USB */
|
||||
if (machine_is(powermac)) {
|
||||
struct device_node *of_node;
|
||||
|
||||
of_node = pci_device_to_OF_node(pci_dev);
|
||||
if (of_node)
|
||||
pmac_call_feature(PMAC_FTR_USB_ENABLE,
|
||||
of_node, 0, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Go back to D0 and disable remote wakeup */
|
||||
pci_back_from_sleep(pci_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int resume_common(struct device *dev, bool hibernated)
|
||||
{
|
||||
struct pci_dev *pci_dev = to_pci_dev(dev);
|
||||
struct usb_hcd *hcd = pci_get_drvdata(pci_dev);
|
||||
int retval;
|
||||
|
||||
if (hcd->state != HC_STATE_SUSPENDED) {
|
||||
dev_dbg(dev, "can't resume, not suspended!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
retval = pci_enable_device(pci_dev);
|
||||
if (retval < 0) {
|
||||
dev_err(dev, "can't re-enable after resume, %d!\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
pci_set_master(pci_dev);
|
||||
|
||||
clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
|
||||
|
||||
if (hcd->driver->pci_resume) {
|
||||
retval = hcd->driver->pci_resume(hcd, hibernated);
|
||||
if (retval) {
|
||||
dev_err(dev, "PCI post-resume error %d!\n", retval);
|
||||
usb_hc_died(hcd);
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int hcd_pci_resume(struct device *dev)
|
||||
{
|
||||
return resume_common(dev, false);
|
||||
}
|
||||
|
||||
static int hcd_pci_restore(struct device *dev)
|
||||
{
|
||||
return resume_common(dev, true);
|
||||
}
|
||||
|
||||
struct dev_pm_ops usb_hcd_pci_pm_ops = {
|
||||
.suspend = hcd_pci_suspend,
|
||||
.suspend_noirq = hcd_pci_suspend_noirq,
|
||||
.resume_noirq = hcd_pci_resume_noirq,
|
||||
.resume = hcd_pci_resume,
|
||||
.freeze = check_root_hub_suspended,
|
||||
.freeze_noirq = check_root_hub_suspended,
|
||||
.thaw_noirq = NULL,
|
||||
.thaw = NULL,
|
||||
.poweroff = hcd_pci_suspend,
|
||||
.poweroff_noirq = hcd_pci_suspend_noirq,
|
||||
.restore_noirq = hcd_pci_resume_noirq,
|
||||
.restore = hcd_pci_restore,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(usb_hcd_pci_pm_ops);
|
||||
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
@@ -128,6 +128,27 @@ static inline int is_root_hub(struct usb_device *udev)
|
||||
#define KERNEL_REL ((LINUX_VERSION_CODE >> 16) & 0x0ff)
|
||||
#define KERNEL_VER ((LINUX_VERSION_CODE >> 8) & 0x0ff)
|
||||
|
||||
/* usb 3.0 root hub device descriptor */
|
||||
static const u8 usb3_rh_dev_descriptor[18] = {
|
||||
0x12, /* __u8 bLength; */
|
||||
0x01, /* __u8 bDescriptorType; Device */
|
||||
0x00, 0x03, /* __le16 bcdUSB; v3.0 */
|
||||
|
||||
0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
|
||||
0x00, /* __u8 bDeviceSubClass; */
|
||||
0x03, /* __u8 bDeviceProtocol; USB 3.0 hub */
|
||||
0x09, /* __u8 bMaxPacketSize0; 2^9 = 512 Bytes */
|
||||
|
||||
0x6b, 0x1d, /* __le16 idVendor; Linux Foundation */
|
||||
0x02, 0x00, /* __le16 idProduct; device 0x0002 */
|
||||
KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */
|
||||
|
||||
0x03, /* __u8 iManufacturer; */
|
||||
0x02, /* __u8 iProduct; */
|
||||
0x01, /* __u8 iSerialNumber; */
|
||||
0x01 /* __u8 bNumConfigurations; */
|
||||
};
|
||||
|
||||
/* usb 2.0 root hub device descriptor */
|
||||
static const u8 usb2_rh_dev_descriptor [18] = {
|
||||
0x12, /* __u8 bLength; */
|
||||
@@ -273,6 +294,47 @@ static const u8 hs_rh_config_descriptor [] = {
|
||||
0x0c /* __u8 ep_bInterval; (256ms -- usb 2.0 spec) */
|
||||
};
|
||||
|
||||
static const u8 ss_rh_config_descriptor[] = {
|
||||
/* one configuration */
|
||||
0x09, /* __u8 bLength; */
|
||||
0x02, /* __u8 bDescriptorType; Configuration */
|
||||
0x19, 0x00, /* __le16 wTotalLength; FIXME */
|
||||
0x01, /* __u8 bNumInterfaces; (1) */
|
||||
0x01, /* __u8 bConfigurationValue; */
|
||||
0x00, /* __u8 iConfiguration; */
|
||||
0xc0, /* __u8 bmAttributes;
|
||||
Bit 7: must be set,
|
||||
6: Self-powered,
|
||||
5: Remote wakeup,
|
||||
4..0: resvd */
|
||||
0x00, /* __u8 MaxPower; */
|
||||
|
||||
/* one interface */
|
||||
0x09, /* __u8 if_bLength; */
|
||||
0x04, /* __u8 if_bDescriptorType; Interface */
|
||||
0x00, /* __u8 if_bInterfaceNumber; */
|
||||
0x00, /* __u8 if_bAlternateSetting; */
|
||||
0x01, /* __u8 if_bNumEndpoints; */
|
||||
0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
|
||||
0x00, /* __u8 if_bInterfaceSubClass; */
|
||||
0x00, /* __u8 if_bInterfaceProtocol; */
|
||||
0x00, /* __u8 if_iInterface; */
|
||||
|
||||
/* one endpoint (status change endpoint) */
|
||||
0x07, /* __u8 ep_bLength; */
|
||||
0x05, /* __u8 ep_bDescriptorType; Endpoint */
|
||||
0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
|
||||
0x03, /* __u8 ep_bmAttributes; Interrupt */
|
||||
/* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8)
|
||||
* see hub.c:hub_configure() for details. */
|
||||
(USB_MAXCHILDREN + 1 + 7) / 8, 0x00,
|
||||
0x0c /* __u8 ep_bInterval; (256ms -- usb 2.0 spec) */
|
||||
/*
|
||||
* All 3.0 hubs should have an endpoint companion descriptor,
|
||||
* but we're ignoring that for now. FIXME?
|
||||
*/
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
@@ -426,23 +488,39 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
|
||||
case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
|
||||
switch (wValue & 0xff00) {
|
||||
case USB_DT_DEVICE << 8:
|
||||
if (hcd->driver->flags & HCD_USB2)
|
||||
switch (hcd->driver->flags & HCD_MASK) {
|
||||
case HCD_USB3:
|
||||
bufp = usb3_rh_dev_descriptor;
|
||||
break;
|
||||
case HCD_USB2:
|
||||
bufp = usb2_rh_dev_descriptor;
|
||||
else if (hcd->driver->flags & HCD_USB11)
|
||||
break;
|
||||
case HCD_USB11:
|
||||
bufp = usb11_rh_dev_descriptor;
|
||||
else
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
len = 18;
|
||||
if (hcd->has_tt)
|
||||
patch_protocol = 1;
|
||||
break;
|
||||
case USB_DT_CONFIG << 8:
|
||||
if (hcd->driver->flags & HCD_USB2) {
|
||||
switch (hcd->driver->flags & HCD_MASK) {
|
||||
case HCD_USB3:
|
||||
bufp = ss_rh_config_descriptor;
|
||||
len = sizeof ss_rh_config_descriptor;
|
||||
break;
|
||||
case HCD_USB2:
|
||||
bufp = hs_rh_config_descriptor;
|
||||
len = sizeof hs_rh_config_descriptor;
|
||||
} else {
|
||||
break;
|
||||
case HCD_USB11:
|
||||
bufp = fs_rh_config_descriptor;
|
||||
len = sizeof fs_rh_config_descriptor;
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
if (device_can_wakeup(&hcd->self.root_hub->dev))
|
||||
patch_wakeup = 1;
|
||||
@@ -755,23 +833,6 @@ static struct attribute_group usb_bus_attr_group = {
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static struct class *usb_host_class;
|
||||
|
||||
int usb_host_init(void)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
usb_host_class = class_create(THIS_MODULE, "usb_host");
|
||||
if (IS_ERR(usb_host_class))
|
||||
retval = PTR_ERR(usb_host_class);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void usb_host_cleanup(void)
|
||||
{
|
||||
class_destroy(usb_host_class);
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_bus_init - shared initialization code
|
||||
* @bus: the bus structure being initialized
|
||||
@@ -818,12 +879,6 @@ static int usb_register_bus(struct usb_bus *bus)
|
||||
set_bit (busnum, busmap.busmap);
|
||||
bus->busnum = busnum;
|
||||
|
||||
bus->dev = device_create(usb_host_class, bus->controller, MKDEV(0, 0),
|
||||
bus, "usb_host%d", busnum);
|
||||
result = PTR_ERR(bus->dev);
|
||||
if (IS_ERR(bus->dev))
|
||||
goto error_create_class_dev;
|
||||
|
||||
/* Add it to the local list of buses */
|
||||
list_add (&bus->bus_list, &usb_bus_list);
|
||||
mutex_unlock(&usb_bus_list_lock);
|
||||
@@ -834,8 +889,6 @@ static int usb_register_bus(struct usb_bus *bus)
|
||||
"number %d\n", bus->busnum);
|
||||
return 0;
|
||||
|
||||
error_create_class_dev:
|
||||
clear_bit(busnum, busmap.busmap);
|
||||
error_find_busnum:
|
||||
mutex_unlock(&usb_bus_list_lock);
|
||||
return result;
|
||||
@@ -865,8 +918,6 @@ static void usb_deregister_bus (struct usb_bus *bus)
|
||||
usb_notify_remove_bus(bus);
|
||||
|
||||
clear_bit (bus->busnum, busmap.busmap);
|
||||
|
||||
device_unregister(bus->dev);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1199,7 +1250,8 @@ static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
|
||||
|
||||
/* Map the URB's buffers for DMA access.
|
||||
* Lower level HCD code should use *_dma exclusively,
|
||||
* unless it uses pio or talks to another transport.
|
||||
* unless it uses pio or talks to another transport,
|
||||
* or uses the provided scatter gather list for bulk.
|
||||
*/
|
||||
if (is_root_hub(urb->dev))
|
||||
return 0;
|
||||
@@ -1520,6 +1572,92 @@ rescan:
|
||||
}
|
||||
}
|
||||
|
||||
/* Check whether a new configuration or alt setting for an interface
|
||||
* will exceed the bandwidth for the bus (or the host controller resources).
|
||||
* Only pass in a non-NULL config or interface, not both!
|
||||
* Passing NULL for both new_config and new_intf means the device will be
|
||||
* de-configured by issuing a set configuration 0 command.
|
||||
*/
|
||||
int usb_hcd_check_bandwidth(struct usb_device *udev,
|
||||
struct usb_host_config *new_config,
|
||||
struct usb_interface *new_intf)
|
||||
{
|
||||
int num_intfs, i, j;
|
||||
struct usb_interface_cache *intf_cache;
|
||||
struct usb_host_interface *alt = 0;
|
||||
int ret = 0;
|
||||
struct usb_hcd *hcd;
|
||||
struct usb_host_endpoint *ep;
|
||||
|
||||
hcd = bus_to_hcd(udev->bus);
|
||||
if (!hcd->driver->check_bandwidth)
|
||||
return 0;
|
||||
|
||||
/* Configuration is being removed - set configuration 0 */
|
||||
if (!new_config && !new_intf) {
|
||||
for (i = 1; i < 16; ++i) {
|
||||
ep = udev->ep_out[i];
|
||||
if (ep)
|
||||
hcd->driver->drop_endpoint(hcd, udev, ep);
|
||||
ep = udev->ep_in[i];
|
||||
if (ep)
|
||||
hcd->driver->drop_endpoint(hcd, udev, ep);
|
||||
}
|
||||
hcd->driver->check_bandwidth(hcd, udev);
|
||||
return 0;
|
||||
}
|
||||
/* Check if the HCD says there's enough bandwidth. Enable all endpoints
|
||||
* each interface's alt setting 0 and ask the HCD to check the bandwidth
|
||||
* of the bus. There will always be bandwidth for endpoint 0, so it's
|
||||
* ok to exclude it.
|
||||
*/
|
||||
if (new_config) {
|
||||
num_intfs = new_config->desc.bNumInterfaces;
|
||||
/* Remove endpoints (except endpoint 0, which is always on the
|
||||
* schedule) from the old config from the schedule
|
||||
*/
|
||||
for (i = 1; i < 16; ++i) {
|
||||
ep = udev->ep_out[i];
|
||||
if (ep) {
|
||||
ret = hcd->driver->drop_endpoint(hcd, udev, ep);
|
||||
if (ret < 0)
|
||||
goto reset;
|
||||
}
|
||||
ep = udev->ep_in[i];
|
||||
if (ep) {
|
||||
ret = hcd->driver->drop_endpoint(hcd, udev, ep);
|
||||
if (ret < 0)
|
||||
goto reset;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < num_intfs; ++i) {
|
||||
|
||||
/* Dig the endpoints for alt setting 0 out of the
|
||||
* interface cache for this interface
|
||||
*/
|
||||
intf_cache = new_config->intf_cache[i];
|
||||
for (j = 0; j < intf_cache->num_altsetting; j++) {
|
||||
if (intf_cache->altsetting[j].desc.bAlternateSetting == 0)
|
||||
alt = &intf_cache->altsetting[j];
|
||||
}
|
||||
if (!alt) {
|
||||
printk(KERN_DEBUG "Did not find alt setting 0 for intf %d\n", i);
|
||||
continue;
|
||||
}
|
||||
for (j = 0; j < alt->desc.bNumEndpoints; j++) {
|
||||
ret = hcd->driver->add_endpoint(hcd, udev, &alt->endpoint[j]);
|
||||
if (ret < 0)
|
||||
goto reset;
|
||||
}
|
||||
}
|
||||
}
|
||||
ret = hcd->driver->check_bandwidth(hcd, udev);
|
||||
reset:
|
||||
if (ret < 0)
|
||||
hcd->driver->reset_bandwidth(hcd, udev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Disables the endpoint: synchronizes with the hcd to make sure all
|
||||
* endpoint state is gone from hardware. usb_hcd_flush_endpoint() must
|
||||
* have been called previously. Use for set_configuration, set_interface,
|
||||
@@ -1897,8 +2035,20 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
||||
retval = -ENOMEM;
|
||||
goto err_allocate_root_hub;
|
||||
}
|
||||
rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH :
|
||||
USB_SPEED_FULL;
|
||||
|
||||
switch (hcd->driver->flags & HCD_MASK) {
|
||||
case HCD_USB11:
|
||||
rhdev->speed = USB_SPEED_FULL;
|
||||
break;
|
||||
case HCD_USB2:
|
||||
rhdev->speed = USB_SPEED_HIGH;
|
||||
break;
|
||||
case HCD_USB3:
|
||||
rhdev->speed = USB_SPEED_SUPER;
|
||||
break;
|
||||
default:
|
||||
goto err_allocate_root_hub;
|
||||
}
|
||||
hcd->self.root_hub = rhdev;
|
||||
|
||||
/* wakeup flag init defaults to "everything works" for root hubs,
|
||||
|
@@ -173,6 +173,8 @@ struct hc_driver {
|
||||
#define HCD_LOCAL_MEM 0x0002 /* HC needs local memory */
|
||||
#define HCD_USB11 0x0010 /* USB 1.1 */
|
||||
#define HCD_USB2 0x0020 /* USB 2.0 */
|
||||
#define HCD_USB3 0x0040 /* USB 3.0 */
|
||||
#define HCD_MASK 0x0070
|
||||
|
||||
/* called to init HCD and root hub */
|
||||
int (*reset) (struct usb_hcd *hcd);
|
||||
@@ -182,10 +184,10 @@ struct hc_driver {
|
||||
* a whole, not just the root hub; they're for PCI bus glue.
|
||||
*/
|
||||
/* called after suspending the hub, before entering D3 etc */
|
||||
int (*pci_suspend) (struct usb_hcd *hcd, pm_message_t message);
|
||||
int (*pci_suspend)(struct usb_hcd *hcd);
|
||||
|
||||
/* called after entering D0 (etc), before resuming the hub */
|
||||
int (*pci_resume) (struct usb_hcd *hcd);
|
||||
int (*pci_resume)(struct usb_hcd *hcd, bool hibernated);
|
||||
|
||||
/* cleanly make HCD stop writing memory and doing I/O */
|
||||
void (*stop) (struct usb_hcd *hcd);
|
||||
@@ -224,6 +226,43 @@ struct hc_driver {
|
||||
void (*relinquish_port)(struct usb_hcd *, int);
|
||||
/* has a port been handed over to a companion? */
|
||||
int (*port_handed_over)(struct usb_hcd *, int);
|
||||
|
||||
/* xHCI specific functions */
|
||||
/* Called by usb_alloc_dev to alloc HC device structures */
|
||||
int (*alloc_dev)(struct usb_hcd *, struct usb_device *);
|
||||
/* Called by usb_release_dev to free HC device structures */
|
||||
void (*free_dev)(struct usb_hcd *, struct usb_device *);
|
||||
|
||||
/* Bandwidth computation functions */
|
||||
/* Note that add_endpoint() can only be called once per endpoint before
|
||||
* check_bandwidth() or reset_bandwidth() must be called.
|
||||
* drop_endpoint() can only be called once per endpoint also.
|
||||
* A call to xhci_drop_endpoint() followed by a call to xhci_add_endpoint() will
|
||||
* add the endpoint to the schedule with possibly new parameters denoted by a
|
||||
* different endpoint descriptor in usb_host_endpoint.
|
||||
* A call to xhci_add_endpoint() followed by a call to xhci_drop_endpoint() is
|
||||
* not allowed.
|
||||
*/
|
||||
/* Allocate endpoint resources and add them to a new schedule */
|
||||
int (*add_endpoint)(struct usb_hcd *, struct usb_device *, struct usb_host_endpoint *);
|
||||
/* Drop an endpoint from a new schedule */
|
||||
int (*drop_endpoint)(struct usb_hcd *, struct usb_device *, struct usb_host_endpoint *);
|
||||
/* Check that a new hardware configuration, set using
|
||||
* endpoint_enable and endpoint_disable, does not exceed bus
|
||||
* bandwidth. This must be called before any set configuration
|
||||
* or set interface requests are sent to the device.
|
||||
*/
|
||||
int (*check_bandwidth)(struct usb_hcd *, struct usb_device *);
|
||||
/* Reset the device schedule to the last known good schedule,
|
||||
* which was set from a previous successful call to
|
||||
* check_bandwidth(). This reverts any add_endpoint() and
|
||||
* drop_endpoint() calls since that last successful call.
|
||||
* Used for when a check_bandwidth() call fails due to resource
|
||||
* or bandwidth constraints.
|
||||
*/
|
||||
void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
|
||||
/* Returns the hardware-chosen device address */
|
||||
int (*address_device)(struct usb_hcd *, struct usb_device *udev);
|
||||
};
|
||||
|
||||
extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
|
||||
@@ -242,6 +281,9 @@ extern void usb_hcd_disable_endpoint(struct usb_device *udev,
|
||||
extern void usb_hcd_reset_endpoint(struct usb_device *udev,
|
||||
struct usb_host_endpoint *ep);
|
||||
extern void usb_hcd_synchronize_unlinks(struct usb_device *udev);
|
||||
extern int usb_hcd_check_bandwidth(struct usb_device *udev,
|
||||
struct usb_host_config *new_config,
|
||||
struct usb_interface *new_intf);
|
||||
extern int usb_hcd_get_frame_number(struct usb_device *udev);
|
||||
|
||||
extern struct usb_hcd *usb_create_hcd(const struct hc_driver *driver,
|
||||
@@ -261,14 +303,11 @@ struct pci_device_id;
|
||||
extern int usb_hcd_pci_probe(struct pci_dev *dev,
|
||||
const struct pci_device_id *id);
|
||||
extern void usb_hcd_pci_remove(struct pci_dev *dev);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
extern int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t msg);
|
||||
extern int usb_hcd_pci_resume(struct pci_dev *dev);
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
extern void usb_hcd_pci_shutdown(struct pci_dev *dev);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
extern struct dev_pm_ops usb_hcd_pci_pm_ops;
|
||||
#endif
|
||||
#endif /* CONFIG_PCI */
|
||||
|
||||
/* pci-ish (pdev null is ok) buffer alloc/mapping support */
|
||||
|
@@ -155,6 +155,8 @@ static inline char *portspeed(int portstatus)
|
||||
return "480 Mb/s";
|
||||
else if (portstatus & (1 << USB_PORT_FEAT_LOWSPEED))
|
||||
return "1.5 Mb/s";
|
||||
else if (portstatus & (1 << USB_PORT_FEAT_SUPERSPEED))
|
||||
return "5.0 Gb/s";
|
||||
else
|
||||
return "12 Mb/s";
|
||||
}
|
||||
@@ -457,13 +459,13 @@ static void hub_tt_kevent (struct work_struct *work)
|
||||
|
||||
spin_lock_irqsave (&hub->tt.lock, flags);
|
||||
while (--limit && !list_empty (&hub->tt.clear_list)) {
|
||||
struct list_head *temp;
|
||||
struct list_head *next;
|
||||
struct usb_tt_clear *clear;
|
||||
struct usb_device *hdev = hub->hdev;
|
||||
int status;
|
||||
|
||||
temp = hub->tt.clear_list.next;
|
||||
clear = list_entry (temp, struct usb_tt_clear, clear_list);
|
||||
next = hub->tt.clear_list.next;
|
||||
clear = list_entry (next, struct usb_tt_clear, clear_list);
|
||||
list_del (&clear->clear_list);
|
||||
|
||||
/* drop lock so HCD can concurrently report other TT errors */
|
||||
@@ -951,6 +953,9 @@ static int hub_configure(struct usb_hub *hub,
|
||||
ret);
|
||||
hub->tt.hub = hdev;
|
||||
break;
|
||||
case 3:
|
||||
/* USB 3.0 hubs don't have a TT */
|
||||
break;
|
||||
default:
|
||||
dev_dbg(hub_dev, "Unrecognized hub protocol %d\n",
|
||||
hdev->descriptor.bDeviceProtocol);
|
||||
@@ -1323,6 +1328,11 @@ EXPORT_SYMBOL_GPL(usb_set_device_state);
|
||||
* 0 is reserved by USB for default address; (b) Linux's USB stack
|
||||
* uses always #1 for the root hub of the controller. So USB stack's
|
||||
* port #1, which is wusb virtual-port #0 has address #2.
|
||||
*
|
||||
* Devices connected under xHCI are not as simple. The host controller
|
||||
* supports virtualization, so the hardware assigns device addresses and
|
||||
* the HCD must setup data structures before issuing a set address
|
||||
* command to the hardware.
|
||||
*/
|
||||
static void choose_address(struct usb_device *udev)
|
||||
{
|
||||
@@ -1642,6 +1652,9 @@ int usb_new_device(struct usb_device *udev)
|
||||
err = usb_configure_device(udev); /* detect & probe dev/intfs */
|
||||
if (err < 0)
|
||||
goto fail;
|
||||
dev_dbg(&udev->dev, "udev %d, busnum %d, minor = %d\n",
|
||||
udev->devnum, udev->bus->busnum,
|
||||
(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
|
||||
/* export the usbdev device-node for libusb */
|
||||
udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
|
||||
(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
|
||||
@@ -2395,19 +2408,29 @@ EXPORT_SYMBOL_GPL(usb_ep0_reinit);
|
||||
static int hub_set_address(struct usb_device *udev, int devnum)
|
||||
{
|
||||
int retval;
|
||||
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
|
||||
|
||||
if (devnum <= 1)
|
||||
/*
|
||||
* The host controller will choose the device address,
|
||||
* instead of the core having chosen it earlier
|
||||
*/
|
||||
if (!hcd->driver->address_device && devnum <= 1)
|
||||
return -EINVAL;
|
||||
if (udev->state == USB_STATE_ADDRESS)
|
||||
return 0;
|
||||
if (udev->state != USB_STATE_DEFAULT)
|
||||
return -EINVAL;
|
||||
retval = usb_control_msg(udev, usb_sndaddr0pipe(),
|
||||
USB_REQ_SET_ADDRESS, 0, devnum, 0,
|
||||
NULL, 0, USB_CTRL_SET_TIMEOUT);
|
||||
if (hcd->driver->address_device) {
|
||||
retval = hcd->driver->address_device(hcd, udev);
|
||||
} else {
|
||||
retval = usb_control_msg(udev, usb_sndaddr0pipe(),
|
||||
USB_REQ_SET_ADDRESS, 0, devnum, 0,
|
||||
NULL, 0, USB_CTRL_SET_TIMEOUT);
|
||||
if (retval == 0)
|
||||
update_address(udev, devnum);
|
||||
}
|
||||
if (retval == 0) {
|
||||
/* Device now using proper address. */
|
||||
update_address(udev, devnum);
|
||||
usb_set_device_state(udev, USB_STATE_ADDRESS);
|
||||
usb_ep0_reinit(udev);
|
||||
}
|
||||
@@ -2430,6 +2453,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
|
||||
static DEFINE_MUTEX(usb_address0_mutex);
|
||||
|
||||
struct usb_device *hdev = hub->hdev;
|
||||
struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
|
||||
int i, j, retval;
|
||||
unsigned delay = HUB_SHORT_RESET_TIME;
|
||||
enum usb_device_speed oldspeed = udev->speed;
|
||||
@@ -2452,11 +2476,24 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
|
||||
|
||||
mutex_lock(&usb_address0_mutex);
|
||||
|
||||
/* Reset the device; full speed may morph to high speed */
|
||||
retval = hub_port_reset(hub, port1, udev, delay);
|
||||
if (retval < 0) /* error or disconnect */
|
||||
if ((hcd->driver->flags & HCD_USB3) && udev->config) {
|
||||
/* FIXME this will need special handling by the xHCI driver. */
|
||||
dev_dbg(&udev->dev,
|
||||
"xHCI reset of configured device "
|
||||
"not supported yet.\n");
|
||||
retval = -EINVAL;
|
||||
goto fail;
|
||||
/* success, speed is known */
|
||||
} else if (!udev->config && oldspeed == USB_SPEED_SUPER) {
|
||||
/* Don't reset USB 3.0 devices during an initial setup */
|
||||
usb_set_device_state(udev, USB_STATE_DEFAULT);
|
||||
} else {
|
||||
/* Reset the device; full speed may morph to high speed */
|
||||
/* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */
|
||||
retval = hub_port_reset(hub, port1, udev, delay);
|
||||
if (retval < 0) /* error or disconnect */
|
||||
goto fail;
|
||||
/* success, speed is known */
|
||||
}
|
||||
retval = -ENODEV;
|
||||
|
||||
if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) {
|
||||
@@ -2471,6 +2508,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
|
||||
* reported as 0xff in the device descriptor). WUSB1.0[4.8.1].
|
||||
*/
|
||||
switch (udev->speed) {
|
||||
case USB_SPEED_SUPER:
|
||||
case USB_SPEED_VARIABLE: /* fixed at 512 */
|
||||
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);
|
||||
break;
|
||||
@@ -2496,16 +2534,20 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
|
||||
case USB_SPEED_LOW: speed = "low"; break;
|
||||
case USB_SPEED_FULL: speed = "full"; break;
|
||||
case USB_SPEED_HIGH: speed = "high"; break;
|
||||
case USB_SPEED_SUPER:
|
||||
speed = "super";
|
||||
break;
|
||||
case USB_SPEED_VARIABLE:
|
||||
speed = "variable";
|
||||
type = "Wireless ";
|
||||
break;
|
||||
default: speed = "?"; break;
|
||||
}
|
||||
dev_info (&udev->dev,
|
||||
"%s %s speed %sUSB device using %s and address %d\n",
|
||||
(udev->config) ? "reset" : "new", speed, type,
|
||||
udev->bus->controller->driver->name, devnum);
|
||||
if (udev->speed != USB_SPEED_SUPER)
|
||||
dev_info(&udev->dev,
|
||||
"%s %s speed %sUSB device using %s and address %d\n",
|
||||
(udev->config) ? "reset" : "new", speed, type,
|
||||
udev->bus->controller->driver->name, devnum);
|
||||
|
||||
/* Set up TT records, if needed */
|
||||
if (hdev->tt) {
|
||||
@@ -2530,7 +2572,11 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
|
||||
* value.
|
||||
*/
|
||||
for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) {
|
||||
if (USE_NEW_SCHEME(retry_counter)) {
|
||||
/*
|
||||
* An xHCI controller cannot send any packets to a device until
|
||||
* a set address command successfully completes.
|
||||
*/
|
||||
if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3)) {
|
||||
struct usb_device_descriptor *buf;
|
||||
int r = 0;
|
||||
|
||||
@@ -2596,7 +2642,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
|
||||
* unauthorized address in the Connect Ack sequence;
|
||||
* authorization will assign the final address.
|
||||
*/
|
||||
if (udev->wusb == 0) {
|
||||
if (udev->wusb == 0) {
|
||||
for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
|
||||
retval = hub_set_address(udev, devnum);
|
||||
if (retval >= 0)
|
||||
@@ -2609,13 +2655,20 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
|
||||
devnum, retval);
|
||||
goto fail;
|
||||
}
|
||||
if (udev->speed == USB_SPEED_SUPER) {
|
||||
devnum = udev->devnum;
|
||||
dev_info(&udev->dev,
|
||||
"%s SuperSpeed USB device using %s and address %d\n",
|
||||
(udev->config) ? "reset" : "new",
|
||||
udev->bus->controller->driver->name, devnum);
|
||||
}
|
||||
|
||||
/* cope with hardware quirkiness:
|
||||
* - let SET_ADDRESS settle, some device hardware wants it
|
||||
* - read ep0 maxpacket even for high and low speed,
|
||||
*/
|
||||
msleep(10);
|
||||
if (USE_NEW_SCHEME(retry_counter))
|
||||
if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3))
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2634,8 +2687,11 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
|
||||
if (retval)
|
||||
goto fail;
|
||||
|
||||
i = udev->descriptor.bMaxPacketSize0 == 0xff? /* wusb device? */
|
||||
512 : udev->descriptor.bMaxPacketSize0;
|
||||
if (udev->descriptor.bMaxPacketSize0 == 0xff ||
|
||||
udev->speed == USB_SPEED_SUPER)
|
||||
i = 512;
|
||||
else
|
||||
i = udev->descriptor.bMaxPacketSize0;
|
||||
if (le16_to_cpu(udev->ep0.desc.wMaxPacketSize) != i) {
|
||||
if (udev->speed != USB_SPEED_FULL ||
|
||||
!(i == 8 || i == 16 || i == 32 || i == 64)) {
|
||||
@@ -2847,19 +2903,41 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
|
||||
}
|
||||
|
||||
usb_set_device_state(udev, USB_STATE_POWERED);
|
||||
udev->speed = USB_SPEED_UNKNOWN;
|
||||
udev->bus_mA = hub->mA_per_port;
|
||||
udev->level = hdev->level + 1;
|
||||
udev->wusb = hub_is_wusb(hub);
|
||||
|
||||
/* set the address */
|
||||
choose_address(udev);
|
||||
if (udev->devnum <= 0) {
|
||||
status = -ENOTCONN; /* Don't retry */
|
||||
goto loop;
|
||||
/*
|
||||
* USB 3.0 devices are reset automatically before the connect
|
||||
* port status change appears, and the root hub port status
|
||||
* shows the correct speed. We also get port change
|
||||
* notifications for USB 3.0 devices from the USB 3.0 portion of
|
||||
* an external USB 3.0 hub, but this isn't handled correctly yet
|
||||
* FIXME.
|
||||
*/
|
||||
|
||||
if (!(hcd->driver->flags & HCD_USB3))
|
||||
udev->speed = USB_SPEED_UNKNOWN;
|
||||
else if ((hdev->parent == NULL) &&
|
||||
(portstatus & (1 << USB_PORT_FEAT_SUPERSPEED)))
|
||||
udev->speed = USB_SPEED_SUPER;
|
||||
else
|
||||
udev->speed = USB_SPEED_UNKNOWN;
|
||||
|
||||
/*
|
||||
* xHCI needs to issue an address device command later
|
||||
* in the hub_port_init sequence for SS/HS/FS/LS devices.
|
||||
*/
|
||||
if (!(hcd->driver->flags & HCD_USB3)) {
|
||||
/* set the address */
|
||||
choose_address(udev);
|
||||
if (udev->devnum <= 0) {
|
||||
status = -ENOTCONN; /* Don't retry */
|
||||
goto loop;
|
||||
}
|
||||
}
|
||||
|
||||
/* reset and get descriptor */
|
||||
/* reset (non-USB 3.0 devices) and get descriptor */
|
||||
status = hub_port_init(hub, udev, port1, i);
|
||||
if (status < 0)
|
||||
goto loop;
|
||||
|
@@ -47,7 +47,10 @@
|
||||
#define USB_PORT_FEAT_L1 5 /* L1 suspend */
|
||||
#define USB_PORT_FEAT_POWER 8
|
||||
#define USB_PORT_FEAT_LOWSPEED 9
|
||||
/* This value was never in Table 11-17 */
|
||||
#define USB_PORT_FEAT_HIGHSPEED 10
|
||||
/* This value is also fake */
|
||||
#define USB_PORT_FEAT_SUPERSPEED 11
|
||||
#define USB_PORT_FEAT_C_CONNECTION 16
|
||||
#define USB_PORT_FEAT_C_ENABLE 17
|
||||
#define USB_PORT_FEAT_C_SUSPEND 18
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#include <linux/mm.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/nls.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/usb/quirks.h>
|
||||
@@ -364,6 +365,7 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
|
||||
int i;
|
||||
int urb_flags;
|
||||
int dma;
|
||||
int use_sg;
|
||||
|
||||
if (!io || !dev || !sg
|
||||
|| usb_pipecontrol(pipe)
|
||||
@@ -391,7 +393,19 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
|
||||
if (io->entries <= 0)
|
||||
return io->entries;
|
||||
|
||||
io->urbs = kmalloc(io->entries * sizeof *io->urbs, mem_flags);
|
||||
/* If we're running on an xHCI host controller, queue the whole scatter
|
||||
* gather list with one call to urb_enqueue(). This is only for bulk,
|
||||
* as that endpoint type does not care how the data gets broken up
|
||||
* across frames.
|
||||
*/
|
||||
if (usb_pipebulk(pipe) &&
|
||||
bus_to_hcd(dev->bus)->driver->flags & HCD_USB3) {
|
||||
io->urbs = kmalloc(sizeof *io->urbs, mem_flags);
|
||||
use_sg = true;
|
||||
} else {
|
||||
io->urbs = kmalloc(io->entries * sizeof *io->urbs, mem_flags);
|
||||
use_sg = false;
|
||||
}
|
||||
if (!io->urbs)
|
||||
goto nomem;
|
||||
|
||||
@@ -401,62 +415,92 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
|
||||
if (usb_pipein(pipe))
|
||||
urb_flags |= URB_SHORT_NOT_OK;
|
||||
|
||||
for_each_sg(sg, sg, io->entries, i) {
|
||||
unsigned len;
|
||||
|
||||
io->urbs[i] = usb_alloc_urb(0, mem_flags);
|
||||
if (!io->urbs[i]) {
|
||||
io->entries = i;
|
||||
if (use_sg) {
|
||||
io->urbs[0] = usb_alloc_urb(0, mem_flags);
|
||||
if (!io->urbs[0]) {
|
||||
io->entries = 0;
|
||||
goto nomem;
|
||||
}
|
||||
|
||||
io->urbs[i]->dev = NULL;
|
||||
io->urbs[i]->pipe = pipe;
|
||||
io->urbs[i]->interval = period;
|
||||
io->urbs[i]->transfer_flags = urb_flags;
|
||||
io->urbs[0]->dev = NULL;
|
||||
io->urbs[0]->pipe = pipe;
|
||||
io->urbs[0]->interval = period;
|
||||
io->urbs[0]->transfer_flags = urb_flags;
|
||||
|
||||
io->urbs[i]->complete = sg_complete;
|
||||
io->urbs[i]->context = io;
|
||||
io->urbs[0]->complete = sg_complete;
|
||||
io->urbs[0]->context = io;
|
||||
/* A length of zero means transfer the whole sg list */
|
||||
io->urbs[0]->transfer_buffer_length = length;
|
||||
if (length == 0) {
|
||||
for_each_sg(sg, sg, io->entries, i) {
|
||||
io->urbs[0]->transfer_buffer_length +=
|
||||
sg_dma_len(sg);
|
||||
}
|
||||
}
|
||||
io->urbs[0]->sg = io;
|
||||
io->urbs[0]->num_sgs = io->entries;
|
||||
io->entries = 1;
|
||||
} else {
|
||||
for_each_sg(sg, sg, io->entries, i) {
|
||||
unsigned len;
|
||||
|
||||
/*
|
||||
* Some systems need to revert to PIO when DMA is temporarily
|
||||
* unavailable. For their sakes, both transfer_buffer and
|
||||
* transfer_dma are set when possible. However this can only
|
||||
* work on systems without:
|
||||
*
|
||||
* - HIGHMEM, since DMA buffers located in high memory are
|
||||
* not directly addressable by the CPU for PIO;
|
||||
*
|
||||
* - IOMMU, since dma_map_sg() is allowed to use an IOMMU to
|
||||
* make virtually discontiguous buffers be "dma-contiguous"
|
||||
* so that PIO and DMA need diferent numbers of URBs.
|
||||
*
|
||||
* So when HIGHMEM or IOMMU are in use, transfer_buffer is NULL
|
||||
* to prevent stale pointers and to help spot bugs.
|
||||
*/
|
||||
if (dma) {
|
||||
io->urbs[i]->transfer_dma = sg_dma_address(sg);
|
||||
len = sg_dma_len(sg);
|
||||
io->urbs[i] = usb_alloc_urb(0, mem_flags);
|
||||
if (!io->urbs[i]) {
|
||||
io->entries = i;
|
||||
goto nomem;
|
||||
}
|
||||
|
||||
io->urbs[i]->dev = NULL;
|
||||
io->urbs[i]->pipe = pipe;
|
||||
io->urbs[i]->interval = period;
|
||||
io->urbs[i]->transfer_flags = urb_flags;
|
||||
|
||||
io->urbs[i]->complete = sg_complete;
|
||||
io->urbs[i]->context = io;
|
||||
|
||||
/*
|
||||
* Some systems need to revert to PIO when DMA is
|
||||
* temporarily unavailable. For their sakes, both
|
||||
* transfer_buffer and transfer_dma are set when
|
||||
* possible. However this can only work on systems
|
||||
* without:
|
||||
*
|
||||
* - HIGHMEM, since DMA buffers located in high memory
|
||||
* are not directly addressable by the CPU for PIO;
|
||||
*
|
||||
* - IOMMU, since dma_map_sg() is allowed to use an
|
||||
* IOMMU to make virtually discontiguous buffers be
|
||||
* "dma-contiguous" so that PIO and DMA need diferent
|
||||
* numbers of URBs.
|
||||
*
|
||||
* So when HIGHMEM or IOMMU are in use, transfer_buffer
|
||||
* is NULL to prevent stale pointers and to help spot
|
||||
* bugs.
|
||||
*/
|
||||
if (dma) {
|
||||
io->urbs[i]->transfer_dma = sg_dma_address(sg);
|
||||
len = sg_dma_len(sg);
|
||||
#if defined(CONFIG_HIGHMEM) || defined(CONFIG_GART_IOMMU)
|
||||
io->urbs[i]->transfer_buffer = NULL;
|
||||
io->urbs[i]->transfer_buffer = NULL;
|
||||
#else
|
||||
io->urbs[i]->transfer_buffer = sg_virt(sg);
|
||||
io->urbs[i]->transfer_buffer = sg_virt(sg);
|
||||
#endif
|
||||
} else {
|
||||
/* hc may use _only_ transfer_buffer */
|
||||
io->urbs[i]->transfer_buffer = sg_virt(sg);
|
||||
len = sg->length;
|
||||
}
|
||||
} else {
|
||||
/* hc may use _only_ transfer_buffer */
|
||||
io->urbs[i]->transfer_buffer = sg_virt(sg);
|
||||
len = sg->length;
|
||||
}
|
||||
|
||||
if (length) {
|
||||
len = min_t(unsigned, len, length);
|
||||
length -= len;
|
||||
if (length == 0)
|
||||
io->entries = i + 1;
|
||||
if (length) {
|
||||
len = min_t(unsigned, len, length);
|
||||
length -= len;
|
||||
if (length == 0)
|
||||
io->entries = i + 1;
|
||||
}
|
||||
io->urbs[i]->transfer_buffer_length = len;
|
||||
}
|
||||
io->urbs[i]->transfer_buffer_length = len;
|
||||
io->urbs[--i]->transfer_flags &= ~URB_NO_INTERRUPT;
|
||||
}
|
||||
io->urbs[--i]->transfer_flags &= ~URB_NO_INTERRUPT;
|
||||
|
||||
/* transaction state */
|
||||
io->count = io->entries;
|
||||
@@ -509,6 +553,10 @@ EXPORT_SYMBOL_GPL(usb_sg_init);
|
||||
* could be transferred. That capability is less useful for low or full
|
||||
* speed interrupt endpoints, which allow at most one packet per millisecond,
|
||||
* of at most 8 or 64 bytes (respectively).
|
||||
*
|
||||
* It is not necessary to call this function to reserve bandwidth for devices
|
||||
* under an xHCI host controller, as the bandwidth is reserved when the
|
||||
* configuration or interface alt setting is selected.
|
||||
*/
|
||||
void usb_sg_wait(struct usb_sg_request *io)
|
||||
{
|
||||
@@ -759,7 +807,7 @@ static int usb_string_sub(struct usb_device *dev, unsigned int langid,
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_string - returns ISO 8859-1 version of a string descriptor
|
||||
* usb_string - returns UTF-8 version of a string descriptor
|
||||
* @dev: the device whose string descriptor is being retrieved
|
||||
* @index: the number of the descriptor
|
||||
* @buf: where to put the string
|
||||
@@ -767,17 +815,10 @@ static int usb_string_sub(struct usb_device *dev, unsigned int langid,
|
||||
* Context: !in_interrupt ()
|
||||
*
|
||||
* This converts the UTF-16LE encoded strings returned by devices, from
|
||||
* usb_get_string_descriptor(), to null-terminated ISO-8859-1 encoded ones
|
||||
* that are more usable in most kernel contexts. Note that all characters
|
||||
* in the chosen descriptor that can't be encoded using ISO-8859-1
|
||||
* are converted to the question mark ("?") character, and this function
|
||||
* usb_get_string_descriptor(), to null-terminated UTF-8 encoded ones
|
||||
* that are more usable in most kernel contexts. Note that this function
|
||||
* chooses strings in the first language supported by the device.
|
||||
*
|
||||
* The ASCII (or, redundantly, "US-ASCII") character set is the seven-bit
|
||||
* subset of ISO 8859-1. ISO-8859-1 is the eight-bit subset of Unicode,
|
||||
* and is appropriate for use many uses of English and several other
|
||||
* Western European languages. (But it doesn't include the "Euro" symbol.)
|
||||
*
|
||||
* This call is synchronous, and may not be used in an interrupt context.
|
||||
*
|
||||
* Returns length of the string (>= 0) or usb_control_msg status (< 0).
|
||||
@@ -786,7 +827,6 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
|
||||
{
|
||||
unsigned char *tbuf;
|
||||
int err;
|
||||
unsigned int u, idx;
|
||||
|
||||
if (dev->state == USB_STATE_SUSPENDED)
|
||||
return -EHOSTUNREACH;
|
||||
@@ -821,16 +861,9 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
|
||||
goto errout;
|
||||
|
||||
size--; /* leave room for trailing NULL char in output buffer */
|
||||
for (idx = 0, u = 2; u < err; u += 2) {
|
||||
if (idx >= size)
|
||||
break;
|
||||
if (tbuf[u+1]) /* high byte */
|
||||
buf[idx++] = '?'; /* non ISO-8859-1 character */
|
||||
else
|
||||
buf[idx++] = tbuf[u];
|
||||
}
|
||||
buf[idx] = 0;
|
||||
err = idx;
|
||||
err = utf16s_to_utf8s((wchar_t *) &tbuf[2], (err - 2) / 2,
|
||||
UTF16_LITTLE_ENDIAN, buf, size);
|
||||
buf[err] = 0;
|
||||
|
||||
if (tbuf[1] != USB_DT_STRING)
|
||||
dev_dbg(&dev->dev,
|
||||
@@ -843,6 +876,9 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_string);
|
||||
|
||||
/* one UTF-8-encoded 16-bit character has at most three bytes */
|
||||
#define MAX_USB_STRING_SIZE (127 * 3 + 1)
|
||||
|
||||
/**
|
||||
* usb_cache_string - read a string descriptor and cache it for later use
|
||||
* @udev: the device whose string descriptor is being read
|
||||
@@ -860,9 +896,9 @@ char *usb_cache_string(struct usb_device *udev, int index)
|
||||
if (index <= 0)
|
||||
return NULL;
|
||||
|
||||
buf = kmalloc(256, GFP_KERNEL);
|
||||
buf = kmalloc(MAX_USB_STRING_SIZE, GFP_KERNEL);
|
||||
if (buf) {
|
||||
len = usb_string(udev, index, buf, 256);
|
||||
len = usb_string(udev, index, buf, MAX_USB_STRING_SIZE);
|
||||
if (len > 0) {
|
||||
smallbuf = kmalloc(++len, GFP_KERNEL);
|
||||
if (!smallbuf)
|
||||
@@ -1664,6 +1700,21 @@ free_interfaces:
|
||||
if (ret)
|
||||
goto free_interfaces;
|
||||
|
||||
/* Make sure we have bandwidth (and available HCD resources) for this
|
||||
* configuration. Remove endpoints from the schedule if we're dropping
|
||||
* this configuration to set configuration 0. After this point, the
|
||||
* host controller will not allow submissions to dropped endpoints. If
|
||||
* this call fails, the device state is unchanged.
|
||||
*/
|
||||
if (cp)
|
||||
ret = usb_hcd_check_bandwidth(dev, cp, NULL);
|
||||
else
|
||||
ret = usb_hcd_check_bandwidth(dev, NULL, NULL);
|
||||
if (ret < 0) {
|
||||
usb_autosuspend_device(dev);
|
||||
goto free_interfaces;
|
||||
}
|
||||
|
||||
/* if it's already configured, clear out old state first.
|
||||
* getting rid of old interfaces means unbinding their drivers.
|
||||
*/
|
||||
@@ -1686,6 +1737,7 @@ free_interfaces:
|
||||
dev->actconfig = cp;
|
||||
if (!cp) {
|
||||
usb_set_device_state(dev, USB_STATE_ADDRESS);
|
||||
usb_hcd_check_bandwidth(dev, NULL, NULL);
|
||||
usb_autosuspend_device(dev);
|
||||
goto free_interfaces;
|
||||
}
|
||||
|
@@ -552,8 +552,8 @@ static struct attribute *dev_string_attrs[] = {
|
||||
static mode_t dev_string_attrs_are_visible(struct kobject *kobj,
|
||||
struct attribute *a, int n)
|
||||
{
|
||||
struct usb_device *udev = to_usb_device(
|
||||
container_of(kobj, struct device, kobj));
|
||||
struct device *dev = container_of(kobj, struct device, kobj);
|
||||
struct usb_device *udev = to_usb_device(dev);
|
||||
|
||||
if (a == &dev_attr_manufacturer.attr) {
|
||||
if (udev->manufacturer == NULL)
|
||||
@@ -585,8 +585,8 @@ static ssize_t
|
||||
read_descriptors(struct kobject *kobj, struct bin_attribute *attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct usb_device *udev = to_usb_device(
|
||||
container_of(kobj, struct device, kobj));
|
||||
struct device *dev = container_of(kobj, struct device, kobj);
|
||||
struct usb_device *udev = to_usb_device(dev);
|
||||
size_t nleft = count;
|
||||
size_t srclen, n;
|
||||
int cfgno;
|
||||
@@ -786,8 +786,8 @@ static struct attribute *intf_assoc_attrs[] = {
|
||||
static mode_t intf_assoc_attrs_are_visible(struct kobject *kobj,
|
||||
struct attribute *a, int n)
|
||||
{
|
||||
struct usb_interface *intf = to_usb_interface(
|
||||
container_of(kobj, struct device, kobj));
|
||||
struct device *dev = container_of(kobj, struct device, kobj);
|
||||
struct usb_interface *intf = to_usb_interface(dev);
|
||||
|
||||
if (intf->intf_assoc == NULL)
|
||||
return 0;
|
||||
|
@@ -241,6 +241,12 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb);
|
||||
* If the USB subsystem can't allocate sufficient bandwidth to perform
|
||||
* the periodic request, submitting such a periodic request should fail.
|
||||
*
|
||||
* For devices under xHCI, the bandwidth is reserved at configuration time, or
|
||||
* when the alt setting is selected. If there is not enough bus bandwidth, the
|
||||
* configuration/alt setting request will fail. Therefore, submissions to
|
||||
* periodic endpoints on devices under xHCI should never fail due to bandwidth
|
||||
* constraints.
|
||||
*
|
||||
* Device drivers must explicitly request that repetition, by ensuring that
|
||||
* some URB is always on the endpoint's queue (except possibly for short
|
||||
* periods during completion callacks). When there is no longer an urb
|
||||
@@ -351,6 +357,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
|
||||
if (xfertype == USB_ENDPOINT_XFER_ISOC) {
|
||||
int n, len;
|
||||
|
||||
/* FIXME SuperSpeed isoc endpoints have up to 16 bursts */
|
||||
/* "high bandwidth" mode, 1-3 packets/uframe? */
|
||||
if (dev->speed == USB_SPEED_HIGH) {
|
||||
int mult = 1 + ((max >> 11) & 0x03);
|
||||
@@ -426,6 +433,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
|
||||
return -EINVAL;
|
||||
/* too big? */
|
||||
switch (dev->speed) {
|
||||
case USB_SPEED_SUPER: /* units are 125us */
|
||||
/* Handle up to 2^(16-1) microframes */
|
||||
if (urb->interval > (1 << 15))
|
||||
return -EINVAL;
|
||||
max = 1 << 15;
|
||||
case USB_SPEED_HIGH: /* units are microframes */
|
||||
/* NOTE usb handles 2^15 */
|
||||
if (urb->interval > (1024 * 8))
|
||||
|
@@ -34,6 +34,7 @@
|
||||
#include <linux/usb.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/debugfs.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <linux/scatterlist.h>
|
||||
@@ -139,8 +140,7 @@ static int __find_interface(struct device *dev, void *data)
|
||||
struct find_interface_arg *arg = data;
|
||||
struct usb_interface *intf;
|
||||
|
||||
/* can't look at usb devices, only interfaces */
|
||||
if (is_usb_device(dev))
|
||||
if (!is_usb_interface(dev))
|
||||
return 0;
|
||||
|
||||
intf = to_usb_interface(dev);
|
||||
@@ -184,11 +184,16 @@ EXPORT_SYMBOL_GPL(usb_find_interface);
|
||||
static void usb_release_dev(struct device *dev)
|
||||
{
|
||||
struct usb_device *udev;
|
||||
struct usb_hcd *hcd;
|
||||
|
||||
udev = to_usb_device(dev);
|
||||
hcd = bus_to_hcd(udev->bus);
|
||||
|
||||
usb_destroy_configuration(udev);
|
||||
usb_put_hcd(bus_to_hcd(udev->bus));
|
||||
/* Root hubs aren't real devices, so don't free HCD resources */
|
||||
if (hcd->driver->free_dev && udev->parent)
|
||||
hcd->driver->free_dev(hcd, udev);
|
||||
usb_put_hcd(hcd);
|
||||
kfree(udev->product);
|
||||
kfree(udev->manufacturer);
|
||||
kfree(udev->serial);
|
||||
@@ -359,6 +364,13 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
|
||||
kfree(dev);
|
||||
return NULL;
|
||||
}
|
||||
/* Root hubs aren't true devices, so don't allocate HCD resources */
|
||||
if (usb_hcd->driver->alloc_dev && parent &&
|
||||
!usb_hcd->driver->alloc_dev(usb_hcd, dev)) {
|
||||
usb_put_hcd(bus_to_hcd(bus));
|
||||
kfree(dev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
device_initialize(&dev->dev);
|
||||
dev->dev.bus = &usb_bus_type;
|
||||
@@ -386,18 +398,24 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
|
||||
*/
|
||||
if (unlikely(!parent)) {
|
||||
dev->devpath[0] = '0';
|
||||
dev->route = 0;
|
||||
|
||||
dev->dev.parent = bus->controller;
|
||||
dev_set_name(&dev->dev, "usb%d", bus->busnum);
|
||||
root_hub = 1;
|
||||
} else {
|
||||
/* match any labeling on the hubs; it's one-based */
|
||||
if (parent->devpath[0] == '0')
|
||||
if (parent->devpath[0] == '0') {
|
||||
snprintf(dev->devpath, sizeof dev->devpath,
|
||||
"%d", port1);
|
||||
else
|
||||
/* Root ports are not counted in route string */
|
||||
dev->route = 0;
|
||||
} else {
|
||||
snprintf(dev->devpath, sizeof dev->devpath,
|
||||
"%s.%d", parent->devpath, port1);
|
||||
dev->route = parent->route +
|
||||
(port1 << ((parent->level - 1)*4));
|
||||
}
|
||||
|
||||
dev->dev.parent = &parent->dev;
|
||||
dev_set_name(&dev->dev, "%d-%s", bus->busnum, dev->devpath);
|
||||
@@ -810,12 +828,12 @@ void usb_buffer_dmasync(struct urb *urb)
|
||||
return;
|
||||
|
||||
if (controller->dma_mask) {
|
||||
dma_sync_single(controller,
|
||||
dma_sync_single_for_cpu(controller,
|
||||
urb->transfer_dma, urb->transfer_buffer_length,
|
||||
usb_pipein(urb->pipe)
|
||||
? DMA_FROM_DEVICE : DMA_TO_DEVICE);
|
||||
if (usb_pipecontrol(urb->pipe))
|
||||
dma_sync_single(controller,
|
||||
dma_sync_single_for_cpu(controller,
|
||||
urb->setup_dma,
|
||||
sizeof(struct usb_ctrlrequest),
|
||||
DMA_TO_DEVICE);
|
||||
@@ -933,8 +951,8 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in,
|
||||
|| !controller->dma_mask)
|
||||
return;
|
||||
|
||||
dma_sync_sg(controller, sg, n_hw_ents,
|
||||
is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
|
||||
dma_sync_sg_for_cpu(controller, sg, n_hw_ents,
|
||||
is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_buffer_dmasync_sg);
|
||||
#endif
|
||||
@@ -1012,6 +1030,35 @@ static struct notifier_block usb_bus_nb = {
|
||||
.notifier_call = usb_bus_notify,
|
||||
};
|
||||
|
||||
struct dentry *usb_debug_root;
|
||||
EXPORT_SYMBOL_GPL(usb_debug_root);
|
||||
|
||||
struct dentry *usb_debug_devices;
|
||||
|
||||
static int usb_debugfs_init(void)
|
||||
{
|
||||
usb_debug_root = debugfs_create_dir("usb", NULL);
|
||||
if (!usb_debug_root)
|
||||
return -ENOENT;
|
||||
|
||||
usb_debug_devices = debugfs_create_file("devices", 0444,
|
||||
usb_debug_root, NULL,
|
||||
&usbfs_devices_fops);
|
||||
if (!usb_debug_devices) {
|
||||
debugfs_remove(usb_debug_root);
|
||||
usb_debug_root = NULL;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void usb_debugfs_cleanup(void)
|
||||
{
|
||||
debugfs_remove(usb_debug_devices);
|
||||
debugfs_remove(usb_debug_root);
|
||||
}
|
||||
|
||||
/*
|
||||
* Init
|
||||
*/
|
||||
@@ -1023,6 +1070,10 @@ static int __init usb_init(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
retval = usb_debugfs_init();
|
||||
if (retval)
|
||||
goto out;
|
||||
|
||||
retval = ksuspend_usb_init();
|
||||
if (retval)
|
||||
goto out;
|
||||
@@ -1032,9 +1083,6 @@ static int __init usb_init(void)
|
||||
retval = bus_register_notifier(&usb_bus_type, &usb_bus_nb);
|
||||
if (retval)
|
||||
goto bus_notifier_failed;
|
||||
retval = usb_host_init();
|
||||
if (retval)
|
||||
goto host_init_failed;
|
||||
retval = usb_major_init();
|
||||
if (retval)
|
||||
goto major_init_failed;
|
||||
@@ -1064,8 +1112,6 @@ usb_devio_init_failed:
|
||||
driver_register_failed:
|
||||
usb_major_cleanup();
|
||||
major_init_failed:
|
||||
usb_host_cleanup();
|
||||
host_init_failed:
|
||||
bus_unregister_notifier(&usb_bus_type, &usb_bus_nb);
|
||||
bus_notifier_failed:
|
||||
bus_unregister(&usb_bus_type);
|
||||
@@ -1090,10 +1136,10 @@ static void __exit usb_exit(void)
|
||||
usb_deregister(&usbfs_driver);
|
||||
usb_devio_cleanup();
|
||||
usb_hub_cleanup();
|
||||
usb_host_cleanup();
|
||||
bus_unregister_notifier(&usb_bus_type, &usb_bus_nb);
|
||||
bus_unregister(&usb_bus_type);
|
||||
ksuspend_usb_cleanup();
|
||||
usb_debugfs_cleanup();
|
||||
}
|
||||
|
||||
subsys_initcall(usb_init);
|
||||
|
@@ -41,8 +41,6 @@ extern int usb_hub_init(void);
|
||||
extern void usb_hub_cleanup(void);
|
||||
extern int usb_major_init(void);
|
||||
extern void usb_major_cleanup(void);
|
||||
extern int usb_host_init(void);
|
||||
extern void usb_host_cleanup(void);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
@@ -106,6 +104,7 @@ extern struct workqueue_struct *ksuspend_usb_wq;
|
||||
extern struct bus_type usb_bus_type;
|
||||
extern struct device_type usb_device_type;
|
||||
extern struct device_type usb_if_device_type;
|
||||
extern struct device_type usb_ep_device_type;
|
||||
extern struct usb_device_driver usb_generic_driver;
|
||||
|
||||
static inline int is_usb_device(const struct device *dev)
|
||||
@@ -113,6 +112,16 @@ static inline int is_usb_device(const struct device *dev)
|
||||
return dev->type == &usb_device_type;
|
||||
}
|
||||
|
||||
static inline int is_usb_interface(const struct device *dev)
|
||||
{
|
||||
return dev->type == &usb_if_device_type;
|
||||
}
|
||||
|
||||
static inline int is_usb_endpoint(const struct device *dev)
|
||||
{
|
||||
return dev->type == &usb_ep_device_type;
|
||||
}
|
||||
|
||||
/* Do the same for device drivers and interface drivers. */
|
||||
|
||||
static inline int is_usb_device_driver(struct device_driver *drv)
|
||||
|
Reference in New Issue
Block a user