.. | .. |
---|
44 | 44 | #define UVC_STRING_STREAMING_IDX 1 |
---|
45 | 45 | |
---|
46 | 46 | static struct usb_string uvc_en_us_strings[] = { |
---|
47 | | - [UVC_STRING_CONTROL_IDX].s = "UVC Camera", |
---|
| 47 | + /* [UVC_STRING_CONTROL_IDX].s = DYNAMIC, */ |
---|
48 | 48 | [UVC_STRING_STREAMING_IDX].s = "Video Streaming", |
---|
49 | 49 | { } |
---|
50 | 50 | }; |
---|
.. | .. |
---|
263 | 263 | (struct usb_descriptor_header *)&uvc_ss_bulk_streaming_comp, |
---|
264 | 264 | NULL, |
---|
265 | 265 | }; |
---|
266 | | -void uvc_set_trace_param(unsigned int trace) |
---|
267 | | -{ |
---|
268 | | - uvc_gadget_trace_param = trace; |
---|
269 | | -} |
---|
270 | | -EXPORT_SYMBOL(uvc_set_trace_param); |
---|
271 | 266 | |
---|
272 | 267 | /* -------------------------------------------------------------------------- |
---|
273 | 268 | * Control requests |
---|
.. | .. |
---|
289 | 284 | |
---|
290 | 285 | memset(&v4l2_event, 0, sizeof(v4l2_event)); |
---|
291 | 286 | v4l2_event.type = UVC_EVENT_DATA; |
---|
292 | | - uvc_event->data.length = req->actual; |
---|
293 | | - memcpy(&uvc_event->data.data, req->buf, req->actual); |
---|
| 287 | + uvc_event->data.length = min_t(unsigned int, req->actual, |
---|
| 288 | + sizeof(uvc_event->data.data)); |
---|
| 289 | + memcpy(&uvc_event->data.data, req->buf, uvc_event->data.length); |
---|
294 | 290 | v4l2_event_queue(&uvc->vdev, &v4l2_event); |
---|
295 | 291 | } |
---|
296 | 292 | } |
---|
.. | .. |
---|
302 | 298 | struct v4l2_event v4l2_event; |
---|
303 | 299 | struct uvc_event *uvc_event = (void *)&v4l2_event.u.data; |
---|
304 | 300 | |
---|
305 | | - /* printk(KERN_INFO "setup request %02x %02x value %04x index %04x %04x\n", |
---|
306 | | - * ctrl->bRequestType, ctrl->bRequest, le16_to_cpu(ctrl->wValue), |
---|
307 | | - * le16_to_cpu(ctrl->wIndex), le16_to_cpu(ctrl->wLength)); |
---|
308 | | - */ |
---|
309 | | - |
---|
310 | 301 | uvc_trace(UVC_TRACE_CONTROL, |
---|
311 | 302 | "setup request %02x %02x value %04x index %04x %04x\n", |
---|
312 | 303 | ctrl->bRequestType, ctrl->bRequest, le16_to_cpu(ctrl->wValue), |
---|
313 | 304 | le16_to_cpu(ctrl->wIndex), le16_to_cpu(ctrl->wLength)); |
---|
314 | 305 | |
---|
315 | 306 | if ((ctrl->bRequestType & USB_TYPE_MASK) != USB_TYPE_CLASS) { |
---|
316 | | - INFO(f->config->cdev, "invalid request type\n"); |
---|
| 307 | + uvcg_info(f, "invalid request type\n"); |
---|
317 | 308 | return -EINVAL; |
---|
318 | 309 | } |
---|
319 | 310 | |
---|
.. | .. |
---|
348 | 339 | struct uvc_device *uvc = to_uvc(f); |
---|
349 | 340 | struct f_uvc_opts *opts; |
---|
350 | 341 | |
---|
351 | | - INFO(f->config->cdev, "uvc_function_get_alt(%u)\n", interface); |
---|
| 342 | + uvcg_info(f, "%s(%u)\n", __func__, interface); |
---|
352 | 343 | |
---|
353 | 344 | opts = fi_to_f_uvc_opts(f->fi); |
---|
354 | 345 | |
---|
.. | .. |
---|
379 | 370 | struct f_uvc_opts *opts; |
---|
380 | 371 | int ret; |
---|
381 | 372 | |
---|
382 | | - INFO(cdev, "uvc_function_set_alt(%u, %u)\n", interface, alt); |
---|
| 373 | + uvcg_info(f, "%s(%u, %u)\n", __func__, interface, alt); |
---|
383 | 374 | |
---|
384 | 375 | opts = fi_to_f_uvc_opts(f->fi); |
---|
385 | 376 | |
---|
.. | .. |
---|
387 | 378 | if (alt) |
---|
388 | 379 | return -EINVAL; |
---|
389 | 380 | |
---|
390 | | - INFO(cdev, "reset UVC Control\n"); |
---|
| 381 | + uvcg_info(f, "reset UVC Control\n"); |
---|
391 | 382 | usb_ep_disable(uvc->control_ep); |
---|
392 | 383 | |
---|
393 | 384 | if (!uvc->control_ep->desc) |
---|
.. | .. |
---|
516 | 507 | struct uvc_device *uvc = to_uvc(f); |
---|
517 | 508 | struct v4l2_event v4l2_event; |
---|
518 | 509 | |
---|
519 | | - INFO(f->config->cdev, "uvc_function_disable\n"); |
---|
| 510 | + uvcg_info(f, "%s()\n", __func__); |
---|
520 | 511 | |
---|
521 | 512 | memset(&v4l2_event, 0, sizeof(v4l2_event)); |
---|
522 | 513 | v4l2_event.type = UVC_EVENT_DISCONNECT; |
---|
523 | 514 | v4l2_event_queue(&uvc->vdev, &v4l2_event); |
---|
524 | 515 | |
---|
525 | 516 | uvc->state = UVC_STATE_DISCONNECTED; |
---|
526 | | - f->config->cdev->gadget->uvc_enabled = false; |
---|
527 | 517 | |
---|
528 | 518 | usb_ep_disable(uvc->video.ep); |
---|
529 | 519 | usb_ep_disable(uvc->control_ep); |
---|
.. | .. |
---|
560 | 550 | void |
---|
561 | 551 | uvc_function_connect(struct uvc_device *uvc) |
---|
562 | 552 | { |
---|
563 | | - struct usb_composite_dev *cdev = uvc->func.config->cdev; |
---|
564 | 553 | int ret; |
---|
565 | 554 | |
---|
566 | | - cdev->gadget->uvc_enabled = true; |
---|
567 | | - |
---|
568 | 555 | if ((ret = usb_function_activate(&uvc->func)) < 0) |
---|
569 | | - INFO(cdev, "UVC connect failed with %d\n", ret); |
---|
| 556 | + uvcg_info(&uvc->func, "UVC connect failed with %d\n", ret); |
---|
570 | 557 | } |
---|
571 | 558 | |
---|
572 | 559 | void |
---|
573 | 560 | uvc_function_disconnect(struct uvc_device *uvc) |
---|
574 | 561 | { |
---|
575 | | - struct usb_composite_dev *cdev = uvc->func.config->cdev; |
---|
576 | 562 | int ret; |
---|
577 | 563 | |
---|
578 | 564 | if ((ret = usb_function_deactivate(&uvc->func)) < 0) |
---|
579 | | - INFO(cdev, "UVC disconnect failed with %d\n", ret); |
---|
| 565 | + uvcg_info(&uvc->func, "UVC disconnect failed with %d\n", ret); |
---|
580 | 566 | } |
---|
581 | 567 | |
---|
582 | 568 | /* -------------------------------------------------------------------------- |
---|
.. | .. |
---|
606 | 592 | uvc->vdev.release = video_device_release_empty; |
---|
607 | 593 | uvc->vdev.vfl_dir = VFL_DIR_TX; |
---|
608 | 594 | uvc->vdev.lock = &uvc->video.mutex; |
---|
| 595 | + uvc->vdev.device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; |
---|
609 | 596 | strlcpy(uvc->vdev.name, cdev->gadget->name, sizeof(uvc->vdev.name)); |
---|
610 | 597 | |
---|
611 | 598 | video_set_drvdata(&uvc->vdev, uvc); |
---|
612 | 599 | |
---|
613 | | - ret = video_register_device(&uvc->vdev, VFL_TYPE_GRABBER, -1); |
---|
| 600 | + ret = video_register_device(&uvc->vdev, VFL_TYPE_VIDEO, -1); |
---|
614 | 601 | if (ret < 0) |
---|
615 | 602 | return ret; |
---|
616 | 603 | |
---|
.. | .. |
---|
794 | 781 | int ret = -EINVAL; |
---|
795 | 782 | u8 address; |
---|
796 | 783 | |
---|
797 | | - INFO(cdev, "uvc_function_bind\n"); |
---|
| 784 | + uvcg_info(f, "%s()\n", __func__); |
---|
798 | 785 | |
---|
799 | 786 | opts = fi_to_f_uvc_opts(f->fi); |
---|
800 | 787 | /* Sanity check the streaming endpoint module parameters. |
---|
.. | .. |
---|
815 | 802 | if (opts->streaming_maxburst && |
---|
816 | 803 | (opts->streaming_maxpacket % 1024) != 0) { |
---|
817 | 804 | opts->streaming_maxpacket = roundup(opts->streaming_maxpacket, 1024); |
---|
818 | | - INFO(cdev, "overriding streaming_maxpacket to %d\n", |
---|
819 | | - opts->streaming_maxpacket); |
---|
| 805 | + uvcg_info(f, "overriding streaming_maxpacket to %d\n", |
---|
| 806 | + opts->streaming_maxpacket); |
---|
820 | 807 | } |
---|
821 | 808 | |
---|
822 | 809 | /* Fill in the FS/HS/SS Video Streaming specific descriptors from the |
---|
.. | .. |
---|
880 | 867 | /* Allocate endpoints. */ |
---|
881 | 868 | ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep); |
---|
882 | 869 | if (!ep) { |
---|
883 | | - INFO(cdev, "Unable to allocate control EP\n"); |
---|
| 870 | + uvcg_info(f, "Unable to allocate control EP\n"); |
---|
884 | 871 | goto error; |
---|
885 | 872 | } |
---|
886 | 873 | uvc->control_ep = ep; |
---|
.. | .. |
---|
921 | 908 | } |
---|
922 | 909 | |
---|
923 | 910 | if (!ep) { |
---|
924 | | - INFO(cdev, "Unable to allocate streaming EP\n"); |
---|
| 911 | + uvcg_info(f, "Unable to allocate streaming EP\n"); |
---|
925 | 912 | goto error; |
---|
926 | 913 | } |
---|
927 | 914 | uvc->video.ep = ep; |
---|
.. | .. |
---|
937 | 924 | uvc_ss_bulk_streaming_ep.bEndpointAddress = address; |
---|
938 | 925 | } |
---|
939 | 926 | |
---|
| 927 | +#if defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_NO_GKI) |
---|
940 | 928 | if (opts->device_name) |
---|
941 | 929 | uvc_en_us_strings[UVC_STRING_CONTROL_IDX].s = opts->device_name; |
---|
| 930 | +#endif |
---|
942 | 931 | |
---|
| 932 | + uvc_en_us_strings[UVC_STRING_CONTROL_IDX].s = opts->function_name; |
---|
943 | 933 | us = usb_gstrings_attach(cdev, uvc_function_strings, |
---|
944 | 934 | ARRAY_SIZE(uvc_en_us_strings)); |
---|
945 | 935 | if (IS_ERR(us)) { |
---|
.. | .. |
---|
1014 | 1004 | uvc->control_req->context = uvc; |
---|
1015 | 1005 | |
---|
1016 | 1006 | if (v4l2_device_register(&cdev->gadget->dev, &uvc->v4l2_dev)) { |
---|
1017 | | - printk(KERN_INFO "v4l2_device_register failed\n"); |
---|
| 1007 | + uvcg_err(f, "failed to register V4L2 device\n"); |
---|
1018 | 1008 | goto error; |
---|
1019 | 1009 | } |
---|
1020 | 1010 | |
---|
1021 | | - uvc->video.async_wq = alloc_workqueue("uvcgvideo", |
---|
1022 | | - WQ_UNBOUND | WQ_HIGHPRI, |
---|
1023 | | - 0); |
---|
1024 | | - if (!uvc->video.async_wq) |
---|
1025 | | - goto error; |
---|
1026 | | - |
---|
1027 | 1011 | /* Initialise video. */ |
---|
1028 | | - ret = uvcg_video_init(&uvc->video); |
---|
| 1012 | + ret = uvcg_video_init(&uvc->video, uvc); |
---|
1029 | 1013 | if (ret < 0) |
---|
1030 | | - goto error; |
---|
| 1014 | + goto v4l2_error; |
---|
1031 | 1015 | |
---|
1032 | 1016 | if (opts->streaming_bulk) |
---|
1033 | 1017 | uvc->video.max_payload_size = uvc->video.imagesize; |
---|
1034 | 1018 | /* Register a V4L2 device. */ |
---|
1035 | 1019 | ret = uvc_register_video(uvc); |
---|
1036 | 1020 | if (ret < 0) { |
---|
1037 | | - printk(KERN_INFO "Unable to register video device\n"); |
---|
1038 | | - goto error; |
---|
| 1021 | + uvcg_err(f, "failed to register video device\n"); |
---|
| 1022 | + goto v4l2_error; |
---|
1039 | 1023 | } |
---|
1040 | 1024 | |
---|
1041 | 1025 | return 0; |
---|
1042 | 1026 | |
---|
1043 | | -error: |
---|
| 1027 | +v4l2_error: |
---|
1044 | 1028 | v4l2_device_unregister(&uvc->v4l2_dev); |
---|
1045 | | - |
---|
| 1029 | +error: |
---|
1046 | 1030 | if (uvc->control_req) |
---|
1047 | 1031 | usb_ep_free_request(cdev->gadget->ep0, uvc->control_req); |
---|
1048 | 1032 | kfree(uvc->control_buf); |
---|
.. | .. |
---|
1061 | 1045 | |
---|
1062 | 1046 | mutex_destroy(&opts->lock); |
---|
1063 | 1047 | |
---|
| 1048 | +#if defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_NO_GKI) |
---|
1064 | 1049 | if (opts->device_name_allocated) { |
---|
1065 | 1050 | opts->device_name_allocated = false; |
---|
1066 | 1051 | kfree(opts->device_name); |
---|
1067 | 1052 | opts->device_name = NULL; |
---|
1068 | 1053 | } |
---|
| 1054 | +#endif |
---|
1069 | 1055 | |
---|
1070 | 1056 | kfree(opts); |
---|
1071 | 1057 | } |
---|
.. | .. |
---|
1114 | 1100 | pd->bmControls[0] = 1; |
---|
1115 | 1101 | pd->bmControls[1] = 0; |
---|
1116 | 1102 | pd->iProcessing = 0; |
---|
| 1103 | + pd->bmVideoStandards = 0; |
---|
1117 | 1104 | |
---|
1118 | 1105 | od = &opts->uvc_output_terminal; |
---|
1119 | 1106 | od->bLength = UVC_DT_OUTPUT_TERMINAL_SIZE; |
---|
.. | .. |
---|
1185 | 1172 | |
---|
1186 | 1173 | opts->streaming_interval = 1; |
---|
1187 | 1174 | opts->streaming_maxpacket = 1024; |
---|
1188 | | - opts->uvc_num_request = UVC_NUM_REQUESTS; |
---|
1189 | 1175 | opts->pm_qos_latency = 0; |
---|
| 1176 | + snprintf(opts->function_name, sizeof(opts->function_name), "UVC Camera"); |
---|
1190 | 1177 | |
---|
1191 | 1178 | ret = uvcg_attach_configfs(opts); |
---|
1192 | 1179 | if (ret < 0) { |
---|
.. | .. |
---|
1206 | 1193 | kfree(uvc); |
---|
1207 | 1194 | } |
---|
1208 | 1195 | |
---|
1209 | | -static void uvc_unbind(struct usb_configuration *c, struct usb_function *f) |
---|
| 1196 | +static void uvc_function_unbind(struct usb_configuration *c, |
---|
| 1197 | + struct usb_function *f) |
---|
1210 | 1198 | { |
---|
1211 | 1199 | struct usb_composite_dev *cdev = c->cdev; |
---|
1212 | 1200 | struct uvc_device *uvc = to_uvc(f); |
---|
| 1201 | + long wait_ret = 1; |
---|
1213 | 1202 | |
---|
1214 | | - INFO(cdev, "%s\n", __func__); |
---|
| 1203 | + uvcg_info(f, "%s()\n", __func__); |
---|
| 1204 | + |
---|
| 1205 | + /* If we know we're connected via v4l2, then there should be a cleanup |
---|
| 1206 | + * of the device from userspace either via UVC_EVENT_DISCONNECT or |
---|
| 1207 | + * though the video device removal uevent. Allow some time for the |
---|
| 1208 | + * application to close out before things get deleted. |
---|
| 1209 | + */ |
---|
| 1210 | + if (uvc->func_connected) { |
---|
| 1211 | + uvcg_dbg(f, "waiting for clean disconnect\n"); |
---|
| 1212 | + wait_ret = wait_event_interruptible_timeout(uvc->func_connected_queue, |
---|
| 1213 | + uvc->func_connected == false, msecs_to_jiffies(500)); |
---|
| 1214 | + uvcg_dbg(f, "done waiting with ret: %ld\n", wait_ret); |
---|
| 1215 | + } |
---|
1215 | 1216 | |
---|
1216 | 1217 | device_remove_file(&uvc->vdev.dev, &dev_attr_function_name); |
---|
1217 | 1218 | video_unregister_device(&uvc->vdev); |
---|
1218 | 1219 | v4l2_device_unregister(&uvc->v4l2_dev); |
---|
1219 | 1220 | |
---|
| 1221 | + if (uvc->func_connected) { |
---|
| 1222 | + /* Wait for the release to occur to ensure there are no longer any |
---|
| 1223 | + * pending operations that may cause panics when resources are cleaned |
---|
| 1224 | + * up. |
---|
| 1225 | + */ |
---|
| 1226 | + uvcg_warn(f, "%s no clean disconnect, wait for release\n", __func__); |
---|
| 1227 | + wait_ret = wait_event_interruptible_timeout(uvc->func_connected_queue, |
---|
| 1228 | + uvc->func_connected == false, msecs_to_jiffies(1000)); |
---|
| 1229 | + uvcg_dbg(f, "done waiting for release with ret: %ld\n", wait_ret); |
---|
| 1230 | + } |
---|
| 1231 | + |
---|
1220 | 1232 | usb_ep_free_request(cdev->gadget->ep0, uvc->control_req); |
---|
1221 | 1233 | kfree(uvc->control_buf); |
---|
1222 | | - |
---|
1223 | | - if (uvc->video.async_wq) |
---|
1224 | | - destroy_workqueue(uvc->video.async_wq); |
---|
1225 | 1234 | |
---|
1226 | 1235 | usb_free_all_descriptors(f); |
---|
1227 | 1236 | } |
---|
.. | .. |
---|
1238 | 1247 | |
---|
1239 | 1248 | mutex_init(&uvc->video.mutex); |
---|
1240 | 1249 | uvc->state = UVC_STATE_DISCONNECTED; |
---|
| 1250 | + init_waitqueue_head(&uvc->func_connected_queue); |
---|
1241 | 1251 | opts = fi_to_f_uvc_opts(fi); |
---|
1242 | 1252 | |
---|
1243 | 1253 | mutex_lock(&opts->lock); |
---|
.. | .. |
---|
1268 | 1278 | /* Register the function. */ |
---|
1269 | 1279 | uvc->func.name = "uvc"; |
---|
1270 | 1280 | uvc->func.bind = uvc_function_bind; |
---|
1271 | | - uvc->func.unbind = uvc_unbind; |
---|
| 1281 | + uvc->func.unbind = uvc_function_unbind; |
---|
1272 | 1282 | uvc->func.get_alt = uvc_function_get_alt; |
---|
1273 | 1283 | uvc->func.set_alt = uvc_function_set_alt; |
---|
1274 | 1284 | uvc->func.disable = uvc_function_disable; |
---|