Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
multi.c
Go to the documentation of this file.
1 /*
2  * multi.c -- Multifunction Composite driver
3  *
4  * Copyright (C) 2008 David Brownell
5  * Copyright (C) 2008 Nokia Corporation
6  * Copyright (C) 2009 Samsung Electronics
7  * Author: Michal Nazarewicz ([email protected])
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  */
14 
15 
16 #include <linux/kernel.h>
17 #include <linux/module.h>
18 
19 #if defined USB_ETH_RNDIS
20 # undef USB_ETH_RNDIS
21 #endif
22 #ifdef CONFIG_USB_G_MULTI_RNDIS
23 # define USB_ETH_RNDIS y
24 #endif
25 
26 
27 #define DRIVER_DESC "Multifunction Composite Gadget"
28 
30 MODULE_AUTHOR("Michal Nazarewicz");
31 MODULE_LICENSE("GPL");
32 
33 
34 /***************************** All the files... *****************************/
35 
36 /*
37  * kbuild is not very cooperative with respect to linking separately
38  * compiled library objects into one module. So for now we won't use
39  * separate compilation ... ensuring init/exit sections work to shrink
40  * the runtime footprint, and giving us at least some parts of what
41  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
42  */
43 #include "f_mass_storage.c"
44 
45 #include "u_serial.c"
46 #include "f_acm.c"
47 
48 #include "f_ecm.c"
49 #include "f_subset.c"
50 #ifdef USB_ETH_RNDIS
51 # include "f_rndis.c"
52 # include "rndis.c"
53 #endif
54 #include "u_ether.c"
55 
57 
58 /***************************** Device Descriptor ****************************/
59 
60 #define MULTI_VENDOR_NUM 0x1d6b /* Linux Foundation */
61 #define MULTI_PRODUCT_NUM 0x0104 /* Multifunction Composite Gadget */
62 
63 
64 enum {
66 #ifdef CONFIG_USB_G_MULTI_RNDIS
67  MULTI_RNDIS_CONFIG_NUM,
68 #endif
69 #ifdef CONFIG_USB_G_MULTI_CDC
70  MULTI_CDC_CONFIG_NUM,
71 #endif
72 };
73 
74 
75 static struct usb_device_descriptor device_desc = {
76  .bLength = sizeof device_desc,
78 
79  .bcdUSB = cpu_to_le16(0x0200),
80 
81  .bDeviceClass = USB_CLASS_MISC /* 0xEF */,
82  .bDeviceSubClass = 2,
83  .bDeviceProtocol = 1,
84 
85  /* Vendor and product id can be overridden by module parameters. */
86  .idVendor = cpu_to_le16(MULTI_VENDOR_NUM),
87  .idProduct = cpu_to_le16(MULTI_PRODUCT_NUM),
88 };
89 
90 
91 static const struct usb_descriptor_header *otg_desc[] = {
92  (struct usb_descriptor_header *) &(struct usb_otg_descriptor){
93  .bLength = sizeof(struct usb_otg_descriptor),
95 
96  /*
97  * REVISIT SRP-only hardware is possible, although
98  * it would not be called "OTG" ...
99  */
100  .bmAttributes = USB_OTG_SRP | USB_OTG_HNP,
101  },
102  NULL,
103 };
104 
105 
106 enum {
109 };
110 
111 static struct usb_string strings_dev[] = {
114  [USB_GADGET_SERIAL_IDX].s = "",
115  [MULTI_STRING_RNDIS_CONFIG_IDX].s = "Multifunction with RNDIS",
116  [MULTI_STRING_CDC_CONFIG_IDX].s = "Multifunction with CDC ECM",
117  { } /* end of list */
118 };
119 
120 static struct usb_gadget_strings *dev_strings[] = {
121  &(struct usb_gadget_strings){
122  .language = 0x0409, /* en-us */
123  .strings = strings_dev,
124  },
125  NULL,
126 };
127 
128 
129 
130 
131 /****************************** Configurations ******************************/
132 
133 static struct fsg_module_parameters fsg_mod_data = { .stall = 1 };
134 FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
135 
136 static struct fsg_common fsg_common;
137 
138 static u8 hostaddr[ETH_ALEN];
139 
140 
141 /********** RNDIS **********/
142 
143 #ifdef USB_ETH_RNDIS
144 
145 static __init int rndis_do_config(struct usb_configuration *c)
146 {
147  int ret;
148 
149  if (gadget_is_otg(c->cdev->gadget)) {
150  c->descriptors = otg_desc;
152  }
153 
154  ret = rndis_bind_config(c, hostaddr);
155  if (ret < 0)
156  return ret;
157 
158  ret = acm_bind_config(c, 0);
159  if (ret < 0)
160  return ret;
161 
162  ret = fsg_bind_config(c->cdev, c, &fsg_common);
163  if (ret < 0)
164  return ret;
165 
166  return 0;
167 }
168 
169 static int rndis_config_register(struct usb_composite_dev *cdev)
170 {
171  static struct usb_configuration config = {
172  .bConfigurationValue = MULTI_RNDIS_CONFIG_NUM,
173  .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
174  };
175 
176  config.label = strings_dev[MULTI_STRING_RNDIS_CONFIG_IDX].s;
177  config.iConfiguration = strings_dev[MULTI_STRING_RNDIS_CONFIG_IDX].id;
178 
179  return usb_add_config(cdev, &config, rndis_do_config);
180 }
181 
182 #else
183 
184 static int rndis_config_register(struct usb_composite_dev *cdev)
185 {
186  return 0;
187 }
188 
189 #endif
190 
191 
192 /********** CDC ECM **********/
193 
194 #ifdef CONFIG_USB_G_MULTI_CDC
195 
196 static __init int cdc_do_config(struct usb_configuration *c)
197 {
198  int ret;
199 
200  if (gadget_is_otg(c->cdev->gadget)) {
201  c->descriptors = otg_desc;
203  }
204 
205  ret = ecm_bind_config(c, hostaddr);
206  if (ret < 0)
207  return ret;
208 
209  ret = acm_bind_config(c, 0);
210  if (ret < 0)
211  return ret;
212 
213  ret = fsg_bind_config(c->cdev, c, &fsg_common);
214  if (ret < 0)
215  return ret;
216 
217  return 0;
218 }
219 
220 static int cdc_config_register(struct usb_composite_dev *cdev)
221 {
222  static struct usb_configuration config = {
223  .bConfigurationValue = MULTI_CDC_CONFIG_NUM,
224  .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
225  };
226 
227  config.label = strings_dev[MULTI_STRING_CDC_CONFIG_IDX].s;
228  config.iConfiguration = strings_dev[MULTI_STRING_CDC_CONFIG_IDX].id;
229 
230  return usb_add_config(cdev, &config, cdc_do_config);
231 }
232 
233 #else
234 
235 static int cdc_config_register(struct usb_composite_dev *cdev)
236 {
237  return 0;
238 }
239 
240 #endif
241 
242 
243 
244 /****************************** Gadget Bind ******************************/
245 
246 
247 static int __ref multi_bind(struct usb_composite_dev *cdev)
248 {
249  struct usb_gadget *gadget = cdev->gadget;
250  int status;
251 
252  if (!can_support_ecm(cdev->gadget)) {
253  dev_err(&gadget->dev, "controller '%s' not usable\n",
254  gadget->name);
255  return -EINVAL;
256  }
257 
258  /* set up network link layer */
259  status = gether_setup(cdev->gadget, hostaddr);
260  if (status < 0)
261  return status;
262 
263  /* set up serial link layer */
264  status = gserial_setup(cdev->gadget, 1);
265  if (status < 0)
266  goto fail0;
267 
268  /* set up mass storage function */
269  {
270  void *retp;
271  retp = fsg_common_from_params(&fsg_common, cdev, &fsg_mod_data);
272  if (IS_ERR(retp)) {
273  status = PTR_ERR(retp);
274  goto fail1;
275  }
276  }
277 
278  /* allocate string IDs */
279  status = usb_string_ids_tab(cdev, strings_dev);
280  if (unlikely(status < 0))
281  goto fail2;
282  device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
283 
284  /* register configurations */
285  status = rndis_config_register(cdev);
286  if (unlikely(status < 0))
287  goto fail2;
288 
289  status = cdc_config_register(cdev);
290  if (unlikely(status < 0))
291  goto fail2;
292  usb_composite_overwrite_options(cdev, &coverwrite);
293 
294  /* we're done */
295  dev_info(&gadget->dev, DRIVER_DESC "\n");
296  fsg_common_put(&fsg_common);
297  return 0;
298 
299 
300  /* error recovery */
301 fail2:
302  fsg_common_put(&fsg_common);
303 fail1:
304  gserial_cleanup();
305 fail0:
306  gether_cleanup();
307  return status;
308 }
309 
310 static int __exit multi_unbind(struct usb_composite_dev *cdev)
311 {
312  gserial_cleanup();
313  gether_cleanup();
314  return 0;
315 }
316 
317 
318 /****************************** Some noise ******************************/
319 
320 
321 static __refdata struct usb_composite_driver multi_driver = {
322  .name = "g_multi",
323  .dev = &device_desc,
324  .strings = dev_strings,
325  .max_speed = USB_SPEED_HIGH,
326  .bind = multi_bind,
327  .unbind = __exit_p(multi_unbind),
328  .needs_serial = 1,
329 };
330 
331 
332 static int __init multi_init(void)
333 {
334  return usb_composite_probe(&multi_driver);
335 }
336 module_init(multi_init);
337 
338 static void __exit multi_exit(void)
339 {
340  usb_composite_unregister(&multi_driver);
341 }
342 module_exit(multi_exit);