2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2024-12-20 19:23:57 +08:00

[PATCH] usbcore: recovery from Set-Configuration failure

This patch (as703) improves the error handling when a Set-Configuration
request fails.  The old interfaces are all unregistered before the
request is sent, and if the request fails then we don't know what config
the device is using.  So it makes no sense to leave actconfig pointing
to the old configuration with its invalid interfaces.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Alan Stern 2006-06-01 13:59:16 -04:00 committed by Greg Kroah-Hartman
parent df9a1f482d
commit 6ad07129a8

View File

@ -1411,6 +1411,12 @@ free_interfaces:
return ret; return ret;
} }
} }
i = dev->bus_mA - cp->desc.bMaxPower * 2;
if (i < 0)
dev_warn(&dev->dev, "new config #%d exceeds power "
"limit by %dmA\n",
configuration, -i);
} }
/* if it's already configured, clear out old state first. /* if it's already configured, clear out old state first.
@ -1419,92 +1425,85 @@ free_interfaces:
if (dev->state != USB_STATE_ADDRESS) if (dev->state != USB_STATE_ADDRESS)
usb_disable_device (dev, 1); // Skip ep0 usb_disable_device (dev, 1); // Skip ep0
if (cp) {
i = dev->bus_mA - cp->desc.bMaxPower * 2;
if (i < 0)
dev_warn(&dev->dev, "new config #%d exceeds power "
"limit by %dmA\n",
configuration, -i);
}
if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_SET_CONFIGURATION, 0, configuration, 0, USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0) NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0) {
goto free_interfaces;
/* All the old state is gone, so what else can we do?
* The device is probably useless now anyway.
*/
cp = NULL;
}
dev->actconfig = cp; dev->actconfig = cp;
if (!cp) if (!cp) {
usb_set_device_state(dev, USB_STATE_ADDRESS); usb_set_device_state(dev, USB_STATE_ADDRESS);
else { goto free_interfaces;
usb_set_device_state(dev, USB_STATE_CONFIGURED); }
usb_set_device_state(dev, USB_STATE_CONFIGURED);
/* Initialize the new interface structures and the /* Initialize the new interface structures and the
* hc/hcd/usbcore interface/endpoint state. * hc/hcd/usbcore interface/endpoint state.
*/
for (i = 0; i < nintf; ++i) {
struct usb_interface_cache *intfc;
struct usb_interface *intf;
struct usb_host_interface *alt;
cp->interface[i] = intf = new_interfaces[i];
intfc = cp->intf_cache[i];
intf->altsetting = intfc->altsetting;
intf->num_altsetting = intfc->num_altsetting;
kref_get(&intfc->ref);
alt = usb_altnum_to_altsetting(intf, 0);
/* No altsetting 0? We'll assume the first altsetting.
* We could use a GetInterface call, but if a device is
* so non-compliant that it doesn't have altsetting 0
* then I wouldn't trust its reply anyway.
*/ */
for (i = 0; i < nintf; ++i) { if (!alt)
struct usb_interface_cache *intfc; alt = &intf->altsetting[0];
struct usb_interface *intf;
struct usb_host_interface *alt;
cp->interface[i] = intf = new_interfaces[i]; intf->cur_altsetting = alt;
intfc = cp->intf_cache[i]; usb_enable_interface(dev, intf);
intf->altsetting = intfc->altsetting; intf->dev.parent = &dev->dev;
intf->num_altsetting = intfc->num_altsetting; intf->dev.driver = NULL;
kref_get(&intfc->ref); intf->dev.bus = &usb_bus_type;
intf->dev.dma_mask = dev->dev.dma_mask;
intf->dev.release = release_interface;
device_initialize (&intf->dev);
mark_quiesced(intf);
sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d",
dev->bus->busnum, dev->devpath,
configuration, alt->desc.bInterfaceNumber);
}
kfree(new_interfaces);
alt = usb_altnum_to_altsetting(intf, 0); if (cp->string == NULL)
cp->string = usb_cache_string(dev, cp->desc.iConfiguration);
/* No altsetting 0? We'll assume the first altsetting. /* Now that all the interfaces are set up, register them
* We could use a GetInterface call, but if a device is * to trigger binding of drivers to interfaces. probe()
* so non-compliant that it doesn't have altsetting 0 * routines may install different altsettings and may
* then I wouldn't trust its reply anyway. * claim() any interfaces not yet bound. Many class drivers
*/ * need that: CDC, audio, video, etc.
if (!alt) */
alt = &intf->altsetting[0]; for (i = 0; i < nintf; ++i) {
struct usb_interface *intf = cp->interface[i];
intf->cur_altsetting = alt; dev_dbg (&dev->dev,
usb_enable_interface(dev, intf); "adding %s (config #%d, interface %d)\n",
intf->dev.parent = &dev->dev; intf->dev.bus_id, configuration,
intf->dev.driver = NULL; intf->cur_altsetting->desc.bInterfaceNumber);
intf->dev.bus = &usb_bus_type; ret = device_add (&intf->dev);
intf->dev.dma_mask = dev->dev.dma_mask; if (ret != 0) {
intf->dev.release = release_interface; dev_err(&dev->dev, "device_add(%s) --> %d\n",
device_initialize (&intf->dev); intf->dev.bus_id, ret);
mark_quiesced(intf); continue;
sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d",
dev->bus->busnum, dev->devpath,
configuration,
alt->desc.bInterfaceNumber);
}
kfree(new_interfaces);
if (cp->string == NULL)
cp->string = usb_cache_string(dev,
cp->desc.iConfiguration);
/* Now that all the interfaces are set up, register them
* to trigger binding of drivers to interfaces. probe()
* routines may install different altsettings and may
* claim() any interfaces not yet bound. Many class drivers
* need that: CDC, audio, video, etc.
*/
for (i = 0; i < nintf; ++i) {
struct usb_interface *intf = cp->interface[i];
dev_dbg (&dev->dev,
"adding %s (config #%d, interface %d)\n",
intf->dev.bus_id, configuration,
intf->cur_altsetting->desc.bInterfaceNumber);
ret = device_add (&intf->dev);
if (ret != 0) {
dev_err(&dev->dev,
"device_add(%s) --> %d\n",
intf->dev.bus_id,
ret);
continue;
}
usb_create_sysfs_intf_files (intf);
} }
usb_create_sysfs_intf_files (intf);
} }
return 0; return 0;