--- /dev/null
+From b81ac4395bbeaf36e078dea1a48c02dd97b76235 Mon Sep 17 00:00:00 2001
+From: Dan Vacura <w36195@motorola.com>
+Date: Tue, 3 May 2022 15:10:38 -0500
+Subject: usb: gadget: uvc: allow for application to cleanly shutdown
+
+From: Dan Vacura <w36195@motorola.com>
+
+commit b81ac4395bbeaf36e078dea1a48c02dd97b76235 upstream.
+
+Several types of kernel panics can occur due to timing during the uvc
+gadget removal. This appears to be a problem with gadget resources being
+managed by both the client application's v4l2 open/close and the UDC
+gadget bind/unbind. Since the concept of USB_GADGET_DELAYED_STATUS
+doesn't exist for unbind, add a wait to allow for the application to
+close out.
+
+Some examples of the panics that can occur are:
+
+<1>[ 1147.652313] Unable to handle kernel NULL pointer dereference at
+virtual address 0000000000000028
+<4>[ 1147.652510] Call trace:
+<4>[ 1147.652514] usb_gadget_disconnect+0x74/0x1f0
+<4>[ 1147.652516] usb_gadget_deactivate+0x38/0x168
+<4>[ 1147.652520] usb_function_deactivate+0x54/0x90
+<4>[ 1147.652524] uvc_function_disconnect+0x14/0x38
+<4>[ 1147.652527] uvc_v4l2_release+0x34/0xa0
+<4>[ 1147.652537] __fput+0xdc/0x2c0
+<4>[ 1147.652540] ____fput+0x10/0x1c
+<4>[ 1147.652545] task_work_run+0xe4/0x12c
+<4>[ 1147.652549] do_notify_resume+0x108/0x168
+
+<1>[ 282.950561][ T1472] Unable to handle kernel NULL pointer
+dereference at virtual address 00000000000005b8
+<6>[ 282.953111][ T1472] Call trace:
+<6>[ 282.953121][ T1472] usb_function_deactivate+0x54/0xd4
+<6>[ 282.953134][ T1472] uvc_v4l2_release+0xac/0x1e4
+<6>[ 282.953145][ T1472] v4l2_release+0x134/0x1f0
+<6>[ 282.953167][ T1472] __fput+0xf4/0x428
+<6>[ 282.953178][ T1472] ____fput+0x14/0x24
+<6>[ 282.953193][ T1472] task_work_run+0xac/0x130
+
+<3>[ 213.410077][ T29] configfs-gadget gadget: uvc: Failed to queue
+request (-108).
+<1>[ 213.410116][ T29] Unable to handle kernel NULL pointer
+dereference at virtual address 0000000000000003
+<6>[ 213.413460][ T29] Call trace:
+<6>[ 213.413474][ T29] uvcg_video_pump+0x1f0/0x384
+<6>[ 213.413489][ T29] process_one_work+0x2a4/0x544
+<6>[ 213.413502][ T29] worker_thread+0x350/0x784
+<6>[ 213.413515][ T29] kthread+0x2ac/0x320
+<6>[ 213.413528][ T29] ret_from_fork+0x10/0x30
+
+Signed-off-by: Dan Vacura <w36195@motorola.com>
+Cc: stable <stable@vger.kernel.org>
+Link: https://lore.kernel.org/r/20220503201039.71720-1-w36195@motorola.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/gadget/function/f_uvc.c | 25 +++++++++++++++++++++++++
+ drivers/usb/gadget/function/uvc.h | 2 ++
+ drivers/usb/gadget/function/uvc_v4l2.c | 3 ++-
+ 3 files changed, 29 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/gadget/function/f_uvc.c
++++ b/drivers/usb/gadget/function/f_uvc.c
+@@ -888,13 +888,37 @@ static void uvc_function_unbind(struct u
+ {
+ struct usb_composite_dev *cdev = c->cdev;
+ struct uvc_device *uvc = to_uvc(f);
++ long wait_ret = 1;
+
+ uvcg_info(f, "%s()\n", __func__);
+
++ /* If we know we're connected via v4l2, then there should be a cleanup
++ * of the device from userspace either via UVC_EVENT_DISCONNECT or
++ * though the video device removal uevent. Allow some time for the
++ * application to close out before things get deleted.
++ */
++ if (uvc->func_connected) {
++ uvcg_dbg(f, "waiting for clean disconnect\n");
++ wait_ret = wait_event_interruptible_timeout(uvc->func_connected_queue,
++ uvc->func_connected == false, msecs_to_jiffies(500));
++ uvcg_dbg(f, "done waiting with ret: %ld\n", wait_ret);
++ }
++
+ device_remove_file(&uvc->vdev.dev, &dev_attr_function_name);
+ video_unregister_device(&uvc->vdev);
+ v4l2_device_unregister(&uvc->v4l2_dev);
+
++ if (uvc->func_connected) {
++ /* Wait for the release to occur to ensure there are no longer any
++ * pending operations that may cause panics when resources are cleaned
++ * up.
++ */
++ uvcg_warn(f, "%s no clean disconnect, wait for release\n", __func__);
++ wait_ret = wait_event_interruptible_timeout(uvc->func_connected_queue,
++ uvc->func_connected == false, msecs_to_jiffies(1000));
++ uvcg_dbg(f, "done waiting for release with ret: %ld\n", wait_ret);
++ }
++
+ usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
+ kfree(uvc->control_buf);
+
+@@ -913,6 +937,7 @@ static struct usb_function *uvc_alloc(st
+
+ mutex_init(&uvc->video.mutex);
+ uvc->state = UVC_STATE_DISCONNECTED;
++ init_waitqueue_head(&uvc->func_connected_queue);
+ opts = fi_to_f_uvc_opts(fi);
+
+ mutex_lock(&opts->lock);
+--- a/drivers/usb/gadget/function/uvc.h
++++ b/drivers/usb/gadget/function/uvc.h
+@@ -14,6 +14,7 @@
+ #include <linux/spinlock.h>
+ #include <linux/usb/composite.h>
+ #include <linux/videodev2.h>
++#include <linux/wait.h>
+
+ #include <media/v4l2-device.h>
+ #include <media/v4l2-dev.h>
+@@ -118,6 +119,7 @@ struct uvc_device {
+ struct usb_function func;
+ struct uvc_video video;
+ bool func_connected;
++ wait_queue_head_t func_connected_queue;
+
+ /* Descriptors */
+ struct {
+--- a/drivers/usb/gadget/function/uvc_v4l2.c
++++ b/drivers/usb/gadget/function/uvc_v4l2.c
+@@ -252,10 +252,11 @@ uvc_v4l2_subscribe_event(struct v4l2_fh
+
+ static void uvc_v4l2_disable(struct uvc_device *uvc)
+ {
+- uvc->func_connected = false;
+ uvc_function_disconnect(uvc);
+ uvcg_video_enable(&uvc->video, 0);
+ uvcg_free_buffers(&uvc->video.queue);
++ uvc->func_connected = false;
++ wake_up_interruptible(&uvc->func_connected_queue);
+ }
+
+ static int
--- /dev/null
+From e6bab2b66329b40462fb1bed6f98bc3fcf543a1c Mon Sep 17 00:00:00 2001
+From: Michael Tretter <m.tretter@pengutronix.de>
+Date: Sun, 17 Oct 2021 23:50:13 +0200
+Subject: usb: gadget: uvc: rename function to be more consistent
+
+From: Michael Tretter <m.tretter@pengutronix.de>
+
+commit e6bab2b66329b40462fb1bed6f98bc3fcf543a1c upstream.
+
+When enabling info debugging for the uvc gadget, the bind and unbind
+infos use different formats. Change the unbind to visually match the
+bind.
+
+Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
+Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
+Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
+Link: https://lore.kernel.org/r/20211017215017.18392-3-m.grzeschik@pengutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/gadget/function/f_uvc.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+--- a/drivers/usb/gadget/function/f_uvc.c
++++ b/drivers/usb/gadget/function/f_uvc.c
+@@ -883,12 +883,13 @@ static void uvc_free(struct usb_function
+ kfree(uvc);
+ }
+
+-static void uvc_unbind(struct usb_configuration *c, struct usb_function *f)
++static void uvc_function_unbind(struct usb_configuration *c,
++ struct usb_function *f)
+ {
+ struct usb_composite_dev *cdev = c->cdev;
+ struct uvc_device *uvc = to_uvc(f);
+
+- uvcg_info(f, "%s\n", __func__);
++ uvcg_info(f, "%s()\n", __func__);
+
+ device_remove_file(&uvc->vdev.dev, &dev_attr_function_name);
+ video_unregister_device(&uvc->vdev);
+@@ -942,7 +943,7 @@ static struct usb_function *uvc_alloc(st
+ /* Register the function. */
+ uvc->func.name = "uvc";
+ uvc->func.bind = uvc_function_bind;
+- uvc->func.unbind = uvc_unbind;
++ uvc->func.unbind = uvc_function_unbind;
+ uvc->func.get_alt = uvc_function_get_alt;
+ uvc->func.set_alt = uvc_function_set_alt;
+ uvc->func.disable = uvc_function_disable;