177 lines
6.6 KiB
Diff
177 lines
6.6 KiB
Diff
From e4826bb782c7fca70e8c1b7cbe1bb726400399b5 Mon Sep 17 00:00:00 2001
|
|
From: Hans Verkuil <hans.verkuil@cisco.com>
|
|
Date: Wed, 7 Jun 2017 11:46:12 -0300
|
|
Subject: [PATCH 25/79] cec: add CEC_CAP_NEEDS_HPD
|
|
|
|
Add a new capability CEC_CAP_NEEDS_HPD. If this capability is set
|
|
then the hardware can only use CEC if the HDMI Hotplug Detect pin
|
|
is high. Such hardware cannot handle the corner case in the CEC specification
|
|
where it is possible to transmit messages even if no hotplug signal is
|
|
present (needed for some displays that turn off the HPD when in standby,
|
|
but still have CEC enabled).
|
|
|
|
Typically hardware that needs this capability have the HPD wired to the CEC
|
|
block, often to a 'power' or 'active' pin.
|
|
|
|
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
|
|
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
|
|
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
|
---
|
|
drivers/media/cec/cec-adap.c | 20 ++++++++++++++------
|
|
drivers/media/cec/cec-api.c | 5 ++++-
|
|
drivers/media/cec/cec-core.c | 1 +
|
|
include/media/cec.h | 1 +
|
|
include/uapi/linux/cec.h | 2 ++
|
|
5 files changed, 22 insertions(+), 7 deletions(-)
|
|
|
|
diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c
|
|
index 193cea1..ab82e84 100644
|
|
--- a/drivers/media/cec/cec-adap.c
|
|
+++ b/drivers/media/cec/cec-adap.c
|
|
@@ -368,6 +368,8 @@ int cec_thread_func(void *_adap)
|
|
* transmit should be canceled.
|
|
*/
|
|
err = wait_event_interruptible_timeout(adap->kthread_waitq,
|
|
+ (adap->needs_hpd &&
|
|
+ (!adap->is_configured && !adap->is_configuring)) ||
|
|
kthread_should_stop() ||
|
|
(!adap->transmitting &&
|
|
!list_empty(&adap->transmit_queue)),
|
|
@@ -383,7 +385,9 @@ int cec_thread_func(void *_adap)
|
|
|
|
mutex_lock(&adap->lock);
|
|
|
|
- if (kthread_should_stop()) {
|
|
+ if ((adap->needs_hpd &&
|
|
+ (!adap->is_configured && !adap->is_configuring)) ||
|
|
+ kthread_should_stop()) {
|
|
cec_flush(adap);
|
|
goto unlock;
|
|
}
|
|
@@ -675,7 +679,7 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg,
|
|
return -EINVAL;
|
|
}
|
|
if (!adap->is_configured && !adap->is_configuring) {
|
|
- if (msg->msg[0] != 0xf0) {
|
|
+ if (adap->needs_hpd || msg->msg[0] != 0xf0) {
|
|
dprintk(1, "%s: adapter is unconfigured\n", __func__);
|
|
return -ENONET;
|
|
}
|
|
@@ -1154,7 +1158,9 @@ static int cec_config_log_addr(struct cec_adapter *adap,
|
|
*/
|
|
static void cec_adap_unconfigure(struct cec_adapter *adap)
|
|
{
|
|
- WARN_ON(adap->ops->adap_log_addr(adap, CEC_LOG_ADDR_INVALID));
|
|
+ if (!adap->needs_hpd ||
|
|
+ adap->phys_addr != CEC_PHYS_ADDR_INVALID)
|
|
+ WARN_ON(adap->ops->adap_log_addr(adap, CEC_LOG_ADDR_INVALID));
|
|
adap->log_addrs.log_addr_mask = 0;
|
|
adap->is_configuring = false;
|
|
adap->is_configured = false;
|
|
@@ -1383,6 +1389,8 @@ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block)
|
|
if (phys_addr == adap->phys_addr || adap->devnode.unregistered)
|
|
return;
|
|
|
|
+ dprintk(1, "new physical address %x.%x.%x.%x\n",
|
|
+ cec_phys_addr_exp(phys_addr));
|
|
if (phys_addr == CEC_PHYS_ADDR_INVALID ||
|
|
adap->phys_addr != CEC_PHYS_ADDR_INVALID) {
|
|
adap->phys_addr = CEC_PHYS_ADDR_INVALID;
|
|
@@ -1392,7 +1400,7 @@ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block)
|
|
if (adap->monitor_all_cnt)
|
|
WARN_ON(call_op(adap, adap_monitor_all_enable, false));
|
|
mutex_lock(&adap->devnode.lock);
|
|
- if (list_empty(&adap->devnode.fhs))
|
|
+ if (adap->needs_hpd || list_empty(&adap->devnode.fhs))
|
|
WARN_ON(adap->ops->adap_enable(adap, false));
|
|
mutex_unlock(&adap->devnode.lock);
|
|
if (phys_addr == CEC_PHYS_ADDR_INVALID)
|
|
@@ -1400,7 +1408,7 @@ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block)
|
|
}
|
|
|
|
mutex_lock(&adap->devnode.lock);
|
|
- if (list_empty(&adap->devnode.fhs) &&
|
|
+ if ((adap->needs_hpd || list_empty(&adap->devnode.fhs)) &&
|
|
adap->ops->adap_enable(adap, true)) {
|
|
mutex_unlock(&adap->devnode.lock);
|
|
return;
|
|
@@ -1408,7 +1416,7 @@ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block)
|
|
|
|
if (adap->monitor_all_cnt &&
|
|
call_op(adap, adap_monitor_all_enable, true)) {
|
|
- if (list_empty(&adap->devnode.fhs))
|
|
+ if (adap->needs_hpd || list_empty(&adap->devnode.fhs))
|
|
WARN_ON(adap->ops->adap_enable(adap, false));
|
|
mutex_unlock(&adap->devnode.lock);
|
|
return;
|
|
diff --git a/drivers/media/cec/cec-api.c b/drivers/media/cec/cec-api.c
|
|
index 999926f..f7eb4c5 100644
|
|
--- a/drivers/media/cec/cec-api.c
|
|
+++ b/drivers/media/cec/cec-api.c
|
|
@@ -202,7 +202,8 @@ static long cec_transmit(struct cec_adapter *adap, struct cec_fh *fh,
|
|
err = -EPERM;
|
|
else if (adap->is_configuring)
|
|
err = -ENONET;
|
|
- else if (!adap->is_configured && msg.msg[0] != 0xf0)
|
|
+ else if (!adap->is_configured &&
|
|
+ (adap->needs_hpd || msg.msg[0] != 0xf0))
|
|
err = -ENONET;
|
|
else if (cec_is_busy(adap, fh))
|
|
err = -EBUSY;
|
|
@@ -515,6 +516,7 @@ static int cec_open(struct inode *inode, struct file *filp)
|
|
|
|
mutex_lock(&devnode->lock);
|
|
if (list_empty(&devnode->fhs) &&
|
|
+ !adap->needs_hpd &&
|
|
adap->phys_addr == CEC_PHYS_ADDR_INVALID) {
|
|
err = adap->ops->adap_enable(adap, true);
|
|
if (err) {
|
|
@@ -559,6 +561,7 @@ static int cec_release(struct inode *inode, struct file *filp)
|
|
mutex_lock(&devnode->lock);
|
|
list_del(&fh->list);
|
|
if (list_empty(&devnode->fhs) &&
|
|
+ !adap->needs_hpd &&
|
|
adap->phys_addr == CEC_PHYS_ADDR_INVALID) {
|
|
WARN_ON(adap->ops->adap_enable(adap, false));
|
|
}
|
|
diff --git a/drivers/media/cec/cec-core.c b/drivers/media/cec/cec-core.c
|
|
index 2f87748..b516d59 100644
|
|
--- a/drivers/media/cec/cec-core.c
|
|
+++ b/drivers/media/cec/cec-core.c
|
|
@@ -230,6 +230,7 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
|
|
adap->log_addrs.cec_version = CEC_OP_CEC_VERSION_2_0;
|
|
adap->log_addrs.vendor_id = CEC_VENDOR_ID_NONE;
|
|
adap->capabilities = caps;
|
|
+ adap->needs_hpd = caps & CEC_CAP_NEEDS_HPD;
|
|
adap->available_log_addrs = available_las;
|
|
adap->sequence = 0;
|
|
adap->ops = ops;
|
|
diff --git a/include/media/cec.h b/include/media/cec.h
|
|
index 23c1faa..56643b2 100644
|
|
--- a/include/media/cec.h
|
|
+++ b/include/media/cec.h
|
|
@@ -164,6 +164,7 @@ struct cec_adapter {
|
|
u8 available_log_addrs;
|
|
|
|
u16 phys_addr;
|
|
+ bool needs_hpd;
|
|
bool is_configuring;
|
|
bool is_configured;
|
|
u32 monitor_all_cnt;
|
|
diff --git a/include/uapi/linux/cec.h b/include/uapi/linux/cec.h
|
|
index a0dfe27..44579a2 100644
|
|
--- a/include/uapi/linux/cec.h
|
|
+++ b/include/uapi/linux/cec.h
|
|
@@ -336,6 +336,8 @@ static inline int cec_is_unconfigured(__u16 log_addr_mask)
|
|
#define CEC_CAP_RC (1 << 4)
|
|
/* Hardware can monitor all messages, not just directed and broadcast. */
|
|
#define CEC_CAP_MONITOR_ALL (1 << 5)
|
|
+/* Hardware can use CEC only if the HDMI HPD pin is high. */
|
|
+#define CEC_CAP_NEEDS_HPD (1 << 6)
|
|
|
|
/**
|
|
* struct cec_caps - CEC capabilities structure.
|
|
--
|
|
1.9.1
|
|
|