diff options
author | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2012-12-23 15:10:01 -0500 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2013-01-21 13:52:40 -0500 |
commit | cf9a08ae5aece88987bbeee8eb0dd0ebb5015815 (patch) | |
tree | bbc7e204bd532b6ff84586653f57bc7ec6bf6380 /drivers/usb/gadget/zero.c | |
parent | de53c25447117eae6b3f8952f663f08a09e0dbb7 (diff) |
usb: gadget: convert source sink and loopback to new function interface
This patch converts the f_sourcesink and f_loopback file to the USB-function
module. Both functions shares a few common utility functions which are
currently implemented in g_zero.c itself. This patch moves the common
code into the sourcesink file and creates one module out of the the two
functions (source sink and loop back).
The g_zero gadget is function specific to source sink and loop back to
set a few options. This Symbol dependency enforces a modul load right
now.
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/gadget/zero.c')
-rw-r--r-- | drivers/usb/gadget/zero.c | 196 |
1 files changed, 116 insertions, 80 deletions
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 8ba0bee4e6c0..a331ab13f1e5 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c | |||
@@ -10,7 +10,6 @@ | |||
10 | * (at your option) any later version. | 10 | * (at your option) any later version. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | |||
14 | /* | 13 | /* |
15 | * Gadget Zero only needs two bulk endpoints, and is an example of how you | 14 | * Gadget Zero only needs two bulk endpoints, and is an example of how you |
16 | * can write a hardware-agnostic gadget driver running inside a USB device. | 15 | * can write a hardware-agnostic gadget driver running inside a USB device. |
@@ -43,23 +42,11 @@ | |||
43 | #include <linux/kernel.h> | 42 | #include <linux/kernel.h> |
44 | #include <linux/slab.h> | 43 | #include <linux/slab.h> |
45 | #include <linux/device.h> | 44 | #include <linux/device.h> |
45 | #include <linux/module.h> | ||
46 | #include <linux/err.h> | ||
47 | #include <linux/usb/composite.h> | ||
46 | 48 | ||
47 | #include "g_zero.h" | 49 | #include "g_zero.h" |
48 | #include "gadget_chips.h" | ||
49 | |||
50 | |||
51 | /*-------------------------------------------------------------------------*/ | ||
52 | |||
53 | /* | ||
54 | * Kbuild is not very cooperative with respect to linking separately | ||
55 | * compiled library objects into one module. So for now we won't use | ||
56 | * separate compilation ... ensuring init/exit sections work to shrink | ||
57 | * the runtime footprint, and giving us at least some parts of what | ||
58 | * a "gcc --combine ... part1.c part2.c part3.c ... " build would. | ||
59 | */ | ||
60 | #include "f_sourcesink.c" | ||
61 | #include "f_loopback.c" | ||
62 | |||
63 | /*-------------------------------------------------------------------------*/ | 50 | /*-------------------------------------------------------------------------*/ |
64 | USB_GADGET_COMPOSITE_OPTIONS(); | 51 | USB_GADGET_COMPOSITE_OPTIONS(); |
65 | 52 | ||
@@ -67,9 +54,6 @@ USB_GADGET_COMPOSITE_OPTIONS(); | |||
67 | 54 | ||
68 | static const char longname[] = "Gadget Zero"; | 55 | static const char longname[] = "Gadget Zero"; |
69 | 56 | ||
70 | unsigned buflen = 4096; /* only used for bulk endpoints */ | ||
71 | module_param(buflen, uint, 0); | ||
72 | |||
73 | /* | 57 | /* |
74 | * Normally the "loopback" configuration is second (index 1) so | 58 | * Normally the "loopback" configuration is second (index 1) so |
75 | * it's not the default. Here's where to change that order, to | 59 | * it's not the default. Here's where to change that order, to |
@@ -79,6 +63,13 @@ module_param(buflen, uint, 0); | |||
79 | static bool loopdefault = 0; | 63 | static bool loopdefault = 0; |
80 | module_param(loopdefault, bool, S_IRUGO|S_IWUSR); | 64 | module_param(loopdefault, bool, S_IRUGO|S_IWUSR); |
81 | 65 | ||
66 | struct usb_zero_options gzero_options = { | ||
67 | .isoc_interval = 4, | ||
68 | .isoc_maxpacket = 1024, | ||
69 | .bulk_buflen = 4096, | ||
70 | .qlen = 32, | ||
71 | }; | ||
72 | |||
82 | /*-------------------------------------------------------------------------*/ | 73 | /*-------------------------------------------------------------------------*/ |
83 | 74 | ||
84 | /* Thanks to NetChip Technologies for donating this product ID. | 75 | /* Thanks to NetChip Technologies for donating this product ID. |
@@ -129,10 +120,12 @@ static struct usb_otg_descriptor otg_descriptor = { | |||
129 | .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, | 120 | .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, |
130 | }; | 121 | }; |
131 | 122 | ||
132 | const struct usb_descriptor_header *otg_desc[] = { | 123 | static const struct usb_descriptor_header *otg_desc[] = { |
133 | (struct usb_descriptor_header *) &otg_descriptor, | 124 | (struct usb_descriptor_header *) &otg_descriptor, |
134 | NULL, | 125 | NULL, |
135 | }; | 126 | }; |
127 | #else | ||
128 | #define otg_desc NULL | ||
136 | #endif | 129 | #endif |
137 | 130 | ||
138 | /* string IDs are assigned dynamically */ | 131 | /* string IDs are assigned dynamically */ |
@@ -163,58 +156,6 @@ static struct usb_gadget_strings *dev_strings[] = { | |||
163 | 156 | ||
164 | /*-------------------------------------------------------------------------*/ | 157 | /*-------------------------------------------------------------------------*/ |
165 | 158 | ||
166 | struct usb_request *alloc_ep_req(struct usb_ep *ep, int len) | ||
167 | { | ||
168 | struct usb_request *req; | ||
169 | |||
170 | req = usb_ep_alloc_request(ep, GFP_ATOMIC); | ||
171 | if (req) { | ||
172 | if (len) | ||
173 | req->length = len; | ||
174 | else | ||
175 | req->length = buflen; | ||
176 | req->buf = kmalloc(req->length, GFP_ATOMIC); | ||
177 | if (!req->buf) { | ||
178 | usb_ep_free_request(ep, req); | ||
179 | req = NULL; | ||
180 | } | ||
181 | } | ||
182 | return req; | ||
183 | } | ||
184 | |||
185 | void free_ep_req(struct usb_ep *ep, struct usb_request *req) | ||
186 | { | ||
187 | kfree(req->buf); | ||
188 | usb_ep_free_request(ep, req); | ||
189 | } | ||
190 | |||
191 | static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep) | ||
192 | { | ||
193 | int value; | ||
194 | |||
195 | if (ep->driver_data) { | ||
196 | value = usb_ep_disable(ep); | ||
197 | if (value < 0) | ||
198 | DBG(cdev, "disable %s --> %d\n", | ||
199 | ep->name, value); | ||
200 | ep->driver_data = NULL; | ||
201 | } | ||
202 | } | ||
203 | |||
204 | void disable_endpoints(struct usb_composite_dev *cdev, | ||
205 | struct usb_ep *in, struct usb_ep *out, | ||
206 | struct usb_ep *iso_in, struct usb_ep *iso_out) | ||
207 | { | ||
208 | disable_ep(cdev, in); | ||
209 | disable_ep(cdev, out); | ||
210 | if (iso_in) | ||
211 | disable_ep(cdev, iso_in); | ||
212 | if (iso_out) | ||
213 | disable_ep(cdev, iso_out); | ||
214 | } | ||
215 | |||
216 | /*-------------------------------------------------------------------------*/ | ||
217 | |||
218 | static struct timer_list autoresume_timer; | 159 | static struct timer_list autoresume_timer; |
219 | 160 | ||
220 | static void zero_autoresume(unsigned long _c) | 161 | static void zero_autoresume(unsigned long _c) |
@@ -258,23 +199,63 @@ static void zero_resume(struct usb_composite_dev *cdev) | |||
258 | 199 | ||
259 | static struct usb_configuration loopback_driver = { | 200 | static struct usb_configuration loopback_driver = { |
260 | .label = "loopback", | 201 | .label = "loopback", |
261 | .strings = loopback_strings, | ||
262 | .bConfigurationValue = 2, | 202 | .bConfigurationValue = 2, |
263 | .bmAttributes = USB_CONFIG_ATT_SELFPOWER, | 203 | .bmAttributes = USB_CONFIG_ATT_SELFPOWER, |
264 | /* .iConfiguration = DYNAMIC */ | 204 | /* .iConfiguration = DYNAMIC */ |
265 | }; | 205 | }; |
266 | 206 | ||
207 | static struct usb_function *func_ss; | ||
208 | static struct usb_function_instance *func_inst_ss; | ||
209 | |||
210 | static int ss_config_setup(struct usb_configuration *c, | ||
211 | const struct usb_ctrlrequest *ctrl) | ||
212 | { | ||
213 | switch (ctrl->bRequest) { | ||
214 | case 0x5b: | ||
215 | case 0x5c: | ||
216 | return func_ss->setup(func_ss, ctrl); | ||
217 | default: | ||
218 | return -EOPNOTSUPP; | ||
219 | } | ||
220 | } | ||
221 | |||
267 | static struct usb_configuration sourcesink_driver = { | 222 | static struct usb_configuration sourcesink_driver = { |
268 | .label = "source/sink", | 223 | .label = "source/sink", |
269 | .strings = sourcesink_strings, | ||
270 | .setup = ss_config_setup, | 224 | .setup = ss_config_setup, |
271 | .bConfigurationValue = 3, | 225 | .bConfigurationValue = 3, |
272 | .bmAttributes = USB_CONFIG_ATT_SELFPOWER, | 226 | .bmAttributes = USB_CONFIG_ATT_SELFPOWER, |
273 | /* .iConfiguration = DYNAMIC */ | 227 | /* .iConfiguration = DYNAMIC */ |
274 | }; | 228 | }; |
275 | 229 | ||
230 | module_param_named(buflen, gzero_options.bulk_buflen, uint, 0); | ||
231 | module_param_named(pattern, gzero_options.pattern, uint, S_IRUGO|S_IWUSR); | ||
232 | MODULE_PARM_DESC(pattern, "0 = all zeroes, 1 = mod63, 2 = none"); | ||
233 | |||
234 | module_param_named(isoc_interval, gzero_options.isoc_interval, uint, | ||
235 | S_IRUGO|S_IWUSR); | ||
236 | MODULE_PARM_DESC(isoc_interval, "1 - 16"); | ||
237 | |||
238 | module_param_named(isoc_maxpacket, gzero_options.isoc_maxpacket, uint, | ||
239 | S_IRUGO|S_IWUSR); | ||
240 | MODULE_PARM_DESC(isoc_maxpacket, "0 - 1023 (fs), 0 - 1024 (hs/ss)"); | ||
241 | |||
242 | module_param_named(isoc_mult, gzero_options.isoc_mult, uint, S_IRUGO|S_IWUSR); | ||
243 | MODULE_PARM_DESC(isoc_mult, "0 - 2 (hs/ss only)"); | ||
244 | |||
245 | module_param_named(isoc_maxburst, gzero_options.isoc_maxburst, uint, | ||
246 | S_IRUGO|S_IWUSR); | ||
247 | MODULE_PARM_DESC(isoc_maxburst, "0 - 15 (ss only)"); | ||
248 | |||
249 | static struct usb_function *func_lb; | ||
250 | static struct usb_function_instance *func_inst_lb; | ||
251 | |||
252 | module_param_named(qlen, gzero_options.qlen, uint, S_IRUGO|S_IWUSR); | ||
253 | MODULE_PARM_DESC(qlen, "depth of loopback queue"); | ||
254 | |||
276 | static int __init zero_bind(struct usb_composite_dev *cdev) | 255 | static int __init zero_bind(struct usb_composite_dev *cdev) |
277 | { | 256 | { |
257 | struct f_ss_opts *ss_opts; | ||
258 | struct f_lb_opts *lb_opts; | ||
278 | int status; | 259 | int status; |
279 | 260 | ||
280 | /* Allocate string descriptor numbers ... note that string | 261 | /* Allocate string descriptor numbers ... note that string |
@@ -290,6 +271,36 @@ static int __init zero_bind(struct usb_composite_dev *cdev) | |||
290 | 271 | ||
291 | setup_timer(&autoresume_timer, zero_autoresume, (unsigned long) cdev); | 272 | setup_timer(&autoresume_timer, zero_autoresume, (unsigned long) cdev); |
292 | 273 | ||
274 | func_inst_ss = usb_get_function_instance("SourceSink"); | ||
275 | if (IS_ERR(func_inst_ss)) | ||
276 | return PTR_ERR(func_inst_ss); | ||
277 | |||
278 | ss_opts = container_of(func_inst_ss, struct f_ss_opts, func_inst); | ||
279 | ss_opts->pattern = gzero_options.pattern; | ||
280 | ss_opts->isoc_interval = gzero_options.isoc_interval; | ||
281 | ss_opts->isoc_maxpacket = gzero_options.isoc_maxpacket; | ||
282 | ss_opts->isoc_mult = gzero_options.isoc_mult; | ||
283 | ss_opts->isoc_maxburst = gzero_options.isoc_maxpacket; | ||
284 | ss_opts->bulk_buflen = gzero_options.bulk_buflen; | ||
285 | |||
286 | func_ss = usb_get_function(func_inst_ss); | ||
287 | if (IS_ERR(func_ss)) | ||
288 | goto err_put_func_inst_ss; | ||
289 | |||
290 | func_inst_lb = usb_get_function_instance("Loopback"); | ||
291 | if (IS_ERR(func_inst_lb)) | ||
292 | goto err_put_func_ss; | ||
293 | |||
294 | lb_opts = container_of(func_inst_lb, struct f_lb_opts, func_inst); | ||
295 | lb_opts->bulk_buflen = gzero_options.bulk_buflen; | ||
296 | lb_opts->qlen = gzero_options.qlen; | ||
297 | |||
298 | func_lb = usb_get_function(func_inst_lb); | ||
299 | if (IS_ERR(func_lb)) { | ||
300 | status = PTR_ERR(func_lb); | ||
301 | goto err_put_func_inst_lb; | ||
302 | } | ||
303 | |||
293 | sourcesink_driver.iConfiguration = strings_dev[USB_GZERO_SS_DESC].id; | 304 | sourcesink_driver.iConfiguration = strings_dev[USB_GZERO_SS_DESC].id; |
294 | loopback_driver.iConfiguration = strings_dev[USB_GZERO_LB_DESC].id; | 305 | loopback_driver.iConfiguration = strings_dev[USB_GZERO_LB_DESC].id; |
295 | 306 | ||
@@ -315,25 +326,50 @@ static int __init zero_bind(struct usb_composite_dev *cdev) | |||
315 | * SH3 only allows one config... | 326 | * SH3 only allows one config... |
316 | */ | 327 | */ |
317 | if (loopdefault) { | 328 | if (loopdefault) { |
318 | usb_add_config(cdev, &loopback_driver, loopback_bind_config); | 329 | usb_add_config_only(cdev, &loopback_driver); |
319 | usb_add_config(cdev, &sourcesink_driver, | 330 | usb_add_config_only(cdev, &sourcesink_driver); |
320 | sourcesink_bind_config); | ||
321 | } else { | 331 | } else { |
322 | usb_add_config(cdev, &sourcesink_driver, | 332 | usb_add_config_only(cdev, &sourcesink_driver); |
323 | sourcesink_bind_config); | 333 | usb_add_config_only(cdev, &loopback_driver); |
324 | usb_add_config(cdev, &loopback_driver, loopback_bind_config); | ||
325 | } | 334 | } |
335 | status = usb_add_function(&sourcesink_driver, func_ss); | ||
336 | if (status) | ||
337 | goto err_conf_flb; | ||
326 | 338 | ||
339 | usb_ep_autoconfig_reset(cdev->gadget); | ||
340 | status = usb_add_function(&loopback_driver, func_lb); | ||
341 | if (status) | ||
342 | goto err_conf_flb; | ||
343 | |||
344 | usb_ep_autoconfig_reset(cdev->gadget); | ||
327 | usb_composite_overwrite_options(cdev, &coverwrite); | 345 | usb_composite_overwrite_options(cdev, &coverwrite); |
328 | 346 | ||
329 | INFO(cdev, "%s, version: " DRIVER_VERSION "\n", longname); | 347 | INFO(cdev, "%s, version: " DRIVER_VERSION "\n", longname); |
330 | 348 | ||
331 | return 0; | 349 | return 0; |
350 | |||
351 | err_conf_flb: | ||
352 | usb_put_function(func_lb); | ||
353 | func_lb = NULL; | ||
354 | err_put_func_inst_lb: | ||
355 | usb_put_function_instance(func_inst_lb); | ||
356 | func_inst_lb = NULL; | ||
357 | err_put_func_ss: | ||
358 | usb_put_function(func_ss); | ||
359 | func_ss = NULL; | ||
360 | err_put_func_inst_ss: | ||
361 | usb_put_function_instance(func_inst_ss); | ||
362 | func_inst_ss = NULL; | ||
363 | return status; | ||
332 | } | 364 | } |
333 | 365 | ||
334 | static int zero_unbind(struct usb_composite_dev *cdev) | 366 | static int zero_unbind(struct usb_composite_dev *cdev) |
335 | { | 367 | { |
336 | del_timer_sync(&autoresume_timer); | 368 | del_timer_sync(&autoresume_timer); |
369 | if (!IS_ERR_OR_NULL(func_ss)) | ||
370 | usb_put_function(func_ss); | ||
371 | if (!IS_ERR_OR_NULL(func_lb)) | ||
372 | usb_put_function(func_lb); | ||
337 | return 0; | 373 | return 0; |
338 | } | 374 | } |
339 | 375 | ||