Alan Stern wrote:
On Mon, 11 Jun 2007, Craig W. Nadler wrote:
+
+               first_intf = intf_assoc->bFirstInterface;
+               last_intf = first_intf + (intf_assoc->bInterfaceCount - 1);
+               if (inum >= first_intf && inum <= last_intf) {
+                       if (!retval) {
+                               retval = intf_assoc;
+                       } else {
+                               dev_err (&dev->dev, "Interface #%d referenced"
+                                               " by multiple IADs\n", inum);
+                       }

Are you really sure this needs to be an error and not a warning?

Remember also what I said earlier about putting extraneous space
characters between a function name and the following open paren.

The IAD spec. states that an interface can only be referenced by one IAD. The structure of the IAD also forces the interfaces referenced to be consecutively numbered. The interfaces are referenced in the descriptor by the interface number of the first associated interface and the number of interfaces.


diff -uprN a/include/linux/usb.h b/include/linux/usb.h
--- a/include/linux/usb.h       2007-05-24 17:22:47.000000000 -0400
+++ b/include/linux/usb.h       2007-06-09 03:20:51.000000000 -0400
@@ -245,6 +250,11 @@ struct usb_host_config {
        struct usb_config_descriptor    desc;
char *string; /* iConfiguration string, if present */
+       
+       /* List of any Interface Association Descriptors in this
+        * configuration. */
+       struct usb_interface_assoc_descriptor *intf_assoc[USB_MAXIADS];

This may be just my own confusion, but is it necessary to list
interface association descriptors in both the host_interface and the
host_config structures?

The list of IADs in the host_config is all the IADs for that configuration. The IAD pointer in the host_interface structure is only the one that references that interface. The first is used if you're looking at the configuration and trying to find groups of associated interfaces. The second is used if you are probing an interface and trying to find other interfaces associated with it.

An updated patch is attached.


Best Regards,

Craig Nadler
diff -uprN a/drivers/usb/core/config.c b/drivers/usb/core/config.c
--- a/drivers/usb/core/config.c	2007-06-07 17:27:31.000000000 -0400
+++ b/drivers/usb/core/config.c	2007-06-13 23:05:33.000000000 -0400
@@ -232,6 +232,7 @@ static int usb_parse_configuration(struc
 	struct usb_descriptor_header *header;
 	int len, retval;
 	u8 inums[USB_MAXINTERFACES], nalts[USB_MAXINTERFACES];
+	unsigned iad_num = 0;
 
 	memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE);
 	if (config->desc.bDescriptorType != USB_DT_CONFIG ||
@@ -309,6 +310,20 @@ static int usb_parse_configuration(struc
 				++n;
 			}
 
+		} else if (header->bDescriptorType ==
+				USB_DT_INTERFACE_ASSOCIATION) {
+			if (iad_num == USB_MAXIADS) {
+				dev_warn(ddev, "found more Interface "
+					       "Association Descriptors "
+					       "than allocated for in "
+					       "configuration %d\n", cfgno);
+			} else {
+				config->intf_assoc[iad_num] =
+					(struct usb_interface_assoc_descriptor 
+					*)header;
+				iad_num++;
+			}
+
 		} else if (header->bDescriptorType == USB_DT_DEVICE ||
 			    header->bDescriptorType == USB_DT_CONFIG)
 			dev_warn(ddev, "config %d contains an unexpected "
diff -uprN a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
--- a/drivers/usb/core/devices.c	2007-06-07 17:27:31.000000000 -0400
+++ b/drivers/usb/core/devices.c	2007-06-13 22:02:16.000000000 -0400
@@ -102,6 +102,10 @@ static const char *format_config =
 /* C:  #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA */
   "C:%c #Ifs=%2d Cfg#=%2d Atr=%02x MxPwr=%3dmA\n";
   
+static const char *format_iad =
+/* A:  FirstIf#=dd IfCount=dd Cls=xx(sssss) Sub=xx Prot=xx */
+  "A:  FirstIf#=%2d IfCount=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x\n";
+  
 static const char *format_iface =
 /* I:  If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=xxxx*/
   "I:%c If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
@@ -146,6 +150,7 @@ static const struct class_info clas_info
 	{USB_CLASS_STILL_IMAGE,		"still"},
 	{USB_CLASS_CSCID,		"scard"},
 	{USB_CLASS_CONTENT_SEC,		"c-sec"},
+	{USB_CLASS_VIDEO,		"video"},
 	{-1,				"unk."}		/* leave as last */
 };
 
@@ -288,6 +293,21 @@ static char *usb_dump_interface(
 	return start;
 }
 
+static char *usb_dump_iad_descriptor(char *start, char *end,
+	const struct usb_interface_assoc_descriptor *iad)
+{
+	if (start > end)
+		return start;
+	start += sprintf(start, format_iad,
+			 iad->bFirstInterface,
+			 iad->bInterfaceCount,
+			 iad->bFunctionClass,
+			 class_decode(iad->bFunctionClass),
+			 iad->bFunctionSubClass,
+			 iad->bFunctionProtocol);
+	return start;
+}
+
 /* TBD:
  * 0. TBDs
  * 1. marking active interface altsettings (code lists all, but should mark
@@ -324,6 +344,12 @@ static char *usb_dump_config (
 	if (!config)		/* getting these some in 2.3.7; none in 2.3.6 */
 		return start + sprintf(start, "(null Cfg. desc.)\n");
 	start = usb_dump_config_descriptor(start, end, &config->desc, active);
+	for (i = 0; i < USB_MAXIADS; i++) {
+		if (config->intf_assoc[i] == NULL)
+			break;
+		start = usb_dump_iad_descriptor(start, end,
+					config->intf_assoc[i]);
+	}
 	for (i = 0; i < config->desc.bNumInterfaces; i++) {
 		intfc = config->intf_cache[i];
 		interface = config->interface[i];
diff -uprN a/drivers/usb/core/message.c b/drivers/usb/core/message.c
--- a/drivers/usb/core/message.c	2007-06-07 17:27:31.000000000 -0400
+++ b/drivers/usb/core/message.c	2007-06-13 22:02:16.000000000 -0400
@@ -1315,6 +1315,40 @@ static void release_interface(struct dev
 	kfree(intf);
 }
 
+
+
+static struct usb_interface_assoc_descriptor *find_iad(
+	struct usb_device	*dev,
+	struct usb_host_config	*config,
+	u8			inum)
+{
+	u8 i;
+	struct usb_interface_assoc_descriptor *retval = NULL;
+	
+	for (i=0; (i < USB_MAXIADS && config->intf_assoc[i]); i++) {
+		struct usb_interface_assoc_descriptor *intf_assoc;
+		u8 first_intf, last_intf;
+
+		intf_assoc = config->intf_assoc[i];
+		if (intf_assoc->bInterfaceCount == 0)
+			continue;
+
+		first_intf = intf_assoc->bFirstInterface;
+		last_intf = first_intf + (intf_assoc->bInterfaceCount - 1);
+		if (inum >= first_intf && inum <= last_intf) {
+			if (!retval) {
+				retval = intf_assoc;
+			} else {
+				dev_err(&dev->dev, "Interface #%d referenced"
+						" by multiple IADs\n", inum);
+			}
+		}
+	}
+
+	return retval;
+}
+
+
 /*
  * usb_set_configuration - Makes a particular device setting be current
  * @dev: the device whose configuration is being updated
@@ -1461,6 +1495,7 @@ free_interfaces:
 		intfc = cp->intf_cache[i];
 		intf->altsetting = intfc->altsetting;
 		intf->num_altsetting = intfc->num_altsetting;
+		intf->intf_assoc = find_iad(dev, cp, i);
 		kref_get(&intfc->ref);
 
 		alt = usb_altnum_to_altsetting(intf, 0);
diff -uprN a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
--- a/drivers/usb/core/sysfs.c	2007-06-07 17:27:31.000000000 -0400
+++ b/drivers/usb/core/sysfs.c	2007-06-13 23:14:05.000000000 -0400
@@ -329,6 +329,25 @@ void usb_remove_sysfs_dev_files(struct u
 	sysfs_remove_group(&dev->kobj, &dev_attr_grp);
 }
 
+/* Interface Accociation Descriptor fields */
+#define usb_intf_assoc_attr(field, format_string)			\
+static ssize_t								\
+show_iad_##field (struct device *dev, struct device_attribute *attr,	\
+		char *buf)						\
+{									\
+	struct usb_interface *intf = to_usb_interface (dev);		\
+									\
+	return sprintf (buf, format_string,				\
+			intf->intf_assoc->field); 		\
+}									\
+static DEVICE_ATTR(iad_##field, S_IRUGO, show_iad_##field, NULL);
+
+usb_intf_assoc_attr (bFirstInterface, "%02x\n")
+usb_intf_assoc_attr (bInterfaceCount, "%02d\n")
+usb_intf_assoc_attr (bFunctionClass, "%02x\n")
+usb_intf_assoc_attr (bFunctionSubClass, "%02x\n")
+usb_intf_assoc_attr (bFunctionProtocol, "%02x\n")
+
 /* Interface fields */
 #define usb_intf_attr(field, format_string)				\
 static ssize_t								\
@@ -392,6 +411,18 @@ static ssize_t show_modalias(struct devi
 }
 static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
 
+static struct attribute *intf_assoc_attrs[] = {
+	&dev_attr_iad_bFirstInterface.attr,
+	&dev_attr_iad_bInterfaceCount.attr,
+	&dev_attr_iad_bFunctionClass.attr,
+	&dev_attr_iad_bFunctionSubClass.attr,
+	&dev_attr_iad_bFunctionProtocol.attr,
+	NULL,
+};
+static struct attribute_group intf_assoc_attr_grp = {
+	.attrs = intf_assoc_attrs,
+};
+
 static struct attribute *intf_attrs[] = {
 	&dev_attr_bInterfaceNumber.attr,
 	&dev_attr_bAlternateSetting.attr,
@@ -443,6 +474,8 @@ int usb_create_sysfs_intf_files(struct u
 		alt->string = usb_cache_string(udev, alt->desc.iInterface);
 	if (alt->string)
 		retval = device_create_file(dev, &dev_attr_interface);
+	if (intf->intf_assoc)
+		retval = sysfs_create_group(&dev->kobj, &intf_assoc_attr_grp);
 	usb_create_intf_ep_files(intf, udev);
 	return 0;
 }
@@ -454,4 +487,5 @@ void usb_remove_sysfs_intf_files(struct 
 	usb_remove_intf_ep_files(intf);
 	device_remove_file(dev, &dev_attr_interface);
 	sysfs_remove_group(&dev->kobj, &intf_attr_grp);
+	sysfs_remove_group(&intf->dev.kobj, &intf_assoc_attr_grp);
 }
diff -uprN a/include/linux/usb.h b/include/linux/usb.h
--- a/include/linux/usb.h	2007-06-07 17:27:31.000000000 -0400
+++ b/include/linux/usb.h	2007-06-13 22:02:16.000000000 -0400
@@ -146,6 +146,10 @@ struct usb_interface {
 					 * active alternate setting */
 	unsigned num_altsetting;	/* number of alternate settings */
 
+	/* If there is an interface association descriptor then it will list
+	 * the associated interfaces */
+	struct usb_interface_assoc_descriptor *intf_assoc;
+
 	int minor;			/* minor number this interface is
 					 * bound to */
 	enum usb_interface_condition condition;		/* state of binding */
@@ -175,6 +179,7 @@ void usb_put_intf(struct usb_interface *
 
 /* this maximum is arbitrary */
 #define USB_MAXINTERFACES	32
+#define USB_MAXIADS		USB_MAXINTERFACES/2
 
 /**
  * struct usb_interface_cache - long-term representation of a device interface
@@ -245,6 +250,11 @@ struct usb_host_config {
 	struct usb_config_descriptor	desc;
 
 	char *string;		/* iConfiguration string, if present */
+	
+	/* List of any Interface Association Descriptors in this
+	 * configuration. */
+	struct usb_interface_assoc_descriptor *intf_assoc[USB_MAXIADS];
+
 	/* the interfaces associated with this configuration,
 	 * stored in no particular order */
 	struct usb_interface *interface[USB_MAXINTERFACES];
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to