| .. | .. |
|---|
| 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; |
|---|