aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorMichal Nazarewicz <m.nazarewicz@samsung.com>2009-10-28 11:57:30 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-12-11 14:55:19 -0500
commitb97503ffa79f0a4aa13c7cd8b449b98d3077c78f (patch)
tree41a87deca5a6baa0f91af2f9016b9ae320ea4a58 /drivers/usb
parent9c610213370ad2e58a892f890a11a90615edf020 (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')
-rw-r--r--drivers/usb/gadget/f_acm.c28
-rw-r--r--drivers/usb/gadget/f_rndis.c35
2 files changed, 59 insertions, 4 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
104static struct usb_interface_assoc_descriptor
105acm_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
102static struct usb_interface_descriptor acm_control_interface_desc __initdata = { 118static 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
180static struct usb_descriptor_header *acm_fs_function[] __initdata = { 196static 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
218static struct usb_descriptor_header *acm_hs_function[] __initdata = { 235static 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 */
237static struct usb_string acm_string_defs[] = { 256static 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 */
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index c9966cc07d3a..95dae4c1ea40 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -4,6 +4,8 @@
4 * Copyright (C) 2003-2005,2008 David Brownell 4 * Copyright (C) 2003-2005,2008 David Brownell
5 * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger 5 * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
6 * Copyright (C) 2008 Nokia Corporation 6 * Copyright (C) 2008 Nokia Corporation
7 * Copyright (C) 2009 Samsung Electronics
8 * Author: Michal Nazarewicz (m.nazarewicz@samsung.com)
7 * 9 *
8 * This program is free software; you can redistribute it and/or modify 10 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by 11 * 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 = {
149 .bDataInterface = 0x01, 151 .bDataInterface = 0x01,
150}; 152};
151 153
152static struct usb_cdc_acm_descriptor acm_descriptor __initdata = { 154static struct usb_cdc_acm_descriptor rndis_acm_descriptor __initdata = {
153 .bLength = sizeof acm_descriptor, 155 .bLength = sizeof rndis_acm_descriptor,
154 .bDescriptorType = USB_DT_CS_INTERFACE, 156 .bDescriptorType = USB_DT_CS_INTERFACE,
155 .bDescriptorSubType = USB_CDC_ACM_TYPE, 157 .bDescriptorSubType = USB_CDC_ACM_TYPE,
156 158
@@ -179,6 +181,20 @@ static struct usb_interface_descriptor rndis_data_intf __initdata = {
179 /* .iInterface = DYNAMIC */ 181 /* .iInterface = DYNAMIC */
180}; 182};
181 183
184
185static struct usb_interface_assoc_descriptor
186rndis_iad_descriptor = {
187 .bLength = sizeof rndis_iad_descriptor,
188 .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
189
190 .bFirstInterface = 0, /* XXX, hardcoded */
191 .bInterfaceCount = 2, // control + data
192 .bFunctionClass = USB_CLASS_COMM,
193 .bFunctionSubClass = USB_CDC_SUBCLASS_ETHERNET,
194 .bFunctionProtocol = USB_CDC_PROTO_NONE,
195 /* .iFunction = DYNAMIC */
196};
197
182/* full speed support: */ 198/* full speed support: */
183 199
184static struct usb_endpoint_descriptor fs_notify_desc __initdata = { 200static struct usb_endpoint_descriptor fs_notify_desc __initdata = {
@@ -208,11 +224,12 @@ static struct usb_endpoint_descriptor fs_out_desc __initdata = {
208}; 224};
209 225
210static struct usb_descriptor_header *eth_fs_function[] __initdata = { 226static struct usb_descriptor_header *eth_fs_function[] __initdata = {
227 (struct usb_descriptor_header *) &rndis_iad_descriptor,
211 /* control interface matches ACM, not Ethernet */ 228 /* control interface matches ACM, not Ethernet */
212 (struct usb_descriptor_header *) &rndis_control_intf, 229 (struct usb_descriptor_header *) &rndis_control_intf,
213 (struct usb_descriptor_header *) &header_desc, 230 (struct usb_descriptor_header *) &header_desc,
214 (struct usb_descriptor_header *) &call_mgmt_descriptor, 231 (struct usb_descriptor_header *) &call_mgmt_descriptor,
215 (struct usb_descriptor_header *) &acm_descriptor, 232 (struct usb_descriptor_header *) &rndis_acm_descriptor,
216 (struct usb_descriptor_header *) &rndis_union_desc, 233 (struct usb_descriptor_header *) &rndis_union_desc,
217 (struct usb_descriptor_header *) &fs_notify_desc, 234 (struct usb_descriptor_header *) &fs_notify_desc,
218 /* data interface has no altsetting */ 235 /* data interface has no altsetting */
@@ -252,11 +269,12 @@ static struct usb_endpoint_descriptor hs_out_desc __initdata = {
252}; 269};
253 270
254static struct usb_descriptor_header *eth_hs_function[] __initdata = { 271static struct usb_descriptor_header *eth_hs_function[] __initdata = {
272 (struct usb_descriptor_header *) &rndis_iad_descriptor,
255 /* control interface matches ACM, not Ethernet */ 273 /* control interface matches ACM, not Ethernet */
256 (struct usb_descriptor_header *) &rndis_control_intf, 274 (struct usb_descriptor_header *) &rndis_control_intf,
257 (struct usb_descriptor_header *) &header_desc, 275 (struct usb_descriptor_header *) &header_desc,
258 (struct usb_descriptor_header *) &call_mgmt_descriptor, 276 (struct usb_descriptor_header *) &call_mgmt_descriptor,
259 (struct usb_descriptor_header *) &acm_descriptor, 277 (struct usb_descriptor_header *) &rndis_acm_descriptor,
260 (struct usb_descriptor_header *) &rndis_union_desc, 278 (struct usb_descriptor_header *) &rndis_union_desc,
261 (struct usb_descriptor_header *) &hs_notify_desc, 279 (struct usb_descriptor_header *) &hs_notify_desc,
262 /* data interface has no altsetting */ 280 /* data interface has no altsetting */
@@ -271,6 +289,7 @@ static struct usb_descriptor_header *eth_hs_function[] __initdata = {
271static struct usb_string rndis_string_defs[] = { 289static struct usb_string rndis_string_defs[] = {
272 [0].s = "RNDIS Communications Control", 290 [0].s = "RNDIS Communications Control",
273 [1].s = "RNDIS Ethernet Data", 291 [1].s = "RNDIS Ethernet Data",
292 [2].s = "RNDIS",
274 { } /* end of list */ 293 { } /* end of list */
275}; 294};
276 295
@@ -587,6 +606,7 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
587 if (status < 0) 606 if (status < 0)
588 goto fail; 607 goto fail;
589 rndis->ctrl_id = status; 608 rndis->ctrl_id = status;
609 rndis_iad_descriptor.bFirstInterface = status;
590 610
591 rndis_control_intf.bInterfaceNumber = status; 611 rndis_control_intf.bInterfaceNumber = status;
592 rndis_union_desc.bMasterInterface0 = status; 612 rndis_union_desc.bMasterInterface0 = status;
@@ -798,6 +818,13 @@ int __init rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
798 return status; 818 return status;
799 rndis_string_defs[1].id = status; 819 rndis_string_defs[1].id = status;
800 rndis_data_intf.iInterface = status; 820 rndis_data_intf.iInterface = status;
821
822 /* IAD iFunction label */
823 status = usb_string_id(c->cdev);
824 if (status < 0)
825 return status;
826 rndis_string_defs[2].id = status;
827 rndis_iad_descriptor.iFunction = status;
801 } 828 }
802 829
803 /* allocate and initialize one new instance */ 830 /* allocate and initialize one new instance */