USB: Interface Association Descriptors added to CDC & RNDIS
Without Interface Association Descriptor, the CDC serial and RNDIS functions did not work correctly when added to a composite gadget with other functions. This is because, it defined two interfaces and some hosts tried to treat each interface separatelly. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: David Brownell <dbrownell@users.sourceforge.net> Cc: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
9c61021337
commit
b97503ffa7
@ -4,6 +4,8 @@
|
|||||||
* Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
|
* Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
|
||||||
* Copyright (C) 2008 by David Brownell
|
* Copyright (C) 2008 by David Brownell
|
||||||
* Copyright (C) 2008 by Nokia Corporation
|
* Copyright (C) 2008 by Nokia Corporation
|
||||||
|
* Copyright (C) 2009 by Samsung Electronics
|
||||||
|
* Author: Michal Nazarewicz (m.nazarewicz@samsung.com)
|
||||||
*
|
*
|
||||||
* This software is distributed under the terms of the GNU General
|
* This software is distributed under the terms of the GNU General
|
||||||
* Public License ("GPL") as published by the Free Software Foundation,
|
* Public License ("GPL") as published by the Free Software Foundation,
|
||||||
@ -99,6 +101,20 @@ static inline struct f_acm *port_to_acm(struct gserial *p)
|
|||||||
|
|
||||||
/* interface and class descriptors: */
|
/* interface and class descriptors: */
|
||||||
|
|
||||||
|
static struct usb_interface_assoc_descriptor
|
||||||
|
acm_iad_descriptor = {
|
||||||
|
.bLength = sizeof acm_iad_descriptor,
|
||||||
|
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
|
||||||
|
|
||||||
|
/* .bFirstInterface = DYNAMIC, */
|
||||||
|
.bInterfaceCount = 2, // control + data
|
||||||
|
.bFunctionClass = USB_CLASS_COMM,
|
||||||
|
.bFunctionSubClass = USB_CDC_SUBCLASS_ACM,
|
||||||
|
.bFunctionProtocol = USB_CDC_PROTO_NONE,
|
||||||
|
/* .iFunction = DYNAMIC */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
static struct usb_interface_descriptor acm_control_interface_desc __initdata = {
|
static struct usb_interface_descriptor acm_control_interface_desc __initdata = {
|
||||||
.bLength = USB_DT_INTERFACE_SIZE,
|
.bLength = USB_DT_INTERFACE_SIZE,
|
||||||
.bDescriptorType = USB_DT_INTERFACE,
|
.bDescriptorType = USB_DT_INTERFACE,
|
||||||
@ -178,6 +194,7 @@ static struct usb_endpoint_descriptor acm_fs_out_desc __initdata = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static struct usb_descriptor_header *acm_fs_function[] __initdata = {
|
static struct usb_descriptor_header *acm_fs_function[] __initdata = {
|
||||||
|
(struct usb_descriptor_header *) &acm_iad_descriptor,
|
||||||
(struct usb_descriptor_header *) &acm_control_interface_desc,
|
(struct usb_descriptor_header *) &acm_control_interface_desc,
|
||||||
(struct usb_descriptor_header *) &acm_header_desc,
|
(struct usb_descriptor_header *) &acm_header_desc,
|
||||||
(struct usb_descriptor_header *) &acm_call_mgmt_descriptor,
|
(struct usb_descriptor_header *) &acm_call_mgmt_descriptor,
|
||||||
@ -216,6 +233,7 @@ static struct usb_endpoint_descriptor acm_hs_out_desc __initdata = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static struct usb_descriptor_header *acm_hs_function[] __initdata = {
|
static struct usb_descriptor_header *acm_hs_function[] __initdata = {
|
||||||
|
(struct usb_descriptor_header *) &acm_iad_descriptor,
|
||||||
(struct usb_descriptor_header *) &acm_control_interface_desc,
|
(struct usb_descriptor_header *) &acm_control_interface_desc,
|
||||||
(struct usb_descriptor_header *) &acm_header_desc,
|
(struct usb_descriptor_header *) &acm_header_desc,
|
||||||
(struct usb_descriptor_header *) &acm_call_mgmt_descriptor,
|
(struct usb_descriptor_header *) &acm_call_mgmt_descriptor,
|
||||||
@ -232,11 +250,13 @@ static struct usb_descriptor_header *acm_hs_function[] __initdata = {
|
|||||||
|
|
||||||
#define ACM_CTRL_IDX 0
|
#define ACM_CTRL_IDX 0
|
||||||
#define ACM_DATA_IDX 1
|
#define ACM_DATA_IDX 1
|
||||||
|
#define ACM_IAD_IDX 2
|
||||||
|
|
||||||
/* static strings, in UTF-8 */
|
/* static strings, in UTF-8 */
|
||||||
static struct usb_string acm_string_defs[] = {
|
static struct usb_string acm_string_defs[] = {
|
||||||
[ACM_CTRL_IDX].s = "CDC Abstract Control Model (ACM)",
|
[ACM_CTRL_IDX].s = "CDC Abstract Control Model (ACM)",
|
||||||
[ACM_DATA_IDX].s = "CDC ACM Data",
|
[ACM_DATA_IDX].s = "CDC ACM Data",
|
||||||
|
[ACM_IAD_IDX ].s = "CDC Serial",
|
||||||
{ /* ZEROES END LIST */ },
|
{ /* ZEROES END LIST */ },
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -563,6 +583,7 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
|
|||||||
if (status < 0)
|
if (status < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
acm->ctrl_id = status;
|
acm->ctrl_id = status;
|
||||||
|
acm_iad_descriptor.bFirstInterface = status;
|
||||||
|
|
||||||
acm_control_interface_desc.bInterfaceNumber = status;
|
acm_control_interface_desc.bInterfaceNumber = status;
|
||||||
acm_union_desc .bMasterInterface0 = status;
|
acm_union_desc .bMasterInterface0 = status;
|
||||||
@ -732,6 +753,13 @@ int __init acm_bind_config(struct usb_configuration *c, u8 port_num)
|
|||||||
acm_string_defs[ACM_DATA_IDX].id = status;
|
acm_string_defs[ACM_DATA_IDX].id = status;
|
||||||
|
|
||||||
acm_data_interface_desc.iInterface = status;
|
acm_data_interface_desc.iInterface = status;
|
||||||
|
|
||||||
|
status = usb_string_id(c->cdev);
|
||||||
|
if (status < 0)
|
||||||
|
return status;
|
||||||
|
acm_string_defs[ACM_IAD_IDX].id = status;
|
||||||
|
|
||||||
|
acm_iad_descriptor.iFunction = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* allocate and initialize one new instance */
|
/* allocate and initialize one new instance */
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
* Copyright (C) 2003-2005,2008 David Brownell
|
* Copyright (C) 2003-2005,2008 David Brownell
|
||||||
* Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
|
* Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
|
||||||
* Copyright (C) 2008 Nokia Corporation
|
* Copyright (C) 2008 Nokia Corporation
|
||||||
|
* Copyright (C) 2009 Samsung Electronics
|
||||||
|
* Author: Michal Nazarewicz (m.nazarewicz@samsung.com)
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -149,8 +151,8 @@ static struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor __initdata = {
|
|||||||
.bDataInterface = 0x01,
|
.bDataInterface = 0x01,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct usb_cdc_acm_descriptor acm_descriptor __initdata = {
|
static struct usb_cdc_acm_descriptor rndis_acm_descriptor __initdata = {
|
||||||
.bLength = sizeof acm_descriptor,
|
.bLength = sizeof rndis_acm_descriptor,
|
||||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||||
.bDescriptorSubType = USB_CDC_ACM_TYPE,
|
.bDescriptorSubType = USB_CDC_ACM_TYPE,
|
||||||
|
|
||||||
@ -179,6 +181,20 @@ static struct usb_interface_descriptor rndis_data_intf __initdata = {
|
|||||||
/* .iInterface = DYNAMIC */
|
/* .iInterface = DYNAMIC */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static struct usb_interface_assoc_descriptor
|
||||||
|
rndis_iad_descriptor = {
|
||||||
|
.bLength = sizeof rndis_iad_descriptor,
|
||||||
|
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
|
||||||
|
|
||||||
|
.bFirstInterface = 0, /* XXX, hardcoded */
|
||||||
|
.bInterfaceCount = 2, // control + data
|
||||||
|
.bFunctionClass = USB_CLASS_COMM,
|
||||||
|
.bFunctionSubClass = USB_CDC_SUBCLASS_ETHERNET,
|
||||||
|
.bFunctionProtocol = USB_CDC_PROTO_NONE,
|
||||||
|
/* .iFunction = DYNAMIC */
|
||||||
|
};
|
||||||
|
|
||||||
/* full speed support: */
|
/* full speed support: */
|
||||||
|
|
||||||
static struct usb_endpoint_descriptor fs_notify_desc __initdata = {
|
static struct usb_endpoint_descriptor fs_notify_desc __initdata = {
|
||||||
@ -208,11 +224,12 @@ static struct usb_endpoint_descriptor fs_out_desc __initdata = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static struct usb_descriptor_header *eth_fs_function[] __initdata = {
|
static struct usb_descriptor_header *eth_fs_function[] __initdata = {
|
||||||
|
(struct usb_descriptor_header *) &rndis_iad_descriptor,
|
||||||
/* control interface matches ACM, not Ethernet */
|
/* control interface matches ACM, not Ethernet */
|
||||||
(struct usb_descriptor_header *) &rndis_control_intf,
|
(struct usb_descriptor_header *) &rndis_control_intf,
|
||||||
(struct usb_descriptor_header *) &header_desc,
|
(struct usb_descriptor_header *) &header_desc,
|
||||||
(struct usb_descriptor_header *) &call_mgmt_descriptor,
|
(struct usb_descriptor_header *) &call_mgmt_descriptor,
|
||||||
(struct usb_descriptor_header *) &acm_descriptor,
|
(struct usb_descriptor_header *) &rndis_acm_descriptor,
|
||||||
(struct usb_descriptor_header *) &rndis_union_desc,
|
(struct usb_descriptor_header *) &rndis_union_desc,
|
||||||
(struct usb_descriptor_header *) &fs_notify_desc,
|
(struct usb_descriptor_header *) &fs_notify_desc,
|
||||||
/* data interface has no altsetting */
|
/* data interface has no altsetting */
|
||||||
@ -252,11 +269,12 @@ static struct usb_endpoint_descriptor hs_out_desc __initdata = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static struct usb_descriptor_header *eth_hs_function[] __initdata = {
|
static struct usb_descriptor_header *eth_hs_function[] __initdata = {
|
||||||
|
(struct usb_descriptor_header *) &rndis_iad_descriptor,
|
||||||
/* control interface matches ACM, not Ethernet */
|
/* control interface matches ACM, not Ethernet */
|
||||||
(struct usb_descriptor_header *) &rndis_control_intf,
|
(struct usb_descriptor_header *) &rndis_control_intf,
|
||||||
(struct usb_descriptor_header *) &header_desc,
|
(struct usb_descriptor_header *) &header_desc,
|
||||||
(struct usb_descriptor_header *) &call_mgmt_descriptor,
|
(struct usb_descriptor_header *) &call_mgmt_descriptor,
|
||||||
(struct usb_descriptor_header *) &acm_descriptor,
|
(struct usb_descriptor_header *) &rndis_acm_descriptor,
|
||||||
(struct usb_descriptor_header *) &rndis_union_desc,
|
(struct usb_descriptor_header *) &rndis_union_desc,
|
||||||
(struct usb_descriptor_header *) &hs_notify_desc,
|
(struct usb_descriptor_header *) &hs_notify_desc,
|
||||||
/* data interface has no altsetting */
|
/* data interface has no altsetting */
|
||||||
@ -271,6 +289,7 @@ static struct usb_descriptor_header *eth_hs_function[] __initdata = {
|
|||||||
static struct usb_string rndis_string_defs[] = {
|
static struct usb_string rndis_string_defs[] = {
|
||||||
[0].s = "RNDIS Communications Control",
|
[0].s = "RNDIS Communications Control",
|
||||||
[1].s = "RNDIS Ethernet Data",
|
[1].s = "RNDIS Ethernet Data",
|
||||||
|
[2].s = "RNDIS",
|
||||||
{ } /* end of list */
|
{ } /* end of list */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -587,6 +606,7 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
|
|||||||
if (status < 0)
|
if (status < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
rndis->ctrl_id = status;
|
rndis->ctrl_id = status;
|
||||||
|
rndis_iad_descriptor.bFirstInterface = status;
|
||||||
|
|
||||||
rndis_control_intf.bInterfaceNumber = status;
|
rndis_control_intf.bInterfaceNumber = status;
|
||||||
rndis_union_desc.bMasterInterface0 = status;
|
rndis_union_desc.bMasterInterface0 = status;
|
||||||
@ -798,6 +818,13 @@ int __init rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
|
|||||||
return status;
|
return status;
|
||||||
rndis_string_defs[1].id = status;
|
rndis_string_defs[1].id = status;
|
||||||
rndis_data_intf.iInterface = status;
|
rndis_data_intf.iInterface = status;
|
||||||
|
|
||||||
|
/* IAD iFunction label */
|
||||||
|
status = usb_string_id(c->cdev);
|
||||||
|
if (status < 0)
|
||||||
|
return status;
|
||||||
|
rndis_string_defs[2].id = status;
|
||||||
|
rndis_iad_descriptor.iFunction = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* allocate and initialize one new instance */
|
/* allocate and initialize one new instance */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user