diff options
Diffstat (limited to 'drivers/media/cec')
| -rw-r--r-- | drivers/media/cec/cec-adap.c | 81 | ||||
| -rw-r--r-- | drivers/media/cec/cec-api.c | 44 | ||||
| -rw-r--r-- | drivers/media/cec/cec-core.c | 27 | ||||
| -rw-r--r-- | drivers/media/cec/cec-priv.h | 2 | 
4 files changed, 66 insertions, 88 deletions
| diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c index 98f88c43f62c..2b1e540587d6 100644 --- a/drivers/media/cec/cec-adap.c +++ b/drivers/media/cec/cec-adap.c @@ -540,7 +540,7 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status,  	unsigned int attempts_made = arb_lost_cnt + nack_cnt +  				     low_drive_cnt + error_cnt; -	dprintk(2, "%s: status %02x\n", __func__, status); +	dprintk(2, "%s: status 0x%02x\n", __func__, status);  	if (attempts_made < 1)  		attempts_made = 1; @@ -1788,9 +1788,6 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg,  	int la_idx = cec_log_addr2idx(adap, dest_laddr);  	bool from_unregistered = init_laddr == 0xf;  	struct cec_msg tx_cec_msg = { }; -#ifdef CONFIG_MEDIA_CEC_RC -	int scancode; -#endif  	dprintk(2, "%s: %*ph\n", __func__, msg->len, msg->msg); @@ -1886,9 +1883,11 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg,  		 */  		case 0x60:  			if (msg->len == 2) -				scancode = msg->msg[2]; +				rc_keydown(adap->rc, RC_PROTO_CEC, +					   msg->msg[2], 0);  			else -				scancode = msg->msg[2] << 8 | msg->msg[3]; +				rc_keydown(adap->rc, RC_PROTO_CEC, +					   msg->msg[2] << 8 | msg->msg[3], 0);  			break;  		/*  		 * Other function messages that are not handled. @@ -1901,54 +1900,11 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg,  		 */  		case 0x56: case 0x57:  		case 0x67: case 0x68: case 0x69: case 0x6a: -			scancode = -1;  			break;  		default: -			scancode = msg->msg[2]; -			break; -		} - -		/* Was repeating, but keypress timed out */ -		if (adap->rc_repeating && !adap->rc->keypressed) { -			adap->rc_repeating = false; -			adap->rc_last_scancode = -1; -		} -		/* Different keypress from last time, ends repeat mode */ -		if (adap->rc_last_scancode != scancode) { -			rc_keyup(adap->rc); -			adap->rc_repeating = false; -		} -		/* We can't handle this scancode */ -		if (scancode < 0) { -			adap->rc_last_scancode = scancode; -			break; -		} - -		/* Send key press */ -		rc_keydown(adap->rc, RC_PROTO_CEC, scancode, 0); - -		/* When in repeating mode, we're done */ -		if (adap->rc_repeating) -			break; - -		/* -		 * We are not repeating, but the new scancode is -		 * the same as the last one, and this second key press is -		 * within 550 ms (the 'Follower Safety Timeout') from the -		 * previous key press, so we now enable the repeating mode. -		 */ -		if (adap->rc_last_scancode == scancode && -		    msg->rx_ts - adap->rc_last_keypress < 550 * NSEC_PER_MSEC) { -			adap->rc_repeating = true; +			rc_keydown(adap->rc, RC_PROTO_CEC, msg->msg[2], 0);  			break;  		} -		/* -		 * Not in repeating mode, so avoid triggering repeat mode -		 * by calling keyup. -		 */ -		rc_keyup(adap->rc); -		adap->rc_last_scancode = scancode; -		adap->rc_last_keypress = msg->rx_ts;  #endif  		break; @@ -1958,8 +1914,6 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg,  			break;  #ifdef CONFIG_MEDIA_CEC_RC  		rc_keyup(adap->rc); -		adap->rc_repeating = false; -		adap->rc_last_scancode = -1;  #endif  		break; @@ -2053,6 +2007,29 @@ void cec_monitor_all_cnt_dec(struct cec_adapter *adap)  		WARN_ON(call_op(adap, adap_monitor_all_enable, 0));  } +/* + * Helper functions to keep track of the 'monitor pin' use count. + * + * These functions are called with adap->lock held. + */ +int cec_monitor_pin_cnt_inc(struct cec_adapter *adap) +{ +	int ret = 0; + +	if (adap->monitor_pin_cnt == 0) +		ret = call_op(adap, adap_monitor_pin_enable, 1); +	if (ret == 0) +		adap->monitor_pin_cnt++; +	return ret; +} + +void cec_monitor_pin_cnt_dec(struct cec_adapter *adap) +{ +	adap->monitor_pin_cnt--; +	if (adap->monitor_pin_cnt == 0) +		WARN_ON(call_op(adap, adap_monitor_pin_enable, 0)); +} +  #ifdef CONFIG_DEBUG_FS  /*   * Log the current state of the CEC adapter. diff --git a/drivers/media/cec/cec-api.c b/drivers/media/cec/cec-api.c index 3dba3aa34a43..492db12b8c4d 100644 --- a/drivers/media/cec/cec-api.c +++ b/drivers/media/cec/cec-api.c @@ -43,24 +43,23 @@ static inline struct cec_devnode *cec_devnode_data(struct file *filp)  /* CEC file operations */ -static unsigned int cec_poll(struct file *filp, +static __poll_t cec_poll(struct file *filp,  			     struct poll_table_struct *poll)  { -	struct cec_devnode *devnode = cec_devnode_data(filp);  	struct cec_fh *fh = filp->private_data;  	struct cec_adapter *adap = fh->adap; -	unsigned int res = 0; +	__poll_t res = 0; -	if (!devnode->registered) -		return POLLERR | POLLHUP; +	if (!cec_is_registered(adap)) +		return EPOLLERR | EPOLLHUP;  	mutex_lock(&adap->lock);  	if (adap->is_configured &&  	    adap->transmit_queue_sz < CEC_MAX_MSG_TX_QUEUE_SZ) -		res |= POLLOUT | POLLWRNORM; +		res |= EPOLLOUT | EPOLLWRNORM;  	if (fh->queued_msgs) -		res |= POLLIN | POLLRDNORM; +		res |= EPOLLIN | EPOLLRDNORM;  	if (fh->total_queued_events) -		res |= POLLPRI; +		res |= EPOLLPRI;  	poll_wait(filp, &fh->wait, poll);  	mutex_unlock(&adap->lock);  	return res; @@ -354,6 +353,7 @@ static long cec_s_mode(struct cec_adapter *adap, struct cec_fh *fh,  	u32 mode;  	u8 mode_initiator;  	u8 mode_follower; +	bool send_pin_event = false;  	long err = 0;  	if (copy_from_user(&mode, parg, sizeof(mode))) @@ -433,6 +433,19 @@ static long cec_s_mode(struct cec_adapter *adap, struct cec_fh *fh,  		}  	} +	if (!err) { +		bool old_mon_pin = fh->mode_follower == CEC_MODE_MONITOR_PIN; +		bool new_mon_pin = mode_follower == CEC_MODE_MONITOR_PIN; + +		if (old_mon_pin != new_mon_pin) { +			send_pin_event = new_mon_pin; +			if (new_mon_pin) +				err = cec_monitor_pin_cnt_inc(adap); +			else +				cec_monitor_pin_cnt_dec(adap); +		} +	} +  	if (err) {  		mutex_unlock(&adap->lock);  		return err; @@ -440,11 +453,9 @@ static long cec_s_mode(struct cec_adapter *adap, struct cec_fh *fh,  	if (fh->mode_follower == CEC_MODE_FOLLOWER)  		adap->follower_cnt--; -	if (fh->mode_follower == CEC_MODE_MONITOR_PIN) -		adap->monitor_pin_cnt--;  	if (mode_follower == CEC_MODE_FOLLOWER)  		adap->follower_cnt++; -	if (mode_follower == CEC_MODE_MONITOR_PIN) { +	if (send_pin_event) {  		struct cec_event ev = {  			.flags = CEC_EVENT_FL_INITIAL_STATE,  		}; @@ -452,7 +463,6 @@ static long cec_s_mode(struct cec_adapter *adap, struct cec_fh *fh,  		ev.event = adap->cec_pin_is_high ? CEC_EVENT_PIN_CEC_HIGH :  						   CEC_EVENT_PIN_CEC_LOW;  		cec_queue_event_fh(fh, &ev, 0); -		adap->monitor_pin_cnt++;  	}  	if (mode_follower == CEC_MODE_EXCL_FOLLOWER ||  	    mode_follower == CEC_MODE_EXCL_FOLLOWER_PASSTHRU) { @@ -475,13 +485,12 @@ static long cec_s_mode(struct cec_adapter *adap, struct cec_fh *fh,  static long cec_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)  { -	struct cec_devnode *devnode = cec_devnode_data(filp);  	struct cec_fh *fh = filp->private_data;  	struct cec_adapter *adap = fh->adap;  	bool block = !(filp->f_flags & O_NONBLOCK);  	void __user *parg = (void __user *)arg; -	if (!devnode->registered) +	if (!cec_is_registered(adap))  		return -ENODEV;  	switch (cmd) { @@ -608,16 +617,15 @@ static int cec_release(struct inode *inode, struct file *filp)  	if (fh->mode_follower == CEC_MODE_FOLLOWER)  		adap->follower_cnt--;  	if (fh->mode_follower == CEC_MODE_MONITOR_PIN) -		adap->monitor_pin_cnt--; +		cec_monitor_pin_cnt_dec(adap);  	if (fh->mode_follower == CEC_MODE_MONITOR_ALL)  		cec_monitor_all_cnt_dec(adap);  	mutex_unlock(&adap->lock);  	mutex_lock(&devnode->lock);  	list_del(&fh->list); -	if (list_empty(&devnode->fhs) && -	    !adap->needs_hpd && -	    adap->phys_addr == CEC_PHYS_ADDR_INVALID) { +	if (cec_is_registered(adap) && list_empty(&devnode->fhs) && +	    !adap->needs_hpd && adap->phys_addr == CEC_PHYS_ADDR_INVALID) {  		WARN_ON(adap->ops->adap_enable(adap, false));  	}  	mutex_unlock(&devnode->lock); diff --git a/drivers/media/cec/cec-core.c b/drivers/media/cec/cec-core.c index 5870da6a567f..a9f9525db9ae 100644 --- a/drivers/media/cec/cec-core.c +++ b/drivers/media/cec/cec-core.c @@ -160,8 +160,9 @@ clr_bit:   * This function can safely be called if the device node has never been   * registered or has already been unregistered.   */ -static void cec_devnode_unregister(struct cec_devnode *devnode) +static void cec_devnode_unregister(struct cec_adapter *adap)  { +	struct cec_devnode *devnode = &adap->devnode;  	struct cec_fh *fh;  	mutex_lock(&devnode->lock); @@ -179,6 +180,11 @@ static void cec_devnode_unregister(struct cec_devnode *devnode)  	devnode->unregistered = true;  	mutex_unlock(&devnode->lock); +	mutex_lock(&adap->lock); +	__cec_s_phys_addr(adap, CEC_PHYS_ADDR_INVALID, false); +	__cec_s_log_addrs(adap, NULL, false); +	mutex_unlock(&adap->lock); +  	cdev_device_del(&devnode->cdev, &devnode->dev);  	put_device(&devnode->dev);  } @@ -192,7 +198,7 @@ static void cec_cec_notify(struct cec_adapter *adap, u16 pa)  void cec_register_cec_notifier(struct cec_adapter *adap,  			       struct cec_notifier *notifier)  { -	if (WARN_ON(!adap->devnode.registered)) +	if (WARN_ON(!cec_is_registered(adap)))  		return;  	adap->notifier = notifier; @@ -280,7 +286,6 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,  	adap->rc->priv = adap;  	adap->rc->map_name = RC_MAP_CEC;  	adap->rc->timeout = MS_TO_NS(100); -	adap->rc_last_scancode = -1;  #endif  	return adap;  } @@ -312,17 +317,6 @@ int cec_register_adapter(struct cec_adapter *adap,  			adap->rc = NULL;  			return res;  		} -		/* -		 * The REP_DELAY for CEC is really the time between the initial -		 * 'User Control Pressed' message and the second. The first -		 * keypress is always seen as non-repeating, the second -		 * (provided it has the same UI Command) will start the 'Press -		 * and Hold' (aka repeat) behavior. By setting REP_DELAY to the -		 * same value as REP_PERIOD the expected CEC behavior is -		 * reproduced. -		 */ -		adap->rc->input_dev->rep[REP_DELAY] = -			adap->rc->input_dev->rep[REP_PERIOD];  	}  #endif @@ -373,7 +367,7 @@ void cec_unregister_adapter(struct cec_adapter *adap)  	if (adap->notifier)  		cec_notifier_unregister(adap->notifier);  #endif -	cec_devnode_unregister(&adap->devnode); +	cec_devnode_unregister(adap);  }  EXPORT_SYMBOL_GPL(cec_unregister_adapter); @@ -381,9 +375,6 @@ void cec_delete_adapter(struct cec_adapter *adap)  {  	if (IS_ERR_OR_NULL(adap))  		return; -	mutex_lock(&adap->lock); -	__cec_s_phys_addr(adap, CEC_PHYS_ADDR_INVALID, false); -	mutex_unlock(&adap->lock);  	kthread_stop(adap->kthread);  	if (adap->kthread_config)  		kthread_stop(adap->kthread_config); diff --git a/drivers/media/cec/cec-priv.h b/drivers/media/cec/cec-priv.h index 70767a7900f2..daf597643af8 100644 --- a/drivers/media/cec/cec-priv.h +++ b/drivers/media/cec/cec-priv.h @@ -40,6 +40,8 @@ void cec_put_device(struct cec_devnode *devnode);  /* cec-adap.c */  int cec_monitor_all_cnt_inc(struct cec_adapter *adap);  void cec_monitor_all_cnt_dec(struct cec_adapter *adap); +int cec_monitor_pin_cnt_inc(struct cec_adapter *adap); +void cec_monitor_pin_cnt_dec(struct cec_adapter *adap);  int cec_adap_status(struct seq_file *file, void *priv);  int cec_thread_func(void *_adap);  void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block); |