forked from Minki/linux
USB: address-0 handling during device initialization
This patch (as947) changes the device initialization and enumeration code in hub.c; now udev->devnum will be set to 0 while the device is being accessed at address 0. Until now this wasn't needed because the address value was passed as part of urb->pipe; without that field the device address must be stored elsewhere. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
5e60a16139
commit
4326ed0be9
@ -1481,6 +1481,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
|
||||
case 0:
|
||||
/* TRSTRCY = 10 ms; plus some extra */
|
||||
msleep(10 + 40);
|
||||
udev->devnum = 0; /* Device now at address 0 */
|
||||
/* FALL THROUGH */
|
||||
case -ENOTCONN:
|
||||
case -ENODEV:
|
||||
@ -2005,20 +2006,21 @@ static void ep0_reinit(struct usb_device *udev)
|
||||
#define usb_sndaddr0pipe() (PIPE_CONTROL << 30)
|
||||
#define usb_rcvaddr0pipe() ((PIPE_CONTROL << 30) | USB_DIR_IN)
|
||||
|
||||
static int hub_set_address(struct usb_device *udev)
|
||||
static int hub_set_address(struct usb_device *udev, int devnum)
|
||||
{
|
||||
int retval;
|
||||
|
||||
if (udev->devnum == 0)
|
||||
if (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, udev->devnum, 0,
|
||||
USB_REQ_SET_ADDRESS, 0, devnum, 0,
|
||||
NULL, 0, USB_CTRL_SET_TIMEOUT);
|
||||
if (retval == 0) {
|
||||
udev->devnum = devnum; /* Device now using proper address */
|
||||
usb_set_device_state(udev, USB_STATE_ADDRESS);
|
||||
ep0_reinit(udev);
|
||||
}
|
||||
@ -2045,6 +2047,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
|
||||
unsigned delay = HUB_SHORT_RESET_TIME;
|
||||
enum usb_device_speed oldspeed = udev->speed;
|
||||
char *speed, *type;
|
||||
int devnum = udev->devnum;
|
||||
|
||||
/* root hub ports have a slightly longer reset period
|
||||
* (from USB 2.0 spec, section 7.1.7.5)
|
||||
@ -2074,7 +2077,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
|
||||
goto fail;
|
||||
}
|
||||
oldspeed = udev->speed;
|
||||
|
||||
|
||||
/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
|
||||
* it's fixed size except for full speed devices.
|
||||
* For Wireless USB devices, ep0 max packet is always 512 (tho
|
||||
@ -2115,7 +2118,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
|
||||
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, udev->devnum);
|
||||
udev->bus->controller->driver->name, devnum);
|
||||
|
||||
/* Set up TT records, if needed */
|
||||
if (hdev->tt) {
|
||||
@ -2202,7 +2205,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
|
||||
}
|
||||
|
||||
for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
|
||||
retval = hub_set_address(udev);
|
||||
retval = hub_set_address(udev, devnum);
|
||||
if (retval >= 0)
|
||||
break;
|
||||
msleep(200);
|
||||
@ -2210,7 +2213,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
|
||||
if (retval < 0) {
|
||||
dev_err(&udev->dev,
|
||||
"device not accepting address %d, error %d\n",
|
||||
udev->devnum, retval);
|
||||
devnum, retval);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -2263,8 +2266,10 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
|
||||
retval = 0;
|
||||
|
||||
fail:
|
||||
if (retval)
|
||||
if (retval) {
|
||||
hub_port_disable(hub, port1, 0);
|
||||
udev->devnum = devnum; /* for disconnect processing */
|
||||
}
|
||||
mutex_unlock(&usb_address0_mutex);
|
||||
return retval;
|
||||
}
|
||||
|
@ -284,9 +284,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
|
||||
|
||||
if (!urb || urb->hcpriv || !urb->complete)
|
||||
return -EINVAL;
|
||||
if (!(dev = urb->dev) ||
|
||||
(dev->state < USB_STATE_DEFAULT) ||
|
||||
(!dev->bus) || (dev->devnum <= 0))
|
||||
if (!(dev = urb->dev) || dev->state < USB_STATE_DEFAULT)
|
||||
return -ENODEV;
|
||||
if (dev->bus->controller->power.power_state.event != PM_EVENT_ON
|
||||
|| dev->state == USB_STATE_SUSPENDED)
|
||||
|
Loading…
Reference in New Issue
Block a user