Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 151410
b: refs/heads/master
c: c651527
h: refs/heads/master
v: v3
  • Loading branch information
Sarah Sharp authored and Greg Kroah-Hartman committed Jun 16, 2009
1 parent 071b852 commit aee16f4
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 21 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 0f2a79300a1471cf92ab43af165ea13555c8b0a5
refs/heads/master: c6515272b858742962c1de0f3bf497a048b9abd7
8 changes: 8 additions & 0 deletions trunk/drivers/usb/core/hcd.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,14 @@ 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 *);
/* 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);
Expand Down
74 changes: 55 additions & 19 deletions trunk/drivers/usb/core/hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -1328,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)
{
Expand Down Expand Up @@ -1647,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)));
Expand Down Expand Up @@ -2400,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);
}
Expand Down Expand Up @@ -2525,10 +2543,11 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
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) {
Expand All @@ -2553,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;

Expand Down Expand Up @@ -2619,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)
Expand All @@ -2632,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;
}

Expand Down Expand Up @@ -2877,13 +2907,6 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
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
Expand All @@ -2901,6 +2924,19 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
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 (non-USB 3.0 devices) and get descriptor */
status = hub_port_init(hub, udev, port1, i);
if (status < 0)
Expand Down
14 changes: 13 additions & 1 deletion trunk/drivers/usb/core/usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -348,6 +353,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;
Expand Down
2 changes: 2 additions & 0 deletions trunk/include/linux/usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,7 @@ struct usb_tt;
* @skip_sys_resume: skip the next system resume
* @wusb_dev: if this is a Wireless USB device, link to the WUSB
* specific data for the device.
* @slot_id: Slot ID assigned by xHCI
*
* Notes:
* Usbcore drivers should not set usbdev->state directly. Instead use
Expand Down Expand Up @@ -504,6 +505,7 @@ struct usb_device {
unsigned skip_sys_resume:1;
#endif
struct wusb_dev *wusb_dev;
int slot_id;
};
#define to_usb_device(d) container_of(d, struct usb_device, dev)

Expand Down

0 comments on commit aee16f4

Please sign in to comment.