]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/usb/gadget/g_ffs.c
xps: Transmit Packet Steering
[net-next-2.6.git] / drivers / usb / gadget / g_ffs.c
CommitLineData
c6c56008
MN
1#include <linux/module.h>
2#include <linux/utsname.h>
3
4
5/*
6 * kbuild is not very cooperative with respect to linking separately
7 * compiled library objects into one module. So for now we won't use
8 * separate compilation ... ensuring init/exit sections work to shrink
9 * the runtime footprint, and giving us at least some parts of what
10 * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
11 */
12
13#include "composite.c"
14#include "usbstring.c"
15#include "config.c"
16#include "epautoconf.c"
17
18#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS
19# if defined USB_ETH_RNDIS
20# undef USB_ETH_RNDIS
21# endif
22# ifdef CONFIG_USB_FUNCTIONFS_RNDIS
23# define USB_ETH_RNDIS y
24# endif
25
26# include "f_ecm.c"
27# include "f_subset.c"
28# ifdef USB_ETH_RNDIS
29# include "f_rndis.c"
30# include "rndis.c"
31# endif
32# include "u_ether.c"
33
34static u8 gfs_hostaddr[ETH_ALEN];
f8dae531
MN
35# ifdef CONFIG_USB_FUNCTIONFS_ETH
36static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
c6c56008 37# endif
f8dae531 38#else
c6c56008
MN
39# define gether_cleanup() do { } while (0)
40# define gether_setup(gadget, hostaddr) ((int)0)
f8dae531 41# define gfs_hostaddr NULL
c6c56008
MN
42#endif
43
44#include "f_fs.c"
45
46
47#define DRIVER_NAME "g_ffs"
48#define DRIVER_DESC "USB Function Filesystem"
49#define DRIVER_VERSION "24 Aug 2004"
50
51MODULE_DESCRIPTION(DRIVER_DESC);
52MODULE_AUTHOR("Michal Nazarewicz");
53MODULE_LICENSE("GPL");
54
fc19de61
MN
55#define GFS_VENDOR_ID 0x1d6b /* Linux Foundation */
56#define GFS_PRODUCT_ID 0x0105 /* FunctionFS Gadget */
c6c56008
MN
57
58static struct usb_device_descriptor gfs_dev_desc = {
59 .bLength = sizeof gfs_dev_desc,
60 .bDescriptorType = USB_DT_DEVICE,
61
62 .bcdUSB = cpu_to_le16(0x0200),
63 .bDeviceClass = USB_CLASS_PER_INTERFACE,
64
fc19de61
MN
65 .idVendor = cpu_to_le16(GFS_VENDOR_ID),
66 .idProduct = cpu_to_le16(GFS_PRODUCT_ID),
c6c56008
MN
67};
68
fc19de61
MN
69module_param_named(bDeviceClass, gfs_dev_desc.bDeviceClass, byte, 0644);
70MODULE_PARM_DESC(bDeviceClass, "USB Device class");
71module_param_named(bDeviceSubClass, gfs_dev_desc.bDeviceSubClass, byte, 0644);
72MODULE_PARM_DESC(bDeviceSubClass, "USB Device subclass");
73module_param_named(bDeviceProtocol, gfs_dev_desc.bDeviceProtocol, byte, 0644);
74MODULE_PARM_DESC(bDeviceProtocol, "USB Device protocol");
c6c56008
MN
75
76
77
78static const struct usb_descriptor_header *gfs_otg_desc[] = {
79 (const struct usb_descriptor_header *)
80 &(const struct usb_otg_descriptor) {
81 .bLength = sizeof(struct usb_otg_descriptor),
82 .bDescriptorType = USB_DT_OTG,
83
fc19de61
MN
84 /*
85 * REVISIT SRP-only hardware is possible, although
86 * it would not be called "OTG" ...
87 */
c6c56008
MN
88 .bmAttributes = USB_OTG_SRP | USB_OTG_HNP,
89 },
90
91 NULL
92};
93
94/* string IDs are assigned dynamically */
95
c6c56008 96static struct usb_string gfs_strings[] = {
c6c56008 97#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
f8dae531 98 { .s = "FunctionFS + RNDIS" },
c6c56008
MN
99#endif
100#ifdef CONFIG_USB_FUNCTIONFS_ETH
f8dae531 101 { .s = "FunctionFS + ECM" },
c6c56008
MN
102#endif
103#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
f8dae531 104 { .s = "FunctionFS" },
c6c56008
MN
105#endif
106 { } /* end of list */
107};
108
109static struct usb_gadget_strings *gfs_dev_strings[] = {
110 &(struct usb_gadget_strings) {
111 .language = 0x0409, /* en-us */
112 .strings = gfs_strings,
113 },
114 NULL,
115};
116
117
f8dae531
MN
118
119struct gfs_configuration {
120 struct usb_configuration c;
121 int (*eth)(struct usb_configuration *c, u8 *ethaddr);
122} gfs_configurations[] = {
c6c56008 123#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
f8dae531
MN
124 {
125 .eth = rndis_bind_config,
126 },
c6c56008
MN
127#endif
128
c6c56008 129#ifdef CONFIG_USB_FUNCTIONFS_ETH
f8dae531
MN
130 {
131 .eth = eth_bind_config,
132 },
c6c56008
MN
133#endif
134
c6c56008 135#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
f8dae531
MN
136 {
137 },
c6c56008 138#endif
f8dae531 139};
c6c56008
MN
140
141
142static int gfs_bind(struct usb_composite_dev *cdev);
143static int gfs_unbind(struct usb_composite_dev *cdev);
f8dae531 144static int gfs_do_config(struct usb_configuration *c);
c6c56008
MN
145
146static struct usb_composite_driver gfs_driver = {
fc19de61 147 .name = DRIVER_NAME,
c6c56008
MN
148 .dev = &gfs_dev_desc,
149 .strings = gfs_dev_strings,
c6c56008 150 .unbind = gfs_unbind,
fc19de61 151 .iProduct = DRIVER_DESC,
c6c56008
MN
152};
153
154
155static struct ffs_data *gfs_ffs_data;
156static unsigned long gfs_registered;
157
158
159static int gfs_init(void)
160{
161 ENTER();
162
163 return functionfs_init();
164}
165module_init(gfs_init);
166
167static void gfs_exit(void)
168{
169 ENTER();
170
171 if (test_and_clear_bit(0, &gfs_registered))
172 usb_composite_unregister(&gfs_driver);
173
174 functionfs_cleanup();
175}
176module_exit(gfs_exit);
177
178
179static int functionfs_ready_callback(struct ffs_data *ffs)
180{
181 int ret;
182
183 ENTER();
184
185 if (WARN_ON(test_and_set_bit(0, &gfs_registered)))
186 return -EBUSY;
187
188 gfs_ffs_data = ffs;
07a18bd7 189 ret = usb_composite_probe(&gfs_driver, gfs_bind);
c6c56008
MN
190 if (unlikely(ret < 0))
191 clear_bit(0, &gfs_registered);
192 return ret;
193}
194
195static void functionfs_closed_callback(struct ffs_data *ffs)
196{
197 ENTER();
198
199 if (test_and_clear_bit(0, &gfs_registered))
200 usb_composite_unregister(&gfs_driver);
201}
202
203
204static int functionfs_check_dev_callback(const char *dev_name)
205{
206 return 0;
207}
208
209
210
211static int gfs_bind(struct usb_composite_dev *cdev)
212{
f8dae531 213 int ret, i;
c6c56008
MN
214
215 ENTER();
216
217 if (WARN_ON(!gfs_ffs_data))
218 return -ENODEV;
219
220 ret = gether_setup(cdev->gadget, gfs_hostaddr);
221 if (unlikely(ret < 0))
222 goto error_quick;
223
f8dae531 224 ret = usb_string_ids_tab(cdev, gfs_strings);
c6c56008
MN
225 if (unlikely(ret < 0))
226 goto error;
c6c56008 227
c6c56008
MN
228 ret = functionfs_bind(gfs_ffs_data, cdev);
229 if (unlikely(ret < 0))
230 goto error;
231
f8dae531
MN
232 for (i = 0; i < ARRAY_SIZE(gfs_configurations); ++i) {
233 struct gfs_configuration *c = gfs_configurations + i;
c6c56008 234
fc19de61
MN
235 c->c.label = gfs_strings[i].s;
236 c->c.iConfiguration = gfs_strings[i].id;
f8dae531
MN
237 c->c.bConfigurationValue = 1 + i;
238 c->c.bmAttributes = USB_CONFIG_ATT_SELFPOWER;
c6c56008 239
c9bfff9c 240 ret = usb_add_config(cdev, &c->c, gfs_do_config);
f8dae531
MN
241 if (unlikely(ret < 0))
242 goto error_unbind;
243 }
c6c56008
MN
244
245 return 0;
246
247error_unbind:
248 functionfs_unbind(gfs_ffs_data);
249error:
250 gether_cleanup();
251error_quick:
252 gfs_ffs_data = NULL;
253 return ret;
254}
255
256static int gfs_unbind(struct usb_composite_dev *cdev)
257{
258 ENTER();
259
fc19de61
MN
260 /*
261 * We may have been called in an error recovery from
c6c56008
MN
262 * composite_bind() after gfs_unbind() failure so we need to
263 * check if gfs_ffs_data is not NULL since gfs_bind() handles
264 * all error recovery itself. I'd rather we werent called
265 * from composite on orror recovery, but what you're gonna
fc19de61
MN
266 * do...?
267 */
c6c56008
MN
268 if (gfs_ffs_data) {
269 gether_cleanup();
270 functionfs_unbind(gfs_ffs_data);
271 gfs_ffs_data = NULL;
272 }
273
274 return 0;
275}
276
277
f8dae531 278static int gfs_do_config(struct usb_configuration *c)
c6c56008 279{
f8dae531
MN
280 struct gfs_configuration *gc =
281 container_of(c, struct gfs_configuration, c);
c6c56008
MN
282 int ret;
283
284 if (WARN_ON(!gfs_ffs_data))
285 return -ENODEV;
286
287 if (gadget_is_otg(c->cdev->gadget)) {
288 c->descriptors = gfs_otg_desc;
289 c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
290 }
291
f8dae531
MN
292 if (gc->eth) {
293 ret = gc->eth(c, gfs_hostaddr);
c6c56008
MN
294 if (unlikely(ret < 0))
295 return ret;
296 }
297
7898aee1 298 ret = functionfs_bind_config(c->cdev, c, gfs_ffs_data);
c6c56008
MN
299 if (unlikely(ret < 0))
300 return ret;
301
fc19de61
MN
302 /*
303 * After previous do_configs there may be some invalid
f588c0db
MN
304 * pointers in c->interface array. This happens every time
305 * a user space function with fewer interfaces than a user
306 * space function that was run before the new one is run. The
307 * compasit's set_config() assumes that if there is no more
308 * then MAX_CONFIG_INTERFACES interfaces in a configuration
309 * then there is a NULL pointer after the last interface in
fc19de61
MN
310 * c->interface array. We need to make sure this is true.
311 */
f588c0db
MN
312 if (c->next_interface_id < ARRAY_SIZE(c->interface))
313 c->interface[c->next_interface_id] = NULL;
314
c6c56008
MN
315 return 0;
316}
317
c6c56008
MN
318
319#ifdef CONFIG_USB_FUNCTIONFS_ETH
fc19de61 320
f8dae531 321static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
c6c56008 322{
f8dae531
MN
323 return can_support_ecm(c->cdev->gadget)
324 ? ecm_bind_config(c, ethaddr)
325 : geth_bind_config(c, ethaddr);
c6c56008 326}
fc19de61 327
c6c56008 328#endif