xref: /linux/drivers/media/test-drivers/vivid/vivid-cec.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * vivid-cec.c - A Virtual Video Test Driver, cec emulation
4  *
5  * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
6  */
7 
8 #include <linux/delay.h>
9 #include <media/cec.h>
10 
11 #include "vivid-core.h"
12 #include "vivid-cec.h"
13 
14 #define CEC_START_BIT_US		4500
15 #define CEC_DATA_BIT_US			2400
16 #define CEC_MARGIN_US			350
17 
18 struct xfer_on_bus {
19 	struct cec_adapter	*adap;
20 	u8			status;
21 };
22 
find_dest_adap(struct vivid_dev * dev,struct cec_adapter * adap,u8 dest)23 static bool find_dest_adap(struct vivid_dev *dev,
24 			   struct cec_adapter *adap, u8 dest)
25 {
26 	unsigned int i, j;
27 
28 	if (dest >= 0xf)
29 		return false;
30 
31 	if (adap != dev->cec_rx_adap && dev->cec_rx_adap &&
32 	    dev->cec_rx_adap->is_configured &&
33 	    cec_has_log_addr(dev->cec_rx_adap, dest))
34 		return true;
35 
36 	for (i = 0, j = 0; i < dev->num_inputs; i++) {
37 		unsigned int menu_idx =
38 			dev->input_is_connected_to_output[i];
39 
40 		if (dev->input_type[i] != HDMI)
41 			continue;
42 		j++;
43 		if (menu_idx < FIXED_MENU_ITEMS)
44 			continue;
45 
46 		struct vivid_dev *dev_tx = vivid_ctrl_hdmi_to_output_instance[menu_idx];
47 		unsigned int output = vivid_ctrl_hdmi_to_output_index[menu_idx];
48 
49 		if (!dev_tx)
50 			continue;
51 
52 		unsigned int hdmi_output = dev_tx->output_to_iface_index[output];
53 
54 		if (adap == dev_tx->cec_tx_adap[hdmi_output])
55 			continue;
56 		if (!dev_tx->cec_tx_adap[hdmi_output]->is_configured)
57 			continue;
58 		if (cec_has_log_addr(dev_tx->cec_tx_adap[hdmi_output], dest))
59 			return true;
60 	}
61 	return false;
62 }
63 
xfer_ready(struct vivid_dev * dev)64 static bool xfer_ready(struct vivid_dev *dev)
65 {
66 	unsigned int i;
67 	bool ready = false;
68 
69 	spin_lock(&dev->cec_xfers_slock);
70 	for (i = 0; i < ARRAY_SIZE(dev->xfers); i++) {
71 		if (dev->xfers[i].sft &&
72 		    dev->xfers[i].sft <= dev->cec_sft) {
73 			ready = true;
74 			break;
75 		}
76 	}
77 	spin_unlock(&dev->cec_xfers_slock);
78 
79 	return ready;
80 }
81 
82 /*
83  * If an adapter tries to send successive messages, it must wait for the
84  * longest signal-free time between its transmissions. But, if another
85  * adapter sends a message in the interim, then the wait can be reduced
86  * because the messages are no longer successive. Make these adjustments
87  * if necessary. Should be called holding cec_xfers_slock.
88  */
adjust_sfts(struct vivid_dev * dev)89 static void adjust_sfts(struct vivid_dev *dev)
90 {
91 	unsigned int i;
92 	u8 initiator;
93 
94 	for (i = 0; i < ARRAY_SIZE(dev->xfers); i++) {
95 		if (dev->xfers[i].sft <= CEC_SIGNAL_FREE_TIME_RETRY)
96 			continue;
97 		initiator = dev->xfers[i].msg[0] >> 4;
98 		if (initiator == dev->last_initiator)
99 			dev->xfers[i].sft = CEC_SIGNAL_FREE_TIME_NEXT_XFER;
100 		else
101 			dev->xfers[i].sft = CEC_SIGNAL_FREE_TIME_NEW_INITIATOR;
102 	}
103 }
104 
105 /*
106  * The main emulation of the bus on which CEC adapters attempt to send
107  * messages to each other. The bus keeps track of how long it has been
108  * signal-free and accepts a pending transmission only if the state of
109  * the bus matches the transmission's signal-free requirements. It calls
110  * cec_transmit_attempt_done() for all transmits that enter the bus and
111  * cec_received_msg() for successful transmits.
112  */
vivid_cec_bus_thread(void * _dev)113 int vivid_cec_bus_thread(void *_dev)
114 {
115 	u32 last_sft;
116 	unsigned int i, j;
117 	unsigned int dest;
118 	ktime_t start, end;
119 	s64 delta_us, retry_us;
120 	struct vivid_dev *dev = _dev;
121 
122 	dev->cec_sft = CEC_SIGNAL_FREE_TIME_NEXT_XFER;
123 	for (;;) {
124 		bool first = true;
125 		int wait_xfer_us = 0;
126 		bool valid_dest = false;
127 		int wait_arb_lost_us = 0;
128 		unsigned int first_idx = 0;
129 		unsigned int first_status = 0;
130 		struct cec_msg first_msg = {};
131 		struct xfer_on_bus xfers_on_bus[MAX_OUTPUTS] = {};
132 
133 		wait_event_interruptible(dev->kthread_waitq_cec, xfer_ready(dev) ||
134 					 kthread_should_stop());
135 		if (kthread_should_stop())
136 			break;
137 		last_sft = dev->cec_sft;
138 		dev->cec_sft = 0;
139 		/*
140 		 * Move the messages that are ready onto the bus. The adapter with
141 		 * the most leading zeros will win control of the bus and any other
142 		 * adapters will lose arbitration.
143 		 */
144 		spin_lock(&dev->cec_xfers_slock);
145 		for (i = 0; i < ARRAY_SIZE(dev->xfers); i++) {
146 			if (!dev->xfers[i].sft || dev->xfers[i].sft > last_sft)
147 				continue;
148 			if (first) {
149 				first = false;
150 				first_idx = i;
151 				xfers_on_bus[first_idx].adap = dev->xfers[i].adap;
152 				memcpy(first_msg.msg, dev->xfers[i].msg, dev->xfers[i].len);
153 				first_msg.len = dev->xfers[i].len;
154 			} else {
155 				xfers_on_bus[i].adap = dev->xfers[i].adap;
156 				xfers_on_bus[i].status = CEC_TX_STATUS_ARB_LOST;
157 				/*
158 				 * For simplicity wait for all 4 bits of the initiator's
159 				 * address even though HDMI specification uses bit-level
160 				 * precision.
161 				 */
162 				wait_arb_lost_us = 4 * CEC_DATA_BIT_US + CEC_START_BIT_US;
163 			}
164 			dev->xfers[i].sft = 0;
165 		}
166 		dev->last_initiator = cec_msg_initiator(&first_msg);
167 		adjust_sfts(dev);
168 		spin_unlock(&dev->cec_xfers_slock);
169 
170 		dest = cec_msg_destination(&first_msg);
171 		valid_dest = cec_msg_is_broadcast(&first_msg);
172 		if (!valid_dest)
173 			valid_dest = find_dest_adap(dev, xfers_on_bus[first_idx].adap, dest);
174 		if (valid_dest) {
175 			first_status = CEC_TX_STATUS_OK;
176 			/*
177 			 * Message length is in bytes, but each byte is transmitted in
178 			 * a block of 10 bits.
179 			 */
180 			wait_xfer_us = first_msg.len * 10 * CEC_DATA_BIT_US;
181 		} else {
182 			first_status = CEC_TX_STATUS_NACK;
183 			/*
184 			 * A message that is not acknowledged stops transmitting after
185 			 * the header block of 10 bits.
186 			 */
187 			wait_xfer_us = 10 * CEC_DATA_BIT_US;
188 		}
189 		wait_xfer_us += CEC_START_BIT_US;
190 		xfers_on_bus[first_idx].status = first_status;
191 
192 		/* Sleep as if sending messages on a real hardware bus. */
193 		start = ktime_get();
194 		if (wait_arb_lost_us) {
195 			usleep_range(wait_arb_lost_us - CEC_MARGIN_US, wait_arb_lost_us);
196 			for (i = 0; i < ARRAY_SIZE(xfers_on_bus); i++) {
197 				if (xfers_on_bus[i].status != CEC_TX_STATUS_ARB_LOST)
198 					continue;
199 				cec_transmit_attempt_done(xfers_on_bus[i].adap,
200 							  CEC_TX_STATUS_ARB_LOST);
201 			}
202 			if (kthread_should_stop())
203 				break;
204 		}
205 		wait_xfer_us -= wait_arb_lost_us;
206 		usleep_range(wait_xfer_us - CEC_MARGIN_US, wait_xfer_us);
207 		cec_transmit_attempt_done(xfers_on_bus[first_idx].adap, first_status);
208 		if (kthread_should_stop())
209 			break;
210 		if (first_status == CEC_TX_STATUS_OK) {
211 			if (xfers_on_bus[first_idx].adap != dev->cec_rx_adap)
212 				cec_received_msg(dev->cec_rx_adap, &first_msg);
213 			for (i = 0, j = 0; i < dev->num_inputs; i++) {
214 				unsigned int menu_idx =
215 					dev->input_is_connected_to_output[i];
216 
217 				if (dev->input_type[i] != HDMI)
218 					continue;
219 				j++;
220 				if (menu_idx < FIXED_MENU_ITEMS)
221 					continue;
222 
223 				struct vivid_dev *dev_tx = vivid_ctrl_hdmi_to_output_instance[menu_idx];
224 				unsigned int output = vivid_ctrl_hdmi_to_output_index[menu_idx];
225 
226 				if (!dev_tx)
227 					continue;
228 
229 				unsigned int hdmi_output = dev_tx->output_to_iface_index[output];
230 
231 				if (xfers_on_bus[first_idx].adap != dev_tx->cec_tx_adap[hdmi_output])
232 					cec_received_msg(dev_tx->cec_tx_adap[hdmi_output], &first_msg);
233 			}
234 		}
235 		end = ktime_get();
236 		/*
237 		 * If the emulated transfer took more or less time than it should
238 		 * have, then compensate by adjusting the wait time needed for the
239 		 * bus to be signal-free for 3 bit periods (the retry time).
240 		 */
241 		delta_us = div_s64(end - start, 1000);
242 		delta_us -= wait_xfer_us + wait_arb_lost_us;
243 		retry_us = CEC_SIGNAL_FREE_TIME_RETRY * CEC_DATA_BIT_US - delta_us;
244 		if (retry_us > CEC_MARGIN_US)
245 			usleep_range(retry_us - CEC_MARGIN_US, retry_us);
246 		dev->cec_sft = CEC_SIGNAL_FREE_TIME_RETRY;
247 		/*
248 		 * If there are no messages that need to be retried, check if any
249 		 * adapters that did not just transmit a message are ready to
250 		 * transmit. If none of these adapters are ready, then increase
251 		 * the signal-free time so that the bus is available to all
252 		 * adapters and go back to waiting for a transmission.
253 		 */
254 		while (dev->cec_sft >= CEC_SIGNAL_FREE_TIME_RETRY &&
255 		       dev->cec_sft < CEC_SIGNAL_FREE_TIME_NEXT_XFER &&
256 		       !xfer_ready(dev) && !kthread_should_stop()) {
257 			usleep_range(2 * CEC_DATA_BIT_US - CEC_MARGIN_US,
258 				     2 * CEC_DATA_BIT_US);
259 			dev->cec_sft += 2;
260 		}
261 	}
262 	return 0;
263 }
264 
vivid_cec_adap_enable(struct cec_adapter * adap,bool enable)265 static int vivid_cec_adap_enable(struct cec_adapter *adap, bool enable)
266 {
267 	adap->cec_pin_is_high = true;
268 	return 0;
269 }
270 
vivid_cec_adap_log_addr(struct cec_adapter * adap,u8 log_addr)271 static int vivid_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
272 {
273 	return 0;
274 }
275 
vivid_cec_adap_transmit(struct cec_adapter * adap,u8 attempts,u32 signal_free_time,struct cec_msg * msg)276 static int vivid_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
277 				   u32 signal_free_time, struct cec_msg *msg)
278 {
279 	struct vivid_dev *dev = cec_get_drvdata(adap);
280 	struct vivid_dev *dev_rx = dev;
281 	u8 idx = cec_msg_initiator(msg);
282 	u8 output = 0;
283 
284 	if (dev->cec_rx_adap != adap) {
285 		int i;
286 
287 		for (i = 0; i < dev->num_hdmi_outputs; i++)
288 			if (dev->cec_tx_adap[i] == adap)
289 				break;
290 		if (i == dev->num_hdmi_outputs)
291 			return -ENONET;
292 		output = dev->hdmi_index_to_output_index[i];
293 		dev_rx = dev->output_to_input_instance[output];
294 		if (!dev_rx)
295 			return -ENONET;
296 	}
297 	spin_lock(&dev_rx->cec_xfers_slock);
298 	dev_rx->xfers[idx].adap = adap;
299 	memcpy(dev_rx->xfers[idx].msg, msg->msg, CEC_MAX_MSG_SIZE);
300 	dev_rx->xfers[idx].len = msg->len;
301 	dev_rx->xfers[idx].sft = CEC_SIGNAL_FREE_TIME_RETRY;
302 	if (signal_free_time > CEC_SIGNAL_FREE_TIME_RETRY) {
303 		if (idx == dev_rx->last_initiator)
304 			dev_rx->xfers[idx].sft = CEC_SIGNAL_FREE_TIME_NEXT_XFER;
305 		else
306 			dev_rx->xfers[idx].sft = CEC_SIGNAL_FREE_TIME_NEW_INITIATOR;
307 	}
308 	spin_unlock(&dev_rx->cec_xfers_slock);
309 	wake_up_interruptible(&dev_rx->kthread_waitq_cec);
310 
311 	return 0;
312 }
313 
vivid_received(struct cec_adapter * adap,struct cec_msg * msg)314 static int vivid_received(struct cec_adapter *adap, struct cec_msg *msg)
315 {
316 	struct vivid_dev *dev = cec_get_drvdata(adap);
317 	struct cec_msg reply;
318 	u8 dest = cec_msg_destination(msg);
319 
320 	if (cec_msg_is_broadcast(msg))
321 		dest = adap->log_addrs.log_addr[0];
322 	cec_msg_init(&reply, dest, cec_msg_initiator(msg));
323 
324 	switch (cec_msg_opcode(msg)) {
325 	case CEC_MSG_SET_OSD_STRING: {
326 		u8 disp_ctl;
327 		char osd[14];
328 
329 		if (!cec_is_sink(adap))
330 			return -ENOMSG;
331 		cec_ops_set_osd_string(msg, &disp_ctl, osd);
332 		switch (disp_ctl) {
333 		case CEC_OP_DISP_CTL_DEFAULT:
334 			strscpy(dev->osd, osd, sizeof(dev->osd));
335 			dev->osd_jiffies = jiffies;
336 			break;
337 		case CEC_OP_DISP_CTL_UNTIL_CLEARED:
338 			strscpy(dev->osd, osd, sizeof(dev->osd));
339 			dev->osd_jiffies = 0;
340 			break;
341 		case CEC_OP_DISP_CTL_CLEAR:
342 			dev->osd[0] = 0;
343 			dev->osd_jiffies = 0;
344 			break;
345 		default:
346 			cec_msg_feature_abort(&reply, cec_msg_opcode(msg),
347 					      CEC_OP_ABORT_INVALID_OP);
348 			cec_transmit_msg(adap, &reply, false);
349 			break;
350 		}
351 		break;
352 	}
353 	case CEC_MSG_VENDOR_COMMAND_WITH_ID: {
354 		u32 vendor_id;
355 		u8 size;
356 		const u8 *vendor_cmd;
357 
358 		/*
359 		 * If we receive <Vendor Command With ID> with our vendor ID
360 		 * and with a payload of size 1, and the payload value is odd,
361 		 * then we reply with the same message, but with the payload
362 		 * byte incremented by 1.
363 		 *
364 		 * If the size is 1 and the payload value is even, then we
365 		 * ignore the message.
366 		 *
367 		 * The reason we reply to odd instead of even payload values
368 		 * is that it allows for testing of the corner case where the
369 		 * reply value is 0 (0xff + 1 % 256).
370 		 *
371 		 * For other sizes we Feature Abort.
372 		 *
373 		 * This is added for the specific purpose of testing the
374 		 * CEC_MSG_FL_REPLY_VENDOR_ID flag using vivid.
375 		 */
376 		cec_ops_vendor_command_with_id(msg, &vendor_id, &size, &vendor_cmd);
377 		if (vendor_id != adap->log_addrs.vendor_id)
378 			break;
379 		if (size == 1) {
380 			// Ignore even op values
381 			if (!(vendor_cmd[0] & 1))
382 				break;
383 			reply.len = msg->len;
384 			memcpy(reply.msg + 1, msg->msg + 1, msg->len - 1);
385 			reply.msg[msg->len - 1]++;
386 		} else {
387 			cec_msg_feature_abort(&reply, cec_msg_opcode(msg),
388 					      CEC_OP_ABORT_INVALID_OP);
389 		}
390 		cec_transmit_msg(adap, &reply, false);
391 		break;
392 	}
393 	default:
394 		return -ENOMSG;
395 	}
396 	return 0;
397 }
398 
399 static const struct cec_adap_ops vivid_cec_adap_ops = {
400 	.adap_enable = vivid_cec_adap_enable,
401 	.adap_log_addr = vivid_cec_adap_log_addr,
402 	.adap_transmit = vivid_cec_adap_transmit,
403 	.received = vivid_received,
404 };
405 
vivid_cec_alloc_adap(struct vivid_dev * dev,unsigned int idx,bool is_source)406 struct cec_adapter *vivid_cec_alloc_adap(struct vivid_dev *dev,
407 					 unsigned int idx,
408 					 bool is_source)
409 {
410 	u32 caps = CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN;
411 	char name[32];
412 
413 	snprintf(name, sizeof(name), "vivid-%03d-vid-%s%d",
414 		 dev->inst, is_source ? "out" : "cap", idx);
415 	return cec_allocate_adapter(&vivid_cec_adap_ops, dev,
416 				    name, caps, CEC_MAX_LOG_ADDRS);
417 }
418