• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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;
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; i < MAX_OUTPUTS && dev->cec_tx_adap[i]; i++) {
37 		if (adap == dev->cec_tx_adap[i])
38 			continue;
39 		if (!dev->cec_tx_adap[i]->is_configured)
40 			continue;
41 		if (cec_has_log_addr(dev->cec_tx_adap[i], dest))
42 			return true;
43 	}
44 	return false;
45 }
46 
xfer_ready(struct vivid_dev * dev)47 static bool xfer_ready(struct vivid_dev *dev)
48 {
49 	unsigned int i;
50 	bool ready = false;
51 
52 	spin_lock(&dev->cec_xfers_slock);
53 	for (i = 0; i < ARRAY_SIZE(dev->xfers); i++) {
54 		if (dev->xfers[i].sft &&
55 		    dev->xfers[i].sft <= dev->cec_sft) {
56 			ready = true;
57 			break;
58 		}
59 	}
60 	spin_unlock(&dev->cec_xfers_slock);
61 
62 	return ready;
63 }
64 
65 /*
66  * If an adapter tries to send successive messages, it must wait for the
67  * longest signal-free time between its transmissions. But, if another
68  * adapter sends a message in the interim, then the wait can be reduced
69  * because the messages are no longer successive. Make these adjustments
70  * if necessary. Should be called holding cec_xfers_slock.
71  */
adjust_sfts(struct vivid_dev * dev)72 static void adjust_sfts(struct vivid_dev *dev)
73 {
74 	unsigned int i;
75 	u8 initiator;
76 
77 	for (i = 0; i < ARRAY_SIZE(dev->xfers); i++) {
78 		if (dev->xfers[i].sft <= CEC_SIGNAL_FREE_TIME_RETRY)
79 			continue;
80 		initiator = dev->xfers[i].msg[0] >> 4;
81 		if (initiator == dev->last_initiator)
82 			dev->xfers[i].sft = CEC_SIGNAL_FREE_TIME_NEXT_XFER;
83 		else
84 			dev->xfers[i].sft = CEC_SIGNAL_FREE_TIME_NEW_INITIATOR;
85 	}
86 }
87 
88 /*
89  * The main emulation of the bus on which CEC adapters attempt to send
90  * messages to each other. The bus keeps track of how long it has been
91  * signal-free and accepts a pending transmission only if the state of
92  * the bus matches the transmission's signal-free requirements. It calls
93  * cec_transmit_attempt_done() for all transmits that enter the bus and
94  * cec_received_msg() for successful transmits.
95  */
vivid_cec_bus_thread(void * _dev)96 int vivid_cec_bus_thread(void *_dev)
97 {
98 	u32 last_sft;
99 	unsigned int i;
100 	unsigned int dest;
101 	ktime_t start, end;
102 	s64 delta_us, retry_us;
103 	struct vivid_dev *dev = _dev;
104 
105 	dev->cec_sft = CEC_SIGNAL_FREE_TIME_NEXT_XFER;
106 	for (;;) {
107 		bool first = true;
108 		int wait_xfer_us = 0;
109 		bool valid_dest = false;
110 		int wait_arb_lost_us = 0;
111 		unsigned int first_idx = 0;
112 		unsigned int first_status = 0;
113 		struct cec_msg first_msg = {};
114 		struct xfer_on_bus xfers_on_bus[MAX_OUTPUTS] = {};
115 
116 		wait_event_interruptible(dev->kthread_waitq_cec, xfer_ready(dev) ||
117 					 kthread_should_stop());
118 		if (kthread_should_stop())
119 			break;
120 		last_sft = dev->cec_sft;
121 		dev->cec_sft = 0;
122 		/*
123 		 * Move the messages that are ready onto the bus. The adapter with
124 		 * the most leading zeros will win control of the bus and any other
125 		 * adapters will lose arbitration.
126 		 */
127 		spin_lock(&dev->cec_xfers_slock);
128 		for (i = 0; i < ARRAY_SIZE(dev->xfers); i++) {
129 			if (!dev->xfers[i].sft || dev->xfers[i].sft > last_sft)
130 				continue;
131 			if (first) {
132 				first = false;
133 				first_idx = i;
134 				xfers_on_bus[first_idx].adap = dev->xfers[i].adap;
135 				memcpy(first_msg.msg, dev->xfers[i].msg, dev->xfers[i].len);
136 				first_msg.len = dev->xfers[i].len;
137 			} else {
138 				xfers_on_bus[i].adap = dev->xfers[i].adap;
139 				xfers_on_bus[i].status = CEC_TX_STATUS_ARB_LOST;
140 				/*
141 				 * For simplicity wait for all 4 bits of the initiator's
142 				 * address even though HDMI specification uses bit-level
143 				 * precision.
144 				 */
145 				wait_arb_lost_us = 4 * CEC_DATA_BIT_US + CEC_START_BIT_US;
146 			}
147 			dev->xfers[i].sft = 0;
148 		}
149 		dev->last_initiator = cec_msg_initiator(&first_msg);
150 		adjust_sfts(dev);
151 		spin_unlock(&dev->cec_xfers_slock);
152 
153 		dest = cec_msg_destination(&first_msg);
154 		valid_dest = cec_msg_is_broadcast(&first_msg);
155 		if (!valid_dest)
156 			valid_dest = find_dest_adap(dev, xfers_on_bus[first_idx].adap, dest);
157 		if (valid_dest) {
158 			first_status = CEC_TX_STATUS_OK;
159 			/*
160 			 * Message length is in bytes, but each byte is transmitted in
161 			 * a block of 10 bits.
162 			 */
163 			wait_xfer_us = first_msg.len * 10 * CEC_DATA_BIT_US;
164 		} else {
165 			first_status = CEC_TX_STATUS_NACK;
166 			/*
167 			 * A message that is not acknowledged stops transmitting after
168 			 * the header block of 10 bits.
169 			 */
170 			wait_xfer_us = 10 * CEC_DATA_BIT_US;
171 		}
172 		wait_xfer_us += CEC_START_BIT_US;
173 		xfers_on_bus[first_idx].status = first_status;
174 
175 		/* Sleep as if sending messages on a real hardware bus. */
176 		start = ktime_get();
177 		if (wait_arb_lost_us) {
178 			usleep_range(wait_arb_lost_us - CEC_MARGIN_US, wait_arb_lost_us);
179 			for (i = 0; i < ARRAY_SIZE(xfers_on_bus); i++) {
180 				if (xfers_on_bus[i].status != CEC_TX_STATUS_ARB_LOST)
181 					continue;
182 				cec_transmit_attempt_done(xfers_on_bus[i].adap,
183 							  CEC_TX_STATUS_ARB_LOST);
184 			}
185 			if (kthread_should_stop())
186 				break;
187 		}
188 		wait_xfer_us -= wait_arb_lost_us;
189 		usleep_range(wait_xfer_us - CEC_MARGIN_US, wait_xfer_us);
190 		cec_transmit_attempt_done(xfers_on_bus[first_idx].adap, first_status);
191 		if (kthread_should_stop())
192 			break;
193 		if (first_status == CEC_TX_STATUS_OK) {
194 			if (xfers_on_bus[first_idx].adap != dev->cec_rx_adap)
195 				cec_received_msg(dev->cec_rx_adap, &first_msg);
196 			for (i = 0; i < MAX_OUTPUTS && dev->cec_tx_adap[i]; i++)
197 				if (xfers_on_bus[first_idx].adap != dev->cec_tx_adap[i])
198 					cec_received_msg(dev->cec_tx_adap[i], &first_msg);
199 		}
200 		end = ktime_get();
201 		/*
202 		 * If the emulated transfer took more or less time than it should
203 		 * have, then compensate by adjusting the wait time needed for the
204 		 * bus to be signal-free for 3 bit periods (the retry time).
205 		 */
206 		delta_us = div_s64(end - start, 1000);
207 		delta_us -= wait_xfer_us + wait_arb_lost_us;
208 		retry_us = CEC_SIGNAL_FREE_TIME_RETRY * CEC_DATA_BIT_US - delta_us;
209 		if (retry_us > CEC_MARGIN_US)
210 			usleep_range(retry_us - CEC_MARGIN_US, retry_us);
211 		dev->cec_sft = CEC_SIGNAL_FREE_TIME_RETRY;
212 		/*
213 		 * If there are no messages that need to be retried, check if any
214 		 * adapters that did not just transmit a message are ready to
215 		 * transmit. If none of these adapters are ready, then increase
216 		 * the signal-free time so that the bus is available to all
217 		 * adapters and go back to waiting for a transmission.
218 		 */
219 		while (dev->cec_sft >= CEC_SIGNAL_FREE_TIME_RETRY &&
220 		       dev->cec_sft < CEC_SIGNAL_FREE_TIME_NEXT_XFER &&
221 		       !xfer_ready(dev) && !kthread_should_stop()) {
222 			usleep_range(2 * CEC_DATA_BIT_US - CEC_MARGIN_US,
223 				     2 * CEC_DATA_BIT_US);
224 			dev->cec_sft += 2;
225 		}
226 	}
227 	return 0;
228 }
229 
vivid_cec_adap_enable(struct cec_adapter * adap,bool enable)230 static int vivid_cec_adap_enable(struct cec_adapter *adap, bool enable)
231 {
232 	adap->cec_pin_is_high = true;
233 	return 0;
234 }
235 
vivid_cec_adap_log_addr(struct cec_adapter * adap,u8 log_addr)236 static int vivid_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
237 {
238 	return 0;
239 }
240 
vivid_cec_adap_transmit(struct cec_adapter * adap,u8 attempts,u32 signal_free_time,struct cec_msg * msg)241 static int vivid_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
242 				   u32 signal_free_time, struct cec_msg *msg)
243 {
244 	struct vivid_dev *dev = cec_get_drvdata(adap);
245 	u8 idx = cec_msg_initiator(msg);
246 
247 	spin_lock(&dev->cec_xfers_slock);
248 	dev->xfers[idx].adap = adap;
249 	memcpy(dev->xfers[idx].msg, msg->msg, CEC_MAX_MSG_SIZE);
250 	dev->xfers[idx].len = msg->len;
251 	dev->xfers[idx].sft = CEC_SIGNAL_FREE_TIME_RETRY;
252 	if (signal_free_time > CEC_SIGNAL_FREE_TIME_RETRY) {
253 		if (idx == dev->last_initiator)
254 			dev->xfers[idx].sft = CEC_SIGNAL_FREE_TIME_NEXT_XFER;
255 		else
256 			dev->xfers[idx].sft = CEC_SIGNAL_FREE_TIME_NEW_INITIATOR;
257 	}
258 	spin_unlock(&dev->cec_xfers_slock);
259 	wake_up_interruptible(&dev->kthread_waitq_cec);
260 
261 	return 0;
262 }
263 
vivid_received(struct cec_adapter * adap,struct cec_msg * msg)264 static int vivid_received(struct cec_adapter *adap, struct cec_msg *msg)
265 {
266 	struct vivid_dev *dev = cec_get_drvdata(adap);
267 	struct cec_msg reply;
268 	u8 dest = cec_msg_destination(msg);
269 	u8 disp_ctl;
270 	char osd[14];
271 
272 	if (cec_msg_is_broadcast(msg))
273 		dest = adap->log_addrs.log_addr[0];
274 	cec_msg_init(&reply, dest, cec_msg_initiator(msg));
275 
276 	switch (cec_msg_opcode(msg)) {
277 	case CEC_MSG_SET_OSD_STRING:
278 		if (!cec_is_sink(adap))
279 			return -ENOMSG;
280 		cec_ops_set_osd_string(msg, &disp_ctl, osd);
281 		switch (disp_ctl) {
282 		case CEC_OP_DISP_CTL_DEFAULT:
283 			strscpy(dev->osd, osd, sizeof(dev->osd));
284 			dev->osd_jiffies = jiffies;
285 			break;
286 		case CEC_OP_DISP_CTL_UNTIL_CLEARED:
287 			strscpy(dev->osd, osd, sizeof(dev->osd));
288 			dev->osd_jiffies = 0;
289 			break;
290 		case CEC_OP_DISP_CTL_CLEAR:
291 			dev->osd[0] = 0;
292 			dev->osd_jiffies = 0;
293 			break;
294 		default:
295 			cec_msg_feature_abort(&reply, cec_msg_opcode(msg),
296 					      CEC_OP_ABORT_INVALID_OP);
297 			cec_transmit_msg(adap, &reply, false);
298 			break;
299 		}
300 		break;
301 	default:
302 		return -ENOMSG;
303 	}
304 	return 0;
305 }
306 
307 static const struct cec_adap_ops vivid_cec_adap_ops = {
308 	.adap_enable = vivid_cec_adap_enable,
309 	.adap_log_addr = vivid_cec_adap_log_addr,
310 	.adap_transmit = vivid_cec_adap_transmit,
311 	.received = vivid_received,
312 };
313 
vivid_cec_alloc_adap(struct vivid_dev * dev,unsigned int idx,bool is_source)314 struct cec_adapter *vivid_cec_alloc_adap(struct vivid_dev *dev,
315 					 unsigned int idx,
316 					 bool is_source)
317 {
318 	u32 caps = CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN;
319 	char name[32];
320 
321 	snprintf(name, sizeof(name), "vivid-%03d-vid-%s%d",
322 		 dev->inst, is_source ? "out" : "cap", idx);
323 	return cec_allocate_adapter(&vivid_cec_adap_ops, dev,
324 				    name, caps, CEC_MAX_LOG_ADDRS);
325 }
326