Hi,
here's the version which should be correct and incorporates Greg's
suggestions. Now, does anybody on this list actually have a device with
multiple configurations ?
Regards
Oliver
--- usb-2.5/drivers/usb/core/hub.c 2002-10-12 14:49:17.000000000 +0200
+++ con25/drivers/usb/core/hub.c 2002-10-11 15:37:49.000000000 +0200
@@ -1237,7 +1236,7 @@
return 1;
}
- ret = usb_set_configuration(dev, dev->actconfig->bConfigurationValue);
+ ret = usb_physical_set_conf(dev, dev->actconfig->bConfigurationValue);
if (ret < 0) {
err("failed to set dev %s active configuration (error=%d)",
dev->devpath, ret);
--- usb-2.5/drivers/usb/core/message.c 2002-10-08 21:30:09.000000000 +0200
+++ con25/drivers/usb/core/message.c 2002-10-12 21:31:02.000000000 +0200
@@ -838,6 +838,54 @@
}
/**
+ * usb_physical_set_conf - send the actual message changing configuration
+ * @dev: the device whose configuration is being updated
+ * @configuration: the configuration being chosen.
+ * Context: !in_interrupt ()
+ *
+ * Caller must make sure that disconnect processing waits for this to
complete
+ */
+static inline struct usb_config_descriptor *find_valid_config(struct
usb_device *dev, int configuration)
+{
+ int i;
+
+ for (i=0; i<dev->descriptor.bNumConfigurations; i++) {
+ if (dev->config[i].bConfigurationValue == configuration) {
+ return &dev->config[i];
+
+ }
+ }
+
+ return NULL;
+}
+
+int usb_physical_set_conf(struct usb_device *dev, int configuration)
+{
+ int r;
+ struct usb_config_descriptor *cp;
+
+ r = -EINVAL;
+ cp = find_valid_config(dev, configuration);
+ if (!cp)
+ goto err;
+
+ r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
+ NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
+ if (r)
+ goto err;
+
+ dev->actconfig = cp;
+ dev->toggle[0] = 0;
+ dev->toggle[1] = 0;
+ usb_set_maxpacket(dev);
+
+err:
+ return r;
+
+}
+
+/**
* usb_set_configuration - Makes a particular device setting be current
* @dev: the device whose configuration is being updated
* @configuration: the configuration being chosen.
@@ -871,7 +919,7 @@
{
int i, ret;
struct usb_config_descriptor *cp = NULL;
-
+
for (i=0; i<dev->descriptor.bNumConfigurations; i++) {
if (dev->config[i].bConfigurationValue == configuration) {
cp = &dev->config[i];
@@ -883,17 +931,28 @@
return -EINVAL;
}
- if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
- NULL, 0, HZ * USB_CTRL_SET_TIMEOUT)) < 0)
- return ret;
+ down(&dev->serialize);
- dev->actconfig = cp;
- dev->toggle[0] = 0;
- dev->toggle[1] = 0;
- usb_set_maxpacket(dev);
+ for (i = 0; i < USB_MAXCHILDREN; i++) {
+ struct usb_device **child = dev->children + i;
+ if (*child) {
+ ret = -EBUSY;
+ goto err; /* refuse if children were harmed */
+ }
+ }
+
+ usb_reap_interfaces(dev); /* get rid of all interfaces */
+
+ if ((ret = usb_physical_set_conf(dev, configuration)))
+ goto err;
+
+ dev->desired_conf = configuration; /* for pm */
+
+ ret = usb_register_interfaces(dev); /* reevaluate device */
- return 0;
+err:
+ up(&dev->serialize);
+ return ret;
}
--- usb-2.5/drivers/usb/core/usb.c 2002-10-12 14:49:17.000000000 +0200
+++ con25/drivers/usb/core/usb.c 2002-10-12 21:28:47.000000000 +0200
@@ -78,6 +75,7 @@
{
struct usb_interface * intf = to_usb_interface(dev);
struct usb_driver * driver = to_usb_driver(dev->driver);
+ struct usb_device * udev = interface_to_usbdev(intf);
const struct usb_device_id *id;
int error = -ENODEV;
int m;
@@ -97,7 +95,9 @@
if (id) {
dbg ("%s - got id", __FUNCTION__);
down (&driver->serialize);
+ down (&udev->serialize);
error = driver->probe (intf, id);
+ up (&udev->serialize);
up (&driver->serialize);
}
if (!error)
@@ -113,10 +113,12 @@
{
struct usb_interface *intf;
struct usb_driver *driver;
+ struct usb_device *udev;
int m;
intf = list_entry(dev,struct usb_interface,dev);
driver = to_usb_driver(dev->driver);
+ udev = interface_to_usbdev(intf);
if (!driver) {
err("%s does not have a valid driver to work with!",
@@ -135,10 +137,10 @@
}
/* if we sleep here on an umanaged driver
- * the holder of the lock guards against
+ * the holder of the lock guards against
* module unload */
down(&driver->serialize);
-
+ down(&udev->serialize);
if (intf->driver && intf->driver->disconnect)
intf->driver->disconnect(intf);
@@ -146,6 +148,7 @@
if (intf->driver)
usb_driver_release_interface(driver, intf);
+ up(&udev->serialize);
up(&driver->serialize);
if (driver->owner)
__MOD_DEC_USE_COUNT(driver->owner);
@@ -759,6 +767,26 @@
return -1;
}
+/** usb_reap_interfaces - disconnect all interfaces of a usb device
+ * @dev: pointer to the device whose interfaces shall be disconnected
+ * Context: !in_interrupt ()
+ *
+ * Getting rid of interfaces associated with drivers.
+ * This is for physical disconnection and configuration changes
+ */
+void usb_reap_interfaces(struct usb_device *dev)
+{
+ int i;
+
+ if (dev->actconfig) {
+ for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
+ struct usb_interface *interface =
+&dev->actconfig->interface[i];
+
+ /* remove this interface */
+ device_unregister(&interface->dev);
+ }
+ }
+}
/**
* usb_disconnect - disconnect a device (usbcore-internal)
* @pdev: pointer to device being disconnected
@@ -790,20 +818,13 @@
usb_disconnect(child);
}
- if (dev->actconfig) {
- for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
- struct usb_interface *interface =
&dev->actconfig->interface[i];
-
- /* remove this interface */
- device_unregister(&interface->dev);
- }
- }
+ usb_reap_interfaces(dev);
/* Free the device number and remove the /proc/bus/usb entry */
if (dev->devnum > 0) {
clear_bit(dev->devnum, dev->bus->devmap.devicemap);
usbfs_remove_device(dev);
@@ -921,6 +942,50 @@
}
/*
+ * This registers a device's interfaces with the generic device layer
+ *
+ * for new devices or configuration changes
+ */
+int usb_register_interfaces(struct usb_device *dev)
+{
+ int i;
+
+ /* Register all of the interfaces for this device with the driver core.
+ * Remember, interfaces get bound to drivers, not devices. */
+ for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
+ struct usb_interface *interface = &dev->actconfig->interface[i];
+ struct usb_interface_descriptor *desc = interface->altsetting;
+
+ interface->dev.parent = &dev->dev;
+ interface->dev.driver = NULL;
+ interface->dev.bus = &usb_bus_type;
+ sprintf (&interface->dev.bus_id[0], "%d-%s:%d",
+ dev->bus->busnum, dev->devpath,
+ interface->altsetting->bInterfaceNumber);
+ if (!desc->iInterface
+ || usb_string (dev, desc->iInterface,
+ interface->dev.name,
+ sizeof interface->dev.name) <= 0) {
+ /* typically devices won't bother with interface
+ * descriptions; this is the normal case. an
+ * interface's driver might describe it better.
+ * (also: iInterface is per-altsetting ...)
+ */
+ sprintf (&interface->dev.name[0],
+ "usb-%s-%s interface %d",
+ dev->bus->bus_name, dev->devpath,
+ interface->altsetting->bInterfaceNumber);
+ }
+ dbg ("%s - registering %s", __FUNCTION__, interface->dev.bus_id);
+ device_register (&interface->dev);
+ usb_create_driverfs_intf_files (interface);
+ }
+
+ return 0;
+}
+
+
+/*
* By the time we get here, the device has gotten a new device ID
* and is in the default state. We need to identify the thing and
* get the ball rolling..
@@ -1006,7 +1071,7 @@
}
/* we set the default configuration here */
- err = usb_set_configuration(dev, dev->config[0].bConfigurationValue);
+ err = usb_physical_set_conf(dev, dev->config[0].bConfigurationValue);
if (err) {
err("failed to set device %d default configuration (error=%d)",
dev->devnum, err);
@@ -1042,37 +1107,11 @@
/* add the USB device specific driverfs files */
usb_create_driverfs_dev_files (dev);
-
- /* Register all of the interfaces for this device with the driver core.
- * Remember, interfaces get bound to drivers, not devices. */
- for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
- struct usb_interface *interface = &dev->actconfig->interface[i];
- struct usb_interface_descriptor *desc = interface->altsetting;
-
- interface->dev.parent = &dev->dev;
- interface->dev.driver = NULL;
- interface->dev.bus = &usb_bus_type;
- sprintf (&interface->dev.bus_id[0], "%d-%s:%d",
- dev->bus->busnum, dev->devpath,
- interface->altsetting->bInterfaceNumber);
- if (!desc->iInterface
- || usb_string (dev, desc->iInterface,
- interface->dev.name,
- sizeof interface->dev.name) <= 0) {
- /* typically devices won't bother with interface
- * descriptions; this is the normal case. an
- * interface's driver might describe it better.
- * (also: iInterface is per-altsetting ...)
- */
- sprintf (&interface->dev.name[0],
- "usb-%s-%s interface %d",
- dev->bus->bus_name, dev->devpath,
- interface->altsetting->bInterfaceNumber);
- }
- dbg ("%s - registering %s", __FUNCTION__, interface->dev.bus_id);
- device_register (&interface->dev);
- usb_create_driverfs_intf_files (interface);
- }
+
+ err = usb_register_interfaces(dev);
+
+ if (err)
+ return err;
/* add a /proc/bus/usb entry */
usbfs_add_device(dev);
--- usb-2.5/include/linux/usb.h 2002-10-12 14:49:19.000000000 +0200
+++ con25/include/linux/usb.h 2002-10-12 21:32:23.000000000 +0200
@@ -375,6 +375,7 @@
int have_langid; /* whether string_langid is valid yet */
int string_langid; /* language ID for strings */
+ int desired_conf; /* configuration to restore on resume */
void *hcpriv; /* Host Controller private data */
@@ -1033,6 +1033,9 @@
struct scatterlist *sg, int n_hw_ents);
void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
struct scatterlist *sg, int n_hw_ents);
+void usb_reap_interfaces(struct usb_device *dev);
+int usb_physical_set_conf(struct usb_device *dev, int configuration);
+int usb_register_interfaces(struct usb_device *dev);
/*-------------------------------------------------------------------*
* SYNCHRONOUS CALL SUPPORT *
-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel