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