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 <cstdlib>
7 #include <cstring>
8 
9 #include <unistd.h>
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <inttypes.h>
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <fcntl.h>
16 #include <ctype.h>
17 #include <errno.h>
18 #include <sys/ioctl.h>
19 #include <config.h>
20 #include <sstream>
21 #include <vector>
22 #include <map>
23 
24 #include "cec-compliance.h"
25 
26 #define test_case(name, tags, subtests) {name, tags, subtests, ARRAY_SIZE(subtests)}
27 #define test_case_ext(name, tags, subtests) {name, tags, subtests, subtests##_size}
28 
29 struct remote_test {
30 	const char *name;
31 	const unsigned tags;
32 	struct remote_subtest *subtests;
33 	unsigned num_subtests;
34 };
35 
36 
37 /* System Information */
38 
system_info_polling(struct node * node,unsigned me,unsigned la,bool interactive)39 int system_info_polling(struct node *node, unsigned me, unsigned la, bool interactive)
40 {
41 	struct cec_msg msg = { };
42 
43 	cec_msg_init(&msg, me, la);
44 	fail_on_test(doioctl(node, CEC_TRANSMIT, &msg));
45 	if (node->remote_la_mask & (1 << la)) {
46 		if (!cec_msg_status_is_ok(&msg)) {
47 			fail("Polling a valid remote LA failed\n");
48 			return FAIL_CRITICAL;
49 		}
50 	} else {
51 		if (cec_msg_status_is_ok(&msg)) {
52 			fail("Polling an invalid remote LA was successful\n");
53 			return FAIL_CRITICAL;
54 		}
55 		return OK_NOT_SUPPORTED;
56 	}
57 
58 	return 0;
59 }
60 
system_info_phys_addr(struct node * node,unsigned me,unsigned la,bool interactive)61 int system_info_phys_addr(struct node *node, unsigned me, unsigned la, bool interactive)
62 {
63 	struct cec_msg msg = { };
64 
65 	cec_msg_init(&msg, me, la);
66 	cec_msg_give_physical_addr(&msg, true);
67 	if (!transmit_timeout(node, &msg) || timed_out_or_abort(&msg)) {
68 		fail_or_warn(node, "Give Physical Addr timed out\n");
69 		return node->in_standby ? 0 : FAIL_CRITICAL;
70 	}
71 	fail_on_test(node->remote[la].phys_addr != ((msg.msg[2] << 8) | msg.msg[3]));
72 	fail_on_test(node->remote[la].prim_type != msg.msg[4]);
73 	return 0;
74 }
75 
system_info_version(struct node * node,unsigned me,unsigned la,bool interactive)76 int system_info_version(struct node *node, unsigned me, unsigned la, bool interactive)
77 {
78 	struct cec_msg msg = {};
79 
80 	cec_msg_init(&msg, me, la);
81 	cec_msg_get_cec_version(&msg, true);
82 	if (!transmit_timeout(node, &msg) || timed_out(&msg))
83 		return fail_or_warn(node, "Get CEC Version timed out\n");
84 	if (unrecognized_op(&msg))
85 		return OK_NOT_SUPPORTED;
86 	if (refused(&msg))
87 		return OK_REFUSED;
88 
89 	/* This needs to be kept in sync with newer CEC versions */
90 	fail_on_test(msg.msg[2] < CEC_OP_CEC_VERSION_1_3A ||
91 		     msg.msg[2] > CEC_OP_CEC_VERSION_2_0);
92 	fail_on_test(node->remote[la].cec_version != msg.msg[2]);
93 
94 	return 0;
95 }
96 
system_info_get_menu_lang(struct node * node,unsigned me,unsigned la,bool interactive)97 int system_info_get_menu_lang(struct node *node, unsigned me, unsigned la, bool interactive)
98 {
99 	struct cec_msg msg = {};
100 	char language[4];
101 
102 	cec_msg_init(&msg, me, la);
103 	cec_msg_get_menu_language(&msg, true);
104 	if (!transmit_timeout(node, &msg) || timed_out(&msg))
105 		return fail_or_warn(node, "Get Menu Languages timed out\n");
106 
107 	/* Devices other than TVs shall send Feature Abort [Unregcognized Opcode]
108 	   in reply to Get Menu Language. */
109 	fail_on_test(!is_tv(la, node->remote[la].prim_type) && !unrecognized_op(&msg));
110 
111 	if (unrecognized_op(&msg)) {
112 		if (is_tv(la, node->remote[la].prim_type))
113 			warn("TV did not respond to Get Menu Language.\n");
114 		return OK_NOT_SUPPORTED;
115 	}
116 	if (refused(&msg))
117 		return OK_REFUSED;
118 	if (cec_msg_status_is_abort(&msg))
119 		return OK_PRESUMED;
120 	cec_ops_set_menu_language(&msg, language);
121 	fail_on_test(strcmp(node->remote[la].language, language));
122 
123 	return 0;
124 }
125 
system_info_set_menu_lang(struct node * node,unsigned me,unsigned la,bool interactive)126 static int system_info_set_menu_lang(struct node *node, unsigned me, unsigned la, bool interactive)
127 {
128 	struct cec_msg msg = {};
129 
130 	cec_msg_init(&msg, me, la);
131 	cec_msg_set_menu_language(&msg, "eng");
132 	fail_on_test(!transmit_timeout(node, &msg));
133 	if (unrecognized_op(&msg))
134 		return OK_NOT_SUPPORTED;
135 	if (refused(&msg))
136 		return OK_REFUSED;
137 
138 	return OK_PRESUMED;
139 }
140 
system_info_give_features(struct node * node,unsigned me,unsigned la,bool interactive)141 int system_info_give_features(struct node *node, unsigned me, unsigned la, bool interactive)
142 {
143 	struct cec_msg msg = { };
144 
145 	cec_msg_init(&msg, me, la);
146 	cec_msg_give_features(&msg, true);
147 	if (!transmit_timeout(node, &msg) || timed_out(&msg))
148 		return fail_or_warn(node, "Give Features timed out\n");
149 	if (unrecognized_op(&msg)) {
150 		if (node->remote[la].cec_version < CEC_OP_CEC_VERSION_2_0)
151 			return OK_NOT_SUPPORTED;
152 		fail_on_test_v2(node->remote[la].cec_version, true);
153 	}
154 	if (refused(&msg))
155 		return OK_REFUSED;
156 	if (node->remote[la].cec_version < CEC_OP_CEC_VERSION_2_0)
157 		info("Device has CEC Version < 2.0 but supports Give Features.\n");
158 
159 	/* RC Profile and Device Features are assumed to be 1 byte. As of CEC 2.0 only
160 	   1 byte is used, but this might be extended in future versions. */
161 	uint8_t cec_version, all_device_types;
162 	const uint8_t *rc_profile, *dev_features;
163 
164 	cec_ops_report_features(&msg, &cec_version, &all_device_types, &rc_profile, &dev_features);
165 	fail_on_test(rc_profile == NULL || dev_features == NULL);
166 	info("All Device Types: \t\t%s\n", cec_all_dev_types2s(all_device_types).c_str());
167 	info("RC Profile: \t%s", cec_rc_src_prof2s(*rc_profile, "").c_str());
168 	info("Device Features: \t%s", cec_dev_feat2s(*dev_features, "").c_str());
169 
170 	if (!(cec_has_playback(1 << la) || cec_has_record(1 << la) || cec_has_tuner(1 << la)) &&
171 	    (*dev_features & CEC_OP_FEAT_DEV_HAS_SET_AUDIO_RATE)) {
172 		return fail("Only Playback, Recording or Tuner devices shall set the Set Audio Rate bit\n");
173 	}
174 	if (!(cec_has_playback(1 << la) || cec_has_record(1 << la)) &&
175 	    (*dev_features & CEC_OP_FEAT_DEV_HAS_DECK_CONTROL))
176 		return fail("Only Playback and Recording devices shall set the Supports Deck Control bit\n");
177 	if (!cec_has_tv(1 << la) && node->remote[la].has_rec_tv)
178 		return fail("Only TVs shall set the Record TV Screen bit\n");
179 	if (cec_has_playback(1 << la) && (*dev_features & CEC_OP_FEAT_DEV_SINK_HAS_ARC_TX))
180 		return fail("A Playback device cannot set the Sink Supports ARC Tx bit\n");
181 	if (cec_has_tv(1 << la) && (*dev_features & CEC_OP_FEAT_DEV_SOURCE_HAS_ARC_RX))
182 		return fail("A TV cannot set the Source Supports ARC Rx bit\n");
183 
184 	fail_on_test(cec_version != node->remote[la].cec_version);
185 	fail_on_test(node->remote[la].rc_profile != *rc_profile);
186 	fail_on_test(node->remote[la].dev_features != *dev_features);
187 	fail_on_test(node->remote[la].all_device_types != all_device_types);
188 	return 0;
189 }
190 
191 static struct remote_subtest system_info_subtests[] = {
192 	{ "Polling Message", CEC_LOG_ADDR_MASK_ALL, system_info_polling },
193 	{ "Give Physical Address", CEC_LOG_ADDR_MASK_ALL, system_info_phys_addr },
194 	{ "Give CEC Version", CEC_LOG_ADDR_MASK_ALL, system_info_version },
195 	{ "Get Menu Language", CEC_LOG_ADDR_MASK_ALL, system_info_get_menu_lang },
196 	{ "Set Menu Language", CEC_LOG_ADDR_MASK_ALL, system_info_set_menu_lang },
197 	{ "Give Device Features", CEC_LOG_ADDR_MASK_ALL, system_info_give_features },
198 };
199 
200 
201 /* Core behavior */
202 
core_unknown(struct node * node,unsigned me,unsigned la,bool interactive)203 int core_unknown(struct node *node, unsigned me, unsigned la, bool interactive)
204 {
205 	struct cec_msg msg = { };
206 	const uint8_t unknown_opcode = 0xfe;
207 
208 	/* Unknown opcodes should be responded to with Feature Abort, with abort
209 	   reason Unknown Opcode.
210 
211 	   For CEC 2.0 and before, 0xfe is an unused opcode. The test possibly
212 	   needs to be updated for future CEC versions. */
213 	cec_msg_init(&msg, me, la);
214 	msg.len = 2;
215 	msg.msg[1] = unknown_opcode;
216 	if (!transmit_timeout(node, &msg) || timed_out(&msg))
217 		return fail_or_warn(node, "Unknown Opcode timed out\n");
218 	fail_on_test(!cec_msg_status_is_abort(&msg));
219 
220 	uint8_t abort_msg, reason;
221 
222 	cec_ops_feature_abort(&msg, &abort_msg, &reason);
223 	fail_on_test(reason != CEC_OP_ABORT_UNRECOGNIZED_OP);
224 	fail_on_test(abort_msg != 0xfe);
225 
226 	/* Unknown opcodes that are broadcast should be ignored */
227 	cec_msg_init(&msg, me, CEC_LOG_ADDR_BROADCAST);
228 	msg.len = 2;
229 	msg.msg[1] = unknown_opcode;
230 	fail_on_test(!transmit_timeout(node, &msg));
231 	fail_on_test(!timed_out(&msg));
232 
233 	return 0;
234 }
235 
core_abort(struct node * node,unsigned me,unsigned la,bool interactive)236 int core_abort(struct node *node, unsigned me, unsigned la, bool interactive)
237 {
238 	struct cec_msg msg = {};
239 
240 	/* The Abort message should always be responded to with Feature Abort
241 	   (with any abort reason) */
242 	cec_msg_init(&msg, me, la);
243 	cec_msg_abort(&msg);
244 	if (!transmit_timeout(node, &msg) || timed_out(&msg))
245 		return fail_or_warn(node, "Abort timed out\n");
246 	fail_on_test(!cec_msg_status_is_abort(&msg));
247 	return 0;
248 }
249 
250 static struct remote_subtest core_subtests[] = {
251 	{ "Feature aborts unknown messages", CEC_LOG_ADDR_MASK_ALL, core_unknown },
252 	{ "Feature aborts Abort message", CEC_LOG_ADDR_MASK_ALL, core_abort },
253 };
254 
255 
256 /* Vendor Specific Commands */
257 
vendor_specific_commands_id(struct node * node,unsigned me,unsigned la,bool interactive)258 int vendor_specific_commands_id(struct node *node, unsigned me, unsigned la, bool interactive)
259 {
260 	struct cec_msg msg = {};
261 
262 	cec_msg_init(&msg, me, la);
263 	cec_msg_give_device_vendor_id(&msg, true);
264 	if (!transmit(node, &msg))
265 		return fail_or_warn(node, "Give Device Vendor ID timed out\n");
266 	if (unrecognized_op(&msg))
267 		return OK_NOT_SUPPORTED;
268 	if (refused(&msg))
269 		return OK_REFUSED;
270 	if (cec_msg_status_is_abort(&msg))
271 		return OK_PRESUMED;
272 	fail_on_test(node->remote[la].vendor_id !=
273 		     (uint32_t)((msg.msg[2] << 16) | (msg.msg[3] << 8) | msg.msg[4]));
274 
275 	return 0;
276 }
277 
278 static struct remote_subtest vendor_specific_subtests[] = {
279 	{ "Give Device Vendor ID", CEC_LOG_ADDR_MASK_ALL, vendor_specific_commands_id },
280 };
281 
282 
283 /* Device OSD Transfer */
284 
device_osd_transfer_set(struct node * node,unsigned me,unsigned la,bool interactive)285 static int device_osd_transfer_set(struct node *node, unsigned me, unsigned la, bool interactive)
286 {
287 	struct cec_msg msg = { };
288 
289 	cec_msg_init(&msg, me, la);
290 	cec_msg_set_osd_name(&msg, "Whatever");
291 	fail_on_test(!transmit_timeout(node, &msg));
292 	if (unrecognized_op(&msg)) {
293 		if (is_tv(la, node->remote[la].prim_type) &&
294 		    node->remote[la].cec_version >= CEC_OP_CEC_VERSION_2_0)
295 			warn("TV feature aborted Set OSD Name\n");
296 		return OK_NOT_SUPPORTED;
297 	}
298 	if (refused(&msg))
299 		return OK_REFUSED;
300 
301 	return OK_PRESUMED;
302 }
303 
device_osd_transfer_give(struct node * node,unsigned me,unsigned la,bool interactive)304 int device_osd_transfer_give(struct node *node, unsigned me, unsigned la, bool interactive)
305 {
306 	struct cec_msg msg = { };
307 
308 	/* Todo: CEC 2.0: devices with several logical addresses shall report
309 	   the same for each logical address. */
310 	cec_msg_init(&msg, me, la);
311 	cec_msg_give_osd_name(&msg, true);
312 	if (!transmit_timeout(node, &msg) || timed_out(&msg))
313 		return fail_or_warn(node, "Give OSD Name timed out\n");
314 	fail_on_test(!is_tv(la, node->remote[la].prim_type) && unrecognized_op(&msg));
315 	if (unrecognized_op(&msg))
316 		return OK_NOT_SUPPORTED;
317 	if (refused(&msg))
318 		return OK_REFUSED;
319 	if (cec_msg_status_is_abort(&msg))
320 		return OK_PRESUMED;
321 	char osd_name[15];
322 	cec_ops_set_osd_name(&msg, osd_name);
323 	fail_on_test(!osd_name[0]);
324 	fail_on_test(strcmp(node->remote[la].osd_name, osd_name));
325 	fail_on_test(msg.len != strlen(osd_name) + 2);
326 
327 	return 0;
328 }
329 
330 static struct remote_subtest device_osd_transfer_subtests[] = {
331 	{ "Set OSD Name", CEC_LOG_ADDR_MASK_ALL, device_osd_transfer_set },
332 	{ "Give OSD Name", CEC_LOG_ADDR_MASK_ALL, device_osd_transfer_give },
333 };
334 
335 
336 /* OSD Display */
337 
osd_string_set_default(struct node * node,unsigned me,unsigned la,bool interactive)338 static int osd_string_set_default(struct node *node, unsigned me, unsigned la, bool interactive)
339 {
340 	struct cec_msg msg = { };
341 	char osd[14];
342 	bool unsuitable = false;
343 
344 	sprintf(osd, "Rept %x from %x", la, me);
345 
346 	interactive_info(true, "You should see \"%s\" appear on the screen", osd);
347 	cec_msg_init(&msg, me, la);
348 	cec_msg_set_osd_string(&msg, CEC_OP_DISP_CTL_DEFAULT, osd);
349 	fail_on_test(!transmit_timeout(node, &msg));
350 	/* In CEC 2.0 it is mandatory for a TV to support this if it reports so
351 	   in its Device Features. */
352 	fail_on_test_v2(node->remote[la].cec_version,
353 			unrecognized_op(&msg) &&
354 			(node->remote[la].dev_features & CEC_OP_FEAT_DEV_HAS_SET_OSD_STRING));
355 	if (unrecognized_op(&msg))
356 		return OK_NOT_SUPPORTED;
357 	if (refused(&msg))
358 		return OK_REFUSED;
359 	if (cec_msg_status_is_abort(&msg)) {
360 		warn("The device is in an unsuitable state or cannot display the complete message.\n");
361 		unsuitable = true;
362 	}
363 	node->remote[la].has_osd = true;
364 	if (!interactive)
365 		return OK_PRESUMED;
366 
367 	/* The CEC 1.4b CTS specifies that one should wait at least 20 seconds for the
368 	   string to be cleared on the remote device */
369 	interactive_info(true, "Waiting 20s for OSD string to be cleared on the remote device");
370 	sleep(20);
371 	fail_on_test(!unsuitable && interactive && !question("Did the string appear and then disappear?"));
372 
373 	return 0;
374 }
375 
osd_string_set_until_clear(struct node * node,unsigned me,unsigned la,bool interactive)376 static int osd_string_set_until_clear(struct node *node, unsigned me, unsigned la, bool interactive)
377 {
378 	if (!node->remote[la].has_osd)
379 		return NOTAPPLICABLE;
380 
381 	struct cec_msg msg = { };
382 	char osd[14];
383 	bool unsuitable = false;
384 
385 	strcpy(osd, "Appears 1 sec");
386 	// Make sure the string is the maximum possible length
387 	fail_on_test(strlen(osd) != 13);
388 
389 	interactive_info(true, "You should see \"%s\" appear on the screen for approximately three seconds.", osd);
390 	cec_msg_init(&msg, me, la);
391 	cec_msg_set_osd_string(&msg, CEC_OP_DISP_CTL_UNTIL_CLEARED, osd);
392 	fail_on_test(!transmit(node, &msg));
393 	if (cec_msg_status_is_abort(&msg) && !unrecognized_op(&msg)) {
394 		warn("The device is in an unsuitable state or cannot display the complete message.\n");
395 		unsuitable = true;
396 	}
397 	sleep(3);
398 
399 	cec_msg_init(&msg, me, la);
400 	cec_msg_set_osd_string(&msg, CEC_OP_DISP_CTL_CLEAR, "");
401 	fail_on_test(!transmit_timeout(node, &msg, 250));
402 	fail_on_test(cec_msg_status_is_abort(&msg));
403 	fail_on_test(!unsuitable && interactive && !question("Did the string appear?"));
404 
405 	if (interactive)
406 		return 0;
407 
408 	return OK_PRESUMED;
409 }
410 
osd_string_invalid(struct node * node,unsigned me,unsigned la,bool interactive)411 static int osd_string_invalid(struct node *node, unsigned me, unsigned la, bool interactive)
412 {
413 	if (!node->remote[la].has_osd)
414 		return NOTAPPLICABLE;
415 
416 	struct cec_msg msg = { };
417 
418 	/* Send Set OSD String with an Display Control operand. A Feature Abort is
419 	   expected in reply. */
420 	interactive_info(true, "You should observe no change on the on screen display");
421 	cec_msg_init(&msg, me, la);
422 	cec_msg_set_osd_string(&msg, 0xff, "");
423 	fail_on_test(!transmit_timeout(node, &msg));
424 	fail_on_test(timed_out(&msg));
425 	fail_on_test(!cec_msg_status_is_abort(&msg));
426 	fail_on_test(interactive && question("Did the display change?"));
427 
428 	return 0;
429 }
430 
431 static struct remote_subtest osd_string_subtests[] = {
432 	{ "Set OSD String with default timeout", CEC_LOG_ADDR_MASK_TV, osd_string_set_default },
433 	{ "Set OSD String with no timeout", CEC_LOG_ADDR_MASK_TV, osd_string_set_until_clear },
434 	{ "Set OSD String with invalid operand", CEC_LOG_ADDR_MASK_TV, osd_string_invalid },
435 };
436 
437 
438 /* Routing Control */
439 
routing_control_inactive_source(struct node * node,unsigned me,unsigned la,bool interactive)440 static int routing_control_inactive_source(struct node *node, unsigned me, unsigned la, bool interactive)
441 {
442 	struct cec_msg msg = {};
443 	int response;
444 
445 	interactive_info(true, "Please make sure that the TV is currently viewing this source.");
446 	mode_set_follower(node);
447 	cec_msg_init(&msg, me, la);
448 	cec_msg_inactive_source(&msg, node->phys_addr);
449 	fail_on_test(!transmit(node, &msg));
450 	if (unrecognized_op(&msg))
451 		return OK_NOT_SUPPORTED;
452 	if (refused(&msg))
453 		return OK_REFUSED;
454 	// It may take a bit of time for the Inactive Source message to take
455 	// effect, so sleep a bit.
456 	response = util_receive(node, CEC_LOG_ADDR_TV, 3000, &msg,
457 				CEC_MSG_INACTIVE_SOURCE,
458 				CEC_MSG_ACTIVE_SOURCE, CEC_MSG_SET_STREAM_PATH);
459 	if (me == CEC_LOG_ADDR_TV) {
460 		// Inactive Source should be ignored by all other devices
461 		if (response >= 0)
462 			return fail("Unexpected reply to Inactive Source\n");
463 		fail_on_test(response >= 0);
464 	} else {
465 		if (response < 0)
466 			warn("Expected Active Source or Set Stream Path reply to Inactive Source\n");
467 		fail_on_test(interactive && !question("Did the TV switch away from or stop showing this source?"));
468 	}
469 
470 	return 0;
471 }
472 
routing_control_active_source(struct node * node,unsigned me,unsigned la,bool interactive)473 static int routing_control_active_source(struct node *node, unsigned me, unsigned la, bool interactive)
474 {
475 	struct cec_msg msg = {};
476 
477 	interactive_info(true, "Please switch the TV to another source.");
478 	cec_msg_init(&msg, me, la);
479 	cec_msg_active_source(&msg, node->phys_addr);
480 	fail_on_test(!transmit_timeout(node, &msg));
481 	fail_on_test(interactive && !question("Did the TV switch to this source?"));
482 
483 	if (interactive)
484 		return 0;
485 
486 	return OK_PRESUMED;
487 }
488 
routing_control_req_active_source(struct node * node,unsigned me,unsigned la,bool interactive)489 static int routing_control_req_active_source(struct node *node, unsigned me, unsigned la, bool interactive)
490 {
491 	struct cec_msg msg = {};
492 
493 	/* We have now said that we are active source, so receiving a reply to
494 	   Request Active Source should fail the test. */
495 	cec_msg_init(&msg, me, la);
496 	cec_msg_request_active_source(&msg, true);
497 	fail_on_test(!transmit_timeout(node, &msg));
498 	fail_on_test(!timed_out(&msg));
499 
500 	return 0;
501 }
502 
routing_control_set_stream_path(struct node * node,unsigned me,unsigned la,bool interactive)503 static int routing_control_set_stream_path(struct node *node, unsigned me, unsigned la, bool interactive)
504 {
505 	struct cec_msg msg = {};
506 	uint16_t phys_addr;
507 
508 	/* Send Set Stream Path with the remote physical address. We expect the
509 	   source to eventually send Active Source. The timeout of long_timeout
510 	   seconds is necessary because the device might have to wake up from standby.
511 
512 	   In CEC 2.0 it is mandatory for sources to send Active Source. */
513 	if (is_tv(la, node->remote[la].prim_type))
514 		interactive_info(true, "Please ensure that the device is in standby.");
515 	announce("Sending Set Stream Path and waiting for reply. This may take up to %llu s.", (long long)long_timeout);
516 	cec_msg_init(&msg, me, la);
517 	cec_msg_set_stream_path(&msg, node->remote[la].phys_addr);
518 	msg.reply = CEC_MSG_ACTIVE_SOURCE;
519 	fail_on_test(!transmit_timeout(node, &msg, long_timeout * 1000));
520 	if (timed_out(&msg) && is_tv(la, node->remote[la].prim_type))
521 		return OK_NOT_SUPPORTED;
522 	if (timed_out(&msg) && node->remote[la].cec_version < CEC_OP_CEC_VERSION_2_0) {
523 		warn("Device did not respond to Set Stream Path.\n");
524 		return OK_NOT_SUPPORTED;
525 	}
526 	fail_on_test_v2(node->remote[la].cec_version, timed_out(&msg));
527 	cec_ops_active_source(&msg, &phys_addr);
528 	fail_on_test(phys_addr != node->remote[la].phys_addr);
529 	if (is_tv(la, node->remote[la].prim_type))
530 		fail_on_test(interactive && !question("Did the device go out of standby?"));
531 
532 	if (interactive || node->remote[la].cec_version >= CEC_OP_CEC_VERSION_2_0)
533 		return 0;
534 
535 	return OK_PRESUMED;
536 }
537 
538 static struct remote_subtest routing_control_subtests[] = {
539 	{ "Active Source", CEC_LOG_ADDR_MASK_TV, routing_control_active_source },
540 	{ "Request Active Source", CEC_LOG_ADDR_MASK_ALL, routing_control_req_active_source },
541 	{ "Inactive Source", CEC_LOG_ADDR_MASK_TV, routing_control_inactive_source },
542 	{ "Set Stream Path", CEC_LOG_ADDR_MASK_ALL, routing_control_set_stream_path },
543 };
544 
545 
546 /* Remote Control Passthrough */
547 
rc_passthrough_user_ctrl_pressed(struct node * node,unsigned me,unsigned la,bool interactive)548 static int rc_passthrough_user_ctrl_pressed(struct node *node, unsigned me, unsigned la, bool interactive)
549 {
550 	struct cec_msg msg = {};
551 	struct cec_op_ui_command rc_press;
552 
553 	cec_msg_init(&msg, me, la);
554 	rc_press.ui_cmd = CEC_OP_UI_CMD_VOLUME_UP; // Volume up key (the key is not crucial here)
555 	cec_msg_user_control_pressed(&msg, &rc_press);
556 	fail_on_test(!transmit_timeout(node, &msg));
557 	/* Mandatory for all except devices which have taken logical address 15 */
558 	fail_on_test_v2(node->remote[la].cec_version,
559 			unrecognized_op(&msg) && !(cec_is_unregistered(1 << la)));
560 	if (unrecognized_op(&msg))
561 		return OK_NOT_SUPPORTED;
562 	if (refused(&msg))
563 		return OK_REFUSED;
564 
565 	return OK_PRESUMED;
566 }
567 
rc_passthrough_user_ctrl_released(struct node * node,unsigned me,unsigned la,bool interactive)568 static int rc_passthrough_user_ctrl_released(struct node *node, unsigned me, unsigned la, bool interactive)
569 {
570 	struct cec_msg msg = {};
571 
572 	cec_msg_init(&msg, me, la);
573 	cec_msg_user_control_released(&msg);
574 	fail_on_test(!transmit_timeout(node, &msg));
575 	fail_on_test_v2(node->remote[la].cec_version,
576 			cec_msg_status_is_abort(&msg) && !(la & CEC_LOG_ADDR_MASK_UNREGISTERED));
577 	if (unrecognized_op(&msg))
578 		return OK_NOT_SUPPORTED;
579 	if (refused(&msg))
580 		return OK_REFUSED;
581 	node->remote[la].has_remote_control_passthrough = true;
582 
583 	return OK_PRESUMED;
584 }
585 
586 static struct remote_subtest rc_passthrough_subtests[] = {
587 	{ "User Control Pressed", CEC_LOG_ADDR_MASK_ALL, rc_passthrough_user_ctrl_pressed },
588 	{ "User Control Released", CEC_LOG_ADDR_MASK_ALL, rc_passthrough_user_ctrl_released },
589 };
590 
591 
592 /* Device Menu Control */
593 
594 /*
595   TODO: These are very rudimentary tests which should be expanded.
596  */
597 
dev_menu_ctl_request(struct node * node,unsigned me,unsigned la,bool interactive)598 static int dev_menu_ctl_request(struct node *node, unsigned me, unsigned la, bool interactive)
599 {
600 	struct cec_msg msg = {};
601 
602 	cec_msg_init(&msg, me, la);
603 	cec_msg_menu_request(&msg, true, CEC_OP_MENU_REQUEST_QUERY);
604 	fail_on_test(!transmit_timeout(node, &msg));
605 	if (unrecognized_op(&msg))
606 		return OK_NOT_SUPPORTED;
607 	if (refused(&msg))
608 		return OK_REFUSED;
609 	if (cec_msg_status_is_abort(&msg))
610 		return OK_PRESUMED;
611 	if (node->remote[la].cec_version >= CEC_OP_CEC_VERSION_2_0)
612 		warn("The Device Menu Control feature is deprecated in CEC 2.0\n");
613 
614 	return 0;
615 }
616 
617 static struct remote_subtest dev_menu_ctl_subtests[] = {
618 	{ "Menu Request", static_cast<uint16_t>(~CEC_LOG_ADDR_MASK_TV), dev_menu_ctl_request },
619 	{ "User Control Pressed", CEC_LOG_ADDR_MASK_ALL, rc_passthrough_user_ctrl_pressed },
620 	{ "User Control Released", CEC_LOG_ADDR_MASK_ALL, rc_passthrough_user_ctrl_released },
621 };
622 
623 
624 /* Deck Control */
625 
626 /*
627   TODO: These are very rudimentary tests which should be expanded.
628  */
629 
deck_ctl_give_status(struct node * node,unsigned me,unsigned la,bool interactive)630 static int deck_ctl_give_status(struct node *node, unsigned me, unsigned la, bool interactive)
631 {
632 	struct cec_msg msg = {};
633 
634 	cec_msg_init(&msg, me, la);
635 	cec_msg_give_deck_status(&msg, true, CEC_OP_STATUS_REQ_ONCE);
636 	fail_on_test(!transmit_timeout(node, &msg));
637 	fail_on_test(timed_out(&msg));
638 	if (is_playback_or_rec(la)) {
639 		fail_on_test_v2(node->remote[la].cec_version,
640 				node->remote[la].has_deck_ctl && cec_msg_status_is_abort(&msg));
641 		fail_on_test_v2(node->remote[la].cec_version,
642 				!node->remote[la].has_deck_ctl && !unrecognized_op(&msg));
643 	}
644 	if (unrecognized_op(&msg))
645 		return OK_NOT_SUPPORTED;
646 	if (refused(&msg))
647 		return OK_REFUSED;
648 	if (cec_msg_status_is_abort(&msg))
649 		return OK_PRESUMED;
650 
651 	return 0;
652 }
653 
deck_ctl_deck_status(struct node * node,unsigned me,unsigned la,bool interactive)654 static int deck_ctl_deck_status(struct node *node, unsigned me, unsigned la, bool interactive)
655 {
656 	struct cec_msg msg = {};
657 
658 	cec_msg_init(&msg, me, la);
659 	cec_msg_deck_status(&msg, CEC_OP_DECK_INFO_STOP);
660 	fail_on_test(!transmit_timeout(node, &msg));
661 	if (unrecognized_op(&msg))
662 		return OK_NOT_SUPPORTED;
663 	if (refused(&msg))
664 		return OK_REFUSED;
665 	if (cec_msg_status_is_abort(&msg))
666 		return OK_PRESUMED;
667 
668 	return 0;
669 }
670 
deck_ctl_deck_ctl(struct node * node,unsigned me,unsigned la,bool interactive)671 static int deck_ctl_deck_ctl(struct node *node, unsigned me, unsigned la, bool interactive)
672 {
673 	struct cec_msg msg = {};
674 
675 	cec_msg_init(&msg, me, la);
676 	cec_msg_deck_control(&msg, CEC_OP_DECK_CTL_MODE_STOP);
677 	fail_on_test(!transmit_timeout(node, &msg));
678 	if (is_playback_or_rec(la)) {
679 		fail_on_test_v2(node->remote[la].cec_version,
680 				node->remote[la].has_deck_ctl && unrecognized_op(&msg));
681 		fail_on_test_v2(node->remote[la].cec_version,
682 				!node->remote[la].has_deck_ctl && !unrecognized_op(&msg));
683 	}
684 	if (unrecognized_op(&msg))
685 		return OK_NOT_SUPPORTED;
686 	if (refused(&msg))
687 		return OK_REFUSED;
688 	if (cec_msg_status_is_abort(&msg))
689 		return OK_PRESUMED;
690 
691 	return OK_PRESUMED;
692 }
693 
deck_ctl_play(struct node * node,unsigned me,unsigned la,bool interactive)694 static int deck_ctl_play(struct node *node, unsigned me, unsigned la, bool interactive)
695 {
696 	struct cec_msg msg = {};
697 
698 	cec_msg_init(&msg, me, la);
699 	cec_msg_play(&msg, CEC_OP_PLAY_MODE_PLAY_STILL);
700 	fail_on_test(!transmit_timeout(node, &msg));
701 	if (is_playback_or_rec(la)) {
702 		fail_on_test_v2(node->remote[la].cec_version,
703 				node->remote[la].has_deck_ctl && unrecognized_op(&msg));
704 		fail_on_test_v2(node->remote[la].cec_version,
705 				!node->remote[la].has_deck_ctl && !unrecognized_op(&msg));
706 	}
707 	if (unrecognized_op(&msg))
708 		return OK_NOT_SUPPORTED;
709 	if (refused(&msg))
710 		return OK_REFUSED;
711 	if (cec_msg_status_is_abort(&msg))
712 		return OK_PRESUMED;
713 
714 	return OK_PRESUMED;
715 }
716 
717 static struct remote_subtest deck_ctl_subtests[] = {
718 	{ "Give Deck Status",
719 	  CEC_LOG_ADDR_MASK_PLAYBACK | CEC_LOG_ADDR_MASK_RECORD,
720 	  deck_ctl_give_status },
721 	{ "Deck Status",
722 	  CEC_LOG_ADDR_MASK_ALL,
723 	  deck_ctl_deck_status },
724 	{ "Deck Control",
725 	  CEC_LOG_ADDR_MASK_PLAYBACK | CEC_LOG_ADDR_MASK_RECORD,
726 	  deck_ctl_deck_ctl },
727 	{ "Play",
728 	  CEC_LOG_ADDR_MASK_PLAYBACK | CEC_LOG_ADDR_MASK_RECORD,
729 	  deck_ctl_play },
730 };
731 
732 
733 /* Tuner Control */
734 
bcast_type2s(uint8_t bcast_type)735 static const char *bcast_type2s(uint8_t bcast_type)
736 {
737 	switch (bcast_type) {
738 	case CEC_OP_ANA_BCAST_TYPE_CABLE:
739 		return "Cable";
740 	case CEC_OP_ANA_BCAST_TYPE_SATELLITE:
741 		return "Satellite";
742 	case CEC_OP_ANA_BCAST_TYPE_TERRESTRIAL:
743 		return "Terrestrial";
744 	default:
745 		return "Future use";
746 	}
747 }
748 
log_tuner_service(const struct cec_op_tuner_device_info & info,const char * prefix="")749 static int log_tuner_service(const struct cec_op_tuner_device_info &info,
750 			     const char *prefix = "")
751 {
752 	printf("\t\t%s", prefix);
753 
754 	if (info.is_analog) {
755 		double freq_mhz = (info.analog.ana_freq * 625) / 10000.0;
756 
757 		printf("Analog Channel %.2f MHz (%s, %s)\n", freq_mhz,
758 		       bcast_system2s(info.analog.bcast_system),
759 		       bcast_type2s(info.analog.ana_bcast_type));
760 
761 		switch (info.analog.bcast_system) {
762 		case CEC_OP_BCAST_SYSTEM_PAL_BG:
763 		case CEC_OP_BCAST_SYSTEM_SECAM_LQ:
764 		case CEC_OP_BCAST_SYSTEM_PAL_M:
765 		case CEC_OP_BCAST_SYSTEM_NTSC_M:
766 		case CEC_OP_BCAST_SYSTEM_PAL_I:
767 		case CEC_OP_BCAST_SYSTEM_SECAM_DK:
768 		case CEC_OP_BCAST_SYSTEM_SECAM_BG:
769 		case CEC_OP_BCAST_SYSTEM_SECAM_L:
770 		case CEC_OP_BCAST_SYSTEM_PAL_DK:
771 			break;
772 		default:
773 			return fail("invalid analog bcast_system %u", info.analog.bcast_system);
774 		}
775 		if (info.analog.ana_bcast_type > CEC_OP_ANA_BCAST_TYPE_TERRESTRIAL)
776 			return fail("invalid analog bcast_type %u\n", info.analog.ana_bcast_type);
777 		fail_on_test(!info.analog.ana_freq);
778 		return 0;
779 	}
780 
781 	uint8_t system = info.digital.dig_bcast_system;
782 
783 	printf("%s Channel ", dig_bcast_system2s(system));
784 	if (info.digital.service_id_method) {
785 		uint16_t major = info.digital.channel.major;
786 		uint16_t minor = info.digital.channel.minor;
787 
788 		switch (info.digital.channel.channel_number_fmt) {
789 		case CEC_OP_CHANNEL_NUMBER_FMT_2_PART:
790 			printf("%u.%u\n", major, minor);
791 			break;
792 		case CEC_OP_CHANNEL_NUMBER_FMT_1_PART:
793 			printf("%u\n", minor);
794 			break;
795 		default:
796 			printf("%u.%u\n", major, minor);
797 			return fail("invalid service ID method\n");
798 		}
799 		return 0;
800 	}
801 
802 
803 	switch (system) {
804 	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_GEN:
805 	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_BS:
806 	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_CS:
807 	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_T: {
808 		uint16_t tsid = info.digital.arib.transport_id;
809 		uint16_t sid = info.digital.arib.service_id;
810 		uint16_t onid = info.digital.arib.orig_network_id;
811 
812 		printf("TSID: %u, SID: %u, ONID: %u\n", tsid, sid, onid);
813 		break;
814 	}
815 	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_GEN:
816 	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_SAT:
817 	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_CABLE:
818 	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_T: {
819 		uint16_t tsid = info.digital.atsc.transport_id;
820 		uint16_t pn = info.digital.atsc.program_number;
821 
822 		printf("TSID: %u, Program Number: %u\n", tsid, pn);
823 		break;
824 	}
825 	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_GEN:
826 	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S:
827 	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S2:
828 	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_C:
829 	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_T: {
830 		uint16_t tsid = info.digital.dvb.transport_id;
831 		uint16_t sid = info.digital.dvb.service_id;
832 		uint16_t onid = info.digital.dvb.orig_network_id;
833 
834 		printf("TSID: %u, SID: %u, ONID: %u\n", tsid, sid, onid);
835 		break;
836 	}
837 	default:
838 		break;
839 	}
840 
841 	switch (system) {
842 	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_GEN:
843 	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_GEN:
844 	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_GEN:
845 		warn_once("generic digital broadcast systems should not be used");
846 		break;
847 	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_BS:
848 	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_CS:
849 	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_T:
850 	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_CABLE:
851 	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_SAT:
852 	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_T:
853 	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_C:
854 	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S:
855 	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S2:
856 	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_T:
857 		break;
858 	default:
859 		return fail("invalid digital broadcast system %u", system);
860 	}
861 
862 	if (info.digital.service_id_method > CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL)
863 		return fail("invalid service ID method %u\n", info.digital.service_id_method);
864 
865 	return 0;
866 }
867 
tuner_ctl_test(struct node * node,unsigned me,unsigned la,bool interactive)868 static int tuner_ctl_test(struct node *node, unsigned me, unsigned la, bool interactive)
869 {
870 	struct cec_msg msg = {};
871 	struct cec_op_tuner_device_info info = {};
872 	std::vector<struct cec_op_tuner_device_info> info_vec;
873 	bool has_tuner = (1 << la) & (CEC_LOG_ADDR_MASK_TV | CEC_LOG_ADDR_MASK_TUNER);
874 	int ret;
875 
876 	cec_msg_init(&msg, me, la);
877 	cec_msg_give_tuner_device_status(&msg, true, CEC_OP_STATUS_REQ_ONCE);
878 	fail_on_test(!transmit_timeout(node, &msg));
879 	fail_on_test(!has_tuner && !timed_out_or_abort(&msg));
880 	if (!has_tuner)
881 		return OK_NOT_SUPPORTED;
882 	if (timed_out(&msg) || unrecognized_op(&msg))
883 		return OK_NOT_SUPPORTED;
884 	if (cec_msg_status_is_abort(&msg))
885 		return OK_REFUSED;
886 
887 	printf("\t    Start Channel Scan\n");
888 	cec_ops_tuner_device_status(&msg, &info);
889 	info_vec.push_back(info);
890 	ret = log_tuner_service(info);
891 	if (ret)
892 		return ret;
893 
894 	while (true) {
895 		cec_msg_init(&msg, me, la);
896 		cec_msg_tuner_step_increment(&msg);
897 		fail_on_test(!transmit(node, &msg));
898 		fail_on_test(cec_msg_status_is_abort(&msg));
899 		if (cec_msg_status_is_abort(&msg)) {
900 			fail_on_test(abort_reason(&msg) == CEC_OP_ABORT_UNRECOGNIZED_OP);
901 			if (abort_reason(&msg) == CEC_OP_ABORT_REFUSED) {
902 				warn("Tuner step increment does not wrap.\n");
903 				break;
904 			}
905 
906 			warn("Tuner at end of service list did not receive feature abort refused.\n");
907 			break;
908 		}
909 		cec_msg_init(&msg, me, la);
910 		cec_msg_give_tuner_device_status(&msg, true, CEC_OP_STATUS_REQ_ONCE);
911 		fail_on_test(!transmit_timeout(node, &msg));
912 		fail_on_test(timed_out_or_abort(&msg));
913 		memset(&info, 0, sizeof(info));
914 		cec_ops_tuner_device_status(&msg, &info);
915 		if (!memcmp(&info, &info_vec[0], sizeof(info)))
916 			break;
917 		ret = log_tuner_service(info);
918 		if (ret)
919 			return ret;
920 		info_vec.push_back(info);
921 	}
922 	printf("\t    Finished Channel Scan\n");
923 
924 	printf("\t    Start Channel Test\n");
925 	for (std::vector<struct cec_op_tuner_device_info>::iterator iter = info_vec.begin();
926 			iter != info_vec.end(); iter++) {
927 		cec_msg_init(&msg, me, la);
928 		log_tuner_service(*iter, "Select ");
929 		if (iter->is_analog)
930 			cec_msg_select_analogue_service(&msg, iter->analog.ana_bcast_type,
931 				iter->analog.ana_freq, iter->analog.bcast_system);
932 		else
933 			cec_msg_select_digital_service(&msg, &iter->digital);
934 		fail_on_test(!transmit(node, &msg));
935 		fail_on_test(cec_msg_status_is_abort(&msg));
936 		cec_msg_init(&msg, me, la);
937 		cec_msg_give_tuner_device_status(&msg, true, CEC_OP_STATUS_REQ_ONCE);
938 		fail_on_test(!transmit_timeout(node, &msg));
939 		fail_on_test(timed_out_or_abort(&msg));
940 		memset(&info, 0, sizeof(info));
941 		cec_ops_tuner_device_status(&msg, &info);
942 		if (memcmp(&info, &(*iter), sizeof(info))) {
943 			log_tuner_service(info);
944 			log_tuner_service(*iter);
945 		}
946 		fail_on_test(memcmp(&info, &(*iter), sizeof(info)));
947 	}
948 	printf("\t    Finished Channel Test\n");
949 
950 	cec_msg_init(&msg, me, la);
951 	cec_msg_select_analogue_service(&msg, 3, 16000, 9);
952 	printf("\t\tSelect invalid analog channel\n");
953 	fail_on_test(!transmit_timeout(node, &msg));
954 	fail_on_test(!cec_msg_status_is_abort(&msg));
955 	fail_on_test(abort_reason(&msg) != CEC_OP_ABORT_INVALID_OP);
956 	cec_msg_init(&msg, me, la);
957 	info.digital.service_id_method = CEC_OP_SERVICE_ID_METHOD_BY_DIG_ID;
958 	info.digital.dig_bcast_system = CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S2;
959 	info.digital.dvb.transport_id = 0;
960 	info.digital.dvb.service_id = 0;
961 	info.digital.dvb.orig_network_id = 0;
962 	cec_msg_select_digital_service(&msg, &info.digital);
963 	printf("\t\tSelect invalid digital channel\n");
964 	fail_on_test(!transmit_timeout(node, &msg));
965 	fail_on_test(!cec_msg_status_is_abort(&msg));
966 	fail_on_test(abort_reason(&msg) != CEC_OP_ABORT_INVALID_OP);
967 
968 	return 0;
969 }
970 
971 static struct remote_subtest tuner_ctl_subtests[] = {
972 	{ "Tuner Control", CEC_LOG_ADDR_MASK_TUNER | CEC_LOG_ADDR_MASK_TV, tuner_ctl_test },
973 };
974 
975 
976 /* One Touch Record */
977 
978 /*
979   TODO: These are very rudimentary tests which should be expanded.
980 
981   - The HDMI CEC 1.4b spec details that Standby shall not be acted upon while the
982     device is recording, but it should remember that it received Standby.
983  */
984 
one_touch_rec_tv_screen(struct node * node,unsigned me,unsigned la,bool interactive)985 static int one_touch_rec_tv_screen(struct node *node, unsigned me, unsigned la, bool interactive)
986 {
987 	/*
988 	  TODO:
989 	  - Page 36 in HDMI CEC 1.4b spec lists additional behaviors that should be
990 	    checked for.
991 	  - The TV should ignore this message when received from other LA than Recording or
992 	    Reserved.
993 	 */
994 	struct cec_msg msg = {};
995 
996 	cec_msg_init(&msg, me, la);
997 	cec_msg_record_tv_screen(&msg, true);
998 	fail_on_test(!transmit_timeout(node, &msg));
999 	fail_on_test_v2(node->remote[la].cec_version,
1000 			node->remote[la].has_rec_tv && unrecognized_op(&msg));
1001 	fail_on_test_v2(node->remote[la].cec_version,
1002 			!node->remote[la].has_rec_tv && !unrecognized_op(&msg));
1003 	if (unrecognized_op(&msg))
1004 		return OK_NOT_SUPPORTED;
1005 	if (refused(&msg))
1006 		return OK_REFUSED;
1007 	if (cec_msg_status_is_abort(&msg))
1008 		return OK_PRESUMED;
1009 
1010 	return 0;
1011 }
1012 
one_touch_rec_on(struct node * node,unsigned me,unsigned la,bool interactive)1013 static int one_touch_rec_on(struct node *node, unsigned me, unsigned la, bool interactive)
1014 {
1015 	/*
1016 	  TODO: Page 36 in HDMI CEC 1.4b spec lists additional behaviors that should be
1017 	  checked for.
1018 	 */
1019 	struct cec_msg msg = {};
1020 	struct cec_op_record_src rec_src = {};
1021 
1022 	rec_src.type = CEC_OP_RECORD_SRC_OWN;
1023 	cec_msg_init(&msg, me, la);
1024 	cec_msg_record_on(&msg, true, &rec_src);
1025 	fail_on_test(!transmit_timeout(node, &msg));
1026 	fail_on_test(timed_out(&msg));
1027 	fail_on_test(cec_has_record(1 << la) && unrecognized_op(&msg));
1028 	if (unrecognized_op(&msg))
1029 		return OK_NOT_SUPPORTED;
1030 	if (refused(&msg))
1031 		return OK_REFUSED;
1032 	if (cec_msg_status_is_abort(&msg))
1033 		return OK_PRESUMED;
1034 
1035 	return 0;
1036 }
1037 
one_touch_rec_off(struct node * node,unsigned me,unsigned la,bool interactive)1038 static int one_touch_rec_off(struct node *node, unsigned me, unsigned la, bool interactive)
1039 {
1040 	struct cec_msg msg = {};
1041 
1042 	cec_msg_init(&msg, me, la);
1043 	cec_msg_record_off(&msg, false);
1044 	fail_on_test(!transmit_timeout(node, &msg));
1045 	fail_on_test(cec_has_record(1 << la) && unrecognized_op(&msg));
1046 	if (unrecognized_op(&msg))
1047 		return OK_NOT_SUPPORTED;
1048 	if (refused(&msg))
1049 		return OK_REFUSED;
1050 	if (cec_msg_status_is_abort(&msg))
1051 		return OK_PRESUMED;
1052 	if (timed_out(&msg))
1053 		return OK_PRESUMED;
1054 
1055 	return 0;
1056 }
1057 
one_touch_rec_status(struct node * node,unsigned me,unsigned la,bool interactive)1058 static int one_touch_rec_status(struct node *node, unsigned me, unsigned la, bool interactive)
1059 {
1060 	struct cec_msg msg = {};
1061 
1062 	cec_msg_init(&msg, me, la);
1063 	cec_msg_record_status(&msg, CEC_OP_RECORD_STATUS_DIG_SERVICE);
1064 	fail_on_test(!transmit_timeout(node, &msg));
1065 	if (unrecognized_op(&msg))
1066 		return OK_NOT_SUPPORTED;
1067 	if (refused(&msg))
1068 		return OK_REFUSED;
1069 	if (cec_msg_status_is_abort(&msg))
1070 		return OK_PRESUMED;
1071 
1072 	return 0;
1073 }
1074 
1075 static struct remote_subtest one_touch_rec_subtests[] = {
1076 	{ "Record TV Screen", CEC_LOG_ADDR_MASK_TV, one_touch_rec_tv_screen },
1077 	{ "Record On", CEC_LOG_ADDR_MASK_RECORD, one_touch_rec_on },
1078 	{ "Record Off", CEC_LOG_ADDR_MASK_RECORD, one_touch_rec_off },
1079 	{ "Record Status", CEC_LOG_ADDR_MASK_ALL, one_touch_rec_status },
1080 };
1081 
1082 
1083 /* Timer Programming */
1084 
1085 /*
1086   TODO: These are very rudimentary tests which should be expanded.
1087  */
1088 
timer_prog_set_analog_timer(struct node * node,unsigned me,unsigned la,bool interactive)1089 static int timer_prog_set_analog_timer(struct node *node, unsigned me, unsigned la, bool interactive)
1090 {
1091 	/* TODO: Check the timer status for possible errors, etc. */
1092 
1093 	struct cec_msg msg = {};
1094 
1095 	cec_msg_init(&msg, me, la);
1096 	cec_msg_set_analogue_timer(&msg, true, 1, 1, 0, 0, 1, 0, CEC_OP_REC_SEQ_ONCE_ONLY,
1097 				     CEC_OP_ANA_BCAST_TYPE_CABLE,
1098 				     7668, // 479.25 MHz
1099 				     node->remote[la].bcast_sys);
1100 	fail_on_test(!transmit_timeout(node, &msg, 10000));
1101 	if (timed_out(&msg)) {
1102 		warn("Timed out waiting for Timer Status. Assuming timer was set.\n");
1103 		return OK_PRESUMED;
1104 	}
1105 	if (unrecognized_op(&msg))
1106 		return OK_NOT_SUPPORTED;
1107 	if (refused(&msg))
1108 		return OK_REFUSED;
1109 	if (cec_msg_status_is_abort(&msg))
1110 		return OK_PRESUMED;
1111 
1112 	return 0;
1113 }
1114 
timer_prog_set_digital_timer(struct node * node,unsigned me,unsigned la,bool interactive)1115 static int timer_prog_set_digital_timer(struct node *node, unsigned me, unsigned la, bool interactive)
1116 {
1117 	/* TODO: Check the timer status for possible errors, etc. */
1118 
1119 	struct cec_msg msg = {};
1120 	struct cec_op_digital_service_id digital_service_id = {};
1121 
1122 	digital_service_id.service_id_method = CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL;
1123 	digital_service_id.channel.channel_number_fmt = CEC_OP_CHANNEL_NUMBER_FMT_1_PART;
1124 	digital_service_id.channel.minor = 1;
1125 	digital_service_id.dig_bcast_system = node->remote[la].dig_bcast_sys;
1126 	cec_msg_init(&msg, me, la);
1127 	cec_msg_set_digital_timer(&msg, true, 1, 1, 0, 0, 1, 0, CEC_OP_REC_SEQ_ONCE_ONLY,
1128 				    &digital_service_id);
1129 	fail_on_test(!transmit_timeout(node, &msg, 10000));
1130 	if (timed_out(&msg)) {
1131 		warn("Timed out waiting for Timer Status. Assuming timer was set.\n");
1132 		return OK_PRESUMED;
1133 	}
1134 	if (unrecognized_op(&msg))
1135 		return OK_NOT_SUPPORTED;
1136 	if (refused(&msg))
1137 		return OK_REFUSED;
1138 	if (cec_msg_status_is_abort(&msg))
1139 		return OK_PRESUMED;
1140 
1141 	return 0;
1142 }
1143 
timer_prog_set_ext_timer(struct node * node,unsigned me,unsigned la,bool interactive)1144 static int timer_prog_set_ext_timer(struct node *node, unsigned me, unsigned la, bool interactive)
1145 {
1146 	/* TODO: Check the timer status. */
1147 
1148 	struct cec_msg msg = {};
1149 
1150 	cec_msg_init(&msg, me, la);
1151 	cec_msg_set_ext_timer(&msg, true, 1, 1, 0, 0, 1, 0, CEC_OP_REC_SEQ_ONCE_ONLY,
1152 			      CEC_OP_EXT_SRC_PHYS_ADDR, 0, node->phys_addr);
1153 	fail_on_test(!transmit_timeout(node, &msg, 10000));
1154 	if (timed_out(&msg)) {
1155 		warn("Timed out waiting for Timer Status. Assuming timer was set.\n");
1156 		return OK_PRESUMED;
1157 	}
1158 	if (unrecognized_op(&msg))
1159 		return OK_NOT_SUPPORTED;
1160 	if (refused(&msg))
1161 		return OK_REFUSED;
1162 	if (cec_msg_status_is_abort(&msg))
1163 		return OK_PRESUMED;
1164 
1165 	return 0;
1166 }
1167 
timer_prog_clear_analog_timer(struct node * node,unsigned me,unsigned la,bool interactive)1168 static int timer_prog_clear_analog_timer(struct node *node, unsigned me, unsigned la, bool interactive)
1169 {
1170 	/* TODO: Check the timer cleared status. */
1171 
1172 	struct cec_msg msg = {};
1173 
1174 	cec_msg_init(&msg, me, la);
1175 	cec_msg_clear_analogue_timer(&msg, true, 1, 1, 0, 0, 1, 0, CEC_OP_REC_SEQ_ONCE_ONLY,
1176 				     CEC_OP_ANA_BCAST_TYPE_CABLE,
1177 				     7668, // 479.25 MHz
1178 				     node->remote[la].bcast_sys);
1179 	fail_on_test(!transmit_timeout(node, &msg, 10000));
1180 	if (timed_out(&msg)) {
1181 		warn("Timed out waiting for Timer Cleared Status. Assuming timer was cleared.\n");
1182 		return OK_PRESUMED;
1183 	}
1184 	if (unrecognized_op(&msg))
1185 		return OK_NOT_SUPPORTED;
1186 	if (refused(&msg))
1187 		return OK_REFUSED;
1188 	if (cec_msg_status_is_abort(&msg))
1189 		return OK_PRESUMED;
1190 
1191 	return 0;
1192 }
1193 
timer_prog_clear_digital_timer(struct node * node,unsigned me,unsigned la,bool interactive)1194 static int timer_prog_clear_digital_timer(struct node *node, unsigned me, unsigned la, bool interactive)
1195 {
1196 	/* TODO: Check the timer cleared status. */
1197 
1198 	struct cec_msg msg = {};
1199 	struct cec_op_digital_service_id digital_service_id = {};
1200 
1201 	digital_service_id.service_id_method = CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL;
1202 	digital_service_id.channel.channel_number_fmt = CEC_OP_CHANNEL_NUMBER_FMT_1_PART;
1203 	digital_service_id.channel.minor = 1;
1204 	digital_service_id.dig_bcast_system = node->remote[la].dig_bcast_sys;
1205 	cec_msg_init(&msg, me, la);
1206 	cec_msg_clear_digital_timer(&msg, true, 1, 1, 0, 0, 1, 0, CEC_OP_REC_SEQ_ONCE_ONLY,
1207 				    &digital_service_id);
1208 	fail_on_test(!transmit_timeout(node, &msg, 10000));
1209 	if (timed_out(&msg)) {
1210 		warn("Timed out waiting for Timer Cleared Status. Assuming timer was cleared.\n");
1211 		return OK_PRESUMED;
1212 	}
1213 	if (unrecognized_op(&msg))
1214 		return OK_NOT_SUPPORTED;
1215 	if (refused(&msg))
1216 		return OK_REFUSED;
1217 	if (cec_msg_status_is_abort(&msg))
1218 		return OK_PRESUMED;
1219 
1220 	return 0;
1221 }
1222 
timer_prog_clear_ext_timer(struct node * node,unsigned me,unsigned la,bool interactive)1223 static int timer_prog_clear_ext_timer(struct node *node, unsigned me, unsigned la, bool interactive)
1224 {
1225 	/* TODO: Check the timer cleared status. */
1226 
1227 	struct cec_msg msg = {};
1228 
1229 	cec_msg_init(&msg, me, la);
1230 	cec_msg_clear_ext_timer(&msg, true, 1, 1, 0, 0, 1, 0, CEC_OP_REC_SEQ_ONCE_ONLY,
1231 				CEC_OP_EXT_SRC_PHYS_ADDR, 0, node->phys_addr);
1232 	fail_on_test(!transmit_timeout(node, &msg, 10000));
1233 	if (timed_out(&msg)) {
1234 		warn("Timed out waiting for Timer Cleared Status. Assuming timer was cleared.\n");
1235 		return OK_PRESUMED;
1236 	}
1237 	if (unrecognized_op(&msg))
1238 		return OK_NOT_SUPPORTED;
1239 	if (refused(&msg))
1240 		return OK_REFUSED;
1241 	if (cec_msg_status_is_abort(&msg))
1242 		return OK_PRESUMED;
1243 
1244 	return 0;
1245 }
1246 
timer_prog_set_prog_title(struct node * node,unsigned me,unsigned la,bool interactive)1247 static int timer_prog_set_prog_title(struct node *node, unsigned me, unsigned la, bool interactive)
1248 {
1249 	struct cec_msg msg = {};
1250 
1251 	cec_msg_init(&msg, me, la);
1252 	cec_msg_set_timer_program_title(&msg, "Super-Hans II");
1253 	fail_on_test(!transmit_timeout(node, &msg));
1254 	if (unrecognized_op(&msg))
1255 		return OK_NOT_SUPPORTED;
1256 	if (refused(&msg))
1257 		return OK_REFUSED;
1258 
1259 	return OK_PRESUMED;
1260 }
1261 
timer_prog_timer_status(struct node * node,unsigned me,unsigned la,bool interactive)1262 static int timer_prog_timer_status(struct node *node, unsigned me, unsigned la, bool interactive)
1263 {
1264 	struct cec_msg msg = {};
1265 
1266 	cec_msg_init(&msg, me, la);
1267 	cec_msg_timer_status(&msg, CEC_OP_TIMER_OVERLAP_WARNING_NO_OVERLAP,
1268 			     CEC_OP_MEDIA_INFO_NO_MEDIA,
1269 			     CEC_OP_PROG_INFO_ENOUGH_SPACE,
1270 			     0, 0, 0);
1271 	fail_on_test(!transmit_timeout(node, &msg));
1272 	if (unrecognized_op(&msg))
1273 		return OK_NOT_SUPPORTED;
1274 	if (refused(&msg))
1275 		return OK_REFUSED;
1276 
1277 	return OK_PRESUMED;
1278 }
1279 
timer_prog_timer_clear_status(struct node * node,unsigned me,unsigned la,bool interactive)1280 static int timer_prog_timer_clear_status(struct node *node, unsigned me, unsigned la, bool interactive)
1281 {
1282 	struct cec_msg msg = {};
1283 
1284 	cec_msg_init(&msg, me, la);
1285 	cec_msg_timer_cleared_status(&msg, CEC_OP_TIMER_CLR_STAT_CLEARED);
1286 	fail_on_test(!transmit_timeout(node, &msg));
1287 	if (unrecognized_op(&msg))
1288 		return OK_NOT_SUPPORTED;
1289 	if (refused(&msg))
1290 		return OK_REFUSED;
1291 
1292 	return OK_PRESUMED;
1293 }
1294 
1295 static struct remote_subtest timer_prog_subtests[] = {
1296 	{ "Set Analogue Timer", CEC_LOG_ADDR_MASK_RECORD, timer_prog_set_analog_timer },
1297 	{ "Set Digital Timer", CEC_LOG_ADDR_MASK_RECORD, timer_prog_set_digital_timer },
1298 	{ "Set Timer Program Title", CEC_LOG_ADDR_MASK_RECORD, timer_prog_set_prog_title },
1299 	{ "Set External Timer", CEC_LOG_ADDR_MASK_RECORD, timer_prog_set_ext_timer },
1300 	{ "Clear Analogue Timer", CEC_LOG_ADDR_MASK_RECORD, timer_prog_clear_analog_timer },
1301 	{ "Clear Digital Timer", CEC_LOG_ADDR_MASK_RECORD, timer_prog_clear_digital_timer },
1302 	{ "Clear External Timer", CEC_LOG_ADDR_MASK_RECORD, timer_prog_clear_ext_timer },
1303 	{ "Timer Status", CEC_LOG_ADDR_MASK_RECORD, timer_prog_timer_status },
1304 	{ "Timer Cleared Status", CEC_LOG_ADDR_MASK_RECORD, timer_prog_timer_clear_status },
1305 };
1306 
cdc_hec_discover(struct node * node,unsigned me,unsigned la,bool print)1307 static int cdc_hec_discover(struct node *node, unsigned me, unsigned la, bool print)
1308 {
1309 	/* TODO: For future use cases, it might be necessary to store the results
1310 	   from the HEC discovery to know which HECs are possible to form, etc. */
1311 	struct cec_msg msg = {};
1312 	uint32_t mode = CEC_MODE_INITIATOR | CEC_MODE_FOLLOWER;
1313 	bool has_cdc = false;
1314 
1315 	doioctl(node, CEC_S_MODE, &mode);
1316 	cec_msg_init(&msg, me, la);
1317 	cec_msg_cdc_hec_discover(&msg);
1318 	fail_on_test(!transmit(node, &msg));
1319 
1320 	/* The spec describes that we shall wait for messages
1321 	   up to 1 second, and extend the deadline for every received
1322 	   message. The maximum time to wait for incoming state reports
1323 	   is 5 seconds. */
1324 	unsigned ts_start = get_ts_ms();
1325 	while (get_ts_ms() - ts_start < 5000) {
1326 		uint8_t from;
1327 
1328 		memset(&msg, 0, sizeof(msg));
1329 		msg.timeout = 1000;
1330 		if (doioctl(node, CEC_RECEIVE, &msg))
1331 			break;
1332 		from = cec_msg_initiator(&msg);
1333 		if (msg.msg[1] == CEC_MSG_FEATURE_ABORT) {
1334 			if (from == la)
1335 				return fail("Device replied Feature Abort to broadcast message\n");
1336 
1337 			warn("Device %d replied Feature Abort to broadcast message\n", cec_msg_initiator(&msg));
1338 		}
1339 		if (msg.msg[1] != CEC_MSG_CDC_MESSAGE)
1340 			continue;
1341 		if (msg.msg[4] != CEC_MSG_CDC_HEC_REPORT_STATE)
1342 			continue;
1343 
1344 		uint16_t phys_addr, target_phys_addr, hec_field;
1345 		uint8_t hec_func_state, host_func_state, enc_func_state, cdc_errcode, has_field;
1346 
1347 		cec_ops_cdc_hec_report_state(&msg, &phys_addr, &target_phys_addr,
1348 					     &hec_func_state, &host_func_state,
1349 					     &enc_func_state, &cdc_errcode,
1350 					     &has_field, &hec_field);
1351 
1352 		if (target_phys_addr != node->phys_addr)
1353 			continue;
1354 		if (phys_addr == node->remote[la].phys_addr)
1355 			has_cdc = true;
1356 		if (!print)
1357 			continue;
1358 
1359 		from = cec_msg_initiator(&msg);
1360 		info("Received CDC HEC State report from device %d (%s):\n", from, cec_la2s(from));
1361 		info("Physical address                 : %x.%x.%x.%x\n",
1362 		     cec_phys_addr_exp(phys_addr));
1363 		info("Target physical address          : %x.%x.%x.%x\n",
1364 		     cec_phys_addr_exp(target_phys_addr));
1365 		info("HEC Functionality State          : %s\n", hec_func_state2s(hec_func_state));
1366 		info("Host Functionality State         : %s\n", host_func_state2s(host_func_state));
1367 		info("ENC Functionality State          : %s\n", enc_func_state2s(enc_func_state));
1368 		info("CDC Error Code                   : %s\n", cdc_errcode2s(cdc_errcode));
1369 
1370 		if (has_field) {
1371 			std::ostringstream oss;
1372 
1373 			/* Bit 14 indicates whether or not the device's HDMI
1374 			   output has HEC support/is active. */
1375 			if (!hec_field)
1376 				oss << "None";
1377 			else {
1378 				if (hec_field & (1 << 14))
1379 					oss << "out, ";
1380 				for (int i = 13; i >= 0; i--) {
1381 					if (hec_field & (1 << i))
1382 						oss << "in" << (14 - i) << ", ";
1383 				}
1384 				oss << "\b\b ";
1385 			}
1386 			info("HEC Support Field    : %s\n", oss.str().c_str());
1387 		}
1388 	}
1389 
1390 	mode = CEC_MODE_INITIATOR;
1391 	doioctl(node, CEC_S_MODE, &mode);
1392 
1393 	if (has_cdc)
1394 		return 0;
1395 	return OK_NOT_SUPPORTED;
1396 }
1397 
1398 static struct remote_subtest cdc_subtests[] = {
1399 	{ "CDC_HEC_Discover", CEC_LOG_ADDR_MASK_ALL, cdc_hec_discover },
1400 };
1401 
1402 
1403 /* Post-test checks */
1404 
post_test_check_recognized(struct node * node,unsigned me,unsigned la,bool interactive)1405 static int post_test_check_recognized(struct node *node, unsigned me, unsigned la, bool interactive)
1406 {
1407 	bool fail = false;
1408 
1409 	for (unsigned i = 0; i < 256; i++) {
1410 		if (node->remote[la].recognized_op[i] && node->remote[la].unrecognized_op[i]) {
1411 			struct cec_msg msg = {};
1412 			msg.msg[1] = i;
1413 			fail("Opcode %s has been both recognized by and has been replied\n", opcode2s(&msg).c_str());
1414 			fail("Feature Abort [Unrecognized Opcode] to by the device.\n");
1415 			fail = true;
1416 		}
1417 	}
1418 	fail_on_test(fail);
1419 
1420 	return 0;
1421 }
1422 
1423 static struct remote_subtest post_test_subtests[] = {
1424 	{ "Recognized/unrecognized message consistency", CEC_LOG_ADDR_MASK_ALL, post_test_check_recognized },
1425 };
1426 
1427 
1428 static struct remote_test tests[] = {
1429 	test_case("Core",
1430 		  TAG_CORE,
1431 		  core_subtests),
1432 	test_case_ext("Give Device Power Status feature",
1433 		      TAG_POWER_STATUS,
1434 		      power_status_subtests),
1435 	test_case("System Information feature",
1436 		  TAG_SYSTEM_INFORMATION,
1437 		  system_info_subtests),
1438 	test_case("Vendor Specific Commands feature",
1439 		  TAG_VENDOR_SPECIFIC_COMMANDS,
1440 		  vendor_specific_subtests),
1441 	test_case("Device OSD Transfer feature",
1442 		  TAG_DEVICE_OSD_TRANSFER,
1443 		  device_osd_transfer_subtests),
1444 	test_case("OSD String feature",
1445 		  TAG_OSD_DISPLAY,
1446 		  osd_string_subtests),
1447 	test_case("Remote Control Passthrough feature",
1448 		  TAG_REMOTE_CONTROL_PASSTHROUGH,
1449 		  rc_passthrough_subtests),
1450 	test_case("Device Menu Control feature",
1451 		  TAG_DEVICE_MENU_CONTROL,
1452 		  dev_menu_ctl_subtests),
1453 	test_case("Deck Control feature",
1454 		  TAG_DECK_CONTROL,
1455 		  deck_ctl_subtests),
1456 	test_case("Tuner Control feature",
1457 		  TAG_TUNER_CONTROL,
1458 		  tuner_ctl_subtests),
1459 	test_case("One Touch Record feature",
1460 		  TAG_ONE_TOUCH_RECORD,
1461 		  one_touch_rec_subtests),
1462 	test_case("Timer Programming feature",
1463 		  TAG_TIMER_PROGRAMMING,
1464 		  timer_prog_subtests),
1465 	test_case("Capability Discovery and Control feature",
1466 		  TAG_CAP_DISCOVERY_CONTROL,
1467 		  cdc_subtests),
1468 	test_case_ext("Dynamic Auto Lipsync feature",
1469 		      TAG_DYNAMIC_AUTO_LIPSYNC,
1470 		      dal_subtests),
1471 	test_case_ext("Audio Return Channel feature",
1472 		      TAG_ARC_CONTROL,
1473 		      arc_subtests),
1474 	test_case_ext("System Audio Control feature",
1475 		      TAG_SYSTEM_AUDIO_CONTROL,
1476 		      sac_subtests),
1477 	test_case_ext("Audio Rate Control feature",
1478 		      TAG_AUDIO_RATE_CONTROL,
1479 		      audio_rate_ctl_subtests),
1480 	test_case_ext("One Touch Play feature",
1481 		      TAG_ONE_TOUCH_PLAY,
1482 		      one_touch_play_subtests),
1483 	test_case("Routing Control feature",
1484 		  TAG_ROUTING_CONTROL,
1485 		  routing_control_subtests),
1486 	test_case_ext("Standby/Resume and Power Status",
1487 		      TAG_POWER_STATUS | TAG_STANDBY_RESUME,
1488 		      standby_resume_subtests),
1489 	test_case("Post-test checks",
1490 		  TAG_CORE,
1491 		  post_test_subtests),
1492 };
1493 
1494 static const unsigned num_tests = sizeof(tests) / sizeof(struct remote_test);
1495 
1496 static std::map<std::string, int> mapTests;
1497 static std::map<std::string, bool> mapTestsNoWarnings;
1498 
collectTests()1499 void collectTests()
1500 {
1501 	std::map<std::string, uint64_t> mapTestFuncs;
1502 
1503 	for (unsigned i = 0; i < num_tests; i++) {
1504 		for (unsigned j = 0; j < tests[i].num_subtests; j++) {
1505 			std::string name = safename(tests[i].subtests[j].name);
1506 			uint64_t func = (uint64_t)tests[i].subtests[j].test_fn;
1507 
1508 			if (mapTestFuncs.find(name) != mapTestFuncs.end() &&
1509 			    mapTestFuncs[name] != func) {
1510 				fprintf(stderr, "Duplicate subtest name, but different tests: %s\n",
1511 					tests[i].subtests[j].name);
1512 				std::exit(EXIT_FAILURE);
1513 			}
1514 			mapTestFuncs[name] = func;
1515 			mapTests[name] = DONT_CARE;
1516 			mapTestsNoWarnings[name] = false;
1517 		}
1518 	}
1519 }
1520 
listTests()1521 void listTests()
1522 {
1523 	for (unsigned i = 0; i < num_tests; i++) {
1524 		printf("%s:\n", tests[i].name);
1525 		for (unsigned j = 0; j < tests[i].num_subtests; j++) {
1526 			std::string name = safename(tests[i].subtests[j].name);
1527 
1528 			printf("\t%s\n", name.c_str());
1529 		}
1530 	}
1531 }
1532 
setExpectedResult(char * optarg,bool no_warnings)1533 int setExpectedResult(char *optarg, bool no_warnings)
1534 {
1535 	char *equal = std::strchr(optarg, '=');
1536 
1537 	if (!equal || equal == optarg || !isdigit(equal[1]))
1538 		return 1;
1539 	*equal = 0;
1540 	std::string name = safename(optarg);
1541 	if (mapTests.find(name) == mapTests.end())
1542 		return 1;
1543 	mapTests[name] = strtoul(equal + 1, NULL, 0);
1544 	mapTestsNoWarnings[name] = no_warnings;
1545 	return 0;
1546 }
1547 
testRemote(struct node * node,unsigned me,unsigned la,unsigned test_tags,bool interactive)1548 void testRemote(struct node *node, unsigned me, unsigned la, unsigned test_tags,
1549 		bool interactive)
1550 {
1551 	printf("testing CEC local LA %d (%s) to remote LA %d (%s):\n",
1552 	       me, cec_la2s(me), la, cec_la2s(la));
1553 
1554 	if (!util_interactive_ensure_power_state(node, me, la, interactive, CEC_OP_POWER_STATUS_ON))
1555 		return;
1556 	if (node->remote[la].in_standby && !interactive) {
1557 		announce("The remote device is in standby. It should be powered on when testing. Aborting.");
1558 		return;
1559 	}
1560 	if (!node->remote[la].has_power_status) {
1561 		announce("The device didn't support Give Device Power Status.");
1562 		announce("Assuming that the device is powered on.");
1563 	}
1564 
1565 	int ret = 0;
1566 
1567 	for (unsigned i = 0; i < num_tests; i++) {
1568 		if ((tests[i].tags & test_tags) != tests[i].tags)
1569 			continue;
1570 
1571 		printf("\t%s:\n", tests[i].name);
1572 		for (unsigned j = 0; j < tests[i].num_subtests; j++) {
1573 			const char *name = tests[i].subtests[j].name;
1574 
1575 			if (tests[i].subtests[j].for_cec20 &&
1576 			    (node->remote[la].cec_version < CEC_OP_CEC_VERSION_2_0 ||
1577 			     !node->has_cec20))
1578 				continue;
1579 
1580 			if (tests[i].subtests[j].in_standby) {
1581 				struct cec_log_addrs laddrs = { };
1582 				doioctl(node, CEC_ADAP_G_LOG_ADDRS, &laddrs);
1583 
1584 				if (!laddrs.log_addr_mask)
1585 					continue;
1586 			}
1587 			node->in_standby = tests[i].subtests[j].in_standby;
1588 			mode_set_initiator(node);
1589 			unsigned old_warnings = warnings;
1590 			ret = tests[i].subtests[j].test_fn(node, me, la, interactive);
1591 			bool has_warnings = old_warnings < warnings;
1592 			if (!(tests[i].subtests[j].la_mask & (1 << la)) && !ret)
1593 				ret = OK_UNEXPECTED;
1594 
1595 			if (mapTests[safename(name)] != DONT_CARE) {
1596 				if (ret != mapTests[safename(name)])
1597 					printf("\t    %s: %s (Expected '%s', got '%s')\n",
1598 					       name, ok(FAIL),
1599 					       result_name(mapTests[safename(name)], false),
1600 					       result_name(ret, false));
1601 				else if (has_warnings && mapTestsNoWarnings[safename(name)])
1602 					printf("\t    %s: %s (Expected no warnings, got %d warnings)\n",
1603 					       name, ok(FAIL), warnings - old_warnings);
1604 				else if (ret == FAIL)
1605 					printf("\t    %s: %s\n", name, ok(OK_EXPECTED_FAIL));
1606 				else
1607 					printf("\t    %s: %s\n", name, ok(ret));
1608 			} else if (ret != NOTAPPLICABLE)
1609 				printf("\t    %s: %s\n", name, ok(ret));
1610 			if (ret == FAIL_CRITICAL)
1611 				return;
1612 		}
1613 		printf("\n");
1614 	}
1615 }
1616