| .. | .. |
|---|
| 75 | 75 | strlcpy(cap->card, cdev->gadget->name, sizeof(cap->card)); |
|---|
| 76 | 76 | strlcpy(cap->bus_info, dev_name(&cdev->gadget->dev), |
|---|
| 77 | 77 | sizeof(cap->bus_info)); |
|---|
| 78 | | - |
|---|
| 79 | | - cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; |
|---|
| 80 | | - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; |
|---|
| 81 | | - |
|---|
| 82 | 78 | return 0; |
|---|
| 83 | 79 | } |
|---|
| 84 | 80 | |
|---|
| .. | .. |
|---|
| 119 | 115 | } |
|---|
| 120 | 116 | |
|---|
| 121 | 117 | if (i == ARRAY_SIZE(uvc_formats)) { |
|---|
| 122 | | - printk(KERN_INFO "Unsupported format 0x%08x.\n", |
|---|
| 123 | | - fmt->fmt.pix.pixelformat); |
|---|
| 118 | + uvcg_info(&uvc->func, "Unsupported format 0x%08x.\n", |
|---|
| 119 | + fmt->fmt.pix.pixelformat); |
|---|
| 124 | 120 | return -EINVAL; |
|---|
| 125 | 121 | } |
|---|
| 126 | 122 | |
|---|
| .. | .. |
|---|
| 177 | 173 | if (ret < 0) |
|---|
| 178 | 174 | return ret; |
|---|
| 179 | 175 | |
|---|
| 180 | | - queue_work(video->async_wq, &video->pump); |
|---|
| 176 | + if (uvc->state == UVC_STATE_STREAMING) |
|---|
| 177 | + schedule_work(&video->pump); |
|---|
| 181 | 178 | |
|---|
| 182 | 179 | return ret; |
|---|
| 183 | 180 | } |
|---|
| .. | .. |
|---|
| 217 | 214 | * settings for zero-bandwidth and full-bandwidth |
|---|
| 218 | 215 | * cases, but the same is not true for BULK endpoints, |
|---|
| 219 | 216 | * as they have a single alt-setting. |
|---|
| 217 | + * |
|---|
| 218 | + * For ISOC endpoints, Complete the alternate setting |
|---|
| 219 | + * selection setup phase now that userspace is ready |
|---|
| 220 | + * to provide video frames. |
|---|
| 220 | 221 | */ |
|---|
| 221 | | - if (!usb_endpoint_xfer_bulk(video->ep->desc)) { |
|---|
| 222 | | - /* |
|---|
| 223 | | - * Complete the alternate setting selection |
|---|
| 224 | | - * setup phase now that userspace is ready |
|---|
| 225 | | - * to provide video frames. |
|---|
| 226 | | - */ |
|---|
| 222 | + if (!usb_endpoint_xfer_bulk(video->ep->desc)) |
|---|
| 227 | 223 | uvc_function_setup_continue(uvc); |
|---|
| 228 | | - uvc->state = UVC_STATE_STREAMING; |
|---|
| 229 | | - } |
|---|
| 224 | + |
|---|
| 225 | + uvc->state = UVC_STATE_STREAMING; |
|---|
| 230 | 226 | |
|---|
| 231 | 227 | return 0; |
|---|
| 232 | 228 | } |
|---|
| .. | .. |
|---|
| 248 | 244 | uvc_v4l2_subscribe_event(struct v4l2_fh *fh, |
|---|
| 249 | 245 | const struct v4l2_event_subscription *sub) |
|---|
| 250 | 246 | { |
|---|
| 247 | + struct uvc_device *uvc = video_get_drvdata(fh->vdev); |
|---|
| 248 | + struct uvc_file_handle *handle = to_uvc_file_handle(fh); |
|---|
| 249 | + int ret; |
|---|
| 250 | + |
|---|
| 251 | 251 | if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST) |
|---|
| 252 | 252 | return -EINVAL; |
|---|
| 253 | 253 | |
|---|
| 254 | | - return v4l2_event_subscribe(fh, sub, 2, NULL); |
|---|
| 254 | + if (sub->type == UVC_EVENT_SETUP && uvc->func_connected) |
|---|
| 255 | + return -EBUSY; |
|---|
| 256 | + |
|---|
| 257 | + ret = v4l2_event_subscribe(fh, sub, 2, NULL); |
|---|
| 258 | + if (ret < 0) |
|---|
| 259 | + return ret; |
|---|
| 260 | + |
|---|
| 261 | + if (sub->type == UVC_EVENT_SETUP) { |
|---|
| 262 | + uvc->func_connected = true; |
|---|
| 263 | + handle->is_uvc_app_handle = true; |
|---|
| 264 | + uvc_function_connect(uvc); |
|---|
| 265 | + } |
|---|
| 266 | + |
|---|
| 267 | + return 0; |
|---|
| 268 | +} |
|---|
| 269 | + |
|---|
| 270 | +static void uvc_v4l2_disable(struct uvc_device *uvc) |
|---|
| 271 | +{ |
|---|
| 272 | + uvc_function_disconnect(uvc); |
|---|
| 273 | + uvcg_video_enable(&uvc->video, 0); |
|---|
| 274 | + uvcg_free_buffers(&uvc->video.queue); |
|---|
| 275 | + uvc->func_connected = false; |
|---|
| 276 | + wake_up_interruptible(&uvc->func_connected_queue); |
|---|
| 255 | 277 | } |
|---|
| 256 | 278 | |
|---|
| 257 | 279 | static int |
|---|
| 258 | 280 | uvc_v4l2_unsubscribe_event(struct v4l2_fh *fh, |
|---|
| 259 | 281 | const struct v4l2_event_subscription *sub) |
|---|
| 260 | 282 | { |
|---|
| 261 | | - return v4l2_event_unsubscribe(fh, sub); |
|---|
| 283 | + struct uvc_device *uvc = video_get_drvdata(fh->vdev); |
|---|
| 284 | + struct uvc_file_handle *handle = to_uvc_file_handle(fh); |
|---|
| 285 | + int ret; |
|---|
| 286 | + |
|---|
| 287 | + ret = v4l2_event_unsubscribe(fh, sub); |
|---|
| 288 | + if (ret < 0) |
|---|
| 289 | + return ret; |
|---|
| 290 | + |
|---|
| 291 | + if (sub->type == UVC_EVENT_SETUP && handle->is_uvc_app_handle) { |
|---|
| 292 | + uvc_v4l2_disable(uvc); |
|---|
| 293 | + handle->is_uvc_app_handle = false; |
|---|
| 294 | + } |
|---|
| 295 | + |
|---|
| 296 | + return 0; |
|---|
| 262 | 297 | } |
|---|
| 263 | 298 | |
|---|
| 264 | 299 | static long |
|---|
| .. | .. |
|---|
| 313 | 348 | handle->device = &uvc->video; |
|---|
| 314 | 349 | file->private_data = &handle->vfh; |
|---|
| 315 | 350 | |
|---|
| 316 | | - uvc_function_connect(uvc); |
|---|
| 317 | 351 | return 0; |
|---|
| 318 | 352 | } |
|---|
| 319 | 353 | |
|---|
| .. | .. |
|---|
| 325 | 359 | struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data); |
|---|
| 326 | 360 | struct uvc_video *video = handle->device; |
|---|
| 327 | 361 | |
|---|
| 328 | | - uvc_function_disconnect(uvc); |
|---|
| 329 | | - |
|---|
| 330 | 362 | mutex_lock(&video->mutex); |
|---|
| 331 | | - uvcg_video_enable(video, 0); |
|---|
| 332 | | - uvcg_free_buffers(&video->queue); |
|---|
| 363 | + if (handle->is_uvc_app_handle) |
|---|
| 364 | + uvc_v4l2_disable(uvc); |
|---|
| 333 | 365 | mutex_unlock(&video->mutex); |
|---|
| 334 | 366 | |
|---|
| 335 | 367 | file->private_data = NULL; |
|---|