diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 5da546c4fd7980a7619e8a83fdcebfe77086ce46..f07ab71859dd765715543d52dff728b7103383fb 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2594,16 +2594,14 @@ static int hub_set_address(struct usb_device *udev, int devnum) return 0; if (udev->state != USB_STATE_DEFAULT) return -EINVAL; - if (hcd->driver->address_device) { + if (hcd->driver->address_device) retval = hcd->driver->address_device(hcd, udev); - } else { + 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) { + update_address(udev, devnum); /* Device now using proper address. */ usb_set_device_state(udev, USB_STATE_ADDRESS); usb_ep0_reinit(udev); @@ -3097,16 +3095,17 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, 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. + * Set the address. + * Note xHCI needs to issue an address device command later + * in the hub_port_init sequence for SS/HS/FS/LS devices, + * and xHC will assign an address to the device. But use + * kernel assigned address here, to avoid any address conflict + * issue. */ - if (!(hcd->driver->flags & HCD_USB3)) { - /* set the address */ - choose_address(udev); - if (udev->devnum <= 0) { - status = -ENOTCONN; /* Don't retry */ - goto loop; - } + choose_address(udev); + if (udev->devnum <= 0) { + status = -ENOTCONN; /* Don't retry */ + goto loop; } /* reset (non-USB 3.0 devices) and get descriptor */ diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 7928af5c91cb8fcd6f66630dd3014b125b868be6..caccecb7368e3ec7b2141f5fb9cd5c614b5c62f0 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -2287,15 +2287,15 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) * address given back to us by the HC. */ slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx); - udev->devnum = (slot_ctx->dev_state & DEV_ADDR_MASK) + 1; + /* Use kernel assigned address for devices; store xHC assigned + * address locally. */ + virt_dev->address = (slot_ctx->dev_state & DEV_ADDR_MASK) + 1; /* Zero the input context control for later use */ ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx); ctrl_ctx->add_flags = 0; ctrl_ctx->drop_flags = 0; - xhci_dbg(xhci, "Device address = %d\n", udev->devnum); - /* XXX Meh, not sure if anyone else but choose_address uses this. */ - set_bit(udev->devnum, udev->bus->devmap.devicemap); + xhci_dbg(xhci, "Internal device address = %d\n", virt_dev->address); return 0; } diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 490409f918f2e06be4d185425343c135af2d1496..a7181b491e67d43b4723ebf5d23bb18eb0296573 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -746,6 +746,8 @@ struct xhci_virt_device { /* Rings saved to ensure old alt settings can be re-instated */ struct xhci_ring **ring_cache; int num_rings_cached; + /* Store xHC assigned device address */ + int address; #define XHCI_MAX_RINGS_CACHED 31 struct xhci_virt_ep eps[31]; struct completion cmd_completion;