• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
4  */
5 
6 #include <cstring>
7 #include <map>
8 #include <sstream>
9 #include <vector>
10 
11 #include <sys/ioctl.h>
12 #include <unistd.h>
13 
14 #include "cec-compliance.h"
15 
16 enum Months { Jan = 1, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec };
17 
18 struct remote_test {
19 	const char *name;
20 	const unsigned tags;
21 	const vec_remote_subtests &subtests;
22 };
23 
deck_status_get(struct node * node,unsigned me,unsigned la,__u8 & deck_status)24 static int deck_status_get(struct node *node, unsigned me, unsigned la, __u8 &deck_status)
25 {
26 	struct cec_msg msg;
27 	deck_status = 0;
28 
29 	cec_msg_init(&msg, me, la);
30 	cec_msg_give_deck_status(&msg, true, CEC_OP_STATUS_REQ_ONCE);
31 	fail_on_test(!transmit_timeout(node, &msg));
32 	fail_on_test(timed_out_or_abort(&msg));
33 	cec_ops_deck_status(&msg, &deck_status);
34 
35 	return OK;
36 }
37 
test_play_mode(struct node * node,unsigned me,unsigned la,__u8 play_mode,__u8 expected)38 static int test_play_mode(struct node *node, unsigned me, unsigned la, __u8 play_mode, __u8 expected)
39 {
40 	struct cec_msg msg;
41 	__u8 deck_status;
42 
43 	cec_msg_init(&msg, me, la);
44 	cec_msg_play(&msg, play_mode);
45 	fail_on_test(!transmit_timeout(node, &msg));
46 	fail_on_test(cec_msg_status_is_abort(&msg)); /* Assumes deck has media. */
47 	fail_on_test(deck_status_get(node, me, la, deck_status));
48 	fail_on_test(deck_status != expected);
49 
50 	return OK;
51 }
52 
53 
54 /* System Information */
55 
system_info_polling(struct node * node,unsigned me,unsigned la,bool interactive)56 int system_info_polling(struct node *node, unsigned me, unsigned la, bool interactive)
57 {
58 	struct cec_msg msg;
59 
60 	cec_msg_init(&msg, me, la);
61 	fail_on_test(doioctl(node, CEC_TRANSMIT, &msg));
62 	if (node->remote_la_mask & (1 << la)) {
63 		if (!cec_msg_status_is_ok(&msg)) {
64 			fail("Polling a valid remote LA failed\n");
65 			return FAIL_CRITICAL;
66 		}
67 	} else {
68 		if (cec_msg_status_is_ok(&msg)) {
69 			fail("Polling an invalid remote LA was successful\n");
70 			return FAIL_CRITICAL;
71 		}
72 		return OK_NOT_SUPPORTED;
73 	}
74 
75 	return 0;
76 }
77 
system_info_phys_addr(struct node * node,unsigned me,unsigned la,bool interactive)78 int system_info_phys_addr(struct node *node, unsigned me, unsigned la, bool interactive)
79 {
80 	struct cec_msg msg;
81 
82 	cec_msg_init(&msg, me, la);
83 	cec_msg_give_physical_addr(&msg, true);
84 	if (!transmit_timeout(node, &msg) || timed_out_or_abort(&msg)) {
85 		fail_or_warn(node, "Give Physical Addr timed out\n");
86 		return node->in_standby ? 0 : FAIL_CRITICAL;
87 	}
88 	fail_on_test(node->remote[la].phys_addr != ((msg.msg[2] << 8) | msg.msg[3]));
89 	fail_on_test(node->remote[la].prim_type != msg.msg[4]);
90 	return 0;
91 }
92 
system_info_version(struct node * node,unsigned me,unsigned la,bool interactive)93 int system_info_version(struct node *node, unsigned me, unsigned la, bool interactive)
94 {
95 	struct cec_msg msg;
96 
97 	cec_msg_init(&msg, me, la);
98 	cec_msg_get_cec_version(&msg, true);
99 	if (!transmit_timeout(node, &msg) || timed_out_or_abort(&msg))
100 		return fail_or_warn(node, "Get CEC Version timed out\n");
101 
102 	/* This needs to be kept in sync with newer CEC versions */
103 	fail_on_test(msg.msg[2] < CEC_OP_CEC_VERSION_1_3A ||
104 		     msg.msg[2] > CEC_OP_CEC_VERSION_2_0);
105 	fail_on_test(node->remote[la].cec_version != msg.msg[2]);
106 
107 	return 0;
108 }
109 
system_info_get_menu_lang(struct node * node,unsigned me,unsigned la,bool interactive)110 int system_info_get_menu_lang(struct node *node, unsigned me, unsigned la, bool interactive)
111 {
112 	struct cec_msg msg;
113 	char language[4];
114 
115 	cec_msg_init(&msg, me, la);
116 	cec_msg_get_menu_language(&msg, true);
117 	if (!transmit_timeout(node, &msg) || timed_out(&msg))
118 		return fail_or_warn(node, "Get Menu Languages timed out\n");
119 
120 	/* Devices other than TVs shall send Feature Abort [Unregcognized Opcode]
121 	   in reply to Get Menu Language. */
122 	fail_on_test(!is_tv(la, node->remote[la].prim_type) && !unrecognized_op(&msg));
123 
124 	if (unrecognized_op(&msg)) {
125 		if (is_tv(la, node->remote[la].prim_type))
126 			warn("TV did not respond to Get Menu Language.\n");
127 		return OK_NOT_SUPPORTED;
128 	}
129 	if (refused(&msg))
130 		return OK_REFUSED;
131 	if (cec_msg_status_is_abort(&msg))
132 		return OK_PRESUMED;
133 	cec_ops_set_menu_language(&msg, language);
134 	fail_on_test(strcmp(node->remote[la].language, language));
135 
136 	return 0;
137 }
138 
system_info_set_menu_lang(struct node * node,unsigned me,unsigned la,bool interactive)139 static int system_info_set_menu_lang(struct node *node, unsigned me, unsigned la, bool interactive)
140 {
141 	struct cec_msg msg;
142 
143 	cec_msg_init(&msg, me, la);
144 	cec_msg_set_menu_language(&msg, "eng");
145 	fail_on_test(!transmit_timeout(node, &msg));
146 	if (unrecognized_op(&msg))
147 		return OK_NOT_SUPPORTED;
148 	if (refused(&msg))
149 		return OK_REFUSED;
150 
151 	return OK_PRESUMED;
152 }
153 
system_info_give_features(struct node * node,unsigned me,unsigned la,bool interactive)154 int system_info_give_features(struct node *node, unsigned me, unsigned la, bool interactive)
155 {
156 	struct cec_msg msg;
157 
158 	cec_msg_init(&msg, me, la);
159 	cec_msg_give_features(&msg, true);
160 	if (!transmit_timeout(node, &msg) || timed_out(&msg))
161 		return fail_or_warn(node, "Give Features timed out\n");
162 	if (unrecognized_op(&msg)) {
163 		if (node->remote[la].cec_version < CEC_OP_CEC_VERSION_2_0)
164 			return OK_NOT_SUPPORTED;
165 		fail_on_test_v2(node->remote[la].cec_version, true);
166 	}
167 	if (refused(&msg))
168 		return OK_REFUSED;
169 	if (node->remote[la].cec_version < CEC_OP_CEC_VERSION_2_0)
170 		info("Device has CEC Version < 2.0 but supports Give Features.\n");
171 
172 	/* RC Profile and Device Features are assumed to be 1 byte. As of CEC 2.0 only
173 	   1 byte is used, but this might be extended in future versions. */
174 	__u8 cec_version, all_device_types;
175 	const __u8 *rc_profile, *dev_features;
176 
177 	cec_ops_report_features(&msg, &cec_version, &all_device_types, &rc_profile, &dev_features);
178 	fail_on_test(rc_profile == nullptr || dev_features == nullptr);
179 	info("All Device Types: \t\t%s\n", cec_all_dev_types2s(all_device_types).c_str());
180 	info("RC Profile: \t%s", cec_rc_src_prof2s(*rc_profile, "").c_str());
181 	info("Device Features: \t%s", cec_dev_feat2s(*dev_features, "").c_str());
182 
183 	if (!(cec_has_playback(1 << la) || cec_has_record(1 << la) || cec_has_tuner(1 << la)) &&
184 	    (*dev_features & CEC_OP_FEAT_DEV_HAS_SET_AUDIO_RATE)) {
185 		return fail("Only Playback, Recording or Tuner devices shall set the Set Audio Rate bit\n");
186 	}
187 	if (!(cec_has_playback(1 << la) || cec_has_record(1 << la)) &&
188 	    (*dev_features & CEC_OP_FEAT_DEV_HAS_DECK_CONTROL))
189 		return fail("Only Playback and Recording devices shall set the Supports Deck Control bit\n");
190 	if (!cec_has_tv(1 << la) && node->remote[la].has_rec_tv)
191 		return fail("Only TVs shall set the Record TV Screen bit\n");
192 	if (cec_has_playback(1 << la) && (*dev_features & CEC_OP_FEAT_DEV_SINK_HAS_ARC_TX))
193 		return fail("A Playback device cannot set the Sink Supports ARC Tx bit\n");
194 	if (cec_has_tv(1 << la) && (*dev_features & CEC_OP_FEAT_DEV_SOURCE_HAS_ARC_RX))
195 		return fail("A TV cannot set the Source Supports ARC Rx bit\n");
196 
197 	fail_on_test(cec_version != node->remote[la].cec_version);
198 	fail_on_test(node->remote[la].rc_profile != *rc_profile);
199 	fail_on_test(node->remote[la].dev_features != *dev_features);
200 	fail_on_test(node->remote[la].all_device_types != all_device_types);
201 	return 0;
202 }
203 
204 static const vec_remote_subtests system_info_subtests{
205 	{ "Polling Message", CEC_LOG_ADDR_MASK_ALL, system_info_polling },
206 	{ "Give Physical Address", CEC_LOG_ADDR_MASK_ALL, system_info_phys_addr },
207 	{ "Give CEC Version", CEC_LOG_ADDR_MASK_ALL, system_info_version },
208 	{ "Get Menu Language", CEC_LOG_ADDR_MASK_ALL, system_info_get_menu_lang },
209 	{ "Set Menu Language", CEC_LOG_ADDR_MASK_ALL, system_info_set_menu_lang },
210 	{ "Give Device Features", CEC_LOG_ADDR_MASK_ALL, system_info_give_features },
211 };
212 
213 /* Core behavior */
214 
core_unknown(struct node * node,unsigned me,unsigned la,bool interactive)215 int core_unknown(struct node *node, unsigned me, unsigned la, bool interactive)
216 {
217 	struct cec_msg msg;
218 	const __u8 unknown_opcode = 0xfe;
219 
220 	/* Unknown opcodes should be responded to with Feature Abort, with abort
221 	   reason Unknown Opcode.
222 
223 	   For CEC 2.0 and before, 0xfe is an unused opcode. The test possibly
224 	   needs to be updated for future CEC versions. */
225 	cec_msg_init(&msg, me, la);
226 	msg.len = 2;
227 	msg.msg[1] = unknown_opcode;
228 	if (!transmit_timeout(node, &msg) || timed_out(&msg))
229 		return fail_or_warn(node, "Unknown Opcode timed out\n");
230 	fail_on_test(!cec_msg_status_is_abort(&msg));
231 
232 	__u8 abort_msg, reason;
233 
234 	cec_ops_feature_abort(&msg, &abort_msg, &reason);
235 	fail_on_test(reason != CEC_OP_ABORT_UNRECOGNIZED_OP);
236 	fail_on_test(abort_msg != 0xfe);
237 
238 	/* Unknown opcodes that are broadcast should be ignored */
239 	cec_msg_init(&msg, me, CEC_LOG_ADDR_BROADCAST);
240 	msg.len = 2;
241 	msg.msg[1] = unknown_opcode;
242 	fail_on_test(!transmit_timeout(node, &msg));
243 	fail_on_test(!timed_out(&msg));
244 
245 	return 0;
246 }
247 
core_abort(struct node * node,unsigned me,unsigned la,bool interactive)248 int core_abort(struct node *node, unsigned me, unsigned la, bool interactive)
249 {
250 	struct cec_msg msg;
251 
252 	/* The Abort message should always be responded to with Feature Abort
253 	   (with any abort reason) */
254 	cec_msg_init(&msg, me, la);
255 	cec_msg_abort(&msg);
256 	if (!transmit_timeout(node, &msg) || timed_out(&msg))
257 		return fail_or_warn(node, "Abort timed out\n");
258 	fail_on_test(!cec_msg_status_is_abort(&msg));
259 	return 0;
260 }
261 
262 static const vec_remote_subtests core_subtests{
263 	{ "Wake up", CEC_LOG_ADDR_MASK_ALL, standby_resume_wakeup, true },
264 	{ "Feature aborts unknown messages", CEC_LOG_ADDR_MASK_ALL, core_unknown },
265 	{ "Feature aborts Abort message", CEC_LOG_ADDR_MASK_ALL, core_abort },
266 };
267 
268 /* Vendor Specific Commands */
269 
vendor_specific_commands_id(struct node * node,unsigned me,unsigned la,bool interactive)270 int vendor_specific_commands_id(struct node *node, unsigned me, unsigned la, bool interactive)
271 {
272 	struct cec_msg msg;
273 
274 	cec_msg_init(&msg, me, la);
275 	cec_msg_give_device_vendor_id(&msg, true);
276 	if (!transmit(node, &msg))
277 		return fail_or_warn(node, "Give Device Vendor ID timed out\n");
278 	if (unrecognized_op(&msg))
279 		return OK_NOT_SUPPORTED;
280 	if (refused(&msg))
281 		return OK_REFUSED;
282 	if (cec_msg_status_is_abort(&msg))
283 		return OK_PRESUMED;
284 	fail_on_test(node->remote[la].vendor_id !=
285 		     (__u32)((msg.msg[2] << 16) | (msg.msg[3] << 8) | msg.msg[4]));
286 
287 	return 0;
288 }
289 
290 static const vec_remote_subtests vendor_specific_subtests{
291 	{ "Give Device Vendor ID", CEC_LOG_ADDR_MASK_ALL, vendor_specific_commands_id },
292 };
293 
294 /* Device OSD Transfer */
295 
device_osd_transfer_set(struct node * node,unsigned me,unsigned la,bool interactive)296 static int device_osd_transfer_set(struct node *node, unsigned me, unsigned la, bool interactive)
297 {
298 	struct cec_msg msg;
299 
300 	cec_msg_init(&msg, me, la);
301 	cec_msg_set_osd_name(&msg, "Whatever");
302 	fail_on_test(!transmit_timeout(node, &msg));
303 	if (unrecognized_op(&msg)) {
304 		if (is_tv(la, node->remote[la].prim_type) &&
305 		    node->remote[la].cec_version >= CEC_OP_CEC_VERSION_2_0)
306 			warn("TV feature aborted Set OSD Name\n");
307 		return OK_NOT_SUPPORTED;
308 	}
309 	if (refused(&msg))
310 		return OK_REFUSED;
311 
312 	return OK_PRESUMED;
313 }
314 
device_osd_transfer_give(struct node * node,unsigned me,unsigned la,bool interactive)315 int device_osd_transfer_give(struct node *node, unsigned me, unsigned la, bool interactive)
316 {
317 	struct cec_msg msg;
318 
319 	/* Todo: CEC 2.0: devices with several logical addresses shall report
320 	   the same for each logical address. */
321 	cec_msg_init(&msg, me, la);
322 	cec_msg_give_osd_name(&msg, true);
323 	if (!transmit_timeout(node, &msg) || timed_out(&msg))
324 		return fail_or_warn(node, "Give OSD Name timed out\n");
325 	fail_on_test(!is_tv(la, node->remote[la].prim_type) && unrecognized_op(&msg));
326 	if (unrecognized_op(&msg))
327 		return OK_NOT_SUPPORTED;
328 	if (refused(&msg))
329 		return OK_REFUSED;
330 	if (cec_msg_status_is_abort(&msg))
331 		return OK_PRESUMED;
332 	char osd_name[15];
333 	cec_ops_set_osd_name(&msg, osd_name);
334 	fail_on_test(!osd_name[0]);
335 	fail_on_test(strcmp(node->remote[la].osd_name, osd_name));
336 	fail_on_test(msg.len != strlen(osd_name) + 2);
337 
338 	return 0;
339 }
340 
341 static const vec_remote_subtests device_osd_transfer_subtests{
342 	{ "Set OSD Name", CEC_LOG_ADDR_MASK_ALL, device_osd_transfer_set },
343 	{ "Give OSD Name", CEC_LOG_ADDR_MASK_ALL, device_osd_transfer_give },
344 };
345 
346 /* OSD Display */
347 
osd_string_set_default(struct node * node,unsigned me,unsigned la,bool interactive)348 static int osd_string_set_default(struct node *node, unsigned me, unsigned la, bool interactive)
349 {
350 	struct cec_msg msg;
351 	char osd[14];
352 	bool unsuitable = false;
353 
354 	sprintf(osd, "Rept %x from %x", la, me);
355 
356 	interactive_info(true, "You should see \"%s\" appear on the screen", osd);
357 	cec_msg_init(&msg, me, la);
358 	cec_msg_set_osd_string(&msg, CEC_OP_DISP_CTL_DEFAULT, osd);
359 	fail_on_test(!transmit_timeout(node, &msg));
360 	/* In CEC 2.0 it is mandatory for a TV to support this if it reports so
361 	   in its Device Features. */
362 	fail_on_test_v2(node->remote[la].cec_version,
363 			unrecognized_op(&msg) &&
364 			(node->remote[la].dev_features & CEC_OP_FEAT_DEV_HAS_SET_OSD_STRING));
365 	if (unrecognized_op(&msg))
366 		return OK_NOT_SUPPORTED;
367 	if (refused(&msg))
368 		return OK_REFUSED;
369 	if (cec_msg_status_is_abort(&msg)) {
370 		warn("The device is in an unsuitable state or cannot display the complete message.\n");
371 		unsuitable = true;
372 	}
373 	node->remote[la].has_osd = true;
374 	if (!interactive)
375 		return OK_PRESUMED;
376 
377 	/* The CEC 1.4b CTS specifies that one should wait at least 20 seconds for the
378 	   string to be cleared on the remote device */
379 	interactive_info(true, "Waiting 20s for OSD string to be cleared on the remote device");
380 	sleep(20);
381 	fail_on_test(!unsuitable && interactive && !question("Did the string appear and then disappear?"));
382 
383 	return 0;
384 }
385 
osd_string_set_until_clear(struct node * node,unsigned me,unsigned la,bool interactive)386 static int osd_string_set_until_clear(struct node *node, unsigned me, unsigned la, bool interactive)
387 {
388 	if (!node->remote[la].has_osd)
389 		return NOTAPPLICABLE;
390 
391 	struct cec_msg msg;
392 	char osd[14];
393 	bool unsuitable = false;
394 
395 	strcpy(osd, "Appears 1 sec");
396 	// Make sure the string is the maximum possible length
397 	fail_on_test(strlen(osd) != 13);
398 
399 	interactive_info(true, "You should see \"%s\" appear on the screen for approximately three seconds.", osd);
400 	cec_msg_init(&msg, me, la);
401 	cec_msg_set_osd_string(&msg, CEC_OP_DISP_CTL_UNTIL_CLEARED, osd);
402 	fail_on_test(!transmit(node, &msg));
403 	if (cec_msg_status_is_abort(&msg) && !unrecognized_op(&msg)) {
404 		warn("The device is in an unsuitable state or cannot display the complete message.\n");
405 		unsuitable = true;
406 	}
407 	sleep(3);
408 
409 	cec_msg_init(&msg, me, la);
410 	cec_msg_set_osd_string(&msg, CEC_OP_DISP_CTL_CLEAR, "");
411 	fail_on_test(!transmit_timeout(node, &msg, 250));
412 	fail_on_test(cec_msg_status_is_abort(&msg));
413 	fail_on_test(!unsuitable && interactive && !question("Did the string appear?"));
414 
415 	if (interactive)
416 		return 0;
417 
418 	return OK_PRESUMED;
419 }
420 
osd_string_invalid(struct node * node,unsigned me,unsigned la,bool interactive)421 static int osd_string_invalid(struct node *node, unsigned me, unsigned la, bool interactive)
422 {
423 	if (!node->remote[la].has_osd)
424 		return NOTAPPLICABLE;
425 
426 	struct cec_msg msg;
427 
428 	/* Send Set OSD String with an Display Control operand. A Feature Abort is
429 	   expected in reply. */
430 	interactive_info(true, "You should observe no change on the on screen display");
431 	cec_msg_init(&msg, me, la);
432 	cec_msg_set_osd_string(&msg, 0xff, "");
433 	fail_on_test(!transmit_timeout(node, &msg));
434 	fail_on_test(timed_out(&msg));
435 	fail_on_test(!cec_msg_status_is_abort(&msg));
436 	fail_on_test(interactive && question("Did the display change?"));
437 
438 	return 0;
439 }
440 
441 static const vec_remote_subtests osd_string_subtests{
442 	{ "Set OSD String with default timeout", CEC_LOG_ADDR_MASK_TV, osd_string_set_default },
443 	{ "Set OSD String with no timeout", CEC_LOG_ADDR_MASK_TV, osd_string_set_until_clear },
444 	{ "Set OSD String with invalid operand", CEC_LOG_ADDR_MASK_TV, osd_string_invalid },
445 };
446 
447 /* Routing Control */
448 
routing_control_inactive_source(struct node * node,unsigned me,unsigned la,bool interactive)449 static int routing_control_inactive_source(struct node *node, unsigned me, unsigned la, bool interactive)
450 {
451 	struct cec_msg msg;
452 	int response;
453 
454 	interactive_info(true, "Please make sure that the TV is currently viewing this source.");
455 	mode_set_follower(node);
456 	cec_msg_init(&msg, me, la);
457 	cec_msg_inactive_source(&msg, node->phys_addr);
458 	fail_on_test(!transmit(node, &msg));
459 	if (unrecognized_op(&msg))
460 		return OK_NOT_SUPPORTED;
461 	if (refused(&msg))
462 		return OK_REFUSED;
463 	// It may take a bit of time for the Inactive Source message to take
464 	// effect, so sleep a bit.
465 	response = util_receive(node, CEC_LOG_ADDR_TV, 10000, &msg,
466 				CEC_MSG_INACTIVE_SOURCE,
467 				CEC_MSG_ACTIVE_SOURCE, CEC_MSG_SET_STREAM_PATH);
468 	if (me == CEC_LOG_ADDR_TV) {
469 		// Inactive Source should be ignored by all other devices
470 		if (response >= 0)
471 			return fail("Unexpected reply to Inactive Source\n");
472 		fail_on_test(response >= 0);
473 	} else {
474 		if (response < 0)
475 			warn("Expected Active Source or Set Stream Path reply to Inactive Source\n");
476 		fail_on_test(interactive && !question("Did the TV switch away from or stop showing this source?"));
477 	}
478 
479 	return 0;
480 }
481 
routing_control_active_source(struct node * node,unsigned me,unsigned la,bool interactive)482 static int routing_control_active_source(struct node *node, unsigned me, unsigned la, bool interactive)
483 {
484 	struct cec_msg msg;
485 
486 	interactive_info(true, "Please switch the TV to another source.");
487 	cec_msg_init(&msg, me, la);
488 	cec_msg_active_source(&msg, node->phys_addr);
489 	fail_on_test(!transmit_timeout(node, &msg));
490 	fail_on_test(interactive && !question("Did the TV switch to this source?"));
491 
492 	if (interactive)
493 		return 0;
494 
495 	return OK_PRESUMED;
496 }
497 
routing_control_req_active_source(struct node * node,unsigned me,unsigned la,bool interactive)498 static int routing_control_req_active_source(struct node *node, unsigned me, unsigned la, bool interactive)
499 {
500 	struct cec_msg msg;
501 
502 	/* We have now said that we are active source, so receiving a reply to
503 	   Request Active Source should fail the test. */
504 	cec_msg_init(&msg, me, la);
505 	cec_msg_request_active_source(&msg, true);
506 	fail_on_test(!transmit_timeout(node, &msg));
507 	fail_on_test(!timed_out(&msg));
508 
509 	return 0;
510 }
511 
routing_control_set_stream_path(struct node * node,unsigned me,unsigned la,bool interactive)512 static int routing_control_set_stream_path(struct node *node, unsigned me, unsigned la, bool interactive)
513 {
514 	struct cec_msg msg;
515 	__u16 phys_addr;
516 
517 	/* Send Set Stream Path with the remote physical address. We expect the
518 	   source to eventually send Active Source. The timeout of long_timeout
519 	   seconds is necessary because the device might have to wake up from standby.
520 
521 	   In CEC 2.0 it is mandatory for sources to send Active Source. */
522 	if (is_tv(la, node->remote[la].prim_type))
523 		interactive_info(true, "Please ensure that the device is in standby.");
524 	announce("Sending Set Stream Path and waiting for reply. This may take up to %llu s.", (long long)long_timeout);
525 	cec_msg_init(&msg, me, la);
526 	cec_msg_set_stream_path(&msg, node->remote[la].phys_addr);
527 	msg.reply = CEC_MSG_ACTIVE_SOURCE;
528 	fail_on_test(!transmit_timeout(node, &msg, long_timeout * 1000));
529 	if (timed_out(&msg) && is_tv(la, node->remote[la].prim_type))
530 		return OK_NOT_SUPPORTED;
531 	if (timed_out(&msg) && node->remote[la].cec_version < CEC_OP_CEC_VERSION_2_0) {
532 		warn("Device did not respond to Set Stream Path.\n");
533 		return OK_NOT_SUPPORTED;
534 	}
535 	fail_on_test_v2(node->remote[la].cec_version, timed_out(&msg));
536 	cec_ops_active_source(&msg, &phys_addr);
537 	fail_on_test(phys_addr != node->remote[la].phys_addr);
538 	if (is_tv(la, node->remote[la].prim_type))
539 		fail_on_test(interactive && !question("Did the device go out of standby?"));
540 
541 	if (interactive || node->remote[la].cec_version >= CEC_OP_CEC_VERSION_2_0)
542 		return 0;
543 
544 	return OK_PRESUMED;
545 }
546 
547 static const vec_remote_subtests routing_control_subtests{
548 	{ "Active Source", CEC_LOG_ADDR_MASK_TV, routing_control_active_source },
549 	{ "Request Active Source", CEC_LOG_ADDR_MASK_ALL, routing_control_req_active_source },
550 	{ "Inactive Source", CEC_LOG_ADDR_MASK_TV, routing_control_inactive_source },
551 	{ "Set Stream Path", CEC_LOG_ADDR_MASK_ALL, routing_control_set_stream_path },
552 };
553 
554 /* Remote Control Passthrough */
555 
rc_passthrough_user_ctrl_pressed(struct node * node,unsigned me,unsigned la,bool interactive)556 static int rc_passthrough_user_ctrl_pressed(struct node *node, unsigned me, unsigned la, bool interactive)
557 {
558 	struct cec_msg msg;
559 	struct cec_op_ui_command rc_press;
560 
561 	cec_msg_init(&msg, me, la);
562 	rc_press.ui_cmd = CEC_OP_UI_CMD_VOLUME_UP; // Volume up key (the key is not crucial here)
563 	cec_msg_user_control_pressed(&msg, &rc_press);
564 	fail_on_test(!transmit_timeout(node, &msg));
565 	/* Mandatory for all except devices which have taken logical address 15 */
566 	fail_on_test_v2(node->remote[la].cec_version,
567 			unrecognized_op(&msg) && !(cec_is_unregistered(1 << la)));
568 	if (unrecognized_op(&msg))
569 		return OK_NOT_SUPPORTED;
570 	if (refused(&msg))
571 		return OK_REFUSED;
572 
573 	return OK_PRESUMED;
574 }
575 
rc_passthrough_user_ctrl_released(struct node * node,unsigned me,unsigned la,bool interactive)576 static int rc_passthrough_user_ctrl_released(struct node *node, unsigned me, unsigned la, bool interactive)
577 {
578 	struct cec_msg msg;
579 
580 	cec_msg_init(&msg, me, la);
581 	cec_msg_user_control_released(&msg);
582 	fail_on_test(!transmit_timeout(node, &msg));
583 	fail_on_test_v2(node->remote[la].cec_version,
584 			cec_msg_status_is_abort(&msg) && !(la & CEC_LOG_ADDR_MASK_UNREGISTERED));
585 	if (unrecognized_op(&msg))
586 		return OK_NOT_SUPPORTED;
587 	if (refused(&msg))
588 		return OK_REFUSED;
589 	node->remote[la].has_remote_control_passthrough = true;
590 
591 	return OK_PRESUMED;
592 }
593 
594 static const vec_remote_subtests rc_passthrough_subtests{
595 	{ "User Control Pressed", CEC_LOG_ADDR_MASK_ALL, rc_passthrough_user_ctrl_pressed },
596 	{ "User Control Released", CEC_LOG_ADDR_MASK_ALL, rc_passthrough_user_ctrl_released },
597 };
598 
599 /* Device Menu Control */
600 
601 /*
602   TODO: These are very rudimentary tests which should be expanded.
603  */
604 
dev_menu_ctl_request(struct node * node,unsigned me,unsigned la,bool interactive)605 static int dev_menu_ctl_request(struct node *node, unsigned me, unsigned la, bool interactive)
606 {
607 	struct cec_msg msg;
608 
609 	cec_msg_init(&msg, me, la);
610 	cec_msg_menu_request(&msg, true, CEC_OP_MENU_REQUEST_QUERY);
611 	fail_on_test(!transmit_timeout(node, &msg));
612 	if (unrecognized_op(&msg))
613 		return OK_NOT_SUPPORTED;
614 	if (refused(&msg))
615 		return OK_REFUSED;
616 	if (cec_msg_status_is_abort(&msg))
617 		return OK_PRESUMED;
618 	if (node->remote[la].cec_version >= CEC_OP_CEC_VERSION_2_0)
619 		warn("The Device Menu Control feature is deprecated in CEC 2.0\n");
620 
621 	return 0;
622 }
623 
624 static const vec_remote_subtests dev_menu_ctl_subtests{
625 	{ "Menu Request", static_cast<__u16>(~CEC_LOG_ADDR_MASK_TV), dev_menu_ctl_request },
626 	{ "User Control Pressed", CEC_LOG_ADDR_MASK_ALL, rc_passthrough_user_ctrl_pressed },
627 	{ "User Control Released", CEC_LOG_ADDR_MASK_ALL, rc_passthrough_user_ctrl_released },
628 };
629 
630 /* Deck Control */
631 
deck_ctl_give_status(struct node * node,unsigned me,unsigned la,bool interactive)632 static int deck_ctl_give_status(struct node *node, unsigned me, unsigned la, bool interactive)
633 {
634 	struct cec_msg msg;
635 
636 	cec_msg_init(&msg, me, la);
637 	cec_msg_give_deck_status(&msg, true, CEC_OP_STATUS_REQ_ONCE);
638 	fail_on_test(!transmit_timeout(node, &msg));
639 	fail_on_test(timed_out(&msg));
640 
641 	fail_on_test_v2(node->remote[la].cec_version,
642 	                node->remote[la].has_deck_ctl && cec_msg_status_is_abort(&msg));
643 	fail_on_test_v2(node->remote[la].cec_version,
644 	                !node->remote[la].has_deck_ctl && !unrecognized_op(&msg));
645 	if (unrecognized_op(&msg))
646 		return OK_NOT_SUPPORTED;
647 	if (refused(&msg))
648 		return OK_REFUSED;
649 	if (cec_msg_status_is_abort(&msg))
650 		return OK_PRESUMED;
651 
652 	__u8 deck_info;
653 
654 	cec_ops_deck_status(&msg, &deck_info);
655 	fail_on_test(deck_info < CEC_OP_DECK_INFO_PLAY || deck_info > CEC_OP_DECK_INFO_OTHER);
656 
657 	cec_msg_init(&msg, me, la);
658 	cec_msg_give_deck_status(&msg, true, CEC_OP_STATUS_REQ_ON);
659 	fail_on_test(!transmit_timeout(node, &msg));
660 	fail_on_test(timed_out(&msg));
661 	cec_ops_deck_status(&msg, &deck_info);
662 	fail_on_test(deck_info < CEC_OP_DECK_INFO_PLAY || deck_info > CEC_OP_DECK_INFO_OTHER);
663 
664 	cec_msg_init(&msg, me, la);
665 	cec_msg_give_deck_status(&msg, true, CEC_OP_STATUS_REQ_OFF);
666 	/*
667 	 * Reply would not normally be expected for CEC_OP_STATUS_REQ_OFF.
668 	 * If a reply is received, then the follower failed to turn off
669 	 * status reporting as required.
670 	 */
671 	msg.reply = CEC_MSG_DECK_STATUS;
672 	fail_on_test(!transmit_timeout(node, &msg));
673 	fail_on_test(!timed_out(&msg));
674 
675 	return OK;
676 }
677 
deck_ctl_give_status_invalid(struct node * node,unsigned me,unsigned la,bool interactive)678 static int deck_ctl_give_status_invalid(struct node *node, unsigned me, unsigned la, bool interactive)
679 {
680 	struct cec_msg msg;
681 
682 	cec_msg_init(&msg, me, la);
683 	cec_msg_give_deck_status(&msg, true, 0); /* Invalid Operand */
684 	fail_on_test(!transmit_timeout(node, &msg));
685 	if (unrecognized_op(&msg))
686 		return OK_NOT_SUPPORTED;
687 	fail_on_test(!cec_msg_status_is_abort(&msg));
688 	fail_on_test(abort_reason(&msg) != CEC_OP_ABORT_INVALID_OP);
689 
690 	cec_msg_init(&msg, me, la);
691 	cec_msg_give_deck_status(&msg, true, 4); /* Invalid Operand */
692 	fail_on_test(!transmit_timeout(node, &msg));
693 	fail_on_test(!cec_msg_status_is_abort(&msg));
694 	fail_on_test(abort_reason(&msg) != CEC_OP_ABORT_INVALID_OP);
695 
696 	return OK;
697 }
698 
deck_ctl_deck_ctl(struct node * node,unsigned me,unsigned la,bool interactive)699 static int deck_ctl_deck_ctl(struct node *node, unsigned me, unsigned la, bool interactive)
700 {
701 	struct cec_msg msg;
702 	__u8 deck_status;
703 
704 	cec_msg_init(&msg, me, la);
705 	cec_msg_deck_control(&msg, CEC_OP_DECK_CTL_MODE_STOP);
706 	fail_on_test(!transmit_timeout(node, &msg));
707 	fail_on_test_v2(node->remote[la].cec_version,
708 	                node->remote[la].has_deck_ctl && unrecognized_op(&msg));
709 	fail_on_test_v2(node->remote[la].cec_version,
710 	                !node->remote[la].has_deck_ctl && !unrecognized_op(&msg));
711 	if (unrecognized_op(&msg))
712 		return OK_NOT_SUPPORTED;
713 	if (refused(&msg))
714 		return OK_REFUSED;
715 	fail_on_test(deck_status_get(node, me, la, deck_status));
716 	if (cec_msg_status_is_abort(&msg)) {
717 		if (!incorrect_mode(&msg))
718 			return FAIL;
719 		if (deck_status == CEC_OP_DECK_INFO_NO_MEDIA)
720 			info("Stop: no media.\n");
721 		else
722 			warn("Deck has media but returned Feature Abort with Incorrect Mode.");
723 		return OK;
724 	}
725 	fail_on_test(deck_status != CEC_OP_DECK_INFO_STOP && deck_status != CEC_OP_DECK_INFO_NO_MEDIA);
726 
727 	cec_msg_init(&msg, me, la);
728 	cec_msg_deck_control(&msg, CEC_OP_DECK_CTL_MODE_SKIP_FWD);
729 	fail_on_test(!transmit_timeout(node, &msg));
730 	fail_on_test(deck_status_get(node, me, la, deck_status));
731 	/*
732 	 * If there is no media, Skip Forward should Feature Abort with Incorrect Mode
733 	 * even if Stop did not.  If Skip Forward does not Feature Abort, the deck
734 	 * is assumed to have media.
735 	 */
736 	if (incorrect_mode(&msg)) {
737 		fail_on_test(deck_status != CEC_OP_DECK_INFO_NO_MEDIA);
738 		return OK;
739 	}
740 	fail_on_test(cec_msg_status_is_abort(&msg));
741 	/* Wait for Deck to finish Skip Forward. */
742 	for (int i = 0; deck_status == CEC_OP_DECK_INFO_SKIP_FWD && i < long_timeout; i++) {
743 		sleep(1);
744 		fail_on_test(deck_status_get(node, me, la, deck_status));
745 	}
746 	fail_on_test(deck_status != CEC_OP_DECK_INFO_PLAY);
747 
748 	cec_msg_init(&msg, me, la);
749 	cec_msg_deck_control(&msg, CEC_OP_DECK_CTL_MODE_SKIP_REV);
750 	fail_on_test(!transmit_timeout(node, &msg));
751 	fail_on_test(cec_msg_status_is_abort(&msg)); /* Assumes deck has media. */
752 	fail_on_test(deck_status_get(node, me, la, deck_status));
753 	/* Wait for Deck to finish Skip Reverse. */
754 	for (int i = 0; deck_status == CEC_OP_DECK_INFO_SKIP_REV && i < long_timeout; i++) {
755 		sleep(1);
756 		fail_on_test(deck_status_get(node, me, la, deck_status));
757 	}
758 	fail_on_test(deck_status != CEC_OP_DECK_INFO_PLAY);
759 
760 	cec_msg_init(&msg, me, la);
761 	cec_msg_deck_control(&msg, CEC_OP_DECK_CTL_MODE_EJECT);
762 	fail_on_test(!transmit_timeout(node, &msg));
763 	fail_on_test(cec_msg_status_is_abort(&msg));
764 	fail_on_test(deck_status_get(node, me, la, deck_status));
765 	fail_on_test(deck_status != CEC_OP_DECK_INFO_NO_MEDIA);
766 
767 	return OK;
768 }
769 
deck_ctl_deck_ctl_invalid(struct node * node,unsigned me,unsigned la,bool interactive)770 static int deck_ctl_deck_ctl_invalid(struct node *node, unsigned me, unsigned la, bool interactive)
771 {
772 	struct cec_msg msg;
773 
774 	cec_msg_init(&msg, me, la);
775 	cec_msg_deck_control(&msg, 0); /* Invalid Deck Control operand */
776 	fail_on_test(!transmit_timeout(node, &msg));
777 	if (unrecognized_op(&msg))
778 		return OK_NOT_SUPPORTED;
779 	fail_on_test(!cec_msg_status_is_abort(&msg));
780 	fail_on_test(abort_reason(&msg) != CEC_OP_ABORT_INVALID_OP);
781 
782 	cec_msg_init(&msg, me, la);
783 	cec_msg_deck_control(&msg, 5); /* Invalid Deck Control operand */
784 	fail_on_test(!transmit_timeout(node, &msg));
785 	fail_on_test(!cec_msg_status_is_abort(&msg));
786 	fail_on_test(abort_reason(&msg) != CEC_OP_ABORT_INVALID_OP);
787 
788 	return OK;
789 }
790 
deck_ctl_play(struct node * node,unsigned me,unsigned la,bool interactive)791 static int deck_ctl_play(struct node *node, unsigned me, unsigned la, bool interactive)
792 {
793 	struct cec_msg msg;
794 	__u8 deck_status;
795 
796 	cec_msg_init(&msg, me, la);
797 	cec_msg_play(&msg, CEC_OP_PLAY_MODE_PLAY_FWD);
798 	fail_on_test(!transmit_timeout(node, &msg));
799 	fail_on_test_v2(node->remote[la].cec_version,
800 	                node->remote[la].has_deck_ctl && unrecognized_op(&msg));
801 	fail_on_test_v2(node->remote[la].cec_version,
802 	                !node->remote[la].has_deck_ctl && !unrecognized_op(&msg));
803 	if (unrecognized_op(&msg))
804 		return OK_NOT_SUPPORTED;
805 	if (refused(&msg))
806 		return OK_REFUSED;
807 	fail_on_test(deck_status_get(node, me, la, deck_status));
808 	if (cec_msg_status_is_abort(&msg)) {
809 		if (!incorrect_mode(&msg))
810 			return FAIL;
811 		if (deck_status == CEC_OP_DECK_INFO_NO_MEDIA)
812 			info("Play Still: no media.\n");
813 		else
814 			warn("Deck has media but returned Feature Abort with Incorrect Mode.");
815 		return OK;
816 	}
817 	fail_on_test(deck_status != CEC_OP_DECK_INFO_PLAY);
818 
819 	fail_on_test(test_play_mode(node, me, la, CEC_OP_PLAY_MODE_PLAY_STILL, CEC_OP_DECK_INFO_STILL));
820 	fail_on_test(test_play_mode(node, me, la, CEC_OP_PLAY_MODE_PLAY_REV, CEC_OP_DECK_INFO_PLAY_REV));
821 	fail_on_test(test_play_mode(node, me, la, CEC_OP_PLAY_MODE_PLAY_FAST_FWD_MIN, CEC_OP_DECK_INFO_FAST_FWD));
822 	fail_on_test(test_play_mode(node, me, la, CEC_OP_PLAY_MODE_PLAY_FAST_REV_MIN, CEC_OP_DECK_INFO_FAST_REV));
823 	fail_on_test(test_play_mode(node, me, la, CEC_OP_PLAY_MODE_PLAY_FAST_FWD_MED, CEC_OP_DECK_INFO_FAST_FWD));
824 	fail_on_test(test_play_mode(node, me, la, CEC_OP_PLAY_MODE_PLAY_FAST_REV_MED, CEC_OP_DECK_INFO_FAST_REV));
825 	fail_on_test(test_play_mode(node, me, la, CEC_OP_PLAY_MODE_PLAY_FAST_FWD_MAX, CEC_OP_DECK_INFO_FAST_FWD));
826 	fail_on_test(test_play_mode(node, me, la, CEC_OP_PLAY_MODE_PLAY_FAST_REV_MAX, CEC_OP_DECK_INFO_FAST_REV));
827 	fail_on_test(test_play_mode(node, me, la, CEC_OP_PLAY_MODE_PLAY_SLOW_FWD_MIN, CEC_OP_DECK_INFO_SLOW));
828 	fail_on_test(test_play_mode(node, me, la, CEC_OP_PLAY_MODE_PLAY_SLOW_REV_MIN, CEC_OP_DECK_INFO_SLOW_REV));
829 	fail_on_test(test_play_mode(node, me, la, CEC_OP_PLAY_MODE_PLAY_SLOW_FWD_MED, CEC_OP_DECK_INFO_SLOW));
830 	fail_on_test(test_play_mode(node, me, la, CEC_OP_PLAY_MODE_PLAY_SLOW_REV_MED, CEC_OP_DECK_INFO_SLOW_REV));
831 	fail_on_test(test_play_mode(node, me, la, CEC_OP_PLAY_MODE_PLAY_SLOW_FWD_MAX, CEC_OP_DECK_INFO_SLOW));
832 	fail_on_test(test_play_mode(node, me, la, CEC_OP_PLAY_MODE_PLAY_SLOW_REV_MAX, CEC_OP_DECK_INFO_SLOW_REV));
833 
834 	cec_msg_init(&msg, me, la);
835 	cec_msg_deck_control(&msg, CEC_OP_DECK_CTL_MODE_STOP);
836 	fail_on_test(!transmit_timeout(node, &msg));
837 
838 	return OK;
839 }
840 
deck_ctl_play_invalid(struct node * node,unsigned me,unsigned la,bool interactive)841 static int deck_ctl_play_invalid(struct node *node, unsigned me, unsigned la, bool interactive)
842 {
843 	struct cec_msg msg;
844 
845 	cec_msg_init(&msg, me, la);
846 	cec_msg_play(&msg, 0); /* Invalid Operand */
847 	fail_on_test(!transmit_timeout(node, &msg));
848 	if (unrecognized_op(&msg))
849 		return OK_NOT_SUPPORTED;
850 	fail_on_test(!cec_msg_status_is_abort(&msg));
851 	fail_on_test(abort_reason(&msg) != CEC_OP_ABORT_INVALID_OP);
852 
853 	cec_msg_init(&msg, me, la);
854 	cec_msg_play(&msg, 4); /* Invalid Operand */
855 	fail_on_test(!transmit_timeout(node, &msg));
856 	fail_on_test(!cec_msg_status_is_abort(&msg));
857 	fail_on_test(abort_reason(&msg) != CEC_OP_ABORT_INVALID_OP);
858 
859 	cec_msg_init(&msg, me, la);
860 	cec_msg_play(&msg, 0x26); /* Invalid Operand */
861 	fail_on_test(!transmit_timeout(node, &msg));
862 	fail_on_test(!cec_msg_status_is_abort(&msg));
863 	fail_on_test(abort_reason(&msg) != CEC_OP_ABORT_INVALID_OP);
864 
865 	return OK;
866 }
867 
868 static const vec_remote_subtests deck_ctl_subtests{
869 	{
870 		"Give Deck Status",
871 		CEC_LOG_ADDR_MASK_PLAYBACK | CEC_LOG_ADDR_MASK_RECORD,
872 		deck_ctl_give_status,
873 	},
874 	{
875 		"Give Deck Status Invalid Operand",
876 		CEC_LOG_ADDR_MASK_PLAYBACK | CEC_LOG_ADDR_MASK_RECORD,
877 		deck_ctl_give_status_invalid,
878 	},
879 	{
880 		"Deck Control",
881 		CEC_LOG_ADDR_MASK_PLAYBACK | CEC_LOG_ADDR_MASK_RECORD,
882 		deck_ctl_deck_ctl,
883 	},
884 	{
885 		"Deck Control Invalid Operand",
886 		CEC_LOG_ADDR_MASK_PLAYBACK | CEC_LOG_ADDR_MASK_RECORD,
887 		deck_ctl_deck_ctl_invalid,
888 	},
889 	{
890 		"Play",
891 		CEC_LOG_ADDR_MASK_PLAYBACK | CEC_LOG_ADDR_MASK_RECORD,
892 		deck_ctl_play,
893 	},
894 	{
895 		"Play Invalid Operand",
896 		CEC_LOG_ADDR_MASK_PLAYBACK | CEC_LOG_ADDR_MASK_RECORD,
897 		deck_ctl_play_invalid,
898 	},
899 };
900 
hec_func_state2s(__u8 hfs)901 static const char *hec_func_state2s(__u8 hfs)
902 {
903 	switch (hfs) {
904 	case CEC_OP_HEC_FUNC_STATE_NOT_SUPPORTED:
905 		return "HEC Not Supported";
906 	case CEC_OP_HEC_FUNC_STATE_INACTIVE:
907 		return "HEC Inactive";
908 	case CEC_OP_HEC_FUNC_STATE_ACTIVE:
909 		return "HEC Active";
910 	case CEC_OP_HEC_FUNC_STATE_ACTIVATION_FIELD:
911 		return "HEC Activation Field";
912 	default:
913 		return "Unknown";
914 	}
915 }
916 
host_func_state2s(__u8 hfs)917 static const char *host_func_state2s(__u8 hfs)
918 {
919 	switch (hfs) {
920 	case CEC_OP_HOST_FUNC_STATE_NOT_SUPPORTED:
921 		return "Host Not Supported";
922 	case CEC_OP_HOST_FUNC_STATE_INACTIVE:
923 		return "Host Inactive";
924 	case CEC_OP_HOST_FUNC_STATE_ACTIVE:
925 		return "Host Active";
926 	default:
927 		return "Unknown";
928 	}
929 }
930 
enc_func_state2s(__u8 efs)931 static const char *enc_func_state2s(__u8 efs)
932 {
933 	switch (efs) {
934 	case CEC_OP_ENC_FUNC_STATE_EXT_CON_NOT_SUPPORTED:
935 		return "Ext Con Not Supported";
936 	case CEC_OP_ENC_FUNC_STATE_EXT_CON_INACTIVE:
937 		return "Ext Con Inactive";
938 	case CEC_OP_ENC_FUNC_STATE_EXT_CON_ACTIVE:
939 		return "Ext Con Active";
940 	default:
941 		return "Unknown";
942 	}
943 }
944 
cdc_errcode2s(__u8 cdc_errcode)945 static const char *cdc_errcode2s(__u8 cdc_errcode)
946 {
947 	switch (cdc_errcode) {
948 	case CEC_OP_CDC_ERROR_CODE_NONE:
949 		return "No error";
950 	case CEC_OP_CDC_ERROR_CODE_CAP_UNSUPPORTED:
951 		return "Initiator does not have requested capability";
952 	case CEC_OP_CDC_ERROR_CODE_WRONG_STATE:
953 		return "Initiator is in wrong state";
954 	case CEC_OP_CDC_ERROR_CODE_OTHER:
955 		return "Other error";
956 	default:
957 		return "Unknown";
958 	}
959 }
960 
cdc_hec_discover(struct node * node,unsigned me,unsigned la,bool print)961 static int cdc_hec_discover(struct node *node, unsigned me, unsigned la, bool print)
962 {
963 	/* TODO: For future use cases, it might be necessary to store the results
964 	   from the HEC discovery to know which HECs are possible to form, etc. */
965 	struct cec_msg msg;
966 	__u32 mode = CEC_MODE_INITIATOR | CEC_MODE_FOLLOWER;
967 	bool has_cdc = false;
968 
969 	doioctl(node, CEC_S_MODE, &mode);
970 	cec_msg_init(&msg, me, la);
971 	cec_msg_cdc_hec_discover(&msg);
972 	fail_on_test(!transmit(node, &msg));
973 
974 	/* The spec describes that we shall wait for messages
975 	   up to 1 second, and extend the deadline for every received
976 	   message. The maximum time to wait for incoming state reports
977 	   is 5 seconds. */
978 	unsigned ts_start = get_ts_ms();
979 	while (get_ts_ms() - ts_start < 5000) {
980 		__u8 from;
981 
982 		memset(&msg, 0, sizeof(msg));
983 		msg.timeout = 1000;
984 		if (doioctl(node, CEC_RECEIVE, &msg))
985 			break;
986 		from = cec_msg_initiator(&msg);
987 		if (msg.msg[1] == CEC_MSG_FEATURE_ABORT) {
988 			if (from == la)
989 				return fail("Device replied Feature Abort to broadcast message\n");
990 
991 			warn("Device %d replied Feature Abort to broadcast message\n", cec_msg_initiator(&msg));
992 		}
993 		if (msg.msg[1] != CEC_MSG_CDC_MESSAGE)
994 			continue;
995 		if (msg.msg[4] != CEC_MSG_CDC_HEC_REPORT_STATE)
996 			continue;
997 
998 		__u16 phys_addr, target_phys_addr, hec_field;
999 		__u8 hec_func_state, host_func_state, enc_func_state, cdc_errcode, has_field;
1000 
1001 		cec_ops_cdc_hec_report_state(&msg, &phys_addr, &target_phys_addr,
1002 					     &hec_func_state, &host_func_state,
1003 					     &enc_func_state, &cdc_errcode,
1004 					     &has_field, &hec_field);
1005 
1006 		if (target_phys_addr != node->phys_addr)
1007 			continue;
1008 		if (phys_addr == node->remote[la].phys_addr)
1009 			has_cdc = true;
1010 		if (!print)
1011 			continue;
1012 
1013 		from = cec_msg_initiator(&msg);
1014 		info("Received CDC HEC State report from device %d (%s):\n", from, cec_la2s(from));
1015 		info("Physical address                 : %x.%x.%x.%x\n",
1016 		     cec_phys_addr_exp(phys_addr));
1017 		info("Target physical address          : %x.%x.%x.%x\n",
1018 		     cec_phys_addr_exp(target_phys_addr));
1019 		info("HEC Functionality State          : %s\n", hec_func_state2s(hec_func_state));
1020 		info("Host Functionality State         : %s\n", host_func_state2s(host_func_state));
1021 		info("ENC Functionality State          : %s\n", enc_func_state2s(enc_func_state));
1022 		info("CDC Error Code                   : %s\n", cdc_errcode2s(cdc_errcode));
1023 
1024 		if (has_field) {
1025 			std::ostringstream oss;
1026 
1027 			/* Bit 14 indicates whether or not the device's HDMI
1028 			   output has HEC support/is active. */
1029 			if (!hec_field)
1030 				oss << "None";
1031 			else {
1032 				if (hec_field & (1 << 14))
1033 					oss << "out, ";
1034 				for (int i = 13; i >= 0; i--) {
1035 					if (hec_field & (1 << i))
1036 						oss << "in" << (14 - i) << ", ";
1037 				}
1038 				oss << "\b\b ";
1039 			}
1040 			info("HEC Support Field    : %s\n", oss.str().c_str());
1041 		}
1042 	}
1043 
1044 	mode = CEC_MODE_INITIATOR;
1045 	doioctl(node, CEC_S_MODE, &mode);
1046 
1047 	if (has_cdc)
1048 		return 0;
1049 	return OK_NOT_SUPPORTED;
1050 }
1051 
1052 static const vec_remote_subtests cdc_subtests{
1053 	{ "CDC_HEC_Discover", CEC_LOG_ADDR_MASK_ALL, cdc_hec_discover },
1054 };
1055 
1056 /* Post-test checks */
1057 
post_test_check_recognized(struct node * node,unsigned me,unsigned la,bool interactive)1058 static int post_test_check_recognized(struct node *node, unsigned me, unsigned la, bool interactive)
1059 {
1060 	bool fail = false;
1061 
1062 	for (unsigned i = 0; i < 256; i++) {
1063 		if (node->remote[la].recognized_op[i] && node->remote[la].unrecognized_op[i]) {
1064 			struct cec_msg msg = {};
1065 			msg.msg[1] = i;
1066 			fail("Opcode %s has been both recognized by and has been replied\n", opcode2s(&msg).c_str());
1067 			fail("Feature Abort [Unrecognized Opcode] to by the device.\n");
1068 			fail = true;
1069 		}
1070 	}
1071 	fail_on_test(fail);
1072 
1073 	return 0;
1074 }
1075 
1076 static const vec_remote_subtests post_test_subtests{
1077 	{ "Recognized/unrecognized message consistency", CEC_LOG_ADDR_MASK_ALL, post_test_check_recognized },
1078 };
1079 
1080 static const remote_test tests[] = {
1081 	{ "Core", TAG_CORE, core_subtests },
1082 	{ "Give Device Power Status feature", TAG_POWER_STATUS, power_status_subtests },
1083 	{ "System Information feature", TAG_SYSTEM_INFORMATION, system_info_subtests },
1084 	{ "Vendor Specific Commands feature", TAG_VENDOR_SPECIFIC_COMMANDS, vendor_specific_subtests },
1085 	{ "Device OSD Transfer feature", TAG_DEVICE_OSD_TRANSFER, device_osd_transfer_subtests },
1086 	{ "OSD String feature", TAG_OSD_DISPLAY, osd_string_subtests },
1087 	{ "Remote Control Passthrough feature", TAG_REMOTE_CONTROL_PASSTHROUGH, rc_passthrough_subtests },
1088 	{ "Device Menu Control feature", TAG_DEVICE_MENU_CONTROL, dev_menu_ctl_subtests },
1089 	{ "Deck Control feature", TAG_DECK_CONTROL, deck_ctl_subtests },
1090 	{ "Tuner Control feature", TAG_TUNER_CONTROL, tuner_ctl_subtests },
1091 	{ "One Touch Record feature", TAG_ONE_TOUCH_RECORD, one_touch_rec_subtests },
1092 	{ "Timer Programming feature", TAG_TIMER_PROGRAMMING, timer_prog_subtests },
1093 	{ "Capability Discovery and Control feature", TAG_CAP_DISCOVERY_CONTROL, cdc_subtests },
1094 	{ "Dynamic Auto Lipsync feature", TAG_DYNAMIC_AUTO_LIPSYNC, dal_subtests },
1095 	{ "Audio Return Channel feature", TAG_ARC_CONTROL, arc_subtests },
1096 	{ "System Audio Control feature", TAG_SYSTEM_AUDIO_CONTROL, sac_subtests },
1097 	{ "Audio Rate Control feature", TAG_AUDIO_RATE_CONTROL, audio_rate_ctl_subtests },
1098 	{ "Routing Control feature", TAG_ROUTING_CONTROL, routing_control_subtests },
1099 	{ "Standby/Resume and Power Status", TAG_POWER_STATUS | TAG_STANDBY_RESUME, standby_resume_subtests },
1100 	{ "Post-test checks", TAG_CORE, post_test_subtests },
1101 };
1102 
1103 static std::map<std::string, int> mapTests;
1104 static std::map<std::string, bool> mapTestsNoWarnings;
1105 
collectTests()1106 void collectTests()
1107 {
1108 	std::map<std::string, __u64> mapTestFuncs;
1109 
1110 	for (const auto &test : tests) {
1111 		for (const auto &subtest : test.subtests) {
1112 			std::string name = safename(subtest.name);
1113 			auto func = (__u64)subtest.test_fn;
1114 
1115 			if (mapTestFuncs.find(name) != mapTestFuncs.end() &&
1116 			    mapTestFuncs[name] != func) {
1117 				fprintf(stderr, "Duplicate subtest name, but different tests: %s\n", subtest.name);
1118 				std::exit(EXIT_FAILURE);
1119 			}
1120 			mapTestFuncs[name] = func;
1121 			mapTests[name] = DONT_CARE;
1122 			mapTestsNoWarnings[name] = false;
1123 		}
1124 	}
1125 }
1126 
listTests()1127 void listTests()
1128 {
1129 	for (const auto &test : tests) {
1130 		printf("%s:\n", test.name);
1131 		for (const auto &subtest : test.subtests) {
1132 			printf("\t%s\n", safename(subtest.name).c_str());
1133 		}
1134 	}
1135 }
1136 
setExpectedResult(char * optarg,bool no_warnings)1137 int setExpectedResult(char *optarg, bool no_warnings)
1138 {
1139 	char *equal = std::strchr(optarg, '=');
1140 
1141 	if (!equal || equal == optarg || !isdigit(equal[1]))
1142 		return 1;
1143 	*equal = 0;
1144 	std::string name = safename(optarg);
1145 	if (mapTests.find(name) == mapTests.end())
1146 		return 1;
1147 	mapTests[name] = strtoul(equal + 1, nullptr, 0);
1148 	mapTestsNoWarnings[name] = no_warnings;
1149 	return 0;
1150 }
1151 
testRemote(struct node * node,unsigned me,unsigned la,unsigned test_tags,bool interactive,bool show_ts)1152 void testRemote(struct node *node, unsigned me, unsigned la, unsigned test_tags,
1153 		bool interactive, bool show_ts)
1154 {
1155 	printf("testing CEC local LA %d (%s) to remote LA %d (%s):\n",
1156 	       me, cec_la2s(me), la, cec_la2s(la));
1157 
1158 	if (!util_interactive_ensure_power_state(node, me, la, interactive, CEC_OP_POWER_STATUS_ON))
1159 		return;
1160 	if (!node->remote[la].has_power_status) {
1161 		announce("The device didn't support Give Device Power Status.");
1162 		announce("Assuming that the device is powered on.");
1163 	}
1164 	if (la != CEC_LOG_ADDR_UNREGISTERED &&
1165 	    node->remote[la].phys_addr == CEC_PHYS_ADDR_INVALID) {
1166 		announce("The device has an invalid physical address, this");
1167 		announce("makes it impossible to run the compliance test.");
1168 		ok(FAIL_CRITICAL);
1169 		return;
1170 	}
1171 
1172 	/* Ensure that the remote device knows the initiator's primary device type.*/
1173 	struct cec_msg msg;
1174 
1175 	cec_msg_init(&msg, me, la);
1176 	cec_msg_report_physical_addr(&msg, node->phys_addr, node->prim_devtype);
1177 	transmit_timeout(node, &msg);
1178 
1179 	int ret = 0;
1180 
1181 	for (const auto &test : tests) {
1182 		if ((test.tags & test_tags) != test.tags)
1183 			continue;
1184 
1185 		printf("\t%s:\n", test.name);
1186 		for (const auto &subtest : test.subtests) {
1187 			const char *name = subtest.name;
1188 
1189 			if (subtest.for_cec20 &&
1190 			    (node->remote[la].cec_version < CEC_OP_CEC_VERSION_2_0 || !node->has_cec20))
1191 				continue;
1192 
1193 			if (subtest.in_standby) {
1194 				struct cec_log_addrs laddrs = { };
1195 				doioctl(node, CEC_ADAP_G_LOG_ADDRS, &laddrs);
1196 
1197 				if (!laddrs.log_addr_mask)
1198 					continue;
1199 			}
1200 			std::string start_ts = current_ts();
1201 			node->in_standby = subtest.in_standby;
1202 			mode_set_initiator(node);
1203 			unsigned old_warnings = warnings;
1204 			ret = subtest.test_fn(node, me, la, interactive);
1205 			bool has_warnings = old_warnings < warnings;
1206 			if (!(subtest.la_mask & (1 << la)) && !ret)
1207 				ret = OK_UNEXPECTED;
1208 
1209 			if (mapTests[safename(name)] != DONT_CARE) {
1210 				if (show_ts)
1211 					printf("\t    %s: %s: ", start_ts.c_str(), name);
1212 				else
1213 					printf("\t    %s: ", name);
1214 				if (ret != mapTests[safename(name)])
1215 					printf("%s (Expected '%s', got '%s')\n",
1216 					       ok(FAIL),
1217 					       result_name(mapTests[safename(name)], false),
1218 					       result_name(ret, false));
1219 				else if (has_warnings && mapTestsNoWarnings[safename(name)])
1220 					printf("%s (Expected no warnings, but got %d)\n",
1221 					       ok(FAIL), warnings - old_warnings);
1222 				else if (ret == FAIL)
1223 					printf("%s\n", ok(OK_EXPECTED_FAIL));
1224 				else
1225 					printf("%s\n", ok(ret));
1226 			} else if (ret != NOTAPPLICABLE) {
1227 				if (show_ts)
1228 					printf("\t    %s: %s: %s\n", start_ts.c_str(), name, ok(ret));
1229 				else
1230 					printf("\t    %s: %s\n", name, ok(ret));
1231 			}
1232 			if (ret == FAIL_CRITICAL)
1233 				return;
1234 		}
1235 		printf("\n");
1236 	}
1237 }
1238