From 3099e13bdb21f68d673cf20ad25c0be1ce4578b2 Mon Sep 17 00:00:00 2001 From: William Wu Date: Tue, 27 Nov 2018 15:25:02 +0800 Subject: [PATCH] usb: gadget: f_uvc: support uvc and adb use independently If we use usb gadget as uvc and adb composite function, the adb will be disconnected if the uvc camera apk is closed. I can reproduce this issue by the following steps on rk3399/rk3288 platforms. 1. Set usb gadget as uvc and adb composite function, and open uvc camera apk on rk3399/rk3288 platforms. 2. Connect usb to PC, and use adb shell; 3. Close the uvc camera apk; And then, the adb will also be disconnected. It's because that when close the uvc camera apk, the userspace calls v4l2_release -> uvc_v4l2_release -> uvc_function_disconnect -> usb_gadget_deactivate -> usb_gadget_disconnect -> pullup(gadget, 0), this cause usb controller disconnect the usb connection. This patch adds a uvc_enabled flag to indicate that usb is connected, don't call pullup(gadget, 0) to disconnet usb if we only close uvc camera apk but not plug out usb cable. Change-Id: I0cc5ce8a24e8e06e0dc9215dfd1b92ef702e4311 Signed-off-by: William Wu --- drivers/usb/gadget/function/f_uvc.c | 3 +++ drivers/usb/gadget/udc/core.c | 8 +++++--- include/linux/usb/gadget.h | 2 ++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index 523fbbc7b6f9..b1c755069451 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -381,6 +381,7 @@ uvc_function_disable(struct usb_function *f) v4l2_event_queue(&uvc->vdev, &v4l2_event); uvc->state = UVC_STATE_DISCONNECTED; + f->config->cdev->gadget->uvc_enabled = false; usb_ep_disable(uvc->video.ep); usb_ep_disable(uvc->control_ep); @@ -396,6 +397,8 @@ uvc_function_connect(struct uvc_device *uvc) struct usb_composite_dev *cdev = uvc->func.config->cdev; int ret; + cdev->gadget->uvc_enabled = true; + if ((ret = usb_function_activate(&uvc->func)) < 0) INFO(cdev, "UVC connect failed with %d\n", ret); } diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index b7a3db148f64..d4ce9ca37f1d 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -682,9 +682,11 @@ int usb_gadget_disconnect(struct usb_gadget *gadget) goto out; } - ret = gadget->ops->pullup(gadget, 0); - if (!ret) - gadget->connected = 0; + if (!gadget->uvc_enabled) { + ret = gadget->ops->pullup(gadget, 0); + if (!ret) + gadget->connected = 0; + } out: trace_usb_gadget_disconnect(gadget, ret); diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index d7f77abb45ae..b690286cb10b 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -347,6 +347,7 @@ struct usb_gadget_ops { * @deactivated: True if gadget is deactivated - in deactivated state it cannot * be connected. * @connected: True if gadget is connected. + * @uvc_enabled: True if uvc function is enabled. * * Gadgets have a mostly-portable "gadget driver" implementing device * functions, handling all usb configurations and interfaces. Gadget @@ -396,6 +397,7 @@ struct usb_gadget { unsigned is_selfpowered:1; unsigned deactivated:1; unsigned connected:1; + unsigned uvc_enabled:1; }; #define work_to_gadget(w) (container_of((w), struct usb_gadget, work))