Commit f0b314c4 authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

[PATCH] USB: re-factor enumeration logic

This is an update to some patches from the December/January
timeframe, which will help sort out some of the mess for
drivers that need to use the reset logic.  It's one of the
last significant patches in my gadget-2.6 tree that haven't
yet been merged into the main kernel tree.


More refactoring of the enumeration code paths:

 * The first half of usb_new_device() becomes the second half of a new
   hub_port_init() routine (resets, sets address, gets descriptor)

 * The middle chunk of hub_port_connect_change() becomes the first half
   of that new hub_port_init() routine.

 * Khubd uses that new routine in hub_port_connect_change().

 * Now usb_new_device() cleans up better after faults, and has
   a more useful locking policy (caller owns dev->serialize).

 * Has related minor cleanups including commenting some of
   the curious request sequences coming from khubd.

Refactoring means a lot of the current usb_reset_device() logic won't
need to stay an imperfect clone of the enumeration code ... soon, it
can just call hub_port_init().

Even without touching usb_reset_device(), this eliminates a deadlock.
Previously, address0_sem was used both during probe and during reset,
so probe routines can't implement DFU firmware download (involves a
reset; DFU also uncovers other problems) or safely recover from probe
faults by resetting (usb-storage can try that).  Now that lock is no
longer held during probe(); so those deadlocks are gone.  (And some
drivers, like at76c503, can start to remove ugly workarounds.)
parent ce77b50c
...@@ -779,10 +779,22 @@ int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev ...@@ -779,10 +779,22 @@ int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev
set_bit (devnum, usb_dev->bus->devmap.devicemap); set_bit (devnum, usb_dev->bus->devmap.devicemap);
usb_dev->state = USB_STATE_ADDRESS; usb_dev->state = USB_STATE_ADDRESS;
usb_dev->epmaxpacketin[0] = usb_dev->epmaxpacketout[0] = 64;
retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);
if (retval != sizeof usb_dev->descriptor) {
dev_dbg (parent_dev, "can't read %s device descriptor %d\n",
usb_dev->dev.bus_id, retval);
return (retval < 0) ? retval : -EMSGSIZE;
}
(void) usb_get_dev (usb_dev);
down (&usb_dev->serialize);
retval = usb_new_device (usb_dev); retval = usb_new_device (usb_dev);
if (retval) if (retval)
dev_err (parent_dev, "can't register root hub for %s, %d\n", dev_err (parent_dev, "can't register root hub for %s, %d\n",
usb_dev->dev.bus_id, retval); usb_dev->dev.bus_id, retval);
up (&usb_dev->serialize);
usb_put_dev (usb_dev);
return retval; return retval;
} }
EXPORT_SYMBOL (usb_register_root_hub); EXPORT_SYMBOL (usb_register_root_hub);
......
...@@ -841,8 +841,11 @@ static int hub_port_status(struct usb_device *dev, int port, ...@@ -841,8 +841,11 @@ static int hub_port_status(struct usb_device *dev, int port,
return ret; return ret;
} }
#define HUB_RESET_TRIES 5 #define PORT_RESET_TRIES 5
#define HUB_PROBE_TRIES 2 #define SET_ADDRESS_TRIES 2
#define GET_DESCRIPTOR_TRIES 2
#define SET_CONFIG_TRIES 2
#define HUB_ROOT_RESET_TIME 50 /* times are in msec */ #define HUB_ROOT_RESET_TIME 50 /* times are in msec */
#define HUB_SHORT_RESET_TIME 10 #define HUB_SHORT_RESET_TIME 10
#define HUB_LONG_RESET_TIME 200 #define HUB_LONG_RESET_TIME 200
...@@ -907,7 +910,7 @@ static int hub_port_reset(struct usb_device *hub, int port, ...@@ -907,7 +910,7 @@ static int hub_port_reset(struct usb_device *hub, int port,
int i, status; int i, status;
/* Reset the port */ /* Reset the port */
for (i = 0; i < HUB_RESET_TRIES; i++) { for (i = 0; i < PORT_RESET_TRIES; i++) {
set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET); set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET);
/* return on disconnect or reset */ /* return on disconnect or reset */
...@@ -1003,40 +1006,20 @@ static int hub_port_debounce(struct usb_device *hub, int port) ...@@ -1003,40 +1006,20 @@ static int hub_port_debounce(struct usb_device *hub, int port)
return ((portstatus&USB_PORT_STAT_CONNECTION)) ? 0 : 1; return ((portstatus&USB_PORT_STAT_CONNECTION)) ? 0 : 1;
} }
static void hub_port_connect_change(struct usb_hub *hubstate, int port, /* reset device, (re)assign address, get device descriptor.
u16 portstatus, u16 portchange) * device connection is stable, no more debouncing needed.
* returns device in USB_STATE_ADDRESS, except on error.
* on error return, device is no longer usable (ref dropped).
*
* caller owns dev->serialize for the device, guarding against
* config changes and disconnect processing.
*/
static int
hub_port_init (struct usb_device *hub, struct usb_device *dev, int port)
{ {
struct usb_device *hub = interface_to_usbdev(hubstate->intf); int i, j, retval = -ENODEV;
struct usb_device *dev; unsigned delay = HUB_SHORT_RESET_TIME;
unsigned int delay = HUB_SHORT_RESET_TIME; enum usb_device_speed oldspeed = dev->speed;
int i;
dev_dbg (&hubstate->intf->dev,
"port %d, status %x, change %x, %s\n",
port + 1, portstatus, portchange, portspeed (portstatus));
/* Clear the connection change status */
clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_CONNECTION);
/* Disconnect any existing devices under this port */
if (hub->children[port])
usb_disconnect(&hub->children[port]);
/* Return now if nothing is connected */
if (!(portstatus & USB_PORT_STAT_CONNECTION)) {
if (portstatus & USB_PORT_STAT_ENABLE)
hub_port_disable(hub, port);
return;
}
if (hub_port_debounce(hub, port)) {
dev_err (&hubstate->intf->dev,
"connect-debounce failed, port %d disabled\n",
port+1);
hub_port_disable(hub, port);
return;
}
/* root hub ports have a slightly longer reset period /* root hub ports have a slightly longer reset period
* (from USB 2.0 spec, section 7.1.7.5) * (from USB 2.0 spec, section 7.1.7.5)
...@@ -1046,31 +1029,53 @@ static void hub_port_connect_change(struct usb_hub *hubstate, int port, ...@@ -1046,31 +1029,53 @@ static void hub_port_connect_change(struct usb_hub *hubstate, int port,
/* Some low speed devices have problems with the quick delay, so */ /* Some low speed devices have problems with the quick delay, so */
/* be a bit pessimistic with those devices. RHbug #23670 */ /* be a bit pessimistic with those devices. RHbug #23670 */
if (portstatus & USB_PORT_STAT_LOW_SPEED) if (oldspeed == USB_SPEED_LOW)
delay = HUB_LONG_RESET_TIME; delay = HUB_LONG_RESET_TIME;
down(&usb_address0_sem); down(&usb_address0_sem);
for (i = 0; i < HUB_PROBE_TRIES; i++) { /* Reset the device; full speed may morph to high speed */
switch (hub_port_reset(hub, port, dev, delay)) {
/* Allocate a new device struct */ case 0: /* success, speed is known */
dev = usb_alloc_dev(hub, hub->bus, port); break;
if (!dev) { case 1: /* disconnect, give to companion */
dev_err (&hubstate->intf->dev, retval = -EBUSY;
"couldn't allocate usb_device\n"); /* FALL THROUGH */
break; default: /* error */
} goto fail;
}
dev->state = USB_STATE_POWERED; if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != dev->speed) {
dev_dbg(&dev->dev, "device reset changed speed!\n");
/* Reset the device, and detect its speed */ goto fail;
if (hub_port_reset(hub, port, dev, delay)) { }
usb_put_dev(dev);
break; /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
} * it's fixed size except for full speed devices.
*/
/* Find a new address for it */ switch (dev->speed) {
case USB_SPEED_HIGH: /* fixed at 64 */
i = 64;
break;
case USB_SPEED_FULL: /* 8, 16, 32, or 64 */
/* to determine the ep0 maxpacket size, read the first 8
* bytes from the device descriptor to get bMaxPacketSize0;
* then correct our initial (small) guess.
*/
// FALLTHROUGH
case USB_SPEED_LOW: /* fixed at 8 */
i = 8;
break;
default:
goto fail;
}
dev->epmaxpacketin [0] = i;
dev->epmaxpacketout[0] = i;
/* set the address */
if (dev->devnum <= 0) {
usb_choose_address(dev); usb_choose_address(dev);
if (dev->devnum <= 0)
goto fail;
/* Set up TT records, if needed */ /* Set up TT records, if needed */
if (hub->tt) { if (hub->tt) {
...@@ -1078,12 +1083,21 @@ static void hub_port_connect_change(struct usb_hub *hubstate, int port, ...@@ -1078,12 +1083,21 @@ static void hub_port_connect_change(struct usb_hub *hubstate, int port,
dev->ttport = hub->ttport; dev->ttport = hub->ttport;
} else if (dev->speed != USB_SPEED_HIGH } else if (dev->speed != USB_SPEED_HIGH
&& hub->speed == USB_SPEED_HIGH) { && hub->speed == USB_SPEED_HIGH) {
struct usb_hub *hubstate;
hubstate = usb_get_intfdata (hub->actconfig
->interface[0]);
dev->tt = &hubstate->tt; dev->tt = &hubstate->tt;
dev->ttport = port + 1; dev->ttport = port + 1;
} }
dev_info (&dev->dev, /* force the right log message (below) at low speed */
"new %s speed USB device using address %d\n", oldspeed = USB_SPEED_UNKNOWN;
}
dev_info (&dev->dev,
"%s %s speed USB device using address %d\n",
(oldspeed == USB_SPEED_UNKNOWN) ? "new" : "reset",
({ char *speed; switch (dev->speed) { ({ char *speed; switch (dev->speed) {
case USB_SPEED_LOW: speed = "low"; break; case USB_SPEED_LOW: speed = "low"; break;
case USB_SPEED_FULL: speed = "full"; break; case USB_SPEED_FULL: speed = "full"; break;
...@@ -1091,23 +1105,155 @@ static void hub_port_connect_change(struct usb_hub *hubstate, int port, ...@@ -1091,23 +1105,155 @@ static void hub_port_connect_change(struct usb_hub *hubstate, int port,
default: speed = "?"; break; default: speed = "?"; break;
}; speed;}), }; speed;}),
dev->devnum); dev->devnum);
/* Run it through the hoops (find a driver, etc) */ /* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way?
if (usb_new_device(dev) == 0) { * Because device hardware and firmware is sometimes buggy in
hub->children[port] = dev; * this area, and this is how Linux has done it for ages.
goto done; * Change it cautiously.
*
* NOTE: Windows gets the descriptor first, seemingly to help
* work around device bugs like "can't use addresses with bit 3
* set in certain configurations". Yes, really.
*/
for (i = 0; i < GET_DESCRIPTOR_TRIES; ++i) {
for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
retval = usb_set_address(dev);
if (retval >= 0)
break;
wait_ms(200);
}
if (retval < 0) {
dev_err(&dev->dev,
"device not accepting address %d, error %d\n",
dev->devnum, retval);
fail:
hub_port_disable(hub, port);
clear_bit(dev->devnum, dev->bus->devmap.devicemap);
dev->devnum = -1;
usb_put_dev(dev);
up(&usb_address0_sem);
return retval;
} }
/* cope with hardware quirkiness:
* - let SET_ADDRESS settle, some device hardware wants it
* - read ep0 maxpacket even for high and low speed,
*/
wait_ms(10);
retval = usb_get_device_descriptor(dev, 8);
if (retval >= 8)
break;
wait_ms(100);
}
if (retval != 8) {
dev_err(&dev->dev, "device descriptor read/%s, error %d\n",
"8", retval);
if (retval >= 0)
retval = -EMSGSIZE;
goto fail;
}
if (dev->speed == USB_SPEED_FULL
&& (dev->epmaxpacketin [0]
!= dev->descriptor.bMaxPacketSize0)) {
usb_disable_endpoint(dev, 0);
usb_endpoint_running(dev, 0, 1);
usb_endpoint_running(dev, 0, 0);
dev->epmaxpacketin [0] = dev->descriptor.bMaxPacketSize0;
dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
}
retval = usb_get_device_descriptor(dev, USB_DT_DEVICE_SIZE);
if (retval < (signed)sizeof(dev->descriptor)) {
dev_err(&dev->dev, "device descriptor read/%s, error %d\n",
"all", retval);
if (retval >= 0)
retval = -ENOMSG;
goto fail;
}
/* Free the configuration if there was an error */ /* now dev is visible to other tasks */
usb_put_dev(dev); hub->children[port] = dev;
/* Switch to a long reset time */ up(&usb_address0_sem);
delay = HUB_LONG_RESET_TIME; return 0;
}
static void hub_port_connect_change(struct usb_hub *hubstate, int port,
u16 portstatus, u16 portchange)
{
struct usb_device *hub = interface_to_usbdev(hubstate->intf);
int status, i;
dev_dbg (&hubstate->intf->dev,
"port %d, status %04x, change %04x, %s\n",
port + 1, portstatus, portchange, portspeed (portstatus));
/* Clear the connection change status */
clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_CONNECTION);
if (hubstate->has_indicators) {
set_port_led(hub, hubstate, port + 1, HUB_LED_AUTO);
hubstate->indicator[port] = INDICATOR_AUTO;
}
/* Disconnect any existing devices under this port */
if (hub->children[port])
usb_disconnect(&hub->children[port]);
/* Return now if nothing is connected */
if (!(portstatus & USB_PORT_STAT_CONNECTION)) {
if (portstatus & USB_PORT_STAT_ENABLE)
goto done;
return;
}
if (hub_port_debounce(hub, port)) {
dev_err (&hubstate->intf->dev,
"connect-debounce failed, port %d disabled\n",
port+1);
goto done;
} }
hub_port_disable(hub, port); for (i = 0; i < SET_CONFIG_TRIES; i++) {
struct usb_device *dev;
/* reallocate for each attempt, since references
* to the previous one can escape in various ways
*/
dev = usb_alloc_dev(hub, hub->bus, port);
if (!dev) {
dev_err (&hubstate->intf->dev,
"couldn't allocate port %d usb_device\n", port+1);
goto done;
}
dev->state = USB_STATE_POWERED;
/* hub can tell if it's lowspeed already: D- pullup (not D+) */
if (portstatus & USB_PORT_STAT_LOW_SPEED)
dev->speed = USB_SPEED_LOW;
else
dev->speed = USB_SPEED_UNKNOWN;
/* reset, set address, get descriptor, add to hub's children */
down (&dev->serialize);
status = hub_port_init(hub, dev, port);
if (status == -EBUSY)
break;
if (status < 0)
continue;
/* Run it through the hoops (find a driver, etc) */
status = usb_new_device(dev);
if (status != 0) {
hub->children[port] = NULL;
continue;
}
up (&dev->serialize);
return;
}
done: done:
up(&usb_address0_sem); hub_port_disable(hub, port);
} }
static void hub_events(void) static void hub_events(void)
...@@ -1285,9 +1431,6 @@ static struct usb_driver hub_driver = { ...@@ -1285,9 +1431,6 @@ static struct usb_driver hub_driver = {
.id_table = hub_id_table, .id_table = hub_id_table,
}; };
/*
* This should be a separate module.
*/
int usb_hub_init(void) int usb_hub_init(void)
{ {
pid_t pid; pid_t pid;
......
...@@ -1064,92 +1064,29 @@ static inline void usb_show_string(struct usb_device *dev, char *id, int index) ...@@ -1064,92 +1064,29 @@ static inline void usb_show_string(struct usb_device *dev, char *id, int index)
} }
/* /*
* By the time we get here, we chose a new device address * usb_new_device - perform initial device setup (usbcore-internal)
* and is in the default state. We need to identify the thing and * @dev: newly addressed device (in ADDRESS state)
* get the ball rolling..
* *
* Returns 0 for success, != 0 for error. * This is called with devices which have been enumerated, but not yet
* configured. The device descriptor is available, but not descriptors
* for any device configuration. The caller owns dev->serialize, and
* the device is not visible through sysfs or other filesystem code.
*
* Returns 0 for success (device is configured and listed, with its
* interfaces, in sysfs); else a negative errno value. On error, one
* reference count to the device has been dropped.
* *
* This call is synchronous, and may not be used in an interrupt context. * This call is synchronous, and may not be used in an interrupt context.
* *
* Only the hub driver should ever call this; root hub registration * Only the hub driver should ever call this; root hub registration
* uses it only indirectly. * uses it only indirectly.
*/ */
#define NEW_DEVICE_RETRYS 2
#define SET_ADDRESS_RETRYS 2
int usb_new_device(struct usb_device *dev) int usb_new_device(struct usb_device *dev)
{ {
int err = -EINVAL; int err;
int i; int i;
int j;
int config; int config;
/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
* it's fixed size except for full speed devices.
*/
switch (dev->speed) {
case USB_SPEED_HIGH: /* fixed at 64 */
i = 64;
break;
case USB_SPEED_FULL: /* 8, 16, 32, or 64 */
/* to determine the ep0 maxpacket size, read the first 8
* bytes from the device descriptor to get bMaxPacketSize0;
* then correct our initial (small) guess.
*/
// FALLTHROUGH
case USB_SPEED_LOW: /* fixed at 8 */
i = 8;
break;
default:
goto fail;
}
dev->epmaxpacketin [0] = i;
dev->epmaxpacketout[0] = i;
for (i = 0; i < NEW_DEVICE_RETRYS; ++i) {
for (j = 0; j < SET_ADDRESS_RETRYS; ++j) {
err = usb_set_address(dev);
if (err >= 0)
break;
wait_ms(200);
}
if (err < 0) {
dev_err(&dev->dev,
"device not accepting address %d, error %d\n",
dev->devnum, err);
goto fail;
}
wait_ms(10); /* Let the SET_ADDRESS settle */
/* high and low speed devices don't need this... */
err = usb_get_device_descriptor(dev, 8);
if (err >= 8)
break;
wait_ms(100);
}
if (err < 8) {
dev_err(&dev->dev, "device descriptor read/8, error %d\n", err);
goto fail;
}
if (dev->speed == USB_SPEED_FULL) {
usb_disable_endpoint(dev, 0);
usb_endpoint_running(dev, 0, 1);
usb_endpoint_running(dev, 0, 0);
dev->epmaxpacketin [0] = dev->descriptor.bMaxPacketSize0;
dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
}
/* USB device state == addressed ... still not usable */
err = usb_get_device_descriptor(dev, sizeof(dev->descriptor));
if (err != (signed)sizeof(dev->descriptor)) {
dev_err(&dev->dev, "device descriptor read/all, error %d\n", err);
goto fail;
}
err = usb_get_configuration(dev); err = usb_get_configuration(dev);
if (err < 0) { if (err < 0) {
dev_err(&dev->dev, "can't read configurations, error %d\n", dev_err(&dev->dev, "can't read configurations, error %d\n",
...@@ -1170,13 +1107,10 @@ int usb_new_device(struct usb_device *dev) ...@@ -1170,13 +1107,10 @@ int usb_new_device(struct usb_device *dev)
usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber); usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber);
#endif #endif
down(&dev->serialize);
/* put device-specific files into sysfs */ /* put device-specific files into sysfs */
err = device_add (&dev->dev); err = device_add (&dev->dev);
if (err) { if (err) {
dev_err(&dev->dev, "can't device_add, error %d\n", err); dev_err(&dev->dev, "can't device_add, error %d\n", err);
up(&dev->serialize);
goto fail; goto fail;
} }
usb_create_driverfs_dev_files (dev); usb_create_driverfs_dev_files (dev);
...@@ -1211,7 +1145,6 @@ int usb_new_device(struct usb_device *dev) ...@@ -1211,7 +1145,6 @@ int usb_new_device(struct usb_device *dev)
dev->descriptor.bNumConfigurations); dev->descriptor.bNumConfigurations);
} }
err = usb_set_configuration(dev, config); err = usb_set_configuration(dev, config);
up(&dev->serialize);
if (err) { if (err) {
dev_err(&dev->dev, "can't set config #%d, error %d\n", dev_err(&dev->dev, "can't set config #%d, error %d\n",
config, err); config, err);
...@@ -1226,9 +1159,10 @@ int usb_new_device(struct usb_device *dev) ...@@ -1226,9 +1159,10 @@ int usb_new_device(struct usb_device *dev)
return 0; return 0;
fail: fail:
dev->state = USB_STATE_DEFAULT; dev->state = USB_STATE_NOTATTACHED;
clear_bit(dev->devnum, dev->bus->devmap.devicemap); clear_bit(dev->devnum, dev->bus->devmap.devicemap);
dev->devnum = -1; dev->devnum = -1;
usb_put_dev(dev);
return err; return err;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment