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