All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ricardo Ribalda <ribalda@chromium.org>
To: Laurent Pinchart <laurent.pinchart@ideasonboard.com>,
	Mauro Carvalho Chehab <mchehab@kernel.org>,
	linux-media@vger.kernel.org, linux-kernel@vger.kernel.org
Cc: Ricardo Ribalda <ribalda@chromium.org>
Subject: [PATCH v7 12/12] media: uvcvideo: Implement UVC_QUIRK_PRIVACY_DURING_STREAM
Date: Wed, 23 Dec 2020 14:35:28 +0100	[thread overview]
Message-ID: <20201223133528.55014-13-ribalda@chromium.org> (raw)
In-Reply-To: <20201223133528.55014-1-ribalda@chromium.org>

Some devices can only read the privacy_pin if the device is
streaming.

This patch implement a quirk for such devices, in order to avoid invalid
reads and/or spurious events.

Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
 drivers/media/usb/uvc/uvc_driver.c | 55 +++++++++++++++++++++++++++---
 drivers/media/usb/uvc/uvc_video.c  | 27 +++++++++++++++
 drivers/media/usb/uvc/uvcvideo.h   |  7 ++++
 3 files changed, 84 insertions(+), 5 deletions(-)

diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index f1f6b9cfa676..4ec14c7fb5c4 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -7,6 +7,7 @@
  */
 
 #include <linux/atomic.h>
+#include <linux/dmi.h>
 #include <linux/gpio/consumer.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
@@ -1478,7 +1479,7 @@ static int uvc_parse_control(struct uvc_device *dev)
  * Privacy GPIO
  */
 
-static void uvc_gpio_event(struct uvc_device *dev)
+void uvc_gpio_event(struct uvc_device *dev)
 {
 	struct uvc_entity *unit = dev->gpio_unit;
 	struct uvc_video_chain *chain;
@@ -1487,19 +1488,29 @@ static void uvc_gpio_event(struct uvc_device *dev)
 	if (!unit)
 		return;
 
+	mutex_lock(&unit->gpio.event_mutex);
+
 	new_val = gpiod_get_value_cansleep(unit->gpio.gpio_privacy);
+	if (unit->gpio.last_event_val != new_val) {
+		/* GPIO entities are always on the first chain. */
+		chain = list_first_entry(&dev->chains,
+					 struct uvc_video_chain, list);
+		uvc_ctrl_status_event(chain, unit->controls, &new_val);
+	}
+	unit->gpio.last_event_val = new_val;
 
-	/* GPIO entities are always on the first chain. */
-	chain = list_first_entry(&dev->chains, struct uvc_video_chain, list);
-	uvc_ctrl_status_event(chain, unit->controls, &new_val);
+	mutex_unlock(&unit->gpio.event_mutex);
 }
 
 static int uvc_gpio_get_cur(struct uvc_device *dev, struct uvc_entity *entity,
 			    u8 cs, void *data, u16 size)
 {
-	if (cs != UVC_CT_PRIVACY_CONTROL || size < 1)
+	if (cs != UVC_CT_PRIVACY_CONTROL || size < 1 || !dev->gpio_unit)
 		return -EINVAL;
 
+	if (!dev->gpio_unit->gpio.is_gpio_ready)
+		return -EBUSY;
+
 	*(u8 *)data = gpiod_get_value_cansleep(entity->gpio.gpio_privacy);
 
 	return 0;
@@ -1519,10 +1530,31 @@ static irqreturn_t uvc_gpio_irq(int irq, void *data)
 {
 	struct uvc_device *dev = data;
 
+	if (!dev->gpio_unit->gpio.is_gpio_ready)
+		return IRQ_HANDLED;
+
 	uvc_gpio_event(dev);
 	return IRQ_HANDLED;
 }
 
+static const struct dmi_system_id privacy_valid_during_streamon[] = {
+	{
+		.ident = "HP Elite c1030 Chromebook",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Jinlon"),
+		},
+	},
+	{
+		.ident = "HP Pro c640 Chromebook",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Dratini"),
+		},
+	},
+	{ } /* terminate list */
+};
+
 static int uvc_gpio_parse(struct uvc_device *dev)
 {
 	struct uvc_entity *unit;
@@ -1547,6 +1579,7 @@ static int uvc_gpio_parse(struct uvc_device *dev)
 	}
 
 	unit->gpio.gpio_privacy = gpio_privacy;
+	unit->gpio.last_event_val = -1;
 	unit->gpio.irq = irq;
 	unit->gpio.bControlSize = 1;
 	unit->gpio.bmControls = (u8 *)unit + sizeof(*unit);
@@ -1554,6 +1587,18 @@ static int uvc_gpio_parse(struct uvc_device *dev)
 	unit->get_cur = uvc_gpio_get_cur;
 	unit->get_info = uvc_gpio_get_info;
 	strncpy(unit->name, "GPIO", sizeof(unit->name) - 1);
+	mutex_init(&unit->gpio.event_mutex);
+
+	/*
+	 * Note: This quirk will not match external UVC cameras,
+	 * as they will not have the corresponding ACPI GPIO entity.
+	 */
+	if (dmi_check_system(privacy_valid_during_streamon)) {
+		dev->quirks |= UVC_QUIRK_PRIVACY_DURING_STREAM;
+		unit->gpio.is_gpio_ready = false;
+	} else {
+		unit->gpio.is_gpio_ready = true;
+	}
 
 	list_add_tail(&unit->list, &dev->entities);
 
diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
index f2f565281e63..b333c54d18c1 100644
--- a/drivers/media/usb/uvc/uvc_video.c
+++ b/drivers/media/usb/uvc/uvc_video.c
@@ -2083,6 +2083,29 @@ int uvc_video_init(struct uvc_streaming *stream)
 	return 0;
 }
 
+static void uvc_gpio_privacy_quirks(struct uvc_streaming *stream, bool enable)
+{
+	struct uvc_device *dev = stream->dev;
+	struct uvc_video_chain *first_chain;
+
+	if (!(dev->quirks & UVC_QUIRK_PRIVACY_DURING_STREAM))
+		return;
+
+	if (!dev->gpio_unit)
+		return;
+
+	first_chain = list_first_entry(&dev->chains,
+				       struct uvc_video_chain, list);
+	/* GPIO entities are always on the first chain. */
+	if (stream->chain != first_chain)
+		return;
+
+	dev->gpio_unit->gpio.is_gpio_ready = enable;
+
+	if (enable)
+		uvc_gpio_event(stream->dev);
+}
+
 int uvc_video_start_streaming(struct uvc_streaming *stream)
 {
 	int ret;
@@ -2100,6 +2123,8 @@ int uvc_video_start_streaming(struct uvc_streaming *stream)
 	if (ret < 0)
 		goto error_video;
 
+	uvc_gpio_privacy_quirks(stream, true);
+
 	return 0;
 
 error_video:
@@ -2112,6 +2137,8 @@ int uvc_video_start_streaming(struct uvc_streaming *stream)
 
 void uvc_video_stop_streaming(struct uvc_streaming *stream)
 {
+	uvc_gpio_privacy_quirks(stream, false);
+
 	uvc_video_stop_transfer(stream, 1);
 
 	if (stream->intf->num_altsetting > 1) {
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index 3273d03aca9a..a9290e2d1762 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -209,6 +209,7 @@
 #define UVC_QUIRK_RESTORE_CTRLS_ON_INIT	0x00000400
 #define UVC_QUIRK_FORCE_Y8		0x00000800
 #define UVC_QUIRK_FORCE_BPP		0x00001000
+#define UVC_QUIRK_PRIVACY_DURING_STREAM	0x00002000
 
 /* Format flags */
 #define UVC_FMT_FLAG_COMPRESSED		0x00000001
@@ -366,6 +367,9 @@ struct uvc_entity {
 			u8  *bmControls;
 			struct gpio_desc *gpio_privacy;
 			int irq;
+			struct mutex event_mutex;
+			int last_event_val;
+			bool is_gpio_ready;
 		} gpio;
 	};
 
@@ -831,6 +835,9 @@ extern const struct v4l2_file_operations uvc_fops;
 int uvc_mc_register_entities(struct uvc_video_chain *chain);
 void uvc_mc_cleanup_entity(struct uvc_entity *entity);
 
+/* Privacy gpio */
+void uvc_gpio_event(struct uvc_device *dev);
+
 /* Video */
 int uvc_video_init(struct uvc_streaming *stream);
 int uvc_video_suspend(struct uvc_streaming *stream);
-- 
2.29.2.729.g45daf8777d-goog


      parent reply	other threads:[~2020-12-23 13:37 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-12-23 13:35 [PATCH v7 00/12] Show privacy_gpio as a v4l2_ctrl Ricardo Ribalda
2020-12-23 13:35 ` [PATCH v7 01/12] media: uvcvideo: Move guid to entity Ricardo Ribalda
2020-12-23 13:35 ` [PATCH v7 02/12] media: uvcvideo: Allow extra entities Ricardo Ribalda
2020-12-23 13:35 ` [PATCH v7 03/12] media: uvcvideo: Allow entities with no pads Ricardo Ribalda
2020-12-23 13:35 ` [PATCH v7 04/12] media: uvcvideo: Provide sync and async uvc_ctrl_status_event Ricardo Ribalda
2021-01-26 15:38   ` Laurent Pinchart
2020-12-23 13:35 ` [PATCH v7 05/12] media: uvcvideo: Allow entity-defined get_info and get_cur Ricardo Ribalda
2020-12-23 13:35 ` [PATCH v7 06/12] media: uvcvideo: Implement UVC_EXT_GPIO_UNIT Ricardo Ribalda
2021-01-26 15:53   ` Laurent Pinchart
2021-01-26 15:56     ` Laurent Pinchart
2020-12-23 13:35 ` [PATCH v7 07/12] media: uvcvideo: Add Privacy control based on EXT_GPIO Ricardo Ribalda
2020-12-23 13:35 ` [PATCH v7 08/12] media: uvcvideo: Use dev_ printk aliases Ricardo Ribalda
2020-12-24 12:59   ` Andy Shevchenko
2020-12-24 13:50     ` Laurent Pinchart
2020-12-23 13:35 ` [PATCH v7 09/12] media: uvcvideo: New macro uvc_trace_cont Ricardo Ribalda
2020-12-23 13:35 ` [PATCH v7 10/12] media: uvcvideo: use dev_printk() for uvc_trace() Ricardo Ribalda
2020-12-23 13:35 ` [PATCH v7 11/12] media: uvcvideo: Rename debug functions Ricardo Ribalda
2021-01-26 17:05   ` Laurent Pinchart
2020-12-23 13:35 ` Ricardo Ribalda [this message]

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=20201223133528.55014-13-ribalda@chromium.org \
    --to=ribalda@chromium.org \
    --cc=laurent.pinchart@ideasonboard.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=mchehab@kernel.org \
    /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.