hc
2023-12-11 6778948f9de86c3cfaf36725a7c87dcff9ba247f
kernel/drivers/usb/gadget/function/uvc_v4l2.c
....@@ -75,10 +75,6 @@
7575 strlcpy(cap->card, cdev->gadget->name, sizeof(cap->card));
7676 strlcpy(cap->bus_info, dev_name(&cdev->gadget->dev),
7777 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
-
8278 return 0;
8379 }
8480
....@@ -119,8 +115,8 @@
119115 }
120116
121117 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);
124120 return -EINVAL;
125121 }
126122
....@@ -177,7 +173,8 @@
177173 if (ret < 0)
178174 return ret;
179175
180
- queue_work(video->async_wq, &video->pump);
176
+ if (uvc->state == UVC_STATE_STREAMING)
177
+ schedule_work(&video->pump);
181178
182179 return ret;
183180 }
....@@ -217,16 +214,15 @@
217214 * settings for zero-bandwidth and full-bandwidth
218215 * cases, but the same is not true for BULK endpoints,
219216 * 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.
220221 */
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))
227223 uvc_function_setup_continue(uvc);
228
- uvc->state = UVC_STATE_STREAMING;
229
- }
224
+
225
+ uvc->state = UVC_STATE_STREAMING;
230226
231227 return 0;
232228 }
....@@ -248,17 +244,56 @@
248244 uvc_v4l2_subscribe_event(struct v4l2_fh *fh,
249245 const struct v4l2_event_subscription *sub)
250246 {
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
+
251251 if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST)
252252 return -EINVAL;
253253
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);
255277 }
256278
257279 static int
258280 uvc_v4l2_unsubscribe_event(struct v4l2_fh *fh,
259281 const struct v4l2_event_subscription *sub)
260282 {
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;
262297 }
263298
264299 static long
....@@ -313,7 +348,6 @@
313348 handle->device = &uvc->video;
314349 file->private_data = &handle->vfh;
315350
316
- uvc_function_connect(uvc);
317351 return 0;
318352 }
319353
....@@ -325,11 +359,9 @@
325359 struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data);
326360 struct uvc_video *video = handle->device;
327361
328
- uvc_function_disconnect(uvc);
329
-
330362 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);
333365 mutex_unlock(&video->mutex);
334366
335367 file->private_data = NULL;