forked from mirrors/linux
		
	media: cec: fix remote control passthrough
The 'Press and Hold' operation was not correctly implemented, in particular the requirement that the repeat doesn't start until the second identical keypress arrives. The REP_DELAY value also had to be adjusted (see the comment in the code) to achieve the desired behavior. The 'enabled_protocols' field was also never set, fix that too. Since CEC is a fixed protocol the driver has to set this field. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Acked-by: Sean Young <sean@mess.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
This commit is contained in:
		
							parent
							
								
									d57ea877af
								
							
						
					
					
						commit
						a9a249a2c9
					
				
					 3 changed files with 69 additions and 5 deletions
				
			
		|  | @ -1767,6 +1767,9 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg, | ||||||
| 	int la_idx = cec_log_addr2idx(adap, dest_laddr); | 	int la_idx = cec_log_addr2idx(adap, dest_laddr); | ||||||
| 	bool from_unregistered = init_laddr == 0xf; | 	bool from_unregistered = init_laddr == 0xf; | ||||||
| 	struct cec_msg tx_cec_msg = { }; | 	struct cec_msg tx_cec_msg = { }; | ||||||
|  | #ifdef CONFIG_MEDIA_CEC_RC | ||||||
|  | 	int scancode; | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| 	dprintk(2, "%s: %*ph\n", __func__, msg->len, msg->msg); | 	dprintk(2, "%s: %*ph\n", __func__, msg->len, msg->msg); | ||||||
| 
 | 
 | ||||||
|  | @ -1855,11 +1858,9 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg, | ||||||
| 		 */ | 		 */ | ||||||
| 		case 0x60: | 		case 0x60: | ||||||
| 			if (msg->len == 2) | 			if (msg->len == 2) | ||||||
| 				rc_keydown(adap->rc, RC_TYPE_CEC, | 				scancode = msg->msg[2]; | ||||||
| 					   msg->msg[2], 0); |  | ||||||
| 			else | 			else | ||||||
| 				rc_keydown(adap->rc, RC_TYPE_CEC, | 				scancode = msg->msg[2] << 8 | msg->msg[3]; | ||||||
| 					   msg->msg[2] << 8 | msg->msg[3], 0); |  | ||||||
| 			break; | 			break; | ||||||
| 		/*
 | 		/*
 | ||||||
| 		 * Other function messages that are not handled. | 		 * Other function messages that are not handled. | ||||||
|  | @ -1872,11 +1873,54 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg, | ||||||
| 		 */ | 		 */ | ||||||
| 		case 0x56: case 0x57: | 		case 0x56: case 0x57: | ||||||
| 		case 0x67: case 0x68: case 0x69: case 0x6a: | 		case 0x67: case 0x68: case 0x69: case 0x6a: | ||||||
|  | 			scancode = -1; | ||||||
| 			break; | 			break; | ||||||
| 		default: | 		default: | ||||||
| 			rc_keydown(adap->rc, RC_TYPE_CEC, msg->msg[2], 0); | 			scancode = msg->msg[2]; | ||||||
| 			break; | 			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_TYPE_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; | ||||||
|  | 			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 | #endif | ||||||
| 		break; | 		break; | ||||||
| 
 | 
 | ||||||
|  | @ -1886,6 +1930,8 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg, | ||||||
| 			break; | 			break; | ||||||
| #ifdef CONFIG_MEDIA_CEC_RC | #ifdef CONFIG_MEDIA_CEC_RC | ||||||
| 		rc_keyup(adap->rc); | 		rc_keyup(adap->rc); | ||||||
|  | 		adap->rc_repeating = false; | ||||||
|  | 		adap->rc_last_scancode = -1; | ||||||
| #endif | #endif | ||||||
| 		break; | 		break; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -276,9 +276,11 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, | ||||||
| 	adap->rc->input_id.version = 1; | 	adap->rc->input_id.version = 1; | ||||||
| 	adap->rc->driver_name = CEC_NAME; | 	adap->rc->driver_name = CEC_NAME; | ||||||
| 	adap->rc->allowed_protocols = RC_BIT_CEC; | 	adap->rc->allowed_protocols = RC_BIT_CEC; | ||||||
|  | 	adap->rc->enabled_protocols = RC_BIT_CEC; | ||||||
| 	adap->rc->priv = adap; | 	adap->rc->priv = adap; | ||||||
| 	adap->rc->map_name = RC_MAP_CEC; | 	adap->rc->map_name = RC_MAP_CEC; | ||||||
| 	adap->rc->timeout = MS_TO_NS(100); | 	adap->rc->timeout = MS_TO_NS(100); | ||||||
|  | 	adap->rc_last_scancode = -1; | ||||||
| #endif | #endif | ||||||
| 	return adap; | 	return adap; | ||||||
| } | } | ||||||
|  | @ -310,6 +312,17 @@ int cec_register_adapter(struct cec_adapter *adap, | ||||||
| 			adap->rc = NULL; | 			adap->rc = NULL; | ||||||
| 			return res; | 			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 | #endif | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -190,6 +190,11 @@ struct cec_adapter { | ||||||
| 
 | 
 | ||||||
| 	u32 tx_timeouts; | 	u32 tx_timeouts; | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_MEDIA_CEC_RC | ||||||
|  | 	bool rc_repeating; | ||||||
|  | 	int rc_last_scancode; | ||||||
|  | 	u64 rc_last_keypress; | ||||||
|  | #endif | ||||||
| #ifdef CONFIG_CEC_NOTIFIER | #ifdef CONFIG_CEC_NOTIFIER | ||||||
| 	struct cec_notifier *notifier; | 	struct cec_notifier *notifier; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Hans Verkuil
						Hans Verkuil