diff options
Diffstat (limited to 'drivers/media/cec')
| -rw-r--r-- | drivers/media/cec/Kconfig | 15 | ||||
| -rw-r--r-- | drivers/media/cec/Makefile | 2 | ||||
| -rw-r--r-- | drivers/media/cec/cec-adap.c | 90 | ||||
| -rw-r--r-- | drivers/media/cec/cec-api.c | 13 | ||||
| -rw-r--r-- | drivers/media/cec/cec-core.c | 9 | 
5 files changed, 83 insertions, 46 deletions
| diff --git a/drivers/media/cec/Kconfig b/drivers/media/cec/Kconfig index f944d93e3167..43428cec3a01 100644 --- a/drivers/media/cec/Kconfig +++ b/drivers/media/cec/Kconfig @@ -1,19 +1,6 @@ -config CEC_CORE -	tristate -	depends on MEDIA_CEC_SUPPORT -	default y - -config MEDIA_CEC_NOTIFIER -	bool -  config MEDIA_CEC_RC  	bool "HDMI CEC RC integration"  	depends on CEC_CORE && RC_CORE +	depends on CEC_CORE=m || RC_CORE=y  	---help---  	  Pass on CEC remote control messages to the RC framework. - -config MEDIA_CEC_DEBUG -	bool "HDMI CEC debugfs interface" -	depends on CEC_CORE && DEBUG_FS -	---help--- -	  Turns on the DebugFS interface for CEC devices. diff --git a/drivers/media/cec/Makefile b/drivers/media/cec/Makefile index 402a6c62a3e8..eaf408e64669 100644 --- a/drivers/media/cec/Makefile +++ b/drivers/media/cec/Makefile @@ -1,6 +1,6 @@  cec-objs := cec-core.o cec-adap.o cec-api.o cec-edid.o -ifeq ($(CONFIG_MEDIA_CEC_NOTIFIER),y) +ifeq ($(CONFIG_CEC_NOTIFIER),y)    cec-objs += cec-notifier.o  endif diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c index f5fe01c9da8a..bf45977b2823 100644 --- a/drivers/media/cec/cec-adap.c +++ b/drivers/media/cec/cec-adap.c @@ -28,6 +28,8 @@  #include <linux/string.h>  #include <linux/types.h> +#include <drm/drm_edid.h> +  #include "cec-priv.h"  static void cec_fill_msg_report_features(struct cec_adapter *adap, @@ -366,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)), @@ -381,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;  		} @@ -392,7 +398,7 @@ int cec_thread_func(void *_adap)  			 * happen and is an indication of a faulty CEC adapter  			 * driver, or the CEC bus is in some weird state.  			 */ -			dprintk(0, "message %*ph timed out!\n", +			dprintk(0, "%s: message %*ph timed out!\n", __func__,  				adap->transmitting->msg.len,  				adap->transmitting->msg.msg);  			/* Just give up on this. */ @@ -468,7 +474,7 @@ void cec_transmit_done(struct cec_adapter *adap, u8 status, u8 arb_lost_cnt,  	struct cec_msg *msg;  	u64 ts = ktime_get_ns(); -	dprintk(2, "cec_transmit_done %02x\n", status); +	dprintk(2, "%s: status %02x\n", __func__, status);  	mutex_lock(&adap->lock);  	data = adap->transmitting;  	if (!data) { @@ -477,7 +483,8 @@ void cec_transmit_done(struct cec_adapter *adap, u8 status, u8 arb_lost_cnt,  		 * unplugged while the transmit is ongoing. Ignore this  		 * transmit in that case.  		 */ -		dprintk(1, "cec_transmit_done without an ongoing transmit!\n"); +		dprintk(1, "%s was called without an ongoing transmit!\n", +			__func__);  		goto unlock;  	} @@ -504,6 +511,12 @@ void cec_transmit_done(struct cec_adapter *adap, u8 status, u8 arb_lost_cnt,  	    !(status & (CEC_TX_STATUS_MAX_RETRIES | CEC_TX_STATUS_OK))) {  		/* Retry this message */  		data->attempts--; +		if (msg->timeout) +			dprintk(2, "retransmit: %*ph (attempts: %d, wait for 0x%02x)\n", +				msg->len, msg->msg, data->attempts, msg->reply); +		else +			dprintk(2, "retransmit: %*ph (attempts: %d)\n", +				msg->len, msg->msg, data->attempts);  		/* Add the message in front of the transmit queue */  		list_add(&data->list, &adap->transmit_queue);  		adap->transmit_queue_sz++; @@ -544,6 +557,32 @@ unlock:  }  EXPORT_SYMBOL_GPL(cec_transmit_done); +void cec_transmit_attempt_done(struct cec_adapter *adap, u8 status) +{ +	switch (status) { +	case CEC_TX_STATUS_OK: +		cec_transmit_done(adap, status, 0, 0, 0, 0); +		return; +	case CEC_TX_STATUS_ARB_LOST: +		cec_transmit_done(adap, status, 1, 0, 0, 0); +		return; +	case CEC_TX_STATUS_NACK: +		cec_transmit_done(adap, status, 0, 1, 0, 0); +		return; +	case CEC_TX_STATUS_LOW_DRIVE: +		cec_transmit_done(adap, status, 0, 0, 1, 0); +		return; +	case CEC_TX_STATUS_ERROR: +		cec_transmit_done(adap, status, 0, 0, 0, 1); +		return; +	default: +		/* Should never happen */ +		WARN(1, "cec-%s: invalid status 0x%02x\n", adap->name, status); +		return; +	} +} +EXPORT_SYMBOL_GPL(cec_transmit_attempt_done); +  /*   * Called when waiting for a reply times out.   */ @@ -647,7 +686,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;  		} @@ -911,7 +950,7 @@ void cec_received_msg(struct cec_adapter *adap, struct cec_msg *msg)  	memset(msg->msg + msg->len, 0, sizeof(msg->msg) - msg->len);  	mutex_lock(&adap->lock); -	dprintk(2, "cec_received_msg: %*ph\n", msg->len, msg->msg); +	dprintk(2, "%s: %*ph\n", __func__, msg->len, msg->msg);  	/* Check if this message was for us (directed or broadcast). */  	if (!cec_msg_is_broadcast(msg)) @@ -1112,9 +1151,6 @@ static int cec_config_log_addr(struct cec_adapter *adap,  	las->log_addr[idx] = log_addr;  	las->log_addr_mask |= 1 << log_addr;  	adap->phys_addrs[log_addr] = adap->phys_addr; - -	dprintk(2, "claimed addr %d (%d)\n", log_addr, -		las->primary_device_type[idx]);  	return 1;  } @@ -1126,7 +1162,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; @@ -1300,7 +1338,7 @@ configured:  		/* Report Physical Address */  		cec_msg_report_physical_addr(&msg, adap->phys_addr,  					     las->primary_device_type[i]); -		dprintk(2, "config: la %d pa %x.%x.%x.%x\n", +		dprintk(1, "config: la %d pa %x.%x.%x.%x\n",  			las->log_addr[i],  			cec_phys_addr_exp(adap->phys_addr));  		cec_transmit_msg_fh(adap, &msg, NULL, false); @@ -1355,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)  		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; @@ -1364,7 +1404,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) @@ -1372,7 +1412,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; @@ -1380,7 +1420,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; @@ -1404,6 +1444,18 @@ void cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block)  }  EXPORT_SYMBOL_GPL(cec_s_phys_addr); +void cec_s_phys_addr_from_edid(struct cec_adapter *adap, +			       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_s_phys_addr(adap, pa, false); +} +EXPORT_SYMBOL_GPL(cec_s_phys_addr_from_edid); +  /*   * Called from either the ioctl or a driver to set the logical addresses.   * @@ -1534,12 +1586,12 @@ int __cec_s_log_addrs(struct cec_adapter *adap,  		if (log_addrs->num_log_addrs == 2) {  			if (!(type_mask & ((1 << CEC_LOG_ADDR_TYPE_AUDIOSYSTEM) |  					   (1 << CEC_LOG_ADDR_TYPE_TV)))) { -				dprintk(1, "Two LAs is only allowed for audiosystem and TV\n"); +				dprintk(1, "two LAs is only allowed for audiosystem and TV\n");  				return -EINVAL;  			}  			if (!(type_mask & ((1 << CEC_LOG_ADDR_TYPE_PLAYBACK) |  					   (1 << CEC_LOG_ADDR_TYPE_RECORD)))) { -				dprintk(1, "An audiosystem/TV can only be combined with record or playback\n"); +				dprintk(1, "an audiosystem/TV can only be combined with record or playback\n");  				return -EINVAL;  			}  		} @@ -1653,7 +1705,7 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg,  	bool from_unregistered = init_laddr == 0xf;  	struct cec_msg tx_cec_msg = { }; -	dprintk(1, "cec_receive_notify: %*ph\n", msg->len, msg->msg); +	dprintk(2, "%s: %*ph\n", __func__, msg->len, msg->msg);  	/* If this is a CDC-Only device, then ignore any non-CDC messages */  	if (cec_is_cdc_only(&adap->log_addrs) && @@ -1722,7 +1774,7 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg,  		if (!from_unregistered)  			adap->phys_addrs[init_laddr] = pa; -		dprintk(1, "Reported physical address %x.%x.%x.%x for logical address %d\n", +		dprintk(1, "reported physical address %x.%x.%x.%x for logical address %d\n",  			cec_phys_addr_exp(pa), init_laddr);  		break;  	} @@ -1864,7 +1916,7 @@ void cec_monitor_all_cnt_dec(struct cec_adapter *adap)  		WARN_ON(call_op(adap, adap_monitor_all_enable, 0));  } -#ifdef CONFIG_MEDIA_CEC_DEBUG +#ifdef CONFIG_DEBUG_FS  /*   * Log the current state of the CEC adapter.   * Very useful for debugging. diff --git a/drivers/media/cec/cec-api.c b/drivers/media/cec/cec-api.c index 0860fb458757..f7eb4c54a354 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; @@ -271,16 +272,10 @@ static long cec_receive(struct cec_adapter *adap, struct cec_fh *fh,  			bool block, struct cec_msg __user *parg)  {  	struct cec_msg msg = {}; -	long err = 0; +	long err;  	if (copy_from_user(&msg, parg, sizeof(msg)))  		return -EFAULT; -	mutex_lock(&adap->lock); -	if (!adap->is_configured && fh->mode_follower < CEC_MODE_MONITOR) -		err = -ENONET; -	mutex_unlock(&adap->lock); -	if (err) -		return err;  	err = cec_receive_msg(fh, &msg, block);  	if (err) @@ -521,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) { @@ -565,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 f9ebff90f8eb..b516d599d6c4 100644 --- a/drivers/media/cec/cec-core.c +++ b/drivers/media/cec/cec-core.c @@ -187,7 +187,7 @@ static void cec_devnode_unregister(struct cec_devnode *devnode)  	put_device(&devnode->dev);  } -#ifdef CONFIG_MEDIA_CEC_NOTIFIER +#ifdef CONFIG_CEC_NOTIFIER  static void cec_cec_notify(struct cec_adapter *adap, u16 pa)  {  	cec_s_phys_addr(adap, pa, false); @@ -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; @@ -323,7 +324,7 @@ int cec_register_adapter(struct cec_adapter *adap,  	}  	dev_set_drvdata(&adap->devnode.dev, adap); -#ifdef CONFIG_MEDIA_CEC_DEBUG +#ifdef CONFIG_DEBUG_FS  	if (!top_cec_dir)  		return 0; @@ -355,7 +356,7 @@ void cec_unregister_adapter(struct cec_adapter *adap)  	adap->rc = NULL;  #endif  	debugfs_remove_recursive(adap->cec_dir); -#ifdef CONFIG_MEDIA_CEC_NOTIFIER +#ifdef CONFIG_CEC_NOTIFIER  	if (adap->notifier)  		cec_notifier_unregister(adap->notifier);  #endif @@ -395,7 +396,7 @@ static int __init cec_devnode_init(void)  		return ret;  	} -#ifdef CONFIG_MEDIA_CEC_DEBUG +#ifdef CONFIG_DEBUG_FS  	top_cec_dir = debugfs_create_dir("cec", NULL);  	if (IS_ERR_OR_NULL(top_cec_dir)) {  		pr_warn("cec: Failed to create debugfs cec dir\n"); |