diff options
author | Michal Nazarewicz <m.nazarewicz@samsung.com> | 2009-10-28 11:57:30 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-12-11 14:55:19 -0500 |
commit | b97503ffa79f0a4aa13c7cd8b449b98d3077c78f (patch) | |
tree | 41a87deca5a6baa0f91af2f9016b9ae320ea4a58 /drivers/usb/gadget/f_acm.c | |
parent | 9c610213370ad2e58a892f890a11a90615edf020 (diff) |
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>
Diffstat (limited to 'drivers/usb/gadget/f_acm.c')
-rw-r--r-- | drivers/usb/gadget/f_acm.c | 28 |
1 files changed, 28 insertions, 0 deletions
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c index 4e3657808b0f..d10353d46b86 100644 --- a/drivers/usb/gadget/f_acm.c +++ b/drivers/usb/gadget/f_acm.c | |||
@@ -4,6 +4,8 @@ | |||
4 | * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com) | 4 | * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com) |
5 | * Copyright (C) 2008 by David Brownell | 5 | * Copyright (C) 2008 by David Brownell |
6 | * Copyright (C) 2008 by Nokia Corporation | 6 | * Copyright (C) 2008 by Nokia Corporation |
7 | * Copyright (C) 2009 by Samsung Electronics | ||
8 | * Author: Michal Nazarewicz (m.nazarewicz@samsung.com) | ||
7 | * | 9 | * |
8 | * This software is distributed under the terms of the GNU General | 10 | * This software is distributed under the terms of the GNU General |
9 | * Public License ("GPL") as published by the Free Software Foundation, | 11 | * 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) | |||
99 | 101 | ||
100 | /* interface and class descriptors: */ | 102 | /* interface and class descriptors: */ |
101 | 103 | ||
104 | static struct usb_interface_assoc_descriptor | ||
105 | acm_iad_descriptor = { | ||
106 | .bLength = sizeof acm_iad_descriptor, | ||
107 | .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, | ||
108 | |||
109 | /* .bFirstInterface = DYNAMIC, */ | ||
110 | .bInterfaceCount = 2, // control + data | ||
111 | .bFunctionClass = USB_CLASS_COMM, | ||
112 | .bFunctionSubClass = USB_CDC_SUBCLASS_ACM, | ||
113 | .bFunctionProtocol = USB_CDC_PROTO_NONE, | ||
114 | /* .iFunction = DYNAMIC */ | ||
115 | }; | ||
116 | |||
117 | |||
102 | static struct usb_interface_descriptor acm_control_interface_desc __initdata = { | 118 | static struct usb_interface_descriptor acm_control_interface_desc __initdata = { |
103 | .bLength = USB_DT_INTERFACE_SIZE, | 119 | .bLength = USB_DT_INTERFACE_SIZE, |
104 | .bDescriptorType = USB_DT_INTERFACE, | 120 | .bDescriptorType = USB_DT_INTERFACE, |
@@ -178,6 +194,7 @@ static struct usb_endpoint_descriptor acm_fs_out_desc __initdata = { | |||
178 | }; | 194 | }; |
179 | 195 | ||
180 | static struct usb_descriptor_header *acm_fs_function[] __initdata = { | 196 | static struct usb_descriptor_header *acm_fs_function[] __initdata = { |
197 | (struct usb_descriptor_header *) &acm_iad_descriptor, | ||
181 | (struct usb_descriptor_header *) &acm_control_interface_desc, | 198 | (struct usb_descriptor_header *) &acm_control_interface_desc, |
182 | (struct usb_descriptor_header *) &acm_header_desc, | 199 | (struct usb_descriptor_header *) &acm_header_desc, |
183 | (struct usb_descriptor_header *) &acm_call_mgmt_descriptor, | 200 | (struct usb_descriptor_header *) &acm_call_mgmt_descriptor, |
@@ -216,6 +233,7 @@ static struct usb_endpoint_descriptor acm_hs_out_desc __initdata = { | |||
216 | }; | 233 | }; |
217 | 234 | ||
218 | static struct usb_descriptor_header *acm_hs_function[] __initdata = { | 235 | static struct usb_descriptor_header *acm_hs_function[] __initdata = { |
236 | (struct usb_descriptor_header *) &acm_iad_descriptor, | ||
219 | (struct usb_descriptor_header *) &acm_control_interface_desc, | 237 | (struct usb_descriptor_header *) &acm_control_interface_desc, |
220 | (struct usb_descriptor_header *) &acm_header_desc, | 238 | (struct usb_descriptor_header *) &acm_header_desc, |
221 | (struct usb_descriptor_header *) &acm_call_mgmt_descriptor, | 239 | (struct usb_descriptor_header *) &acm_call_mgmt_descriptor, |
@@ -232,11 +250,13 @@ static struct usb_descriptor_header *acm_hs_function[] __initdata = { | |||
232 | 250 | ||
233 | #define ACM_CTRL_IDX 0 | 251 | #define ACM_CTRL_IDX 0 |
234 | #define ACM_DATA_IDX 1 | 252 | #define ACM_DATA_IDX 1 |
253 | #define ACM_IAD_IDX 2 | ||
235 | 254 | ||
236 | /* static strings, in UTF-8 */ | 255 | /* static strings, in UTF-8 */ |
237 | static struct usb_string acm_string_defs[] = { | 256 | static struct usb_string acm_string_defs[] = { |
238 | [ACM_CTRL_IDX].s = "CDC Abstract Control Model (ACM)", | 257 | [ACM_CTRL_IDX].s = "CDC Abstract Control Model (ACM)", |
239 | [ACM_DATA_IDX].s = "CDC ACM Data", | 258 | [ACM_DATA_IDX].s = "CDC ACM Data", |
259 | [ACM_IAD_IDX ].s = "CDC Serial", | ||
240 | { /* ZEROES END LIST */ }, | 260 | { /* ZEROES END LIST */ }, |
241 | }; | 261 | }; |
242 | 262 | ||
@@ -563,6 +583,7 @@ acm_bind(struct usb_configuration *c, struct usb_function *f) | |||
563 | if (status < 0) | 583 | if (status < 0) |
564 | goto fail; | 584 | goto fail; |
565 | acm->ctrl_id = status; | 585 | acm->ctrl_id = status; |
586 | acm_iad_descriptor.bFirstInterface = status; | ||
566 | 587 | ||
567 | acm_control_interface_desc.bInterfaceNumber = status; | 588 | acm_control_interface_desc.bInterfaceNumber = status; |
568 | acm_union_desc .bMasterInterface0 = status; | 589 | acm_union_desc .bMasterInterface0 = status; |
@@ -732,6 +753,13 @@ int __init acm_bind_config(struct usb_configuration *c, u8 port_num) | |||
732 | acm_string_defs[ACM_DATA_IDX].id = status; | 753 | acm_string_defs[ACM_DATA_IDX].id = status; |
733 | 754 | ||
734 | acm_data_interface_desc.iInterface = status; | 755 | acm_data_interface_desc.iInterface = status; |
756 | |||
757 | status = usb_string_id(c->cdev); | ||
758 | if (status < 0) | ||
759 | return status; | ||
760 | acm_string_defs[ACM_IAD_IDX].id = status; | ||
761 | |||
762 | acm_iad_descriptor.iFunction = status; | ||
735 | } | 763 | } |
736 | 764 | ||
737 | /* allocate and initialize one new instance */ | 765 | /* allocate and initialize one new instance */ |