All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ming Lei <ming.lei@canonical.com>
To: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Cc: linux-media@vger.kernel.org, linux-usb@vger.kernel.org,
	Jeremy Kerr <jeremy.kerr@canonical.com>,
	Mauro Carvalho Chehab <mchehab@redhat.com>
Subject: [PATCH] uvcvideo: add fix suspend/resume quirk for Microdia camera
Date: Mon, 11 Jul 2011 17:48:11 +0800	[thread overview]
Message-ID: <20110711174811.3c383595@tom-ThinkPad-T410> (raw)

>From 989d894a2af7ceadf2574f455d9e68779f4ae674 Mon Sep 17 00:00:00 2001
From: Ming Lei <ming.lei@canonical.com>
Date: Mon, 11 Jul 2011 17:04:31 +0800
Subject: [PATCH] uvcvideo: add fix suspend/resume quirk for Microdia camera

We found this type(0c45:6437) of Microdia camera does not
work(no stream packets sent out from camera any longer) after
resume from sleep, but unbind/bind driver will work again.

So introduce the quirk of UVC_QUIRK_FIX_SUSPEND_RESUME to
fix the problem for this type of Microdia camera.
---
 drivers/media/video/uvc/uvc_driver.c |  146 +++++++++++++++++++---------------
 drivers/media/video/uvc/uvcvideo.h   |    1 +
 2 files changed, 84 insertions(+), 63 deletions(-)

diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index b6eae48..2b356c3 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -1787,6 +1787,68 @@ static int uvc_register_chains(struct uvc_device *dev)
 /* ------------------------------------------------------------------------
  * USB probe, disconnect, suspend and resume
  */
+static int uvc_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct uvc_device *dev = usb_get_intfdata(intf);
+	struct uvc_streaming *stream;
+
+	uvc_trace(UVC_TRACE_SUSPEND, "Suspending interface %u\n",
+		intf->cur_altsetting->desc.bInterfaceNumber);
+
+	/* Controls are cached on the fly so they don't need to be saved. */
+	if (intf->cur_altsetting->desc.bInterfaceSubClass ==
+	    UVC_SC_VIDEOCONTROL)
+		return uvc_status_suspend(dev);
+
+	list_for_each_entry(stream, &dev->streams, list) {
+		if (stream->intf == intf)
+			return uvc_video_suspend(stream);
+	}
+
+	uvc_trace(UVC_TRACE_SUSPEND, "Suspend: video streaming USB interface "
+			"mismatch.\n");
+	return -EINVAL;
+}
+
+static int __uvc_resume(struct usb_interface *intf, int reset)
+{
+	struct uvc_device *dev = usb_get_intfdata(intf);
+	struct uvc_streaming *stream;
+
+	uvc_trace(UVC_TRACE_SUSPEND, "Resuming interface %u\n",
+		intf->cur_altsetting->desc.bInterfaceNumber);
+
+	if (intf->cur_altsetting->desc.bInterfaceSubClass ==
+	    UVC_SC_VIDEOCONTROL) {
+		if (reset) {
+			int ret = uvc_ctrl_resume_device(dev);
+
+			if (ret < 0)
+				return ret;
+		}
+
+		return uvc_status_resume(dev);
+	}
+
+	list_for_each_entry(stream, &dev->streams, list) {
+		if (stream->intf == intf)
+			return uvc_video_resume(stream);
+	}
+
+	uvc_trace(UVC_TRACE_SUSPEND, "Resume: video streaming USB interface "
+			"mismatch.\n");
+	return -EINVAL;
+}
+
+static int uvc_resume(struct usb_interface *intf)
+{
+	return __uvc_resume(intf, 0);
+}
+
+static int uvc_reset_resume(struct usb_interface *intf)
+{
+	return __uvc_resume(intf, 1);
+}
 
 static int uvc_probe(struct usb_interface *intf,
 		     const struct usb_device_id *id)
@@ -1888,6 +1950,18 @@ static int uvc_probe(struct usb_interface *intf,
 			"supported.\n", ret);
 	}
 
+	/* For some buggy cameras, they will not work after wakeup, so
+	 * do unbind in .usb_suspend and do rebind in .usb_resume to
+	 * make it work again.
+	 * */
+	if (dev->quirks & UVC_QUIRK_FIX_SUSPEND_RESUME) {
+		uvc_driver.driver.suspend = NULL;
+		uvc_driver.driver.resume = NULL;
+	} else {
+		uvc_driver.driver.suspend = uvc_suspend;
+		uvc_driver.driver.resume = uvc_resume;
+	}
+
 	uvc_trace(UVC_TRACE_PROBE, "UVC device initialized.\n");
 	usb_enable_autosuspend(udev);
 	return 0;
@@ -1915,69 +1989,6 @@ static void uvc_disconnect(struct usb_interface *intf)
 	uvc_unregister_video(dev);
 }
 
-static int uvc_suspend(struct usb_interface *intf, pm_message_t message)
-{
-	struct uvc_device *dev = usb_get_intfdata(intf);
-	struct uvc_streaming *stream;
-
-	uvc_trace(UVC_TRACE_SUSPEND, "Suspending interface %u\n",
-		intf->cur_altsetting->desc.bInterfaceNumber);
-
-	/* Controls are cached on the fly so they don't need to be saved. */
-	if (intf->cur_altsetting->desc.bInterfaceSubClass ==
-	    UVC_SC_VIDEOCONTROL)
-		return uvc_status_suspend(dev);
-
-	list_for_each_entry(stream, &dev->streams, list) {
-		if (stream->intf == intf)
-			return uvc_video_suspend(stream);
-	}
-
-	uvc_trace(UVC_TRACE_SUSPEND, "Suspend: video streaming USB interface "
-			"mismatch.\n");
-	return -EINVAL;
-}
-
-static int __uvc_resume(struct usb_interface *intf, int reset)
-{
-	struct uvc_device *dev = usb_get_intfdata(intf);
-	struct uvc_streaming *stream;
-
-	uvc_trace(UVC_TRACE_SUSPEND, "Resuming interface %u\n",
-		intf->cur_altsetting->desc.bInterfaceNumber);
-
-	if (intf->cur_altsetting->desc.bInterfaceSubClass ==
-	    UVC_SC_VIDEOCONTROL) {
-		if (reset) {
-			int ret = uvc_ctrl_resume_device(dev);
-
-			if (ret < 0)
-				return ret;
-		}
-
-		return uvc_status_resume(dev);
-	}
-
-	list_for_each_entry(stream, &dev->streams, list) {
-		if (stream->intf == intf)
-			return uvc_video_resume(stream);
-	}
-
-	uvc_trace(UVC_TRACE_SUSPEND, "Resume: video streaming USB interface "
-			"mismatch.\n");
-	return -EINVAL;
-}
-
-static int uvc_resume(struct usb_interface *intf)
-{
-	return __uvc_resume(intf, 0);
-}
-
-static int uvc_reset_resume(struct usb_interface *intf)
-{
-	return __uvc_resume(intf, 1);
-}
-
 /* ------------------------------------------------------------------------
  * Module parameters
  */
@@ -2175,6 +2186,15 @@ static struct usb_device_id uvc_ids[] = {
 	  .bInterfaceSubClass	= 1,
 	  .bInterfaceProtocol	= 0,
 	  .driver_info		= UVC_QUIRK_FIX_BANDWIDTH },
+	/* Microdia camera */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x0c45,
+	  .idProduct		= 0x6437,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_FIX_SUSPEND_RESUME },
 	/* MT6227 */
 	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
 				| USB_DEVICE_ID_MATCH_INT_INFO,
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index 20107fd..3c13b04 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -211,6 +211,7 @@ struct uvc_xu_control {
 #define UVC_QUIRK_FIX_BANDWIDTH		0x00000080
 #define UVC_QUIRK_PROBE_DEF		0x00000100
 #define UVC_QUIRK_RESTRICT_FRAME_RATE	0x00000200
+#define UVC_QUIRK_FIX_SUSPEND_RESUME	0x00000400
 
 /* Format flags */
 #define UVC_FMT_FLAG_COMPRESSED		0x00000001
-- 
1.7.4.1



-- 
Ming Lei

             reply	other threads:[~2011-07-11  9:48 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-07-11  9:48 Ming Lei [this message]
2011-07-11 10:44 ` [PATCH] uvcvideo: add fix suspend/resume quirk for Microdia camera Laurent Pinchart
2011-07-12  1:21   ` Ming Lei
2011-07-12 10:52     ` Ming Lei
2011-07-12 15:44       ` Alan Stern
2011-07-13  7:43         ` Ming Lei
2011-07-13 15:20           ` Alan Stern
2011-07-13 15:30             ` Ming Lei
2011-07-13 15:59               ` Alan Stern
2011-07-14  9:16                 ` Ming Lei
2011-07-14 15:03                   ` Alan Stern
2011-07-15  2:08                     ` Ming Lei
2011-07-15 13:53                     ` Ming Lei
2011-07-15 14:27                       ` Alan Stern
2011-07-15 14:44                         ` Ming Lei
2011-07-15 15:25                           ` Alan Stern
2011-07-16  3:51                             ` [PATCH] uvcvideo: add SetInterface(0) in .reset_resume handler Ming Lei
2011-07-31 15:38                               ` Laurent Pinchart
2011-08-01  0:56                                 ` Ming Lei
2011-08-01 11:26                                   ` Laurent Pinchart
2011-08-01 17:39                                     ` Mauro Carvalho Chehab
2011-08-01 22:19                                       ` [GIT PATCH FOR v3.1] uvcvideo: Set alternate setting 0 on resume if the bus has been reset Laurent Pinchart
2011-07-13  8:35         ` [PATCH] uvcvideo: add fix suspend/resume quirk for Microdia camera Ming Lei
2011-07-13  8:38     ` Laurent Pinchart
2011-07-13  8:51       ` Ming Lei
2011-07-13  8:55         ` Oliver Neukum
2011-07-13  8:59         ` Laurent Pinchart
2011-07-13  9:07           ` Ming Lei
2011-07-11 10:51 ` Sergei Shtylyov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20110711174811.3c383595@tom-ThinkPad-T410 \
    --to=ming.lei@canonical.com \
    --cc=jeremy.kerr@canonical.com \
    --cc=laurent.pinchart@ideasonboard.com \
    --cc=linux-media@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=mchehab@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.