Commit f902c1e9 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

[media] 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: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@s-opensource.com>
parent 2613cc6f
...@@ -368,6 +368,8 @@ int cec_thread_func(void *_adap) ...@@ -368,6 +368,8 @@ int cec_thread_func(void *_adap)
* transmit should be canceled. * transmit should be canceled.
*/ */
err = wait_event_interruptible_timeout(adap->kthread_waitq, err = wait_event_interruptible_timeout(adap->kthread_waitq,
(adap->needs_hpd &&
(!adap->is_configured && !adap->is_configuring)) ||
kthread_should_stop() || kthread_should_stop() ||
(!adap->transmitting && (!adap->transmitting &&
!list_empty(&adap->transmit_queue)), !list_empty(&adap->transmit_queue)),
...@@ -383,7 +385,9 @@ int cec_thread_func(void *_adap) ...@@ -383,7 +385,9 @@ int cec_thread_func(void *_adap)
mutex_lock(&adap->lock); mutex_lock(&adap->lock);
if (kthread_should_stop()) { if ((adap->needs_hpd &&
(!adap->is_configured && !adap->is_configuring)) ||
kthread_should_stop()) {
cec_flush(adap); cec_flush(adap);
goto unlock; goto unlock;
} }
...@@ -682,7 +686,7 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, ...@@ -682,7 +686,7 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg,
return -EINVAL; return -EINVAL;
} }
if (!adap->is_configured && !adap->is_configuring) { 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__); dprintk(1, "%s: adapter is unconfigured\n", __func__);
return -ENONET; return -ENONET;
} }
...@@ -1158,6 +1162,8 @@ static int cec_config_log_addr(struct cec_adapter *adap, ...@@ -1158,6 +1162,8 @@ static int cec_config_log_addr(struct cec_adapter *adap,
*/ */
static void cec_adap_unconfigure(struct cec_adapter *adap) static void cec_adap_unconfigure(struct cec_adapter *adap)
{ {
if (!adap->needs_hpd ||
adap->phys_addr != CEC_PHYS_ADDR_INVALID)
WARN_ON(adap->ops->adap_log_addr(adap, CEC_LOG_ADDR_INVALID)); WARN_ON(adap->ops->adap_log_addr(adap, CEC_LOG_ADDR_INVALID));
adap->log_addrs.log_addr_mask = 0; adap->log_addrs.log_addr_mask = 0;
adap->is_configuring = false; adap->is_configuring = false;
...@@ -1387,6 +1393,8 @@ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block) ...@@ -1387,6 +1393,8 @@ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block)
if (phys_addr == adap->phys_addr || adap->devnode.unregistered) if (phys_addr == adap->phys_addr || adap->devnode.unregistered)
return; return;
dprintk(1, "new physical address %x.%x.%x.%x\n",
cec_phys_addr_exp(phys_addr));
if (phys_addr == CEC_PHYS_ADDR_INVALID || if (phys_addr == CEC_PHYS_ADDR_INVALID ||
adap->phys_addr != CEC_PHYS_ADDR_INVALID) { adap->phys_addr != CEC_PHYS_ADDR_INVALID) {
adap->phys_addr = CEC_PHYS_ADDR_INVALID; adap->phys_addr = CEC_PHYS_ADDR_INVALID;
...@@ -1396,7 +1404,7 @@ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block) ...@@ -1396,7 +1404,7 @@ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block)
if (adap->monitor_all_cnt) if (adap->monitor_all_cnt)
WARN_ON(call_op(adap, adap_monitor_all_enable, false)); WARN_ON(call_op(adap, adap_monitor_all_enable, false));
mutex_lock(&adap->devnode.lock); 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)); WARN_ON(adap->ops->adap_enable(adap, false));
mutex_unlock(&adap->devnode.lock); mutex_unlock(&adap->devnode.lock);
if (phys_addr == CEC_PHYS_ADDR_INVALID) if (phys_addr == CEC_PHYS_ADDR_INVALID)
...@@ -1404,7 +1412,7 @@ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block) ...@@ -1404,7 +1412,7 @@ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block)
} }
mutex_lock(&adap->devnode.lock); 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)) { adap->ops->adap_enable(adap, true)) {
mutex_unlock(&adap->devnode.lock); mutex_unlock(&adap->devnode.lock);
return; return;
...@@ -1412,7 +1420,7 @@ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block) ...@@ -1412,7 +1420,7 @@ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block)
if (adap->monitor_all_cnt && if (adap->monitor_all_cnt &&
call_op(adap, adap_monitor_all_enable, true)) { 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)); WARN_ON(adap->ops->adap_enable(adap, false));
mutex_unlock(&adap->devnode.lock); mutex_unlock(&adap->devnode.lock);
return; return;
......
...@@ -202,7 +202,8 @@ static long cec_transmit(struct cec_adapter *adap, struct cec_fh *fh, ...@@ -202,7 +202,8 @@ static long cec_transmit(struct cec_adapter *adap, struct cec_fh *fh,
err = -EPERM; err = -EPERM;
else if (adap->is_configuring) else if (adap->is_configuring)
err = -ENONET; 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; err = -ENONET;
else if (cec_is_busy(adap, fh)) else if (cec_is_busy(adap, fh))
err = -EBUSY; err = -EBUSY;
...@@ -521,6 +522,7 @@ static int cec_open(struct inode *inode, struct file *filp) ...@@ -521,6 +522,7 @@ static int cec_open(struct inode *inode, struct file *filp)
mutex_lock(&devnode->lock); mutex_lock(&devnode->lock);
if (list_empty(&devnode->fhs) && if (list_empty(&devnode->fhs) &&
!adap->needs_hpd &&
adap->phys_addr == CEC_PHYS_ADDR_INVALID) { adap->phys_addr == CEC_PHYS_ADDR_INVALID) {
err = adap->ops->adap_enable(adap, true); err = adap->ops->adap_enable(adap, true);
if (err) { if (err) {
...@@ -565,6 +567,7 @@ static int cec_release(struct inode *inode, struct file *filp) ...@@ -565,6 +567,7 @@ static int cec_release(struct inode *inode, struct file *filp)
mutex_lock(&devnode->lock); mutex_lock(&devnode->lock);
list_del(&fh->list); list_del(&fh->list);
if (list_empty(&devnode->fhs) && if (list_empty(&devnode->fhs) &&
!adap->needs_hpd &&
adap->phys_addr == CEC_PHYS_ADDR_INVALID) { adap->phys_addr == CEC_PHYS_ADDR_INVALID) {
WARN_ON(adap->ops->adap_enable(adap, false)); WARN_ON(adap->ops->adap_enable(adap, false));
} }
......
...@@ -230,6 +230,7 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, ...@@ -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.cec_version = CEC_OP_CEC_VERSION_2_0;
adap->log_addrs.vendor_id = CEC_VENDOR_ID_NONE; adap->log_addrs.vendor_id = CEC_VENDOR_ID_NONE;
adap->capabilities = caps; adap->capabilities = caps;
adap->needs_hpd = caps & CEC_CAP_NEEDS_HPD;
adap->available_log_addrs = available_las; adap->available_log_addrs = available_las;
adap->sequence = 0; adap->sequence = 0;
adap->ops = ops; adap->ops = ops;
......
...@@ -164,6 +164,7 @@ struct cec_adapter { ...@@ -164,6 +164,7 @@ struct cec_adapter {
u8 available_log_addrs; u8 available_log_addrs;
u16 phys_addr; u16 phys_addr;
bool needs_hpd;
bool is_configuring; bool is_configuring;
bool is_configured; bool is_configured;
u32 monitor_all_cnt; u32 monitor_all_cnt;
......
...@@ -336,6 +336,8 @@ static inline int cec_is_unconfigured(__u16 log_addr_mask) ...@@ -336,6 +336,8 @@ static inline int cec_is_unconfigured(__u16 log_addr_mask)
#define CEC_CAP_RC (1 << 4) #define CEC_CAP_RC (1 << 4)
/* Hardware can monitor all messages, not just directed and broadcast. */ /* Hardware can monitor all messages, not just directed and broadcast. */
#define CEC_CAP_MONITOR_ALL (1 << 5) #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. * struct cec_caps - CEC capabilities structure.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment