diff options
Diffstat (limited to 'drivers/usb/gadget/f_uvc.c')
-rw-r--r-- | drivers/usb/gadget/f_uvc.c | 661 |
1 files changed, 661 insertions, 0 deletions
diff --git a/drivers/usb/gadget/f_uvc.c b/drivers/usb/gadget/f_uvc.c new file mode 100644 index 000000000000..fc2611f8b326 --- /dev/null +++ b/drivers/usb/gadget/f_uvc.c | |||
@@ -0,0 +1,661 @@ | |||
1 | /* | ||
2 | * uvc_gadget.c -- USB Video Class Gadget driver | ||
3 | * | ||
4 | * Copyright (C) 2009-2010 | ||
5 | * Laurent Pinchart (laurent.pinchart@ideasonboard.com) | ||
6 | * | ||
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. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/device.h> | ||
16 | #include <linux/errno.h> | ||
17 | #include <linux/fs.h> | ||
18 | #include <linux/list.h> | ||
19 | #include <linux/mutex.h> | ||
20 | #include <linux/usb/ch9.h> | ||
21 | #include <linux/usb/gadget.h> | ||
22 | #include <linux/usb/video.h> | ||
23 | #include <linux/vmalloc.h> | ||
24 | #include <linux/wait.h> | ||
25 | |||
26 | #include <media/v4l2-dev.h> | ||
27 | #include <media/v4l2-event.h> | ||
28 | |||
29 | #include "uvc.h" | ||
30 | |||
31 | unsigned int uvc_trace_param; | ||
32 | |||
33 | /* -------------------------------------------------------------------------- | ||
34 | * Function descriptors | ||
35 | */ | ||
36 | |||
37 | /* string IDs are assigned dynamically */ | ||
38 | |||
39 | #define UVC_STRING_ASSOCIATION_IDX 0 | ||
40 | #define UVC_STRING_CONTROL_IDX 1 | ||
41 | #define UVC_STRING_STREAMING_IDX 2 | ||
42 | |||
43 | static struct usb_string uvc_en_us_strings[] = { | ||
44 | [UVC_STRING_ASSOCIATION_IDX].s = "UVC Camera", | ||
45 | [UVC_STRING_CONTROL_IDX].s = "Video Control", | ||
46 | [UVC_STRING_STREAMING_IDX].s = "Video Streaming", | ||
47 | { } | ||
48 | }; | ||
49 | |||
50 | static struct usb_gadget_strings uvc_stringtab = { | ||
51 | .language = 0x0409, /* en-us */ | ||
52 | .strings = uvc_en_us_strings, | ||
53 | }; | ||
54 | |||
55 | static struct usb_gadget_strings *uvc_function_strings[] = { | ||
56 | &uvc_stringtab, | ||
57 | NULL, | ||
58 | }; | ||
59 | |||
60 | #define UVC_INTF_VIDEO_CONTROL 0 | ||
61 | #define UVC_INTF_VIDEO_STREAMING 1 | ||
62 | |||
63 | static struct usb_interface_assoc_descriptor uvc_iad __initdata = { | ||
64 | .bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE, | ||
65 | .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, | ||
66 | .bFirstInterface = 0, | ||
67 | .bInterfaceCount = 2, | ||
68 | .bFunctionClass = USB_CLASS_VIDEO, | ||
69 | .bFunctionSubClass = 0x03, | ||
70 | .bFunctionProtocol = 0x00, | ||
71 | .iFunction = 0, | ||
72 | }; | ||
73 | |||
74 | static struct usb_interface_descriptor uvc_control_intf __initdata = { | ||
75 | .bLength = USB_DT_INTERFACE_SIZE, | ||
76 | .bDescriptorType = USB_DT_INTERFACE, | ||
77 | .bInterfaceNumber = UVC_INTF_VIDEO_CONTROL, | ||
78 | .bAlternateSetting = 0, | ||
79 | .bNumEndpoints = 1, | ||
80 | .bInterfaceClass = USB_CLASS_VIDEO, | ||
81 | .bInterfaceSubClass = 0x01, | ||
82 | .bInterfaceProtocol = 0x00, | ||
83 | .iInterface = 0, | ||
84 | }; | ||
85 | |||
86 | static struct usb_endpoint_descriptor uvc_control_ep __initdata = { | ||
87 | .bLength = USB_DT_ENDPOINT_SIZE, | ||
88 | .bDescriptorType = USB_DT_ENDPOINT, | ||
89 | .bEndpointAddress = USB_DIR_IN, | ||
90 | .bmAttributes = USB_ENDPOINT_XFER_INT, | ||
91 | .wMaxPacketSize = cpu_to_le16(16), | ||
92 | .bInterval = 8, | ||
93 | }; | ||
94 | |||
95 | static struct uvc_control_endpoint_descriptor uvc_control_cs_ep __initdata = { | ||
96 | .bLength = UVC_DT_CONTROL_ENDPOINT_SIZE, | ||
97 | .bDescriptorType = USB_DT_CS_ENDPOINT, | ||
98 | .bDescriptorSubType = UVC_EP_INTERRUPT, | ||
99 | .wMaxTransferSize = cpu_to_le16(16), | ||
100 | }; | ||
101 | |||
102 | static struct usb_interface_descriptor uvc_streaming_intf_alt0 __initdata = { | ||
103 | .bLength = USB_DT_INTERFACE_SIZE, | ||
104 | .bDescriptorType = USB_DT_INTERFACE, | ||
105 | .bInterfaceNumber = UVC_INTF_VIDEO_STREAMING, | ||
106 | .bAlternateSetting = 0, | ||
107 | .bNumEndpoints = 0, | ||
108 | .bInterfaceClass = USB_CLASS_VIDEO, | ||
109 | .bInterfaceSubClass = 0x02, | ||
110 | .bInterfaceProtocol = 0x00, | ||
111 | .iInterface = 0, | ||
112 | }; | ||
113 | |||
114 | static struct usb_interface_descriptor uvc_streaming_intf_alt1 __initdata = { | ||
115 | .bLength = USB_DT_INTERFACE_SIZE, | ||
116 | .bDescriptorType = USB_DT_INTERFACE, | ||
117 | .bInterfaceNumber = UVC_INTF_VIDEO_STREAMING, | ||
118 | .bAlternateSetting = 1, | ||
119 | .bNumEndpoints = 1, | ||
120 | .bInterfaceClass = USB_CLASS_VIDEO, | ||
121 | .bInterfaceSubClass = 0x02, | ||
122 | .bInterfaceProtocol = 0x00, | ||
123 | .iInterface = 0, | ||
124 | }; | ||
125 | |||
126 | static struct usb_endpoint_descriptor uvc_streaming_ep = { | ||
127 | .bLength = USB_DT_ENDPOINT_SIZE, | ||
128 | .bDescriptorType = USB_DT_ENDPOINT, | ||
129 | .bEndpointAddress = USB_DIR_IN, | ||
130 | .bmAttributes = USB_ENDPOINT_XFER_ISOC, | ||
131 | .wMaxPacketSize = cpu_to_le16(512), | ||
132 | .bInterval = 1, | ||
133 | }; | ||
134 | |||
135 | static const struct usb_descriptor_header * const uvc_fs_streaming[] = { | ||
136 | (struct usb_descriptor_header *) &uvc_streaming_intf_alt1, | ||
137 | (struct usb_descriptor_header *) &uvc_streaming_ep, | ||
138 | NULL, | ||
139 | }; | ||
140 | |||
141 | static const struct usb_descriptor_header * const uvc_hs_streaming[] = { | ||
142 | (struct usb_descriptor_header *) &uvc_streaming_intf_alt1, | ||
143 | (struct usb_descriptor_header *) &uvc_streaming_ep, | ||
144 | NULL, | ||
145 | }; | ||
146 | |||
147 | /* -------------------------------------------------------------------------- | ||
148 | * Control requests | ||
149 | */ | ||
150 | |||
151 | static void | ||
152 | uvc_function_ep0_complete(struct usb_ep *ep, struct usb_request *req) | ||
153 | { | ||
154 | struct uvc_device *uvc = req->context; | ||
155 | struct v4l2_event v4l2_event; | ||
156 | struct uvc_event *uvc_event = (void *)&v4l2_event.u.data; | ||
157 | |||
158 | if (uvc->event_setup_out) { | ||
159 | uvc->event_setup_out = 0; | ||
160 | |||
161 | memset(&v4l2_event, 0, sizeof(v4l2_event)); | ||
162 | v4l2_event.type = UVC_EVENT_DATA; | ||
163 | uvc_event->data.length = req->actual; | ||
164 | memcpy(&uvc_event->data.data, req->buf, req->actual); | ||
165 | v4l2_event_queue(uvc->vdev, &v4l2_event); | ||
166 | } | ||
167 | } | ||
168 | |||
169 | static int | ||
170 | uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) | ||
171 | { | ||
172 | struct uvc_device *uvc = to_uvc(f); | ||
173 | struct v4l2_event v4l2_event; | ||
174 | struct uvc_event *uvc_event = (void *)&v4l2_event.u.data; | ||
175 | |||
176 | /* printk(KERN_INFO "setup request %02x %02x value %04x index %04x %04x\n", | ||
177 | * ctrl->bRequestType, ctrl->bRequest, le16_to_cpu(ctrl->wValue), | ||
178 | * le16_to_cpu(ctrl->wIndex), le16_to_cpu(ctrl->wLength)); | ||
179 | */ | ||
180 | |||
181 | if ((ctrl->bRequestType & USB_TYPE_MASK) != USB_TYPE_CLASS) { | ||
182 | INFO(f->config->cdev, "invalid request type\n"); | ||
183 | return -EINVAL; | ||
184 | } | ||
185 | |||
186 | /* Stall too big requests. */ | ||
187 | if (le16_to_cpu(ctrl->wLength) > UVC_MAX_REQUEST_SIZE) | ||
188 | return -EINVAL; | ||
189 | |||
190 | memset(&v4l2_event, 0, sizeof(v4l2_event)); | ||
191 | v4l2_event.type = UVC_EVENT_SETUP; | ||
192 | memcpy(&uvc_event->req, ctrl, sizeof(uvc_event->req)); | ||
193 | v4l2_event_queue(uvc->vdev, &v4l2_event); | ||
194 | |||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | static int | ||
199 | uvc_function_get_alt(struct usb_function *f, unsigned interface) | ||
200 | { | ||
201 | struct uvc_device *uvc = to_uvc(f); | ||
202 | |||
203 | INFO(f->config->cdev, "uvc_function_get_alt(%u)\n", interface); | ||
204 | |||
205 | if (interface == uvc->control_intf) | ||
206 | return 0; | ||
207 | else if (interface != uvc->streaming_intf) | ||
208 | return -EINVAL; | ||
209 | else | ||
210 | return uvc->state == UVC_STATE_STREAMING ? 1 : 0; | ||
211 | } | ||
212 | |||
213 | static int | ||
214 | uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) | ||
215 | { | ||
216 | struct uvc_device *uvc = to_uvc(f); | ||
217 | struct v4l2_event v4l2_event; | ||
218 | struct uvc_event *uvc_event = (void *)&v4l2_event.u.data; | ||
219 | |||
220 | INFO(f->config->cdev, "uvc_function_set_alt(%u, %u)\n", interface, alt); | ||
221 | |||
222 | if (interface == uvc->control_intf) { | ||
223 | if (alt) | ||
224 | return -EINVAL; | ||
225 | |||
226 | if (uvc->state == UVC_STATE_DISCONNECTED) { | ||
227 | memset(&v4l2_event, 0, sizeof(v4l2_event)); | ||
228 | v4l2_event.type = UVC_EVENT_CONNECT; | ||
229 | uvc_event->speed = f->config->cdev->gadget->speed; | ||
230 | v4l2_event_queue(uvc->vdev, &v4l2_event); | ||
231 | |||
232 | uvc->state = UVC_STATE_CONNECTED; | ||
233 | } | ||
234 | |||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | if (interface != uvc->streaming_intf) | ||
239 | return -EINVAL; | ||
240 | |||
241 | /* TODO | ||
242 | if (usb_endpoint_xfer_bulk(&uvc->desc.vs_ep)) | ||
243 | return alt ? -EINVAL : 0; | ||
244 | */ | ||
245 | |||
246 | switch (alt) { | ||
247 | case 0: | ||
248 | if (uvc->state != UVC_STATE_STREAMING) | ||
249 | return 0; | ||
250 | |||
251 | if (uvc->video.ep) | ||
252 | usb_ep_disable(uvc->video.ep); | ||
253 | |||
254 | memset(&v4l2_event, 0, sizeof(v4l2_event)); | ||
255 | v4l2_event.type = UVC_EVENT_STREAMOFF; | ||
256 | v4l2_event_queue(uvc->vdev, &v4l2_event); | ||
257 | |||
258 | uvc->state = UVC_STATE_CONNECTED; | ||
259 | break; | ||
260 | |||
261 | case 1: | ||
262 | if (uvc->state != UVC_STATE_CONNECTED) | ||
263 | return 0; | ||
264 | |||
265 | if (uvc->video.ep) | ||
266 | usb_ep_enable(uvc->video.ep, &uvc_streaming_ep); | ||
267 | |||
268 | memset(&v4l2_event, 0, sizeof(v4l2_event)); | ||
269 | v4l2_event.type = UVC_EVENT_STREAMON; | ||
270 | v4l2_event_queue(uvc->vdev, &v4l2_event); | ||
271 | |||
272 | uvc->state = UVC_STATE_STREAMING; | ||
273 | break; | ||
274 | |||
275 | default: | ||
276 | return -EINVAL; | ||
277 | } | ||
278 | |||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | static void | ||
283 | uvc_function_disable(struct usb_function *f) | ||
284 | { | ||
285 | struct uvc_device *uvc = to_uvc(f); | ||
286 | struct v4l2_event v4l2_event; | ||
287 | |||
288 | INFO(f->config->cdev, "uvc_function_disable\n"); | ||
289 | |||
290 | memset(&v4l2_event, 0, sizeof(v4l2_event)); | ||
291 | v4l2_event.type = UVC_EVENT_DISCONNECT; | ||
292 | v4l2_event_queue(uvc->vdev, &v4l2_event); | ||
293 | |||
294 | uvc->state = UVC_STATE_DISCONNECTED; | ||
295 | } | ||
296 | |||
297 | /* -------------------------------------------------------------------------- | ||
298 | * Connection / disconnection | ||
299 | */ | ||
300 | |||
301 | void | ||
302 | uvc_function_connect(struct uvc_device *uvc) | ||
303 | { | ||
304 | struct usb_composite_dev *cdev = uvc->func.config->cdev; | ||
305 | int ret; | ||
306 | |||
307 | if ((ret = usb_function_activate(&uvc->func)) < 0) | ||
308 | INFO(cdev, "UVC connect failed with %d\n", ret); | ||
309 | } | ||
310 | |||
311 | void | ||
312 | uvc_function_disconnect(struct uvc_device *uvc) | ||
313 | { | ||
314 | struct usb_composite_dev *cdev = uvc->func.config->cdev; | ||
315 | int ret; | ||
316 | |||
317 | if ((ret = usb_function_deactivate(&uvc->func)) < 0) | ||
318 | INFO(cdev, "UVC disconnect failed with %d\n", ret); | ||
319 | } | ||
320 | |||
321 | /* -------------------------------------------------------------------------- | ||
322 | * USB probe and disconnect | ||
323 | */ | ||
324 | |||
325 | static int | ||
326 | uvc_register_video(struct uvc_device *uvc) | ||
327 | { | ||
328 | struct usb_composite_dev *cdev = uvc->func.config->cdev; | ||
329 | struct video_device *video; | ||
330 | |||
331 | /* TODO reference counting. */ | ||
332 | video = video_device_alloc(); | ||
333 | if (video == NULL) | ||
334 | return -ENOMEM; | ||
335 | |||
336 | video->parent = &cdev->gadget->dev; | ||
337 | video->minor = -1; | ||
338 | video->fops = &uvc_v4l2_fops; | ||
339 | video->release = video_device_release; | ||
340 | strncpy(video->name, cdev->gadget->name, sizeof(video->name)); | ||
341 | |||
342 | uvc->vdev = video; | ||
343 | video_set_drvdata(video, uvc); | ||
344 | |||
345 | return video_register_device(video, VFL_TYPE_GRABBER, -1); | ||
346 | } | ||
347 | |||
348 | #define UVC_COPY_DESCRIPTOR(mem, dst, desc) \ | ||
349 | do { \ | ||
350 | memcpy(mem, desc, (desc)->bLength); \ | ||
351 | *(dst)++ = mem; \ | ||
352 | mem += (desc)->bLength; \ | ||
353 | } while (0); | ||
354 | |||
355 | #define UVC_COPY_DESCRIPTORS(mem, dst, src) \ | ||
356 | do { \ | ||
357 | const struct usb_descriptor_header * const *__src; \ | ||
358 | for (__src = src; *__src; ++__src) { \ | ||
359 | memcpy(mem, *__src, (*__src)->bLength); \ | ||
360 | *dst++ = mem; \ | ||
361 | mem += (*__src)->bLength; \ | ||
362 | } \ | ||
363 | } while (0) | ||
364 | |||
365 | static struct usb_descriptor_header ** __init | ||
366 | uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) | ||
367 | { | ||
368 | struct uvc_input_header_descriptor *uvc_streaming_header; | ||
369 | struct uvc_header_descriptor *uvc_control_header; | ||
370 | const struct uvc_descriptor_header * const *uvc_streaming_cls; | ||
371 | const struct usb_descriptor_header * const *uvc_streaming_std; | ||
372 | const struct usb_descriptor_header * const *src; | ||
373 | struct usb_descriptor_header **dst; | ||
374 | struct usb_descriptor_header **hdr; | ||
375 | unsigned int control_size; | ||
376 | unsigned int streaming_size; | ||
377 | unsigned int n_desc; | ||
378 | unsigned int bytes; | ||
379 | void *mem; | ||
380 | |||
381 | uvc_streaming_cls = (speed == USB_SPEED_FULL) | ||
382 | ? uvc->desc.fs_streaming : uvc->desc.hs_streaming; | ||
383 | uvc_streaming_std = (speed == USB_SPEED_FULL) | ||
384 | ? uvc_fs_streaming : uvc_hs_streaming; | ||
385 | |||
386 | /* Descriptors layout | ||
387 | * | ||
388 | * uvc_iad | ||
389 | * uvc_control_intf | ||
390 | * Class-specific UVC control descriptors | ||
391 | * uvc_control_ep | ||
392 | * uvc_control_cs_ep | ||
393 | * uvc_streaming_intf_alt0 | ||
394 | * Class-specific UVC streaming descriptors | ||
395 | * uvc_{fs|hs}_streaming | ||
396 | */ | ||
397 | |||
398 | /* Count descriptors and compute their size. */ | ||
399 | control_size = 0; | ||
400 | streaming_size = 0; | ||
401 | bytes = uvc_iad.bLength + uvc_control_intf.bLength | ||
402 | + uvc_control_ep.bLength + uvc_control_cs_ep.bLength | ||
403 | + uvc_streaming_intf_alt0.bLength; | ||
404 | n_desc = 5; | ||
405 | |||
406 | for (src = (const struct usb_descriptor_header**)uvc->desc.control; *src; ++src) { | ||
407 | control_size += (*src)->bLength; | ||
408 | bytes += (*src)->bLength; | ||
409 | n_desc++; | ||
410 | } | ||
411 | for (src = (const struct usb_descriptor_header**)uvc_streaming_cls; *src; ++src) { | ||
412 | streaming_size += (*src)->bLength; | ||
413 | bytes += (*src)->bLength; | ||
414 | n_desc++; | ||
415 | } | ||
416 | for (src = uvc_streaming_std; *src; ++src) { | ||
417 | bytes += (*src)->bLength; | ||
418 | n_desc++; | ||
419 | } | ||
420 | |||
421 | mem = kmalloc((n_desc + 1) * sizeof(*src) + bytes, GFP_KERNEL); | ||
422 | if (mem == NULL) | ||
423 | return NULL; | ||
424 | |||
425 | hdr = mem; | ||
426 | dst = mem; | ||
427 | mem += (n_desc + 1) * sizeof(*src); | ||
428 | |||
429 | /* Copy the descriptors. */ | ||
430 | UVC_COPY_DESCRIPTOR(mem, dst, &uvc_iad); | ||
431 | UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_intf); | ||
432 | |||
433 | uvc_control_header = mem; | ||
434 | UVC_COPY_DESCRIPTORS(mem, dst, | ||
435 | (const struct usb_descriptor_header**)uvc->desc.control); | ||
436 | uvc_control_header->wTotalLength = cpu_to_le16(control_size); | ||
437 | uvc_control_header->bInCollection = 1; | ||
438 | uvc_control_header->baInterfaceNr[0] = uvc->streaming_intf; | ||
439 | |||
440 | UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_ep); | ||
441 | UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_cs_ep); | ||
442 | UVC_COPY_DESCRIPTOR(mem, dst, &uvc_streaming_intf_alt0); | ||
443 | |||
444 | uvc_streaming_header = mem; | ||
445 | UVC_COPY_DESCRIPTORS(mem, dst, | ||
446 | (const struct usb_descriptor_header**)uvc_streaming_cls); | ||
447 | uvc_streaming_header->wTotalLength = cpu_to_le16(streaming_size); | ||
448 | uvc_streaming_header->bEndpointAddress = uvc_streaming_ep.bEndpointAddress; | ||
449 | |||
450 | UVC_COPY_DESCRIPTORS(mem, dst, uvc_streaming_std); | ||
451 | |||
452 | *dst = NULL; | ||
453 | return hdr; | ||
454 | } | ||
455 | |||
456 | static void | ||
457 | uvc_function_unbind(struct usb_configuration *c, struct usb_function *f) | ||
458 | { | ||
459 | struct usb_composite_dev *cdev = c->cdev; | ||
460 | struct uvc_device *uvc = to_uvc(f); | ||
461 | |||
462 | INFO(cdev, "uvc_function_unbind\n"); | ||
463 | |||
464 | if (uvc->vdev) { | ||
465 | if (uvc->vdev->minor == -1) | ||
466 | video_device_release(uvc->vdev); | ||
467 | else | ||
468 | video_unregister_device(uvc->vdev); | ||
469 | uvc->vdev = NULL; | ||
470 | } | ||
471 | |||
472 | if (uvc->control_ep) | ||
473 | uvc->control_ep->driver_data = NULL; | ||
474 | if (uvc->video.ep) | ||
475 | uvc->video.ep->driver_data = NULL; | ||
476 | |||
477 | if (uvc->control_req) { | ||
478 | usb_ep_free_request(cdev->gadget->ep0, uvc->control_req); | ||
479 | kfree(uvc->control_buf); | ||
480 | } | ||
481 | |||
482 | kfree(f->descriptors); | ||
483 | kfree(f->hs_descriptors); | ||
484 | |||
485 | kfree(uvc); | ||
486 | } | ||
487 | |||
488 | static int __init | ||
489 | uvc_function_bind(struct usb_configuration *c, struct usb_function *f) | ||
490 | { | ||
491 | struct usb_composite_dev *cdev = c->cdev; | ||
492 | struct uvc_device *uvc = to_uvc(f); | ||
493 | struct usb_ep *ep; | ||
494 | int ret = -EINVAL; | ||
495 | |||
496 | INFO(cdev, "uvc_function_bind\n"); | ||
497 | |||
498 | /* Allocate endpoints. */ | ||
499 | ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep); | ||
500 | if (!ep) { | ||
501 | INFO(cdev, "Unable to allocate control EP\n"); | ||
502 | goto error; | ||
503 | } | ||
504 | uvc->control_ep = ep; | ||
505 | ep->driver_data = uvc; | ||
506 | |||
507 | ep = usb_ep_autoconfig(cdev->gadget, &uvc_streaming_ep); | ||
508 | if (!ep) { | ||
509 | INFO(cdev, "Unable to allocate streaming EP\n"); | ||
510 | goto error; | ||
511 | } | ||
512 | uvc->video.ep = ep; | ||
513 | ep->driver_data = uvc; | ||
514 | |||
515 | /* Allocate interface IDs. */ | ||
516 | if ((ret = usb_interface_id(c, f)) < 0) | ||
517 | goto error; | ||
518 | uvc_iad.bFirstInterface = ret; | ||
519 | uvc_control_intf.bInterfaceNumber = ret; | ||
520 | uvc->control_intf = ret; | ||
521 | |||
522 | if ((ret = usb_interface_id(c, f)) < 0) | ||
523 | goto error; | ||
524 | uvc_streaming_intf_alt0.bInterfaceNumber = ret; | ||
525 | uvc_streaming_intf_alt1.bInterfaceNumber = ret; | ||
526 | uvc->streaming_intf = ret; | ||
527 | |||
528 | /* Copy descriptors. */ | ||
529 | f->descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL); | ||
530 | f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH); | ||
531 | |||
532 | /* Preallocate control endpoint request. */ | ||
533 | uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL); | ||
534 | uvc->control_buf = kmalloc(UVC_MAX_REQUEST_SIZE, GFP_KERNEL); | ||
535 | if (uvc->control_req == NULL || uvc->control_buf == NULL) { | ||
536 | ret = -ENOMEM; | ||
537 | goto error; | ||
538 | } | ||
539 | |||
540 | uvc->control_req->buf = uvc->control_buf; | ||
541 | uvc->control_req->complete = uvc_function_ep0_complete; | ||
542 | uvc->control_req->context = uvc; | ||
543 | |||
544 | /* Avoid letting this gadget enumerate until the userspace server is | ||
545 | * active. | ||
546 | */ | ||
547 | if ((ret = usb_function_deactivate(f)) < 0) | ||
548 | goto error; | ||
549 | |||
550 | /* Initialise video. */ | ||
551 | ret = uvc_video_init(&uvc->video); | ||
552 | if (ret < 0) | ||
553 | goto error; | ||
554 | |||
555 | /* Register a V4L2 device. */ | ||
556 | ret = uvc_register_video(uvc); | ||
557 | if (ret < 0) { | ||
558 | printk(KERN_INFO "Unable to register video device\n"); | ||
559 | goto error; | ||
560 | } | ||
561 | |||
562 | return 0; | ||
563 | |||
564 | error: | ||
565 | uvc_function_unbind(c, f); | ||
566 | return ret; | ||
567 | } | ||
568 | |||
569 | /* -------------------------------------------------------------------------- | ||
570 | * USB gadget function | ||
571 | */ | ||
572 | |||
573 | /** | ||
574 | * uvc_bind_config - add a UVC function to a configuration | ||
575 | * @c: the configuration to support the UVC instance | ||
576 | * Context: single threaded during gadget setup | ||
577 | * | ||
578 | * Returns zero on success, else negative errno. | ||
579 | * | ||
580 | * Caller must have called @uvc_setup(). Caller is also responsible for | ||
581 | * calling @uvc_cleanup() before module unload. | ||
582 | */ | ||
583 | int __init | ||
584 | uvc_bind_config(struct usb_configuration *c, | ||
585 | const struct uvc_descriptor_header * const *control, | ||
586 | const struct uvc_descriptor_header * const *fs_streaming, | ||
587 | const struct uvc_descriptor_header * const *hs_streaming) | ||
588 | { | ||
589 | struct uvc_device *uvc; | ||
590 | int ret = 0; | ||
591 | |||
592 | /* TODO Check if the USB device controller supports the required | ||
593 | * features. | ||
594 | */ | ||
595 | if (!gadget_is_dualspeed(c->cdev->gadget)) | ||
596 | return -EINVAL; | ||
597 | |||
598 | uvc = kzalloc(sizeof(*uvc), GFP_KERNEL); | ||
599 | if (uvc == NULL) | ||
600 | return -ENOMEM; | ||
601 | |||
602 | uvc->state = UVC_STATE_DISCONNECTED; | ||
603 | |||
604 | /* Validate the descriptors. */ | ||
605 | if (control == NULL || control[0] == NULL || | ||
606 | control[0]->bDescriptorSubType != UVC_DT_HEADER) | ||
607 | goto error; | ||
608 | |||
609 | if (fs_streaming == NULL || fs_streaming[0] == NULL || | ||
610 | fs_streaming[0]->bDescriptorSubType != UVC_DT_INPUT_HEADER) | ||
611 | goto error; | ||
612 | |||
613 | if (hs_streaming == NULL || hs_streaming[0] == NULL || | ||
614 | hs_streaming[0]->bDescriptorSubType != UVC_DT_INPUT_HEADER) | ||
615 | goto error; | ||
616 | |||
617 | uvc->desc.control = control; | ||
618 | uvc->desc.fs_streaming = fs_streaming; | ||
619 | uvc->desc.hs_streaming = hs_streaming; | ||
620 | |||
621 | /* Allocate string descriptor numbers. */ | ||
622 | if ((ret = usb_string_id(c->cdev)) < 0) | ||
623 | goto error; | ||
624 | uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id = ret; | ||
625 | uvc_iad.iFunction = ret; | ||
626 | |||
627 | if ((ret = usb_string_id(c->cdev)) < 0) | ||
628 | goto error; | ||
629 | uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id = ret; | ||
630 | uvc_control_intf.iInterface = ret; | ||
631 | |||
632 | if ((ret = usb_string_id(c->cdev)) < 0) | ||
633 | goto error; | ||
634 | uvc_en_us_strings[UVC_STRING_STREAMING_IDX].id = ret; | ||
635 | uvc_streaming_intf_alt0.iInterface = ret; | ||
636 | uvc_streaming_intf_alt1.iInterface = ret; | ||
637 | |||
638 | /* Register the function. */ | ||
639 | uvc->func.name = "uvc"; | ||
640 | uvc->func.strings = uvc_function_strings; | ||
641 | uvc->func.bind = uvc_function_bind; | ||
642 | uvc->func.unbind = uvc_function_unbind; | ||
643 | uvc->func.get_alt = uvc_function_get_alt; | ||
644 | uvc->func.set_alt = uvc_function_set_alt; | ||
645 | uvc->func.disable = uvc_function_disable; | ||
646 | uvc->func.setup = uvc_function_setup; | ||
647 | |||
648 | ret = usb_add_function(c, &uvc->func); | ||
649 | if (ret) | ||
650 | kfree(uvc); | ||
651 | |||
652 | return 0; | ||
653 | |||
654 | error: | ||
655 | kfree(uvc); | ||
656 | return ret; | ||
657 | } | ||
658 | |||
659 | module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR); | ||
660 | MODULE_PARM_DESC(trace, "Trace level bitmask"); | ||
661 | |||