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