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 <unistd.h>
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <inttypes.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <fcntl.h>
14 #include <ctype.h>
15 #include <errno.h>
16 #include <sys/ioctl.h>
17 #include <config.h>
18 #include <cstdlib>
19
20 #include "cec-compliance.h"
21
22
23 /* Dynamic Auto Lipsync */
24
dal_request_current_latency(struct node * node,unsigned me,unsigned la,bool interactive)25 static int dal_request_current_latency(struct node *node, unsigned me, unsigned la, bool interactive)
26 {
27 struct cec_msg msg = {};
28
29 cec_msg_init(&msg, me, la);
30 cec_msg_request_current_latency(&msg, true, node->remote[la].phys_addr);
31 fail_on_test(!transmit_timeout(node, &msg));
32 fail_on_test_v2(node->remote[la].cec_version,
33 timed_out(&msg) && is_tv(la, node->remote[la].prim_type));
34 if (timed_out(&msg))
35 return OK_NOT_SUPPORTED;
36
37 /* When the device supports Dynamic Auto Lipsync but does not implement
38 CEC 1.4b, or 2.0, a very strict subset of CEC can be supported. If we
39 get here and the version is < 1.4, we know that the device is not
40 complying to this specification. */
41 if (node->remote[la].cec_version < CEC_OP_CEC_VERSION_1_4) {
42 warn("CEC 2.0 specifies that devices with CEC version < 1.4 which implement\n");
43 warn("Dynamic Auto Lipsync shall only implement a very strict subset of CEC.\n");
44 }
45
46 uint16_t phys_addr;
47 uint8_t video_latency, low_latency_mode, audio_out_compensated, audio_out_delay;
48
49 cec_ops_report_current_latency(&msg, &phys_addr, &video_latency, &low_latency_mode,
50 &audio_out_compensated, &audio_out_delay);
51 fail_on_test(phys_addr != node->remote[la].phys_addr);
52 info("Video latency: %d (%dms)\n", video_latency, (video_latency - 1) * 2);
53 info("Low latency mode: %d\n", low_latency_mode);
54 info("Audio output compensation: %d\n", audio_out_compensated);
55 if (audio_out_compensated == CEC_OP_AUD_OUT_COMPENSATED_PARTIAL_DELAY) {
56 info("Audio out delay: %d (%dms)\n", audio_out_delay, (audio_out_delay - 1) * 2);
57 fail_on_test(audio_out_delay == 0 || audio_out_delay > 251);
58 // Warn if the delay is more than 50 ms
59 warn_on_test(audio_out_delay > (50 / 2) + 1);
60 }
61 fail_on_test(video_latency == 0 || video_latency > 251);
62 // Warn if the delay is more than 50 ms and low latency mode is set
63 if (video_latency > (50 / 2) + 1) {
64 if (low_latency_mode)
65 fail("Low latency mode is set, but video latency is > 50ms\n");
66 else
67 warn("Video latency is > 50ms\n");
68 }
69
70 return 0;
71 }
72
dal_req_current_latency_invalid(struct node * node,unsigned me,unsigned la,bool interactive)73 static int dal_req_current_latency_invalid(struct node *node, unsigned me, unsigned la, bool interactive)
74 {
75 struct cec_msg msg = {};
76
77 /* Test that there is no reply when the physical address operand is not the
78 physical address of the remote device. */
79 cec_msg_init(&msg, me, la);
80 cec_msg_request_current_latency(&msg, true, CEC_PHYS_ADDR_INVALID);
81 fail_on_test(!transmit_timeout(node, &msg));
82 fail_on_test(!timed_out(&msg));
83
84 return 0;
85 }
86
87 struct remote_subtest dal_subtests[] = {
88 { "Request Current Latency", CEC_LOG_ADDR_MASK_ALL, dal_request_current_latency },
89 { "Request Current Latency with invalid PA", CEC_LOG_ADDR_MASK_ALL, dal_req_current_latency_invalid },
90 };
91
92 const unsigned dal_subtests_size = ARRAY_SIZE(dal_subtests);
93
94
95 /* Audio Return Channel Control */
96
pa_common_mask(uint16_t pa1,uint16_t pa2)97 static uint16_t pa_common_mask(uint16_t pa1, uint16_t pa2)
98 {
99 uint16_t mask = 0xf000;
100
101 for (int i = 0; i < 3; i++) {
102 if ((pa1 & mask) != (pa2 & mask))
103 break;
104 mask = (mask >> 4) | 0xf000;
105 }
106 return mask << 4;
107 }
pa_are_adjacent(uint16_t pa1,uint16_t pa2)108 static bool pa_are_adjacent(uint16_t pa1, uint16_t pa2)
109 {
110 const uint16_t mask = pa_common_mask(pa1, pa2);
111 const uint16_t trail_mask = ((~mask) & 0xffff) >> 4;
112
113 if (pa1 == CEC_PHYS_ADDR_INVALID || pa2 == CEC_PHYS_ADDR_INVALID || pa1 == pa2)
114 return false;
115 if ((pa1 & trail_mask) || (pa2 & trail_mask))
116 return false;
117 return !((pa1 & ~mask) && (pa2 & ~mask));
118 }
119
pa_is_upstream_from(uint16_t pa1,uint16_t pa2)120 static bool pa_is_upstream_from(uint16_t pa1, uint16_t pa2)
121 {
122 const uint16_t mask = pa_common_mask(pa1, pa2);
123
124 if (pa1 == CEC_PHYS_ADDR_INVALID || pa2 == CEC_PHYS_ADDR_INVALID)
125 return false;
126 return !(pa1 & ~mask) && (pa2 & ~mask);
127 }
128
arc_initiate_tx(struct node * node,unsigned me,unsigned la,bool interactive)129 static int arc_initiate_tx(struct node *node, unsigned me, unsigned la, bool interactive)
130 {
131 /* Check if we are upstream from the device. If we are, then the device is
132 an HDMI source, which means that it is an ARC receiver, not a transmitter. */
133 if (pa_is_upstream_from(node->phys_addr, node->remote[la].phys_addr))
134 return NOTAPPLICABLE;
135
136 struct cec_msg msg = {};
137
138 /*
139 * Note that this is a special case: INITIATE_ARC can reply with two possible
140 * messages: CEC_MSG_REPORT_ARC_INITIATED or CEC_MSG_REPORT_ARC_TERMINATED.
141 * It's the only message that behaves like this.
142 */
143 cec_msg_init(&msg, me, la);
144 cec_msg_initiate_arc(&msg, true);
145 fail_on_test(!transmit_timeout(node, &msg));
146 if (timed_out(&msg)) {
147 fail_on_test_v2(node->remote[la].cec_version, node->remote[la].sink_has_arc_tx);
148 warn("Timed out waiting for Report ARC Initiated/Terminated.\n");
149 return OK_PRESUMED;
150 }
151 if (unrecognized_op(&msg)) {
152 fail_on_test_v2(node->remote[la].cec_version, node->remote[la].sink_has_arc_tx);
153 return OK_NOT_SUPPORTED;
154 }
155 if (cec_msg_opcode(&msg) == CEC_MSG_REPORT_ARC_INITIATED) {
156 fail_on_test(!pa_are_adjacent(node->phys_addr, node->remote[la].phys_addr));
157 fail_on_test_v2(node->remote[la].cec_version, !node->remote[la].sink_has_arc_tx);
158 node->remote[la].arc_initiated = true;
159 }
160 else if (cec_msg_opcode(&msg) == CEC_MSG_REPORT_ARC_TERMINATED)
161 announce("Device supports ARC but is not ready to initiate.");
162 else if (refused(&msg))
163 return OK_REFUSED;
164 else if (cec_msg_status_is_abort(&msg))
165 return OK_PRESUMED;
166
167 return 0;
168 }
169
arc_terminate_tx(struct node * node,unsigned me,unsigned la,bool interactive)170 static int arc_terminate_tx(struct node *node, unsigned me, unsigned la, bool interactive)
171 {
172 /* Check if we are upstream from the device. If we are, then the device is
173 an HDMI source, which means that it is an ARC receiver, not a transmitter. */
174 if (pa_is_upstream_from(node->phys_addr, node->remote[la].phys_addr))
175 return NOTAPPLICABLE;
176 if (!node->remote[la].arc_initiated)
177 return NOTAPPLICABLE;
178
179 struct cec_msg msg = {};
180
181 cec_msg_init(&msg, me, la);
182 cec_msg_terminate_arc(&msg, true);
183 fail_on_test(!transmit_timeout(node, &msg));
184 if (timed_out(&msg)) {
185 warn("Timed out waiting for Report ARC Terminated.\n");
186 return OK_PRESUMED;
187 }
188 fail_on_test(unrecognized_op(&msg));
189 if (cec_msg_status_is_abort(&msg)) {
190 warn("Received Feature Abort for Terminate ARC (but the message was recognized).\n");
191 if (refused(&msg))
192 return OK_REFUSED;
193 return OK_PRESUMED;
194 }
195
196 return 0;
197 }
198
arc_initiate_rx(struct node * node,unsigned me,unsigned la,bool interactive)199 static int arc_initiate_rx(struct node *node, unsigned me, unsigned la, bool interactive)
200 {
201 /* Check if the DUT is upstream from us. If it is, then it is an
202 HDMI sink, which means that it is an ARC transmitter, not receiver. */
203 if (pa_is_upstream_from(node->remote[la].phys_addr, node->phys_addr))
204 return NOTAPPLICABLE;
205
206 struct cec_msg msg = {};
207
208 cec_msg_init(&msg, me, la);
209 cec_msg_request_arc_initiation(&msg, true);
210
211 bool unsupported = false;
212
213 fail_on_test(!transmit_timeout(node, &msg));
214 if (timed_out(&msg) || unrecognized_op(&msg))
215 unsupported = true;
216 else if (cec_msg_status_is_abort(&msg)) {
217 uint8_t abort_msg, reason;
218
219 cec_ops_feature_abort(&msg, &abort_msg, &reason);
220 if (reason == CEC_OP_ABORT_INCORRECT_MODE) {
221 announce("The device supports ARC but is not ready to initiate.");
222 return 0;
223 }
224
225 warn("Device responded Feature Abort with unexpected abort reason. Assuming no ARC support.\n");
226 unsupported = true;
227 }
228
229 if (unsupported) {
230 fail_on_test_v2(node->remote[la].cec_version, node->remote[la].source_has_arc_rx);
231 return OK_NOT_SUPPORTED;
232 }
233 fail_on_test(!pa_are_adjacent(node->phys_addr, node->remote[la].phys_addr));
234 fail_on_test_v2(node->remote[la].cec_version, !node->remote[la].source_has_arc_rx);
235
236 cec_msg_init(&msg, me, la);
237 cec_msg_report_arc_initiated(&msg);
238 fail_on_test(!transmit_timeout(node, &msg));
239 fail_on_test(unrecognized_op(&msg));
240 node->remote[la].arc_initiated = true;
241
242 return 0;
243 }
244
arc_terminate_rx(struct node * node,unsigned me,unsigned la,bool interactive)245 static int arc_terminate_rx(struct node *node, unsigned me, unsigned la, bool interactive)
246 {
247 /* Check if the DUT is upstream from us. If it is, then it is an
248 HDMI sink, which means that it is an ARC transmitter, not receiver. */
249 if (pa_is_upstream_from(node->remote[la].phys_addr, node->phys_addr))
250 return NOTAPPLICABLE;
251 if (!node->remote[la].arc_initiated)
252 return NOTAPPLICABLE;
253
254 struct cec_msg msg = {};
255
256 cec_msg_init(&msg, me, la);
257 cec_msg_request_arc_termination(&msg, true);
258 fail_on_test(!transmit_timeout(node, &msg));
259 if (timed_out(&msg)) {
260 warn("Timed out waiting for Terminate ARC.\n");
261 return OK_PRESUMED;
262 }
263 fail_on_test(unrecognized_op(&msg));
264 if (cec_msg_status_is_abort(&msg)) {
265 warn("Received Feature Abort for Request ARC Termination (but the message was recognized).\n");
266 if (refused(&msg))
267 return OK_REFUSED;
268 return OK_PRESUMED;
269 }
270
271 cec_msg_init(&msg, me, la);
272 cec_msg_report_arc_terminated(&msg);
273 fail_on_test(!transmit_timeout(node, &msg));
274 fail_on_test(unrecognized_op(&msg));
275
276 return 0;
277 }
278
279 struct remote_subtest arc_subtests[] = {
280 { "Initiate ARC (RX)", CEC_LOG_ADDR_MASK_ALL, arc_initiate_rx },
281 { "Terminate ARC (RX)", CEC_LOG_ADDR_MASK_ALL, arc_terminate_rx },
282 { "Initiate ARC (TX)", CEC_LOG_ADDR_MASK_ALL, arc_initiate_tx },
283 { "Terminate ARC (TX)", CEC_LOG_ADDR_MASK_ALL, arc_terminate_tx },
284 };
285
286 const unsigned arc_subtests_size = ARRAY_SIZE(arc_subtests);
287
288
289 /* System Audio Control */
290
291 /*
292 * The following scenarios are defined in section 13.15 of the CEC 1.4
293 * specification.
294 *
295 * These are not tested as they need three CEC devices. An amplifier
296 * provides the audio for a source that is being displayed on a TV.
297 *
298 * 1. Amplifier initiated <System Audio Mode Request> and active source
299 * discovery with a <Request Active Source> broadcast plus the
300 * <Active Source> response.
301 * 2. Post discovery, subsequent amplifier <Set System Audio Mode> [On]
302 * and System Audio Control feature confirmation with TV.
303 * 3. Amplifier broadcasts <Set System Audio Mode> [On] to mute the TV and
304 * unmute amplifier.
305 * 4. Amplifier broadcasts <Set System Audio Mode> [Off] to unmute the TV
306 * and mute the amplifier.
307 * 5. When System Audio Mode is On, muting and unmuting an amplifier sends
308 * a <Report Audio Status> message to the TV.
309 * 6. When System Audio Mode is On, the amplifier sends a <Set System Audio
310 * Mode> [Off] to unmute the TV before going into standby.
311 * 7. When System Audio Mode is On, only the amplifier can control system
312 * volume.
313 *
314 * These are not tested as they are hard-to-test corner cases.
315 *
316 * 1. Optional features in subsection 13.15.4 of version 1.4.
317 *
318 * These are not tested as they deal with 1.3a or older versions and is not
319 * worth spending time on.
320 *
321 * 1. <Request Audio Descriptor> message is from version 1.4 so older versions
322 * report <Feature Abort>.
323 * 2. <Report Audio Descriptor> message is from version 1.4 so older versions
324 * report <Feature Abort>.
325 * 3. System Audio Control is from version 1.3a so older versions report
326 * <Feature Abort>.
327 */
328
sac_request_sad_probe(struct node * node,unsigned me,unsigned la,bool interactive)329 static int sac_request_sad_probe(struct node *node, unsigned me, unsigned la, bool interactive)
330 {
331 struct cec_msg msg = {};
332 uint8_t audio_format_id = 0;
333 uint8_t audio_format_code = 1;
334
335 cec_msg_init(&msg, me, la);
336 cec_msg_request_short_audio_descriptor(&msg, true, 1, &audio_format_id, &audio_format_code);
337 fail_on_test(!transmit_timeout(node, &msg));
338 fail_on_test(timed_out(&msg));
339 if (unrecognized_op(&msg))
340 return OK_NOT_SUPPORTED;
341 if (refused(&msg))
342 return OK_REFUSED;
343 if (cec_msg_status_is_abort(&msg))
344 return OK_PRESUMED;
345 node->remote[la].has_sad = true;
346
347 return 0;
348 }
349
sac_request_sad_invalid(struct node * node,unsigned me,unsigned la,bool interactive)350 static int sac_request_sad_invalid(struct node *node, unsigned me, unsigned la, bool interactive)
351 {
352 if (!node->remote[la].has_sad)
353 return NOTAPPLICABLE;
354
355 struct cec_msg msg = {};
356 uint8_t audio_format_id = CEC_OP_AUD_FMT_ID_CEA861;
357 uint8_t audio_format_code = 63; // This is outside the range of CEA861-F
358
359 cec_msg_init(&msg, me, la);
360 cec_msg_request_short_audio_descriptor(&msg, true, 1, &audio_format_id, &audio_format_code);
361 fail_on_test(!transmit_timeout(node, &msg));
362 fail_on_test(timed_out(&msg));
363 fail_on_test(!cec_msg_status_is_abort(&msg));
364 if (abort_reason(&msg) != CEC_OP_ABORT_INVALID_OP) {
365 warn("Expected Feature Abort [Invalid operand] in reply to Request Short\n");
366 warn("Audio Descriptor with invalid audio format as operand.\n");
367 }
368
369 return 0;
370 }
371
sac_sad_format_check(struct node * node,unsigned me,unsigned la,bool interactive)372 static int sac_sad_format_check(struct node *node, unsigned me, unsigned la, bool interactive)
373 {
374 if (!node->remote[la].has_sad)
375 return NOTAPPLICABLE;
376
377 struct cec_msg msg = {};
378 uint8_t audio_format_id;
379 uint8_t audio_format_code;
380
381 for (unsigned int id = 0; id <= 1; id++) {
382 audio_format_id = id;
383 for (unsigned int fmt_code = 1; fmt_code <= 14; fmt_code++) {
384 audio_format_code = fmt_code;
385
386 cec_msg_init(&msg, me, la);
387 cec_msg_request_short_audio_descriptor(&msg, true, 1, &audio_format_id, &audio_format_code);
388 fail_on_test(!transmit_timeout(node, &msg));
389 fail_on_test(timed_out(&msg));
390 fail_on_test(unrecognized_op(&msg) || refused(&msg));
391
392 if (cec_msg_status_is_abort(&msg) &&
393 abort_reason(&msg) == CEC_OP_ABORT_INVALID_OP)
394 continue;
395
396 uint8_t num_descriptors;
397 uint32_t descriptors[4] = {};
398
399 cec_ops_report_short_audio_descriptor(&msg, &num_descriptors, descriptors);
400 fail_on_test(num_descriptors == 0);
401 if (id == 1 && node->remote[la].cec_version < CEC_OP_CEC_VERSION_2_0)
402 warn("The device has CEC version < 2.0 but reports audio format(s) introduced in CEC 2.0.\n");
403
404 for (int j = 0; j < num_descriptors; j++) {
405 struct short_audio_desc sad;
406
407 sad_decode(&sad, descriptors[j]);
408 if ((id == 0 && sad.format_code != fmt_code) ||
409 (id == 1 && sad.extension_type_code != fmt_code))
410 return fail("Different audio format code reported than requested.\n");
411 info("Supports format %s\n", short_audio_desc2s(sad).c_str());
412
413 /* We need to store the ID and Code for one of the audio formats found,
414 for use in later test(s) */
415 node->remote[la].supp_format_id = audio_format_id;
416 node->remote[la].supp_format_code = audio_format_code;
417 }
418 }
419 }
420
421 return 0;
422 }
423
sac_sad_req_multiple(struct node * node,unsigned me,unsigned la,bool interactive)424 static int sac_sad_req_multiple(struct node *node, unsigned me, unsigned la, bool interactive)
425 {
426 if (!node->remote[la].has_sad || node->remote[la].supp_format_code == 0)
427 return NOTAPPLICABLE;
428
429 /* Check that if we got a response to a Request Short Audio Descriptor
430 with a single format, we also get a response when the same audio format
431 occurs in a request together with other formats. */
432 struct cec_msg msg = {};
433 uint8_t audio_format_id[4] = { };
434 uint8_t audio_format_code[4];
435
436 for (int i = 0; i < 4; i++) {
437 if (node->remote[la].supp_format_code <= 12)
438 audio_format_code[i] = node->remote[la].supp_format_code - 1 + i;
439 else
440 audio_format_code[i] = node->remote[la].supp_format_code - 1 - i;
441 }
442 cec_msg_init(&msg, me, la);
443 cec_msg_request_short_audio_descriptor(&msg, true, 4, audio_format_id, audio_format_code);
444 fail_on_test(!transmit_timeout(node, &msg));
445 fail_on_test(timed_out(&msg));
446 fail_on_test(cec_msg_status_is_abort(&msg));
447
448 return 0;
449 }
450
sac_set_system_audio_mode_direct(struct node * node,unsigned me,unsigned la,bool interactive)451 static int sac_set_system_audio_mode_direct(struct node *node, unsigned me, unsigned la, bool interactive)
452 {
453 struct cec_msg msg = {};
454
455 cec_msg_init(&msg, me, la);
456 cec_msg_set_system_audio_mode(&msg, CEC_OP_SYS_AUD_STATUS_ON);
457 fail_on_test(!transmit_timeout(node, &msg));
458 fail_on_test_v2(node->remote[la].cec_version,
459 unrecognized_op(&msg) && is_tv(la, node->remote[la].prim_type));
460 if (unrecognized_op(&msg))
461 return OK_NOT_SUPPORTED;
462 if (refused(&msg))
463 return OK_REFUSED;
464 node->remote[la].has_set_sys_audio_mode = true;
465
466 return OK_PRESUMED;
467 }
468
sac_set_system_audio_mode_broadcast_on(struct node * node,unsigned me,unsigned la,bool interactive)469 static int sac_set_system_audio_mode_broadcast_on(struct node *node, unsigned me, unsigned la, bool interactive)
470 {
471 struct cec_msg msg = {};
472
473 cec_msg_init(&msg, me, CEC_LOG_ADDR_BROADCAST);
474 cec_msg_set_system_audio_mode(&msg, CEC_OP_SYS_AUD_STATUS_ON);
475 fail_on_test(!transmit_timeout(node, &msg));
476
477 return OK_PRESUMED;
478 }
479
sac_system_audio_mode_status(struct node * node,unsigned me,unsigned la,bool interactive)480 static int sac_system_audio_mode_status(struct node *node, unsigned me, unsigned la, bool interactive)
481 {
482 struct cec_msg msg = {};
483
484 /* The device shall not feature abort System Audio Status if it did not
485 feature abort Set System Audio Mode.
486
487 The message is mandatory for TVs in CEC 2.0. */
488 cec_msg_init(&msg, me, la);
489 cec_msg_system_audio_mode_status(&msg, CEC_OP_SYS_AUD_STATUS_ON);
490 fail_on_test(!transmit_timeout(node, &msg));
491 fail_on_test_v2(node->remote[la].cec_version,
492 is_tv(la, node->remote[la].prim_type) && unrecognized_op(&msg));
493 if (unrecognized_op(&msg) && !node->remote[la].has_set_sys_audio_mode)
494 return OK_NOT_SUPPORTED;
495 fail_on_test(unrecognized_op(&msg));
496 if (refused(&msg))
497 return OK_REFUSED;
498 if (cec_msg_status_is_abort(&msg))
499 return OK_PRESUMED;
500
501 return 0;
502 }
503
sac_set_system_audio_mode_broadcast_off(struct node * node,unsigned me,unsigned la,bool interactive)504 static int sac_set_system_audio_mode_broadcast_off(struct node *node, unsigned me, unsigned la, bool interactive)
505 {
506 struct cec_msg msg = {};
507
508 cec_msg_init(&msg, me, CEC_LOG_ADDR_BROADCAST);
509 cec_msg_set_system_audio_mode(&msg, CEC_OP_SYS_AUD_STATUS_OFF);
510 fail_on_test(!transmit_timeout(node, &msg));
511
512 return OK_PRESUMED;
513 }
514
sac_system_audio_mode_req_on(struct node * node,unsigned me,unsigned la,bool interactive)515 static int sac_system_audio_mode_req_on(struct node *node, unsigned me, unsigned la, bool interactive)
516 {
517 struct cec_msg msg = {};
518 uint8_t status;
519
520 /* Send a System Audio Mode Request to the audio system. This notifies the
521 audio system that our device has SAC capabilities, so it should enable
522 the feature right away by sending Set System Audio Mode with On as status.
523
524 The message is mandatory for audio systems in CEC 2.0. */
525 cec_msg_init(&msg, me, la);
526 cec_msg_system_audio_mode_request(&msg, true, node->phys_addr);
527 fail_on_test(!transmit_timeout(node, &msg));
528 fail_on_test(timed_out(&msg));
529 fail_on_test_v2(node->remote[la].cec_version,
530 cec_has_audiosystem(1 << la) && unrecognized_op(&msg));
531 if (unrecognized_op(&msg))
532 return OK_NOT_SUPPORTED;
533 if (refused(&msg))
534 return OK_REFUSED;
535 if (cec_msg_status_is_abort(&msg))
536 return OK_PRESUMED;
537 node->remote[la].has_sys_audio_mode_req = true;
538 cec_ops_set_system_audio_mode(&msg, &status);
539 fail_on_test(status != CEC_OP_SYS_AUD_STATUS_ON);
540
541 return 0;
542 }
543
sac_give_system_audio_mode_status(struct node * node,unsigned me,unsigned la,bool interactive)544 static int sac_give_system_audio_mode_status(struct node *node, unsigned me, unsigned la, bool interactive)
545 {
546 struct cec_msg msg = {};
547 uint8_t system_audio_status;
548
549 /* The device shall not feature abort Give System Audio Mode Status if it did not
550 feature abort System Audio Mode Request.
551
552 The message is mandatory for audio systems in CEC 2.0. */
553 cec_msg_init(&msg, me, la);
554 cec_msg_give_system_audio_mode_status(&msg, true);
555 fail_on_test(!transmit_timeout(node, &msg));
556 fail_on_test(timed_out(&msg));
557 fail_on_test_v2(node->remote[la].cec_version,
558 cec_has_audiosystem(1 << la) && unrecognized_op(&msg));
559 if (unrecognized_op(&msg) && !node->remote[la].has_sys_audio_mode_req)
560 return OK_NOT_SUPPORTED;
561 fail_on_test(unrecognized_op(&msg));
562 if (refused(&msg))
563 return OK_REFUSED;
564 if (cec_msg_status_is_abort(&msg))
565 return OK_PRESUMED;
566 cec_ops_system_audio_mode_status(&msg, &system_audio_status);
567 fail_on_test(system_audio_status != CEC_OP_SYS_AUD_STATUS_ON);
568
569 return 0;
570 }
571
sac_give_audio_status(struct node * node,unsigned me,unsigned la,bool interactive)572 static int sac_give_audio_status(struct node *node, unsigned me, unsigned la, bool interactive)
573 {
574 struct cec_msg msg = {};
575
576 /* Give Audio Status is mandatory for audio systems in CEC 2.0, except
577 for systems that lack external controls for volume/mute status. */
578 cec_msg_init(&msg, me, la);
579 cec_msg_give_audio_status(&msg, true);
580 fail_on_test(!transmit_timeout(node, &msg));
581 fail_on_test(timed_out(&msg));
582 fail_on_test_v2(node->remote[la].cec_version,
583 cec_has_audiosystem(1 << la) && unrecognized_op(&msg));
584 if (unrecognized_op(&msg))
585 return OK_NOT_SUPPORTED;
586 if (refused(&msg))
587 return OK_REFUSED;
588 if (cec_msg_status_is_abort(&msg))
589 return OK_PRESUMED;
590
591 cec_ops_report_audio_status(&msg, &node->remote[la].mute, &node->remote[la].volume);
592 fail_on_test(node->remote[la].volume > 100);
593 info("Volume: %d %s\n", node->remote[la].volume, node->remote[la].mute ? "(muted)" : "");
594
595 return 0;
596 }
597
sac_util_send_user_control_press(struct node * node,unsigned me,unsigned la,uint8_t ui_cmd)598 static int sac_util_send_user_control_press(struct node *node, unsigned me, unsigned la, uint8_t ui_cmd)
599 {
600 struct cec_msg msg = {};
601 struct cec_op_ui_command rc_press = {};
602
603 /* The device shall not feature abort
604 - User Control Pressed ["Volume Up"]
605 - User Control Pressed ["Volume Down"]
606 - User Control Pressed ["Mute"]
607 if it did not feature abort System Audio Mode Request.
608
609 The messages are mandatory for audio systems and TVs in CEC 2.0,
610 and it is mandatory for audio systems to send Report Audio Status
611 back to the TV in CEC 2.0.
612
613 It is recommended for devices to not send Report Audio Status back
614 more often than once every 500ms. We therefore sleep a second before
615 each User Control Pressed is sent. */
616 bool got_response;
617
618 sleep(1);
619 mode_set_follower(node);
620 cec_msg_init(&msg, me, la);
621 rc_press.ui_cmd = ui_cmd;
622 cec_msg_user_control_pressed(&msg, &rc_press);
623 fail_on_test(!transmit(node, &msg));
624 cec_msg_init(&msg, me, la);
625 cec_msg_user_control_released(&msg);
626 fail_on_test(!transmit_timeout(node, &msg));
627 got_response = util_receive(node, la, 1000, &msg,
628 CEC_MSG_USER_CONTROL_PRESSED, CEC_MSG_REPORT_AUDIO_STATUS) >= 0;
629
630 fail_on_test_v2(node->remote[la].cec_version, !got_response &&
631 cec_has_audiosystem(1 << la));
632 fail_on_test_v2(node->remote[la].cec_version, unrecognized_op(&msg) &&
633 (is_tv(la, node->remote[la].prim_type) || cec_has_audiosystem(1 << la)));
634 if (unrecognized_op(&msg) && !node->remote[la].has_sys_audio_mode_req)
635 return OK_NOT_SUPPORTED;
636 fail_on_test(unrecognized_op(&msg));
637 if (refused(&msg))
638 return OK_REFUSED;
639 if (cec_msg_status_is_abort(&msg))
640 return OK_PRESUMED;
641 if (got_response) {
642 cec_ops_report_audio_status(&msg, &node->remote[la].mute, &node->remote[la].volume);
643 return 0;
644 }
645
646 return OK_PRESUMED;
647 }
648
sac_user_control_press_vol_up(struct node * node,unsigned me,unsigned la,bool interactive)649 static int sac_user_control_press_vol_up(struct node *node, unsigned me, unsigned la, bool interactive)
650 {
651 uint8_t ret, old_volume = node->remote[la].volume;
652
653 if ((ret = sac_util_send_user_control_press(node, me, la, 0x41)))
654 return ret;
655 /* Check that if not already at the highest, the volume was increased. */
656 fail_on_test_v2(node->remote[la].cec_version,
657 la == CEC_LOG_ADDR_AUDIOSYSTEM &&
658 old_volume < 100 && node->remote[la].volume <= old_volume);
659
660 return 0;
661 }
662
sac_user_control_press_vol_down(struct node * node,unsigned me,unsigned la,bool interactive)663 static int sac_user_control_press_vol_down(struct node *node, unsigned me, unsigned la, bool interactive)
664 {
665 uint8_t ret, old_volume = node->remote[la].volume;
666
667 if ((ret = sac_util_send_user_control_press(node, me, la, 0x42)))
668 return ret;
669 /* Check that if not already at the lowest, the volume was lowered. */
670 fail_on_test_v2(node->remote[la].cec_version,
671 la == CEC_LOG_ADDR_AUDIOSYSTEM &&
672 old_volume > 0 && node->remote[la].volume >= old_volume);
673
674 return 0;
675 }
676
sac_user_control_press_mute(struct node * node,unsigned me,unsigned la,bool interactive)677 static int sac_user_control_press_mute(struct node *node, unsigned me, unsigned la, bool interactive)
678 {
679 uint8_t ret, old_mute = node->remote[la].mute;
680
681 if ((ret = sac_util_send_user_control_press(node, me, la, 0x43)))
682 return ret;
683 /* Check that mute has been toggled from what it was before. */
684 fail_on_test_v2(node->remote[la].cec_version,
685 la == CEC_LOG_ADDR_AUDIOSYSTEM &&
686 node->remote[la].mute == old_mute);
687
688 return 0;
689 }
690
sac_user_control_press_mute_function(struct node * node,unsigned me,unsigned la,bool interactive)691 static int sac_user_control_press_mute_function(struct node *node, unsigned me, unsigned la, bool interactive)
692 {
693 uint8_t ret;
694
695 if ((ret = sac_util_send_user_control_press(node, me, la, 0x65)))
696 return ret;
697 fail_on_test_v2(node->remote[la].cec_version,
698 la == CEC_LOG_ADDR_AUDIOSYSTEM &&
699 node->remote[la].mute == CEC_OP_AUD_MUTE_STATUS_ON);
700
701 return 0;
702 }
703
sac_user_control_press_restore_volume_function(struct node * node,unsigned me,unsigned la,bool interactive)704 static int sac_user_control_press_restore_volume_function(struct node *node, unsigned me, unsigned la, bool interactive)
705 {
706 uint8_t ret;
707
708 if ((ret = sac_util_send_user_control_press(node, me, la, 0x66)))
709 return ret;
710 fail_on_test_v2(node->remote[la].cec_version,
711 la == CEC_LOG_ADDR_AUDIOSYSTEM &&
712 node->remote[la].mute == CEC_OP_AUD_MUTE_STATUS_OFF);
713
714 return 0;
715 }
716
sac_user_control_release(struct node * node,unsigned me,unsigned la,bool interactive)717 static int sac_user_control_release(struct node *node, unsigned me, unsigned la, bool interactive)
718 {
719 struct cec_msg msg = {};
720
721 /* The device shall not feature abort User Control Released if it did not
722 feature abort System Audio Mode Request
723
724 The message is mandatory for audio systems and TVs in CEC 2.0. */
725 cec_msg_init(&msg, me, la);
726 cec_msg_user_control_released(&msg);
727 fail_on_test(!transmit_timeout(node, &msg));
728 fail_on_test_v2(node->remote[la].cec_version, unrecognized_op(&msg) &&
729 (is_tv(la, node->remote[la].prim_type) || cec_has_audiosystem(1 << la)));
730 if (unrecognized_op(&msg) && !node->remote[la].has_sys_audio_mode_req)
731 return OK_NOT_SUPPORTED;
732 fail_on_test(unrecognized_op(&msg));
733 if (refused(&msg))
734 return OK_REFUSED;
735 if (cec_msg_status_is_abort(&msg))
736 return OK_PRESUMED;
737
738 return OK_PRESUMED;
739 }
740
sac_system_audio_mode_req_off(struct node * node,unsigned me,unsigned la,bool interactive)741 static int sac_system_audio_mode_req_off(struct node *node, unsigned me, unsigned la, bool interactive)
742 {
743 if (!node->remote[la].has_sys_audio_mode_req)
744 return NOTAPPLICABLE;
745
746 struct cec_msg msg = {};
747 uint8_t status;
748
749 cec_msg_init(&msg, me, la);
750 cec_msg_system_audio_mode_request(&msg, true, CEC_PHYS_ADDR_INVALID);
751 fail_on_test(!transmit_timeout(node, &msg));
752 fail_on_test(timed_out(&msg));
753 fail_on_test_v2(node->remote[la].cec_version,
754 cec_has_audiosystem(1 << la) && unrecognized_op(&msg));
755 if (unrecognized_op(&msg))
756 return OK_NOT_SUPPORTED;
757 if (refused(&msg))
758 return OK_REFUSED;
759 if (cec_msg_status_is_abort(&msg))
760 return OK_PRESUMED;
761 cec_ops_set_system_audio_mode(&msg, &status);
762 fail_on_test(status != CEC_OP_SYS_AUD_STATUS_OFF);
763
764 return 0;
765 }
766
767 struct remote_subtest sac_subtests[] = {
768 { "Request Short Audio Descriptor",
769 CEC_LOG_ADDR_MASK_AUDIOSYSTEM,
770 sac_request_sad_probe },
771 { "Request Short Audio Descriptor, invalid",
772 CEC_LOG_ADDR_MASK_AUDIOSYSTEM,
773 sac_request_sad_invalid },
774 { "Report Short Audio Descriptor consistency",
775 CEC_LOG_ADDR_MASK_AUDIOSYSTEM,
776 sac_sad_format_check },
777 { "Report Short Audio Descriptor, multiple requests in one",
778 CEC_LOG_ADDR_MASK_AUDIOSYSTEM,
779 sac_sad_req_multiple },
780 { "Set System Audio Mode (directly addressed)",
781 CEC_LOG_ADDR_MASK_TV,
782 sac_set_system_audio_mode_direct },
783 { "Set System Audio Mode (broadcast on)",
784 CEC_LOG_ADDR_MASK_TV,
785 sac_set_system_audio_mode_broadcast_on },
786 { "System Audio Mode Status",
787 CEC_LOG_ADDR_MASK_TV,
788 sac_system_audio_mode_status },
789 { "System Audio Mode Request (on)",
790 CEC_LOG_ADDR_MASK_AUDIOSYSTEM,
791 sac_system_audio_mode_req_on },
792 { "Give System Audio Mode Status",
793 CEC_LOG_ADDR_MASK_AUDIOSYSTEM,
794 sac_give_system_audio_mode_status },
795 { "Give Audio Status",
796 CEC_LOG_ADDR_MASK_AUDIOSYSTEM,
797 sac_give_audio_status },
798 { "User Control Pressed (Volume Up)",
799 CEC_LOG_ADDR_MASK_AUDIOSYSTEM | CEC_LOG_ADDR_MASK_TV,
800 sac_user_control_press_vol_up },
801 { "User Control Pressed (Volume Down)",
802 CEC_LOG_ADDR_MASK_AUDIOSYSTEM | CEC_LOG_ADDR_MASK_TV,
803 sac_user_control_press_vol_down },
804 { "User Control Pressed (Mute)",
805 CEC_LOG_ADDR_MASK_AUDIOSYSTEM | CEC_LOG_ADDR_MASK_TV,
806 sac_user_control_press_mute },
807 { "User Control Pressed (Restore Volume Function)",
808 CEC_LOG_ADDR_MASK_AUDIOSYSTEM | CEC_LOG_ADDR_MASK_TV,
809 sac_user_control_press_restore_volume_function },
810 { "User Control Pressed (Mute Function)",
811 CEC_LOG_ADDR_MASK_AUDIOSYSTEM | CEC_LOG_ADDR_MASK_TV,
812 sac_user_control_press_mute_function },
813 { "User Control Released (Audio)",
814 CEC_LOG_ADDR_MASK_AUDIOSYSTEM | CEC_LOG_ADDR_MASK_TV,
815 sac_user_control_release },
816 { "Set System Audio Mode (broadcast off)",
817 CEC_LOG_ADDR_MASK_TV,
818 sac_set_system_audio_mode_broadcast_off },
819 { "System Audio Mode Request (off)",
820 CEC_LOG_ADDR_MASK_AUDIOSYSTEM,
821 sac_system_audio_mode_req_off },
822 };
823
824 const unsigned sac_subtests_size = ARRAY_SIZE(sac_subtests);
825
826
827 /* Audio Rate Control */
828
829 /*
830 TODO: These are very rudimentary tests which should be expanded.
831 */
832
audio_rate_ctl_set_audio_rate(struct node * node,unsigned me,unsigned la,bool interactive)833 static int audio_rate_ctl_set_audio_rate(struct node *node, unsigned me, unsigned la, bool interactive)
834 {
835 struct cec_msg msg = {};
836
837 cec_msg_init(&msg, me, la);
838 cec_msg_set_audio_rate(&msg, CEC_OP_AUD_RATE_WIDE_STD);
839 fail_on_test(!transmit_timeout(node, &msg));
840 /* CEC 2.0: Devices shall use the device feature bit to indicate support. */
841 fail_on_test_v2(node->remote[la].cec_version,
842 node->remote[la].has_aud_rate && unrecognized_op(&msg));
843 fail_on_test_v2(node->remote[la].cec_version,
844 !node->remote[la].has_aud_rate && !unrecognized_op(&msg));
845 if (unrecognized_op(&msg))
846 return OK_NOT_SUPPORTED;
847 if (refused(&msg))
848 return OK_REFUSED;
849
850 return OK_PRESUMED;
851 }
852
853 struct remote_subtest audio_rate_ctl_subtests[] = {
854 { "Set Audio Rate",
855 CEC_LOG_ADDR_MASK_PLAYBACK | CEC_LOG_ADDR_MASK_RECORD | CEC_LOG_ADDR_MASK_TUNER,
856 audio_rate_ctl_set_audio_rate },
857 };
858
859 const unsigned audio_rate_ctl_subtests_size = ARRAY_SIZE(audio_rate_ctl_subtests);
860