Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a9a249a2 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab
Browse files

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: default avatarHans Verkuil <hans.verkuil@cisco.com>
Acked-by: default avatarSean Young <sean@mess.org>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@s-opensource.com>
parent d57ea877
Loading
Loading
Loading
Loading
+51 −5
Original line number Diff line number Diff line
@@ -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);
	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);

@@ -1855,11 +1858,9 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg,
		 */
		case 0x60:
			if (msg->len == 2)
				rc_keydown(adap->rc, RC_TYPE_CEC,
					   msg->msg[2], 0);
				scancode = msg->msg[2];
			else
				rc_keydown(adap->rc, RC_TYPE_CEC,
					   msg->msg[2] << 8 | msg->msg[3], 0);
				scancode = msg->msg[2] << 8 | msg->msg[3];
			break;
		/*
		 * 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 0x67: case 0x68: case 0x69: case 0x6a:
			scancode = -1;
			break;
		default:
			rc_keydown(adap->rc, RC_TYPE_CEC, msg->msg[2], 0);
			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_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
		break;

@@ -1886,6 +1930,8 @@ 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;

+13 −0
Original line number Diff line number Diff line
@@ -276,9 +276,11 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
	adap->rc->input_id.version = 1;
	adap->rc->driver_name = CEC_NAME;
	adap->rc->allowed_protocols = RC_BIT_CEC;
	adap->rc->enabled_protocols = RC_BIT_CEC;
	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;
}
@@ -310,6 +312,17 @@ 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

+5 −0
Original line number Diff line number Diff line
@@ -190,6 +190,11 @@ struct cec_adapter {

	u32 tx_timeouts;

#ifdef CONFIG_MEDIA_CEC_RC
	bool rc_repeating;
	int rc_last_scancode;
	u64 rc_last_keypress;
#endif
#ifdef CONFIG_CEC_NOTIFIER
	struct cec_notifier *notifier;
#endif