blob: eaaed199e453f191daf25362211e2f5333864038 [file] [log] [blame]
Michal Nazarewicz5ab54cf2010-11-12 14:29:28 +01001/*
2 * g_ffs.c -- user mode file system API for USB composite function controllers
3 *
4 * Copyright (C) 2010 Samsung Electronics
Michal Nazarewicz54b83602012-01-13 15:05:16 +01005 * Author: Michal Nazarewicz <mina86@mina86.com>
Michal Nazarewicz5ab54cf2010-11-12 14:29:28 +01006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
Michal Nazarewicz5ab54cf2010-11-12 14:29:28 +010011 */
12
Michal Nazarewiczaa02f172010-11-17 17:09:47 +010013#define pr_fmt(fmt) "g_ffs: " fmt
14
Michal Nazarewiczc6c56002010-05-05 12:53:15 +020015#include <linux/module.h>
16#include <linux/utsname.h>
17
Michal Nazarewiczc6c56002010-05-05 12:53:15 +020018/*
19 * kbuild is not very cooperative with respect to linking separately
20 * compiled library objects into one module. So for now we won't use
21 * separate compilation ... ensuring init/exit sections work to shrink
22 * the runtime footprint, and giving us at least some parts of what
23 * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
24 */
25
26#include "composite.c"
Michal Nazarewiczc6c56002010-05-05 12:53:15 +020027
28#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS
29# if defined USB_ETH_RNDIS
30# undef USB_ETH_RNDIS
31# endif
32# ifdef CONFIG_USB_FUNCTIONFS_RNDIS
33# define USB_ETH_RNDIS y
34# endif
35
36# include "f_ecm.c"
37# include "f_subset.c"
38# ifdef USB_ETH_RNDIS
39# include "f_rndis.c"
40# include "rndis.c"
41# endif
42# include "u_ether.c"
43
44static u8 gfs_hostaddr[ETH_ALEN];
Michal Nazarewiczf8dae532010-06-25 16:29:27 +020045# ifdef CONFIG_USB_FUNCTIONFS_ETH
46static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
Michal Nazarewiczc6c56002010-05-05 12:53:15 +020047# endif
Michal Nazarewiczf8dae532010-06-25 16:29:27 +020048#else
Michal Nazarewiczc6c56002010-05-05 12:53:15 +020049# define gether_cleanup() do { } while (0)
50# define gether_setup(gadget, hostaddr) ((int)0)
Michal Nazarewiczf8dae532010-06-25 16:29:27 +020051# define gfs_hostaddr NULL
Michal Nazarewiczc6c56002010-05-05 12:53:15 +020052#endif
53
54#include "f_fs.c"
55
Michal Nazarewiczc6c56002010-05-05 12:53:15 +020056#define DRIVER_NAME "g_ffs"
57#define DRIVER_DESC "USB Function Filesystem"
58#define DRIVER_VERSION "24 Aug 2004"
59
60MODULE_DESCRIPTION(DRIVER_DESC);
61MODULE_AUTHOR("Michal Nazarewicz");
62MODULE_LICENSE("GPL");
63
Michal Nazarewiczfc19de62010-08-12 17:43:48 +020064#define GFS_VENDOR_ID 0x1d6b /* Linux Foundation */
65#define GFS_PRODUCT_ID 0x0105 /* FunctionFS Gadget */
Michal Nazarewiczc6c56002010-05-05 12:53:15 +020066
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +020067#define GFS_MAX_DEVS 10
68
69struct gfs_ffs_obj {
70 const char *name;
71 bool mounted;
72 bool desc_ready;
73 struct ffs_data *ffs_data;
74};
75
Sebastian Andrzej Siewior7d16e8d2012-09-10 15:01:53 +020076USB_GADGET_COMPOSITE_OPTIONS();
77
Michal Nazarewiczc6c56002010-05-05 12:53:15 +020078static struct usb_device_descriptor gfs_dev_desc = {
79 .bLength = sizeof gfs_dev_desc,
80 .bDescriptorType = USB_DT_DEVICE,
81
82 .bcdUSB = cpu_to_le16(0x0200),
83 .bDeviceClass = USB_CLASS_PER_INTERFACE,
84
Michal Nazarewiczfc19de62010-08-12 17:43:48 +020085 .idVendor = cpu_to_le16(GFS_VENDOR_ID),
86 .idProduct = cpu_to_le16(GFS_PRODUCT_ID),
Michal Nazarewiczc6c56002010-05-05 12:53:15 +020087};
88
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +020089static char *func_names[GFS_MAX_DEVS];
90static unsigned int func_num;
91
Michal Nazarewiczfc19de62010-08-12 17:43:48 +020092module_param_named(bDeviceClass, gfs_dev_desc.bDeviceClass, byte, 0644);
93MODULE_PARM_DESC(bDeviceClass, "USB Device class");
94module_param_named(bDeviceSubClass, gfs_dev_desc.bDeviceSubClass, byte, 0644);
95MODULE_PARM_DESC(bDeviceSubClass, "USB Device subclass");
96module_param_named(bDeviceProtocol, gfs_dev_desc.bDeviceProtocol, byte, 0644);
97MODULE_PARM_DESC(bDeviceProtocol, "USB Device protocol");
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +020098module_param_array_named(functions, func_names, charp, &func_num, 0);
99MODULE_PARM_DESC(functions, "USB Functions list");
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200100
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200101static const struct usb_descriptor_header *gfs_otg_desc[] = {
102 (const struct usb_descriptor_header *)
103 &(const struct usb_otg_descriptor) {
104 .bLength = sizeof(struct usb_otg_descriptor),
105 .bDescriptorType = USB_DT_OTG,
106
Michal Nazarewiczfc19de62010-08-12 17:43:48 +0200107 /*
108 * REVISIT SRP-only hardware is possible, although
109 * it would not be called "OTG" ...
110 */
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200111 .bmAttributes = USB_OTG_SRP | USB_OTG_HNP,
112 },
113
114 NULL
115};
116
Michal Nazarewicz5ab54cf2010-11-12 14:29:28 +0100117/* String IDs are assigned dynamically */
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200118static struct usb_string gfs_strings[] = {
Sebastian Andrzej Siewior276e2e42012-09-06 20:11:21 +0200119 [USB_GADGET_MANUFACTURER_IDX].s = "",
Sebastian Andrzej Siewiord33f74f2012-09-10 15:01:57 +0200120 [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
Sebastian Andrzej Siewior276e2e42012-09-06 20:11:21 +0200121 [USB_GADGET_SERIAL_IDX].s = "",
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200122#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
Michal Nazarewiczf8dae532010-06-25 16:29:27 +0200123 { .s = "FunctionFS + RNDIS" },
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200124#endif
125#ifdef CONFIG_USB_FUNCTIONFS_ETH
Michal Nazarewiczf8dae532010-06-25 16:29:27 +0200126 { .s = "FunctionFS + ECM" },
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200127#endif
128#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
Michal Nazarewiczf8dae532010-06-25 16:29:27 +0200129 { .s = "FunctionFS" },
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200130#endif
131 { } /* end of list */
132};
133
134static struct usb_gadget_strings *gfs_dev_strings[] = {
135 &(struct usb_gadget_strings) {
136 .language = 0x0409, /* en-us */
137 .strings = gfs_strings,
138 },
139 NULL,
140};
141
Michal Nazarewiczf8dae532010-06-25 16:29:27 +0200142struct gfs_configuration {
143 struct usb_configuration c;
144 int (*eth)(struct usb_configuration *c, u8 *ethaddr);
145} gfs_configurations[] = {
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200146#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
Michal Nazarewiczf8dae532010-06-25 16:29:27 +0200147 {
148 .eth = rndis_bind_config,
149 },
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200150#endif
151
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200152#ifdef CONFIG_USB_FUNCTIONFS_ETH
Michal Nazarewiczf8dae532010-06-25 16:29:27 +0200153 {
154 .eth = eth_bind_config,
155 },
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200156#endif
157
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200158#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
Michal Nazarewiczf8dae532010-06-25 16:29:27 +0200159 {
160 },
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200161#endif
Michal Nazarewiczf8dae532010-06-25 16:29:27 +0200162};
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200163
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200164static int gfs_bind(struct usb_composite_dev *cdev);
165static int gfs_unbind(struct usb_composite_dev *cdev);
Michal Nazarewiczf8dae532010-06-25 16:29:27 +0200166static int gfs_do_config(struct usb_configuration *c);
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200167
Sebastian Andrzej Siewiorc2ec75c2012-09-06 20:11:03 +0200168static __refdata struct usb_composite_driver gfs_driver = {
Michal Nazarewiczfc19de62010-08-12 17:43:48 +0200169 .name = DRIVER_NAME,
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200170 .dev = &gfs_dev_desc,
171 .strings = gfs_dev_strings,
Tatyana Brokhman35a0e0b2011-06-29 16:41:49 +0300172 .max_speed = USB_SPEED_HIGH,
Sebastian Andrzej Siewior03e42bd2012-09-06 20:11:04 +0200173 .bind = gfs_bind,
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200174 .unbind = gfs_unbind,
175};
176
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +0200177static DEFINE_MUTEX(gfs_lock);
178static unsigned int missing_funcs;
179static bool gfs_ether_setup;
180static bool gfs_registered;
181static bool gfs_single_func;
182static struct gfs_ffs_obj *ffs_tab;
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200183
Andrzej Pietrasiewicz8545e602012-03-12 12:55:42 +0100184static int __init gfs_init(void)
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200185{
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +0200186 int i;
187
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200188 ENTER();
189
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +0200190 if (!func_num) {
191 gfs_single_func = true;
192 func_num = 1;
193 }
194
195 ffs_tab = kcalloc(func_num, sizeof *ffs_tab, GFP_KERNEL);
196 if (!ffs_tab)
197 return -ENOMEM;
198
199 if (!gfs_single_func)
200 for (i = 0; i < func_num; i++)
201 ffs_tab[i].name = func_names[i];
202
203 missing_funcs = func_num;
204
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200205 return functionfs_init();
206}
207module_init(gfs_init);
208
Andrzej Pietrasiewicz8545e602012-03-12 12:55:42 +0100209static void __exit gfs_exit(void)
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200210{
211 ENTER();
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +0200212 mutex_lock(&gfs_lock);
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200213
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +0200214 if (gfs_registered)
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200215 usb_composite_unregister(&gfs_driver);
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +0200216 gfs_registered = false;
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200217
218 functionfs_cleanup();
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +0200219
220 mutex_unlock(&gfs_lock);
221 kfree(ffs_tab);
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200222}
223module_exit(gfs_exit);
224
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +0200225static struct gfs_ffs_obj *gfs_find_dev(const char *dev_name)
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200226{
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +0200227 int i;
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200228
229 ENTER();
230
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +0200231 if (gfs_single_func)
232 return &ffs_tab[0];
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200233
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +0200234 for (i = 0; i < func_num; i++)
235 if (strcmp(ffs_tab[i].name, dev_name) == 0)
236 return &ffs_tab[i];
237
238 return NULL;
239}
240
241static int functionfs_ready_callback(struct ffs_data *ffs)
242{
243 struct gfs_ffs_obj *ffs_obj;
244 int ret;
245
246 ENTER();
247 mutex_lock(&gfs_lock);
248
249 ffs_obj = ffs->private_data;
250 if (!ffs_obj) {
251 ret = -EINVAL;
252 goto done;
253 }
254
255 if (WARN_ON(ffs_obj->desc_ready)) {
256 ret = -EBUSY;
257 goto done;
258 }
259 ffs_obj->desc_ready = true;
260 ffs_obj->ffs_data = ffs;
261
262 if (--missing_funcs) {
263 ret = 0;
264 goto done;
265 }
266
267 if (gfs_registered) {
268 ret = -EBUSY;
269 goto done;
270 }
271 gfs_registered = true;
272
Sebastian Andrzej Siewior03e42bd2012-09-06 20:11:04 +0200273 ret = usb_composite_probe(&gfs_driver);
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200274 if (unlikely(ret < 0))
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +0200275 gfs_registered = false;
276
277done:
278 mutex_unlock(&gfs_lock);
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200279 return ret;
280}
281
282static void functionfs_closed_callback(struct ffs_data *ffs)
283{
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +0200284 struct gfs_ffs_obj *ffs_obj;
285
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200286 ENTER();
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +0200287 mutex_lock(&gfs_lock);
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200288
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +0200289 ffs_obj = ffs->private_data;
290 if (!ffs_obj)
291 goto done;
292
293 ffs_obj->desc_ready = false;
294 missing_funcs++;
295
296 if (gfs_registered)
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200297 usb_composite_unregister(&gfs_driver);
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +0200298 gfs_registered = false;
299
300done:
301 mutex_unlock(&gfs_lock);
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200302}
303
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +0200304static void *functionfs_acquire_dev_callback(const char *dev_name)
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200305{
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +0200306 struct gfs_ffs_obj *ffs_dev;
307
308 ENTER();
309 mutex_lock(&gfs_lock);
310
311 ffs_dev = gfs_find_dev(dev_name);
312 if (!ffs_dev) {
313 ffs_dev = ERR_PTR(-ENODEV);
314 goto done;
315 }
316
317 if (ffs_dev->mounted) {
318 ffs_dev = ERR_PTR(-EBUSY);
319 goto done;
320 }
321 ffs_dev->mounted = true;
322
323done:
324 mutex_unlock(&gfs_lock);
325 return ffs_dev;
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200326}
327
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +0200328static void functionfs_release_dev_callback(struct ffs_data *ffs_data)
329{
330 struct gfs_ffs_obj *ffs_dev;
331
332 ENTER();
333 mutex_lock(&gfs_lock);
334
335 ffs_dev = ffs_data->private_data;
336 if (ffs_dev)
337 ffs_dev->mounted = false;
338
339 mutex_unlock(&gfs_lock);
340}
341
342/*
343 * It is assumed that gfs_bind is called from a context where gfs_lock is held
344 */
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200345static int gfs_bind(struct usb_composite_dev *cdev)
346{
Michal Nazarewiczf8dae532010-06-25 16:29:27 +0200347 int ret, i;
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200348
349 ENTER();
350
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +0200351 if (missing_funcs)
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200352 return -ENODEV;
353
354 ret = gether_setup(cdev->gadget, gfs_hostaddr);
355 if (unlikely(ret < 0))
356 goto error_quick;
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +0200357 gfs_ether_setup = true;
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200358
Michal Nazarewiczf8dae532010-06-25 16:29:27 +0200359 ret = usb_string_ids_tab(cdev, gfs_strings);
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200360 if (unlikely(ret < 0))
361 goto error;
Sebastian Andrzej Siewiord33f74f2012-09-10 15:01:57 +0200362 gfs_dev_desc.iProduct = gfs_strings[USB_GADGET_PRODUCT_IDX].id;
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200363
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +0200364 for (i = func_num; --i; ) {
365 ret = functionfs_bind(ffs_tab[i].ffs_data, cdev);
366 if (unlikely(ret < 0)) {
367 while (++i < func_num)
368 functionfs_unbind(ffs_tab[i].ffs_data);
369 goto error;
370 }
371 }
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200372
Michal Nazarewiczf8dae532010-06-25 16:29:27 +0200373 for (i = 0; i < ARRAY_SIZE(gfs_configurations); ++i) {
374 struct gfs_configuration *c = gfs_configurations + i;
Sebastian Andrzej Siewior276e2e42012-09-06 20:11:21 +0200375 int sid = USB_GADGET_FIRST_AVAIL_IDX + i;
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200376
Sebastian Andrzej Siewior276e2e42012-09-06 20:11:21 +0200377 c->c.label = gfs_strings[sid].s;
378 c->c.iConfiguration = gfs_strings[sid].id;
Michal Nazarewiczf8dae532010-06-25 16:29:27 +0200379 c->c.bConfigurationValue = 1 + i;
380 c->c.bmAttributes = USB_CONFIG_ATT_SELFPOWER;
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200381
Uwe Kleine-Königc9bfff92010-08-12 17:43:55 +0200382 ret = usb_add_config(cdev, &c->c, gfs_do_config);
Michal Nazarewiczf8dae532010-06-25 16:29:27 +0200383 if (unlikely(ret < 0))
384 goto error_unbind;
385 }
Sebastian Andrzej Siewior7d16e8d2012-09-10 15:01:53 +0200386 usb_composite_overwrite_options(cdev, &coverwrite);
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200387 return 0;
388
389error_unbind:
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +0200390 for (i = 0; i < func_num; i++)
391 functionfs_unbind(ffs_tab[i].ffs_data);
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200392error:
393 gether_cleanup();
394error_quick:
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +0200395 gfs_ether_setup = false;
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200396 return ret;
397}
398
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +0200399/*
400 * It is assumed that gfs_unbind is called from a context where gfs_lock is held
401 */
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200402static int gfs_unbind(struct usb_composite_dev *cdev)
403{
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +0200404 int i;
405
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200406 ENTER();
407
Michal Nazarewiczfc19de62010-08-12 17:43:48 +0200408 /*
409 * We may have been called in an error recovery from
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200410 * composite_bind() after gfs_unbind() failure so we need to
411 * check if gfs_ffs_data is not NULL since gfs_bind() handles
412 * all error recovery itself. I'd rather we werent called
413 * from composite on orror recovery, but what you're gonna
Michal Nazarewiczfc19de62010-08-12 17:43:48 +0200414 * do...?
415 */
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +0200416 if (gfs_ether_setup)
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200417 gether_cleanup();
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +0200418 gfs_ether_setup = false;
419
420 for (i = func_num; --i; )
421 if (ffs_tab[i].ffs_data)
422 functionfs_unbind(ffs_tab[i].ffs_data);
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200423
424 return 0;
425}
426
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +0200427/*
428 * It is assumed that gfs_do_config is called from a context where
429 * gfs_lock is held
430 */
Michal Nazarewiczf8dae532010-06-25 16:29:27 +0200431static int gfs_do_config(struct usb_configuration *c)
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200432{
Michal Nazarewiczf8dae532010-06-25 16:29:27 +0200433 struct gfs_configuration *gc =
434 container_of(c, struct gfs_configuration, c);
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +0200435 int i;
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200436 int ret;
437
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +0200438 if (missing_funcs)
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200439 return -ENODEV;
440
441 if (gadget_is_otg(c->cdev->gadget)) {
442 c->descriptors = gfs_otg_desc;
443 c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
444 }
445
Michal Nazarewiczf8dae532010-06-25 16:29:27 +0200446 if (gc->eth) {
447 ret = gc->eth(c, gfs_hostaddr);
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200448 if (unlikely(ret < 0))
449 return ret;
450 }
451
Andrzej Pietrasiewicz581791f2012-05-14 15:51:52 +0200452 for (i = 0; i < func_num; i++) {
453 ret = functionfs_bind_config(c->cdev, c, ffs_tab[i].ffs_data);
454 if (unlikely(ret < 0))
455 return ret;
456 }
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200457
Michal Nazarewiczfc19de62010-08-12 17:43:48 +0200458 /*
459 * After previous do_configs there may be some invalid
Michal Nazarewiczf588c0d2010-06-14 10:43:34 +0200460 * pointers in c->interface array. This happens every time
461 * a user space function with fewer interfaces than a user
462 * space function that was run before the new one is run. The
463 * compasit's set_config() assumes that if there is no more
464 * then MAX_CONFIG_INTERFACES interfaces in a configuration
465 * then there is a NULL pointer after the last interface in
Michal Nazarewiczfc19de62010-08-12 17:43:48 +0200466 * c->interface array. We need to make sure this is true.
467 */
Michal Nazarewiczf588c0d2010-06-14 10:43:34 +0200468 if (c->next_interface_id < ARRAY_SIZE(c->interface))
469 c->interface[c->next_interface_id] = NULL;
470
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200471 return 0;
472}
473
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200474#ifdef CONFIG_USB_FUNCTIONFS_ETH
Michal Nazarewiczfc19de62010-08-12 17:43:48 +0200475
Michal Nazarewiczf8dae532010-06-25 16:29:27 +0200476static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200477{
Michal Nazarewiczf8dae532010-06-25 16:29:27 +0200478 return can_support_ecm(c->cdev->gadget)
479 ? ecm_bind_config(c, ethaddr)
480 : geth_bind_config(c, ethaddr);
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200481}
Michal Nazarewiczfc19de62010-08-12 17:43:48 +0200482
Michal Nazarewiczc6c56002010-05-05 12:53:15 +0200483#endif