hc
2024-01-03 2f7c68cb55ecb7331f2381deb497c27155f32faf
kernel/drivers/media/usb/uvc/uvc_status.c
....@@ -6,6 +6,7 @@
66 * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
77 */
88
9
+#include <asm/barrier.h>
910 #include <linux/kernel.h>
1011 #include <linux/input.h>
1112 #include <linux/slab.h>
....@@ -179,7 +180,8 @@
179180
180181 switch (status->bAttribute) {
181182 case UVC_CTRL_VALUE_CHANGE:
182
- return uvc_ctrl_status_event(urb, chain, ctrl, status->bValue);
183
+ return uvc_ctrl_status_event_async(urb, chain, ctrl,
184
+ status->bValue);
183185
184186 case UVC_CTRL_INFO_CHANGE:
185187 case UVC_CTRL_FAILURE_CHANGE:
....@@ -309,5 +311,41 @@
309311
310312 void uvc_status_stop(struct uvc_device *dev)
311313 {
314
+ struct uvc_ctrl_work *w = &dev->async_ctrl;
315
+
316
+ /*
317
+ * Prevent the asynchronous control handler from requeing the URB. The
318
+ * barrier is needed so the flush_status change is visible to other
319
+ * CPUs running the asynchronous handler before usb_kill_urb() is
320
+ * called below.
321
+ */
322
+ smp_store_release(&dev->flush_status, true);
323
+
324
+ /*
325
+ * Cancel any pending asynchronous work. If any status event was queued,
326
+ * process it synchronously.
327
+ */
328
+ if (cancel_work_sync(&w->work))
329
+ uvc_ctrl_status_event(w->chain, w->ctrl, w->data);
330
+
331
+ /* Kill the urb. */
312332 usb_kill_urb(dev->int_urb);
333
+
334
+ /*
335
+ * The URB completion handler may have queued asynchronous work. This
336
+ * won't resubmit the URB as flush_status is set, but it needs to be
337
+ * cancelled before returning or it could then race with a future
338
+ * uvc_status_start() call.
339
+ */
340
+ if (cancel_work_sync(&w->work))
341
+ uvc_ctrl_status_event(w->chain, w->ctrl, w->data);
342
+
343
+ /*
344
+ * From this point, there are no events on the queue and the status URB
345
+ * is dead. No events will be queued until uvc_status_start() is called.
346
+ * The barrier is needed to make sure that flush_status is visible to
347
+ * uvc_ctrl_status_event_work() when uvc_status_start() will be called
348
+ * again.
349
+ */
350
+ smp_store_release(&dev->flush_status, false);
313351 }