aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/gadget/multi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget/multi.c')
-rw-r--r--drivers/usb/gadget/multi.c262
1 files changed, 146 insertions, 116 deletions
diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c
index a930d7fd7e7a..795d76232167 100644
--- a/drivers/usb/gadget/multi.c
+++ b/drivers/usb/gadget/multi.c
@@ -24,6 +24,7 @@
24 24
25#include <linux/kernel.h> 25#include <linux/kernel.h>
26#include <linux/utsname.h> 26#include <linux/utsname.h>
27#include <linux/module.h>
27 28
28 29
29#if defined USB_ETH_RNDIS 30#if defined USB_ETH_RNDIS
@@ -35,14 +36,13 @@
35 36
36 37
37#define DRIVER_DESC "Multifunction Composite Gadget" 38#define DRIVER_DESC "Multifunction Composite Gadget"
38#define DRIVER_VERSION "2009/07/21"
39 39
40/*-------------------------------------------------------------------------*/ 40MODULE_DESCRIPTION(DRIVER_DESC);
41MODULE_AUTHOR("Michal Nazarewicz");
42MODULE_LICENSE("GPL");
41 43
42#define MULTI_VENDOR_NUM 0x0525 /* XXX NetChip */
43#define MULTI_PRODUCT_NUM 0xa4ab /* XXX */
44 44
45/*-------------------------------------------------------------------------*/ 45/***************************** All the files... *****************************/
46 46
47/* 47/*
48 * kbuild is not very cooperative with respect to linking separately 48 * kbuild is not very cooperative with respect to linking separately
@@ -57,6 +57,8 @@
57#include "config.c" 57#include "config.c"
58#include "epautoconf.c" 58#include "epautoconf.c"
59 59
60#include "f_mass_storage.c"
61
60#include "u_serial.c" 62#include "u_serial.c"
61#include "f_acm.c" 63#include "f_acm.c"
62 64
@@ -68,13 +70,24 @@
68#endif 70#endif
69#include "u_ether.c" 71#include "u_ether.c"
70 72
71#undef DBG /* u_ether.c has broken idea about macros */
72#undef VDBG /* so clean up after it */
73#undef ERROR
74#undef INFO
75#include "f_mass_storage.c"
76 73
77/*-------------------------------------------------------------------------*/ 74
75/***************************** Device Descriptor ****************************/
76
77#define MULTI_VENDOR_NUM 0x0525 /* XXX NetChip */
78#define MULTI_PRODUCT_NUM 0xa4ab /* XXX */
79
80
81enum {
82 __MULTI_NO_CONFIG,
83#ifdef CONFIG_USB_G_MULTI_RNDIS
84 MULTI_RNDIS_CONFIG_NUM,
85#endif
86#ifdef CONFIG_USB_G_MULTI_CDC
87 MULTI_CDC_CONFIG_NUM,
88#endif
89};
90
78 91
79static struct usb_device_descriptor device_desc = { 92static struct usb_device_descriptor device_desc = {
80 .bLength = sizeof device_desc, 93 .bLength = sizeof device_desc,
@@ -82,80 +95,82 @@ static struct usb_device_descriptor device_desc = {
82 95
83 .bcdUSB = cpu_to_le16(0x0200), 96 .bcdUSB = cpu_to_le16(0x0200),
84 97
85 /* .bDeviceClass = USB_CLASS_COMM, */ 98 .bDeviceClass = USB_CLASS_MISC /* 0xEF */,
86 /* .bDeviceSubClass = 0, */
87 /* .bDeviceProtocol = 0, */
88 .bDeviceClass = 0xEF,
89 .bDeviceSubClass = 2, 99 .bDeviceSubClass = 2,
90 .bDeviceProtocol = 1, 100 .bDeviceProtocol = 1,
91 /* .bMaxPacketSize0 = f(hardware) */
92 101
93 /* Vendor and product id can be overridden by module parameters. */ 102 /* Vendor and product id can be overridden by module parameters. */
94 .idVendor = cpu_to_le16(MULTI_VENDOR_NUM), 103 .idVendor = cpu_to_le16(MULTI_VENDOR_NUM),
95 .idProduct = cpu_to_le16(MULTI_PRODUCT_NUM), 104 .idProduct = cpu_to_le16(MULTI_PRODUCT_NUM),
96 /* .bcdDevice = f(hardware) */
97 /* .iManufacturer = DYNAMIC */
98 /* .iProduct = DYNAMIC */
99 /* NO SERIAL NUMBER */
100 .bNumConfigurations = 1,
101}; 105};
102 106
103static struct usb_otg_descriptor otg_descriptor = {
104 .bLength = sizeof otg_descriptor,
105 .bDescriptorType = USB_DT_OTG,
106
107 /* REVISIT SRP-only hardware is possible, although
108 * it would not be called "OTG" ...
109 */
110 .bmAttributes = USB_OTG_SRP | USB_OTG_HNP,
111};
112 107
113static const struct usb_descriptor_header *otg_desc[] = { 108static const struct usb_descriptor_header *otg_desc[] = {
114 (struct usb_descriptor_header *) &otg_descriptor, 109 (struct usb_descriptor_header *) &(struct usb_otg_descriptor){
110 .bLength = sizeof(struct usb_otg_descriptor),
111 .bDescriptorType = USB_DT_OTG,
112
113 /*
114 * REVISIT SRP-only hardware is possible, although
115 * it would not be called "OTG" ...
116 */
117 .bmAttributes = USB_OTG_SRP | USB_OTG_HNP,
118 },
115 NULL, 119 NULL,
116}; 120};
117 121
118 122
119/* string IDs are assigned dynamically */ 123enum {
120 124 MULTI_STRING_MANUFACTURER_IDX,
121#define STRING_MANUFACTURER_IDX 0 125 MULTI_STRING_PRODUCT_IDX,
122#define STRING_PRODUCT_IDX 1 126#ifdef CONFIG_USB_G_MULTI_RNDIS
127 MULTI_STRING_RNDIS_CONFIG_IDX,
128#endif
129#ifdef CONFIG_USB_G_MULTI_CDC
130 MULTI_STRING_CDC_CONFIG_IDX,
131#endif
132};
123 133
124static char manufacturer[50]; 134static char manufacturer[50];
125 135
126static struct usb_string strings_dev[] = { 136static struct usb_string strings_dev[] = {
127 [STRING_MANUFACTURER_IDX].s = manufacturer, 137 [MULTI_STRING_MANUFACTURER_IDX].s = manufacturer,
128 [STRING_PRODUCT_IDX].s = DRIVER_DESC, 138 [MULTI_STRING_PRODUCT_IDX].s = DRIVER_DESC,
139#ifdef CONFIG_USB_G_MULTI_RNDIS
140 [MULTI_STRING_RNDIS_CONFIG_IDX].s = "Multifunction with RNDIS",
141#endif
142#ifdef CONFIG_USB_G_MULTI_CDC
143 [MULTI_STRING_CDC_CONFIG_IDX].s = "Multifunction with CDC ECM",
144#endif
129 { } /* end of list */ 145 { } /* end of list */
130}; 146};
131 147
132static struct usb_gadget_strings stringtab_dev = {
133 .language = 0x0409, /* en-us */
134 .strings = strings_dev,
135};
136
137static struct usb_gadget_strings *dev_strings[] = { 148static struct usb_gadget_strings *dev_strings[] = {
138 &stringtab_dev, 149 &(struct usb_gadget_strings){
150 .language = 0x0409, /* en-us */
151 .strings = strings_dev,
152 },
139 NULL, 153 NULL,
140}; 154};
141 155
142static u8 hostaddr[ETH_ALEN];
143 156
144 157
145 158
146/****************************** Configurations ******************************/ 159/****************************** Configurations ******************************/
147 160
148static struct fsg_module_parameters mod_data = { 161static struct fsg_module_parameters fsg_mod_data = { .stall = 1 };
149 .stall = 1 162FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
150}; 163
151FSG_MODULE_PARAMETERS(/* no prefix */, mod_data); 164static struct fsg_common fsg_common;
165
166static u8 hostaddr[ETH_ALEN];
152 167
153static struct fsg_common *fsg_common;
154 168
169/********** RNDIS **********/
155 170
156#ifdef USB_ETH_RNDIS 171#ifdef USB_ETH_RNDIS
157 172
158static int __init rndis_do_config(struct usb_configuration *c) 173static __ref int rndis_do_config(struct usb_configuration *c)
159{ 174{
160 int ret; 175 int ret;
161 176
@@ -172,26 +187,42 @@ static int __init rndis_do_config(struct usb_configuration *c)
172 if (ret < 0) 187 if (ret < 0)
173 return ret; 188 return ret;
174 189
175 ret = fsg_add(c->cdev, c, fsg_common); 190 ret = fsg_bind_config(c->cdev, c, &fsg_common);
176 if (ret < 0) 191 if (ret < 0)
177 return ret; 192 return ret;
178 193
179 return 0; 194 return 0;
180} 195}
181 196
182static struct usb_configuration rndis_config_driver = { 197static int rndis_config_register(struct usb_composite_dev *cdev)
183 .label = "Multifunction Composite (RNDIS + MS + ACM)", 198{
184 .bind = rndis_do_config, 199 static struct usb_configuration config = {
185 .bConfigurationValue = 2, 200 .bind = rndis_do_config,
186 /* .iConfiguration = DYNAMIC */ 201 .bConfigurationValue = MULTI_RNDIS_CONFIG_NUM,
187 .bmAttributes = USB_CONFIG_ATT_SELFPOWER, 202 .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
188}; 203 };
204
205 config.label = strings_dev[MULTI_STRING_RNDIS_CONFIG_IDX].s;
206 config.iConfiguration = strings_dev[MULTI_STRING_RNDIS_CONFIG_IDX].id;
207
208 return usb_add_config(cdev, &config);
209}
210
211#else
212
213static int rndis_config_register(struct usb_composite_dev *cdev)
214{
215 return 0;
216}
189 217
190#endif 218#endif
191 219
220
221/********** CDC ECM **********/
222
192#ifdef CONFIG_USB_G_MULTI_CDC 223#ifdef CONFIG_USB_G_MULTI_CDC
193 224
194static int __init cdc_do_config(struct usb_configuration *c) 225static __ref int cdc_do_config(struct usb_configuration *c)
195{ 226{
196 int ret; 227 int ret;
197 228
@@ -208,20 +239,33 @@ static int __init cdc_do_config(struct usb_configuration *c)
208 if (ret < 0) 239 if (ret < 0)
209 return ret; 240 return ret;
210 241
211 ret = fsg_add(c->cdev, c, fsg_common); 242 ret = fsg_bind_config(c->cdev, c, &fsg_common);
212 if (ret < 0) 243 if (ret < 0)
213 return ret; 244 return ret;
214 245
215 return 0; 246 return 0;
216} 247}
217 248
218static struct usb_configuration cdc_config_driver = { 249static int cdc_config_register(struct usb_composite_dev *cdev)
219 .label = "Multifunction Composite (CDC + MS + ACM)", 250{
220 .bind = cdc_do_config, 251 static struct usb_configuration config = {
221 .bConfigurationValue = 1, 252 .bind = cdc_do_config,
222 /* .iConfiguration = DYNAMIC */ 253 .bConfigurationValue = MULTI_CDC_CONFIG_NUM,
223 .bmAttributes = USB_CONFIG_ATT_SELFPOWER, 254 .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
224}; 255 };
256
257 config.label = strings_dev[MULTI_STRING_CDC_CONFIG_IDX].s;
258 config.iConfiguration = strings_dev[MULTI_STRING_CDC_CONFIG_IDX].id;
259
260 return usb_add_config(cdev, &config);
261}
262
263#else
264
265static int cdc_config_register(struct usb_composite_dev *cdev)
266{
267 return 0;
268}
225 269
226#endif 270#endif
227 271
@@ -230,7 +274,7 @@ static struct usb_configuration cdc_config_driver = {
230/****************************** Gadget Bind ******************************/ 274/****************************** Gadget Bind ******************************/
231 275
232 276
233static int __init multi_bind(struct usb_composite_dev *cdev) 277static int __ref multi_bind(struct usb_composite_dev *cdev)
234{ 278{
235 struct usb_gadget *gadget = cdev->gadget; 279 struct usb_gadget *gadget = cdev->gadget;
236 int status, gcnum; 280 int status, gcnum;
@@ -252,67 +296,56 @@ static int __init multi_bind(struct usb_composite_dev *cdev)
252 goto fail0; 296 goto fail0;
253 297
254 /* set up mass storage function */ 298 /* set up mass storage function */
255 fsg_common = fsg_common_from_params(0, cdev, &mod_data); 299 {
256 if (IS_ERR(fsg_common)) { 300 void *retp;
257 status = PTR_ERR(fsg_common); 301 retp = fsg_common_from_params(&fsg_common, cdev, &fsg_mod_data);
258 goto fail1; 302 if (IS_ERR(retp)) {
303 status = PTR_ERR(retp);
304 goto fail1;
305 }
259 } 306 }
260 307
261 308 /* set bcdDevice */
262 gcnum = usb_gadget_controller_number(gadget); 309 gcnum = usb_gadget_controller_number(gadget);
263 if (gcnum >= 0) 310 if (gcnum >= 0) {
264 device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum); 311 device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
265 else { 312 } else {
266 /* We assume that can_support_ecm() tells the truth; 313 WARNING(cdev, "controller '%s' not recognized\n", gadget->name);
267 * but if the controller isn't recognized at all then
268 * that assumption is a bit more likely to be wrong.
269 */
270 WARNING(cdev, "controller '%s' not recognized\n",
271 gadget->name);
272 device_desc.bcdDevice = cpu_to_le16(0x0300 | 0x0099); 314 device_desc.bcdDevice = cpu_to_le16(0x0300 | 0x0099);
273 } 315 }
274 316
275 317 /* allocate string descriptor numbers */
276 /* Allocate string descriptor numbers ... note that string
277 * contents can be overridden by the composite_dev glue.
278 */
279
280 /* device descriptor strings: manufacturer, product */
281 snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", 318 snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
282 init_utsname()->sysname, init_utsname()->release, 319 init_utsname()->sysname, init_utsname()->release,
283 gadget->name); 320 gadget->name);
284 status = usb_string_id(cdev);
285 if (status < 0)
286 goto fail2;
287 strings_dev[STRING_MANUFACTURER_IDX].id = status;
288 device_desc.iManufacturer = status;
289 321
290 status = usb_string_id(cdev); 322 status = usb_string_ids_tab(cdev, strings_dev);
291 if (status < 0) 323 if (unlikely(status < 0))
292 goto fail2; 324 goto fail2;
293 strings_dev[STRING_PRODUCT_IDX].id = status;
294 device_desc.iProduct = status;
295 325
296#ifdef USB_ETH_RNDIS 326 device_desc.iManufacturer =
297 /* register our first configuration */ 327 strings_dev[MULTI_STRING_MANUFACTURER_IDX].id;
298 status = usb_add_config(cdev, &rndis_config_driver); 328 device_desc.iProduct =
299 if (status < 0) 329 strings_dev[MULTI_STRING_PRODUCT_IDX].id;
330
331 /* register configurations */
332 status = rndis_config_register(cdev);
333 if (unlikely(status < 0))
300 goto fail2; 334 goto fail2;
301#endif
302 335
303#ifdef CONFIG_USB_G_MULTI_CDC 336 status = cdc_config_register(cdev);
304 /* register our second configuration */ 337 if (unlikely(status < 0))
305 status = usb_add_config(cdev, &cdc_config_driver);
306 if (status < 0)
307 goto fail2; 338 goto fail2;
308#endif
309 339
310 dev_info(&gadget->dev, DRIVER_DESC ", version: " DRIVER_VERSION "\n"); 340 /* we're done */
311 fsg_common_put(fsg_common); 341 dev_info(&gadget->dev, DRIVER_DESC "\n");
342 fsg_common_put(&fsg_common);
312 return 0; 343 return 0;
313 344
345
346 /* error recovery */
314fail2: 347fail2:
315 fsg_common_put(fsg_common); 348 fsg_common_put(&fsg_common);
316fail1: 349fail1:
317 gserial_cleanup(); 350 gserial_cleanup();
318fail0: 351fail0:
@@ -339,18 +372,15 @@ static struct usb_composite_driver multi_driver = {
339 .unbind = __exit_p(multi_unbind), 372 .unbind = __exit_p(multi_unbind),
340}; 373};
341 374
342MODULE_DESCRIPTION(DRIVER_DESC);
343MODULE_AUTHOR("Michal Nazarewicz");
344MODULE_LICENSE("GPL");
345 375
346static int __init g_multi_init(void) 376static int __init multi_init(void)
347{ 377{
348 return usb_composite_register(&multi_driver); 378 return usb_composite_register(&multi_driver);
349} 379}
350module_init(g_multi_init); 380module_init(multi_init);
351 381
352static void __exit g_multi_cleanup(void) 382static void __exit multi_exit(void)
353{ 383{
354 usb_composite_unregister(&multi_driver); 384 usb_composite_unregister(&multi_driver);
355} 385}
356module_exit(g_multi_cleanup); 386module_exit(multi_exit);