]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
[media] cec: Kconfig cleanup
authorHans Verkuil <hans.verkuil@cisco.com>
Mon, 17 Apr 2017 10:44:35 +0000 (07:44 -0300)
committerMauro Carvalho Chehab <mchehab@s-opensource.com>
Wed, 19 Apr 2017 09:50:52 +0000 (06:50 -0300)
The Kconfig options for the CEC subsystem were a bit messy. In
addition there were two cec sources (cec-edid.c and cec-notifier.c)
that were outside of the media/cec directory, which was weird.

Move those sources to media/cec as well.

The cec-edid and cec-notifier functionality is now part of the cec
module and these are no longer separate modules.

Also remove the MEDIA_CEC_EDID config option and include it with the
main CEC config option (which defined CEC_EDID anyway).

Added static inlines to cec-edid.h for dummy functions when CEC_CORE
isn't defined.

CEC drivers should now depend on CEC_CORE.

CEC drivers that need the cec-notifier functionality must explicitly
select CEC_NOTIFIER.

The s5p-cec and stih-cec drivers depended on VIDEO_DEV instead of
CEC_CORE, fix that as well.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
16 files changed:
MAINTAINERS
drivers/media/Kconfig
drivers/media/Makefile
drivers/media/cec-edid.c [deleted file]
drivers/media/cec-notifier.c [deleted file]
drivers/media/cec/Kconfig [new file with mode: 0644]
drivers/media/cec/Makefile
drivers/media/cec/cec-edid.c [new file with mode: 0644]
drivers/media/cec/cec-notifier.c [new file with mode: 0644]
drivers/media/i2c/Kconfig
drivers/media/platform/Kconfig
drivers/media/platform/vivid/Kconfig
drivers/media/usb/pulse8-cec/Kconfig
drivers/media/usb/rainshadow-cec/Kconfig
include/media/cec-edid.h
include/media/cec.h

index 6919a495bdadbb41745b7631fb5a03ba774ab2eb..cf0101544a084785ff6937f5cc0960c767ba0a5a 100644 (file)
@@ -3075,8 +3075,6 @@ S:        Supported
 F:     Documentation/media/kapi/cec-core.rst
 F:     Documentation/media/uapi/cec
 F:     drivers/media/cec/
-F:     drivers/media/cec-edid.c
-F:     drivers/media/cec-notifier.c
 F:     drivers/media/rc/keymaps/rc-cec.c
 F:     include/media/cec.h
 F:     include/media/cec-edid.h
index 9e9ded44e8a8c7ea1ace2e49ffb0111b840fa033..b72edd27f880fbe99641cd36b44005c6ad9252c6 100644 (file)
@@ -81,27 +81,15 @@ config MEDIA_RC_SUPPORT
          Say Y when you have a TV or an IR device.
 
 config MEDIA_CEC_SUPPORT
-       bool "HDMI CEC support"
-       select MEDIA_CEC_EDID
-       ---help---
-         Enable support for HDMI CEC (Consumer Electronics Control),
-         which is an optional HDMI feature.
-
-         Say Y when you have an HDMI receiver, transmitter or a USB CEC
-         adapter that supports HDMI CEC.
-
-config MEDIA_CEC_DEBUG
-       bool "HDMI CEC debugfs interface"
-       depends on MEDIA_CEC_SUPPORT && DEBUG_FS
-       ---help---
-         Turns on the DebugFS interface for CEC devices.
+       bool "HDMI CEC support"
+       ---help---
+         Enable support for HDMI CEC (Consumer Electronics Control),
+         which is an optional HDMI feature.
 
-config MEDIA_CEC_EDID
-       bool
+         Say Y when you have an HDMI receiver, transmitter or a USB CEC
+         adapter that supports HDMI CEC.
 
-config MEDIA_CEC_NOTIFIER
-       bool
-       select MEDIA_CEC_EDID
+source "drivers/media/cec/Kconfig"
 
 #
 # Media controller
index 8b36a571d4437283393b8c013c10de594001ee55..523fea3648ad71749009fc9f7d0f543d36734128 100644 (file)
@@ -2,20 +2,10 @@
 # Makefile for the kernel multimedia device drivers.
 #
 
-ifeq ($(CONFIG_MEDIA_CEC_EDID),y)
-  obj-$(CONFIG_MEDIA_SUPPORT) += cec-edid.o
-endif
-
-ifeq ($(CONFIG_MEDIA_CEC_NOTIFIER),y)
-  obj-$(CONFIG_MEDIA_SUPPORT) += cec-notifier.o
-endif
-
-ifeq ($(CONFIG_MEDIA_CEC_SUPPORT),y)
-  obj-$(CONFIG_MEDIA_SUPPORT) += cec/
-endif
-
 media-objs     := media-device.o media-devnode.o media-entity.o
 
+obj-$(CONFIG_CEC_CORE) += cec/
+
 #
 # I2C drivers should come before other drivers, otherwise they'll fail
 # when compiled as builtin drivers
diff --git a/drivers/media/cec-edid.c b/drivers/media/cec-edid.c
deleted file mode 100644 (file)
index 5719b99..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * cec-edid - HDMI Consumer Electronics Control EDID & CEC helper functions
- *
- * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <media/cec-edid.h>
-
-/*
- * This EDID is expected to be a CEA-861 compliant, which means that there are
- * at least two blocks and one or more of the extensions blocks are CEA-861
- * blocks.
- *
- * The returned location is guaranteed to be < size - 1.
- */
-static unsigned int cec_get_edid_spa_location(const u8 *edid, unsigned int size)
-{
-       unsigned int blocks = size / 128;
-       unsigned int block;
-       u8 d;
-
-       /* Sanity check: at least 2 blocks and a multiple of the block size */
-       if (blocks < 2 || size % 128)
-               return 0;
-
-       /*
-        * If there are fewer extension blocks than the size, then update
-        * 'blocks'. It is allowed to have more extension blocks than the size,
-        * since some hardware can only read e.g. 256 bytes of the EDID, even
-        * though more blocks are present. The first CEA-861 extension block
-        * should normally be in block 1 anyway.
-        */
-       if (edid[0x7e] + 1 < blocks)
-               blocks = edid[0x7e] + 1;
-
-       for (block = 1; block < blocks; block++) {
-               unsigned int offset = block * 128;
-
-               /* Skip any non-CEA-861 extension blocks */
-               if (edid[offset] != 0x02 || edid[offset + 1] != 0x03)
-                       continue;
-
-               /* search Vendor Specific Data Block (tag 3) */
-               d = edid[offset + 2] & 0x7f;
-               /* Check if there are Data Blocks */
-               if (d <= 4)
-                       continue;
-               if (d > 4) {
-                       unsigned int i = offset + 4;
-                       unsigned int end = offset + d;
-
-                       /* Note: 'end' is always < 'size' */
-                       do {
-                               u8 tag = edid[i] >> 5;
-                               u8 len = edid[i] & 0x1f;
-
-                               if (tag == 3 && len >= 5 && i + len <= end &&
-                                   edid[i + 1] == 0x03 &&
-                                   edid[i + 2] == 0x0c &&
-                                   edid[i + 3] == 0x00)
-                                       return i + 4;
-                               i += len + 1;
-                       } while (i < end);
-               }
-       }
-       return 0;
-}
-
-u16 cec_get_edid_phys_addr(const u8 *edid, unsigned int size,
-                          unsigned int *offset)
-{
-       unsigned int loc = cec_get_edid_spa_location(edid, size);
-
-       if (offset)
-               *offset = loc;
-       if (loc == 0)
-               return CEC_PHYS_ADDR_INVALID;
-       return (edid[loc] << 8) | edid[loc + 1];
-}
-EXPORT_SYMBOL_GPL(cec_get_edid_phys_addr);
-
-void cec_set_edid_phys_addr(u8 *edid, unsigned int size, u16 phys_addr)
-{
-       unsigned int loc = cec_get_edid_spa_location(edid, size);
-       u8 sum = 0;
-       unsigned int i;
-
-       if (loc == 0)
-               return;
-       edid[loc] = phys_addr >> 8;
-       edid[loc + 1] = phys_addr & 0xff;
-       loc &= ~0x7f;
-
-       /* update the checksum */
-       for (i = loc; i < loc + 127; i++)
-               sum += edid[i];
-       edid[i] = 256 - sum;
-}
-EXPORT_SYMBOL_GPL(cec_set_edid_phys_addr);
-
-u16 cec_phys_addr_for_input(u16 phys_addr, u8 input)
-{
-       /* Check if input is sane */
-       if (WARN_ON(input == 0 || input > 0xf))
-               return CEC_PHYS_ADDR_INVALID;
-
-       if (phys_addr == 0)
-               return input << 12;
-
-       if ((phys_addr & 0x0fff) == 0)
-               return phys_addr | (input << 8);
-
-       if ((phys_addr & 0x00ff) == 0)
-               return phys_addr | (input << 4);
-
-       if ((phys_addr & 0x000f) == 0)
-               return phys_addr | input;
-
-       /*
-        * All nibbles are used so no valid physical addresses can be assigned
-        * to the input.
-        */
-       return CEC_PHYS_ADDR_INVALID;
-}
-EXPORT_SYMBOL_GPL(cec_phys_addr_for_input);
-
-int cec_phys_addr_validate(u16 phys_addr, u16 *parent, u16 *port)
-{
-       int i;
-
-       if (parent)
-               *parent = phys_addr;
-       if (port)
-               *port = 0;
-       if (phys_addr == CEC_PHYS_ADDR_INVALID)
-               return 0;
-       for (i = 0; i < 16; i += 4)
-               if (phys_addr & (0xf << i))
-                       break;
-       if (i == 16)
-               return 0;
-       if (parent)
-               *parent = phys_addr & (0xfff0 << i);
-       if (port)
-               *port = (phys_addr >> i) & 0xf;
-       for (i += 4; i < 16; i += 4)
-               if ((phys_addr & (0xf << i)) == 0)
-                       return -EINVAL;
-       return 0;
-}
-EXPORT_SYMBOL_GPL(cec_phys_addr_validate);
-
-MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com>");
-MODULE_DESCRIPTION("CEC EDID helper functions");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/cec-notifier.c b/drivers/media/cec-notifier.c
deleted file mode 100644 (file)
index 5f5209a..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * cec-notifier.c - notify CEC drivers of physical address changes
- *
- * Copyright 2016 Russell King <rmk+kernel@arm.linux.org.uk>
- * Copyright 2016-2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <linux/export.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/kref.h>
-
-#include <media/cec-notifier.h>
-#include <drm/drm_edid.h>
-
-struct cec_notifier {
-       struct mutex lock;
-       struct list_head head;
-       struct kref kref;
-       struct device *dev;
-       struct cec_adapter *cec_adap;
-       void (*callback)(struct cec_adapter *adap, u16 pa);
-
-       u16 phys_addr;
-};
-
-static LIST_HEAD(cec_notifiers);
-static DEFINE_MUTEX(cec_notifiers_lock);
-
-struct cec_notifier *cec_notifier_get(struct device *dev)
-{
-       struct cec_notifier *n;
-
-       mutex_lock(&cec_notifiers_lock);
-       list_for_each_entry(n, &cec_notifiers, head) {
-               if (n->dev == dev) {
-                       kref_get(&n->kref);
-                       mutex_unlock(&cec_notifiers_lock);
-                       return n;
-               }
-       }
-       n = kzalloc(sizeof(*n), GFP_KERNEL);
-       if (!n)
-               goto unlock;
-       n->dev = dev;
-       n->phys_addr = CEC_PHYS_ADDR_INVALID;
-       mutex_init(&n->lock);
-       kref_init(&n->kref);
-       list_add_tail(&n->head, &cec_notifiers);
-unlock:
-       mutex_unlock(&cec_notifiers_lock);
-       return n;
-}
-EXPORT_SYMBOL_GPL(cec_notifier_get);
-
-static void cec_notifier_release(struct kref *kref)
-{
-       struct cec_notifier *n =
-               container_of(kref, struct cec_notifier, kref);
-
-       list_del(&n->head);
-       kfree(n);
-}
-
-void cec_notifier_put(struct cec_notifier *n)
-{
-       mutex_lock(&cec_notifiers_lock);
-       kref_put(&n->kref, cec_notifier_release);
-       mutex_unlock(&cec_notifiers_lock);
-}
-EXPORT_SYMBOL_GPL(cec_notifier_put);
-
-void cec_notifier_set_phys_addr(struct cec_notifier *n, u16 pa)
-{
-       mutex_lock(&n->lock);
-       n->phys_addr = pa;
-       if (n->callback)
-               n->callback(n->cec_adap, n->phys_addr);
-       mutex_unlock(&n->lock);
-}
-EXPORT_SYMBOL_GPL(cec_notifier_set_phys_addr);
-
-void cec_notifier_set_phys_addr_from_edid(struct cec_notifier *n,
-                                         const struct edid *edid)
-{
-       u16 pa = CEC_PHYS_ADDR_INVALID;
-
-       if (edid && edid->extensions)
-               pa = cec_get_edid_phys_addr((const u8 *)edid,
-                               EDID_LENGTH * (edid->extensions + 1), NULL);
-       cec_notifier_set_phys_addr(n, pa);
-}
-EXPORT_SYMBOL_GPL(cec_notifier_set_phys_addr_from_edid);
-
-void cec_notifier_register(struct cec_notifier *n,
-                          struct cec_adapter *adap,
-                          void (*callback)(struct cec_adapter *adap, u16 pa))
-{
-       kref_get(&n->kref);
-       mutex_lock(&n->lock);
-       n->cec_adap = adap;
-       n->callback = callback;
-       n->callback(adap, n->phys_addr);
-       mutex_unlock(&n->lock);
-}
-EXPORT_SYMBOL_GPL(cec_notifier_register);
-
-void cec_notifier_unregister(struct cec_notifier *n)
-{
-       mutex_lock(&n->lock);
-       n->callback = NULL;
-       mutex_unlock(&n->lock);
-       cec_notifier_put(n);
-}
-EXPORT_SYMBOL_GPL(cec_notifier_unregister);
diff --git a/drivers/media/cec/Kconfig b/drivers/media/cec/Kconfig
new file mode 100644 (file)
index 0000000..24b5318
--- /dev/null
@@ -0,0 +1,13 @@
+config CEC_CORE
+       tristate
+       depends on MEDIA_CEC_SUPPORT
+       default y
+
+config MEDIA_CEC_NOTIFIER
+       bool
+
+config MEDIA_CEC_DEBUG
+       bool "HDMI CEC debugfs interface"
+       depends on MEDIA_CEC_SUPPORT && DEBUG_FS
+       ---help---
+         Turns on the DebugFS interface for CEC devices.
index d6686337275ff83a746c5e848e7040548d20775a..402a6c62a3e8b9bb4857ac553e1b9a14c6babc16 100644 (file)
@@ -1,5 +1,7 @@
-cec-objs := cec-core.o cec-adap.o cec-api.o
+cec-objs := cec-core.o cec-adap.o cec-api.o cec-edid.o
 
-ifeq ($(CONFIG_MEDIA_CEC_SUPPORT),y)
-  obj-$(CONFIG_MEDIA_SUPPORT) += cec.o
+ifeq ($(CONFIG_MEDIA_CEC_NOTIFIER),y)
+  cec-objs += cec-notifier.o
 endif
+
+obj-$(CONFIG_CEC_CORE) += cec.o
diff --git a/drivers/media/cec/cec-edid.c b/drivers/media/cec/cec-edid.c
new file mode 100644 (file)
index 0000000..c63dc81
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * cec-edid - HDMI Consumer Electronics Control EDID & CEC helper functions
+ *
+ * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <media/cec-edid.h>
+
+/*
+ * This EDID is expected to be a CEA-861 compliant, which means that there are
+ * at least two blocks and one or more of the extensions blocks are CEA-861
+ * blocks.
+ *
+ * The returned location is guaranteed to be < size - 1.
+ */
+static unsigned int cec_get_edid_spa_location(const u8 *edid, unsigned int size)
+{
+       unsigned int blocks = size / 128;
+       unsigned int block;
+       u8 d;
+
+       /* Sanity check: at least 2 blocks and a multiple of the block size */
+       if (blocks < 2 || size % 128)
+               return 0;
+
+       /*
+        * If there are fewer extension blocks than the size, then update
+        * 'blocks'. It is allowed to have more extension blocks than the size,
+        * since some hardware can only read e.g. 256 bytes of the EDID, even
+        * though more blocks are present. The first CEA-861 extension block
+        * should normally be in block 1 anyway.
+        */
+       if (edid[0x7e] + 1 < blocks)
+               blocks = edid[0x7e] + 1;
+
+       for (block = 1; block < blocks; block++) {
+               unsigned int offset = block * 128;
+
+               /* Skip any non-CEA-861 extension blocks */
+               if (edid[offset] != 0x02 || edid[offset + 1] != 0x03)
+                       continue;
+
+               /* search Vendor Specific Data Block (tag 3) */
+               d = edid[offset + 2] & 0x7f;
+               /* Check if there are Data Blocks */
+               if (d <= 4)
+                       continue;
+               if (d > 4) {
+                       unsigned int i = offset + 4;
+                       unsigned int end = offset + d;
+
+                       /* Note: 'end' is always < 'size' */
+                       do {
+                               u8 tag = edid[i] >> 5;
+                               u8 len = edid[i] & 0x1f;
+
+                               if (tag == 3 && len >= 5 && i + len <= end &&
+                                   edid[i + 1] == 0x03 &&
+                                   edid[i + 2] == 0x0c &&
+                                   edid[i + 3] == 0x00)
+                                       return i + 4;
+                               i += len + 1;
+                       } while (i < end);
+               }
+       }
+       return 0;
+}
+
+u16 cec_get_edid_phys_addr(const u8 *edid, unsigned int size,
+                          unsigned int *offset)
+{
+       unsigned int loc = cec_get_edid_spa_location(edid, size);
+
+       if (offset)
+               *offset = loc;
+       if (loc == 0)
+               return CEC_PHYS_ADDR_INVALID;
+       return (edid[loc] << 8) | edid[loc + 1];
+}
+EXPORT_SYMBOL_GPL(cec_get_edid_phys_addr);
+
+void cec_set_edid_phys_addr(u8 *edid, unsigned int size, u16 phys_addr)
+{
+       unsigned int loc = cec_get_edid_spa_location(edid, size);
+       u8 sum = 0;
+       unsigned int i;
+
+       if (loc == 0)
+               return;
+       edid[loc] = phys_addr >> 8;
+       edid[loc + 1] = phys_addr & 0xff;
+       loc &= ~0x7f;
+
+       /* update the checksum */
+       for (i = loc; i < loc + 127; i++)
+               sum += edid[i];
+       edid[i] = 256 - sum;
+}
+EXPORT_SYMBOL_GPL(cec_set_edid_phys_addr);
+
+u16 cec_phys_addr_for_input(u16 phys_addr, u8 input)
+{
+       /* Check if input is sane */
+       if (WARN_ON(input == 0 || input > 0xf))
+               return CEC_PHYS_ADDR_INVALID;
+
+       if (phys_addr == 0)
+               return input << 12;
+
+       if ((phys_addr & 0x0fff) == 0)
+               return phys_addr | (input << 8);
+
+       if ((phys_addr & 0x00ff) == 0)
+               return phys_addr | (input << 4);
+
+       if ((phys_addr & 0x000f) == 0)
+               return phys_addr | input;
+
+       /*
+        * All nibbles are used so no valid physical addresses can be assigned
+        * to the input.
+        */
+       return CEC_PHYS_ADDR_INVALID;
+}
+EXPORT_SYMBOL_GPL(cec_phys_addr_for_input);
+
+int cec_phys_addr_validate(u16 phys_addr, u16 *parent, u16 *port)
+{
+       int i;
+
+       if (parent)
+               *parent = phys_addr;
+       if (port)
+               *port = 0;
+       if (phys_addr == CEC_PHYS_ADDR_INVALID)
+               return 0;
+       for (i = 0; i < 16; i += 4)
+               if (phys_addr & (0xf << i))
+                       break;
+       if (i == 16)
+               return 0;
+       if (parent)
+               *parent = phys_addr & (0xfff0 << i);
+       if (port)
+               *port = (phys_addr >> i) & 0xf;
+       for (i += 4; i < 16; i += 4)
+               if ((phys_addr & (0xf << i)) == 0)
+                       return -EINVAL;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(cec_phys_addr_validate);
diff --git a/drivers/media/cec/cec-notifier.c b/drivers/media/cec/cec-notifier.c
new file mode 100644 (file)
index 0000000..5f5209a
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * cec-notifier.c - notify CEC drivers of physical address changes
+ *
+ * Copyright 2016 Russell King <rmk+kernel@arm.linux.org.uk>
+ * Copyright 2016-2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/export.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/kref.h>
+
+#include <media/cec-notifier.h>
+#include <drm/drm_edid.h>
+
+struct cec_notifier {
+       struct mutex lock;
+       struct list_head head;
+       struct kref kref;
+       struct device *dev;
+       struct cec_adapter *cec_adap;
+       void (*callback)(struct cec_adapter *adap, u16 pa);
+
+       u16 phys_addr;
+};
+
+static LIST_HEAD(cec_notifiers);
+static DEFINE_MUTEX(cec_notifiers_lock);
+
+struct cec_notifier *cec_notifier_get(struct device *dev)
+{
+       struct cec_notifier *n;
+
+       mutex_lock(&cec_notifiers_lock);
+       list_for_each_entry(n, &cec_notifiers, head) {
+               if (n->dev == dev) {
+                       kref_get(&n->kref);
+                       mutex_unlock(&cec_notifiers_lock);
+                       return n;
+               }
+       }
+       n = kzalloc(sizeof(*n), GFP_KERNEL);
+       if (!n)
+               goto unlock;
+       n->dev = dev;
+       n->phys_addr = CEC_PHYS_ADDR_INVALID;
+       mutex_init(&n->lock);
+       kref_init(&n->kref);
+       list_add_tail(&n->head, &cec_notifiers);
+unlock:
+       mutex_unlock(&cec_notifiers_lock);
+       return n;
+}
+EXPORT_SYMBOL_GPL(cec_notifier_get);
+
+static void cec_notifier_release(struct kref *kref)
+{
+       struct cec_notifier *n =
+               container_of(kref, struct cec_notifier, kref);
+
+       list_del(&n->head);
+       kfree(n);
+}
+
+void cec_notifier_put(struct cec_notifier *n)
+{
+       mutex_lock(&cec_notifiers_lock);
+       kref_put(&n->kref, cec_notifier_release);
+       mutex_unlock(&cec_notifiers_lock);
+}
+EXPORT_SYMBOL_GPL(cec_notifier_put);
+
+void cec_notifier_set_phys_addr(struct cec_notifier *n, u16 pa)
+{
+       mutex_lock(&n->lock);
+       n->phys_addr = pa;
+       if (n->callback)
+               n->callback(n->cec_adap, n->phys_addr);
+       mutex_unlock(&n->lock);
+}
+EXPORT_SYMBOL_GPL(cec_notifier_set_phys_addr);
+
+void cec_notifier_set_phys_addr_from_edid(struct cec_notifier *n,
+                                         const struct edid *edid)
+{
+       u16 pa = CEC_PHYS_ADDR_INVALID;
+
+       if (edid && edid->extensions)
+               pa = cec_get_edid_phys_addr((const u8 *)edid,
+                               EDID_LENGTH * (edid->extensions + 1), NULL);
+       cec_notifier_set_phys_addr(n, pa);
+}
+EXPORT_SYMBOL_GPL(cec_notifier_set_phys_addr_from_edid);
+
+void cec_notifier_register(struct cec_notifier *n,
+                          struct cec_adapter *adap,
+                          void (*callback)(struct cec_adapter *adap, u16 pa))
+{
+       kref_get(&n->kref);
+       mutex_lock(&n->lock);
+       n->cec_adap = adap;
+       n->callback = callback;
+       n->callback(adap, n->phys_addr);
+       mutex_unlock(&n->lock);
+}
+EXPORT_SYMBOL_GPL(cec_notifier_register);
+
+void cec_notifier_unregister(struct cec_notifier *n)
+{
+       mutex_lock(&n->lock);
+       n->callback = NULL;
+       mutex_unlock(&n->lock);
+       cec_notifier_put(n);
+}
+EXPORT_SYMBOL_GPL(cec_notifier_unregister);
index b358d1a40688b665911c982698f18329da8ab34b..40bb4bdc51daa30304d58e9e99365f151fd940f9 100644 (file)
@@ -209,7 +209,6 @@ config VIDEO_ADV7604
        depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
        depends on GPIOLIB || COMPILE_TEST
        select HDMI
-       select MEDIA_CEC_EDID
        ---help---
          Support for the Analog Devices ADV7604 video decoder.
 
@@ -221,7 +220,7 @@ config VIDEO_ADV7604
 
 config VIDEO_ADV7604_CEC
        bool "Enable Analog Devices ADV7604 CEC support"
-       depends on VIDEO_ADV7604 && MEDIA_CEC_SUPPORT
+       depends on VIDEO_ADV7604 && CEC_CORE
        ---help---
          When selected the adv7604 will support the optional
          HDMI CEC feature.
@@ -230,7 +229,6 @@ config VIDEO_ADV7842
        tristate "Analog Devices ADV7842 decoder"
        depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
        select HDMI
-       select MEDIA_CEC_EDID
        ---help---
          Support for the Analog Devices ADV7842 video decoder.
 
@@ -242,7 +240,7 @@ config VIDEO_ADV7842
 
 config VIDEO_ADV7842_CEC
        bool "Enable Analog Devices ADV7842 CEC support"
-       depends on VIDEO_ADV7842 && MEDIA_CEC_SUPPORT
+       depends on VIDEO_ADV7842 && CEC_CORE
        ---help---
          When selected the adv7842 will support the optional
          HDMI CEC feature.
@@ -470,7 +468,6 @@ config VIDEO_ADV7511
        tristate "Analog Devices ADV7511 encoder"
        depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
        select HDMI
-       select MEDIA_CEC_EDID
        ---help---
          Support for the Analog Devices ADV7511 video encoder.
 
@@ -481,7 +478,7 @@ config VIDEO_ADV7511
 
 config VIDEO_ADV7511_CEC
        bool "Enable Analog Devices ADV7511 CEC support"
-       depends on VIDEO_ADV7511 && MEDIA_CEC_SUPPORT
+       depends on VIDEO_ADV7511 && CEC_CORE
        ---help---
          When selected the adv7511 will support the optional
          HDMI CEC feature.
index 73c3bc5deadf40753819572e7fb0042d068a364e..ac026ee1ca07484ffa6b0c51632d1c9958c0d3cd 100644 (file)
@@ -461,34 +461,6 @@ config VIDEO_TI_SC
 config VIDEO_TI_CSC
        tristate
 
-menuconfig V4L_CEC_DRIVERS
-       bool "Platform HDMI CEC drivers"
-       depends on MEDIA_CEC_SUPPORT
-
-if V4L_CEC_DRIVERS
-
-config VIDEO_SAMSUNG_S5P_CEC
-       tristate "Samsung S5P CEC driver"
-       depends on VIDEO_DEV && MEDIA_CEC_SUPPORT && (PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST)
-       select MEDIA_CEC_NOTIFIER
-       ---help---
-         This is a driver for Samsung S5P HDMI CEC interface. It uses the
-         generic CEC framework interface.
-         CEC bus is present in the HDMI connector and enables communication
-         between compatible devices.
-
-config VIDEO_STI_HDMI_CEC
-       tristate "STMicroelectronics STiH4xx HDMI CEC driver"
-       depends on VIDEO_DEV && MEDIA_CEC_SUPPORT && (ARCH_STI || COMPILE_TEST)
-       select MEDIA_CEC_NOTIFIER
-       ---help---
-         This is a driver for STIH4xx HDMI CEC interface. It uses the
-         generic CEC framework interface.
-         CEC bus is present in the HDMI connector and enables communication
-         between compatible devices.
-
-endif #V4L_CEC_DRIVERS
-
 menuconfig V4L_TEST_DRIVERS
        bool "Media test drivers"
        depends on MEDIA_CAMERA_SUPPORT
@@ -520,3 +492,31 @@ menuconfig DVB_PLATFORM_DRIVERS
 if DVB_PLATFORM_DRIVERS
 source "drivers/media/platform/sti/c8sectpfe/Kconfig"
 endif #DVB_PLATFORM_DRIVERS
+
+menuconfig CEC_PLATFORM_DRIVERS
+       bool "CEC platform devices"
+       depends on MEDIA_CEC_SUPPORT
+
+if CEC_PLATFORM_DRIVERS
+
+config VIDEO_SAMSUNG_S5P_CEC
+       tristate "Samsung S5P CEC driver"
+       depends on CEC_CORE && (PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST)
+       select MEDIA_CEC_NOTIFIER
+       ---help---
+         This is a driver for Samsung S5P HDMI CEC interface. It uses the
+         generic CEC framework interface.
+         CEC bus is present in the HDMI connector and enables communication
+         between compatible devices.
+
+config VIDEO_STI_HDMI_CEC
+       tristate "STMicroelectronics STiH4xx HDMI CEC driver"
+       depends on CEC_CORE && (ARCH_STI || COMPILE_TEST)
+       select MEDIA_CEC_NOTIFIER
+       ---help---
+         This is a driver for STIH4xx HDMI CEC interface. It uses the
+         generic CEC framework interface.
+         CEC bus is present in the HDMI connector and enables communication
+         between compatible devices.
+
+endif #CEC_PLATFORM_DRIVERS
index 94ab1364a792c88c896db3d754e6524c6742dfb0..b36ac19dc6e48d60afbc4053fb848d9439dfcd5d 100644 (file)
@@ -7,7 +7,6 @@ config VIDEO_VIVID
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
-       select MEDIA_CEC_EDID
        select VIDEOBUF2_VMALLOC
        select VIDEOBUF2_DMA_CONTIG
        select VIDEO_V4L2_TPG
@@ -27,7 +26,7 @@ config VIDEO_VIVID
 
 config VIDEO_VIVID_CEC
        bool "Enable CEC emulation support"
-       depends on VIDEO_VIVID && MEDIA_CEC_SUPPORT
+       depends on VIDEO_VIVID && CEC_CORE
        ---help---
          When selected the vivid module will emulate the optional
          HDMI CEC feature.
index 6ffc407de62fbdde54e575aa5b589938f09fbfc9..8937f3986a01f1c89e3fcc5b6825cb6b754ddf20 100644 (file)
@@ -1,6 +1,6 @@
 config USB_PULSE8_CEC
        tristate "Pulse Eight HDMI CEC"
-       depends on USB_ACM && MEDIA_CEC_SUPPORT
+       depends on USB_ACM && CEC_CORE
        select SERIO
        select SERIO_SERPORT
        ---help---
index 447291b3cca34bdae347cf1b1f13b0a5ff8d77e8..3eb86607efb8f627566af1ff374053d7f6b980ec 100644 (file)
@@ -1,6 +1,6 @@
 config USB_RAINSHADOW_CEC
        tristate "RainShadow Tech HDMI CEC"
-       depends on USB_ACM && MEDIA_CEC_SUPPORT
+       depends on USB_ACM && CEC_CORE
        select SERIO
        select SERIO_SERPORT
        ---help---
index bdf731ecba1a760438a3f4bcf4ccf6d91b9fb90e..242781fd377fba20081354e9636cd62602f1b12c 100644 (file)
@@ -26,6 +26,8 @@
 #define cec_phys_addr_exp(pa) \
        ((pa) >> 12), ((pa) >> 8) & 0xf, ((pa) >> 4) & 0xf, (pa) & 0xf
 
+#if IS_ENABLED(CONFIG_CEC_CORE)
+
 /**
  * cec_get_edid_phys_addr() - find and return the physical address
  *
@@ -101,4 +103,31 @@ u16 cec_phys_addr_for_input(u16 phys_addr, u8 input);
  */
 int cec_phys_addr_validate(u16 phys_addr, u16 *parent, u16 *port);
 
+#else
+
+static inline u16 cec_get_edid_phys_addr(const u8 *edid, unsigned int size,
+                                        unsigned int *offset)
+{
+       if (offset)
+               *offset = 0;
+       return CEC_PHYS_ADDR_INVALID;
+}
+
+static inline void cec_set_edid_phys_addr(u8 *edid, unsigned int size,
+                                         u16 phys_addr)
+{
+}
+
+static inline u16 cec_phys_addr_for_input(u16 phys_addr, u8 input)
+{
+       return CEC_PHYS_ADDR_INVALID;
+}
+
+static inline int cec_phys_addr_validate(u16 phys_addr, u16 *parent, u16 *port)
+{
+       return 0;
+}
+
+#endif
+
 #endif /* _MEDIA_CEC_EDID_H */
index b313e3ecab7049f3fd4ebc3eb845c6149950c964..bae8d0153de77358028c07109e74d5c64d989500 100644 (file)
@@ -204,7 +204,7 @@ static inline bool cec_is_sink(const struct cec_adapter *adap)
        return adap->phys_addr == 0;
 }
 
-#if IS_ENABLED(CONFIG_MEDIA_CEC_SUPPORT)
+#if IS_ENABLED(CONFIG_CEC_CORE)
 struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
                void *priv, const char *name, u32 caps, u8 available_las);
 int cec_register_adapter(struct cec_adapter *adap, struct device *parent);