1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3 * CEC API compliance test tool.
4 *
5 * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
6 */
7
8 #ifndef _CEC_COMPLIANCE_H_
9 #define _CEC_COMPLIANCE_H_
10
11 #include <linux/cec-funcs.h>
12 #include "cec-htng-funcs.h"
13
14 #include <cec-info.h>
15
16 #include <vector>
17
18 #define TAG_AUDIO_RATE_CONTROL 1
19 #define TAG_ARC_CONTROL (1 << 1)
20 #define TAG_CAP_DISCOVERY_CONTROL (1 << 2)
21 #define TAG_DECK_CONTROL (1 << 3)
22 #define TAG_DEVICE_MENU_CONTROL (1 << 4)
23 #define TAG_DEVICE_OSD_TRANSFER (1 << 5)
24 #define TAG_DYNAMIC_AUTO_LIPSYNC (1 << 6)
25 #define TAG_OSD_DISPLAY (1 << 7)
26 #define TAG_ONE_TOUCH_PLAY (1 << 8)
27 #define TAG_ONE_TOUCH_RECORD (1 << 9)
28 #define TAG_POWER_STATUS (1 << 10)
29 #define TAG_REMOTE_CONTROL_PASSTHROUGH (1 << 11)
30 #define TAG_ROUTING_CONTROL (1 << 12)
31 #define TAG_SYSTEM_AUDIO_CONTROL (1 << 13)
32 #define TAG_SYSTEM_INFORMATION (1 << 14)
33 #define TAG_TIMER_PROGRAMMING (1 << 15)
34 #define TAG_TUNER_CONTROL (1 << 16)
35 #define TAG_VENDOR_SPECIFIC_COMMANDS (1 << 17)
36 #define TAG_STANDBY_RESUME (1 << 18)
37
38 #define TAG_INTERACTIVE (1 << 19)
39 #define TAG_CORE 0
40 #define TAG_ALL (~TAG_INTERACTIVE)
41
42 #define NUM_TAGS 21
43
44 struct short_audio_desc {
45 /* Byte 1 */
46 __u8 num_channels;
47 __u8 format_code;
48
49 /* Byte 2 */
50 __u8 sample_freq_mask;
51
52 /* Byte 3 */
53 union {
54 __u8 bit_depth_mask; // LPCM
55 __u8 max_bitrate; // Format codes 2-8
56 __u8 format_dependent; // Format codes 9-13
57 __u8 wma_profile; // WMA Pro
58 __u8 frame_length_mask; // Extension type codes 4-6, 8-10
59 };
60 __u8 mps; // Format codes 8-10
61 __u8 extension_type_code;
62 };
63
64 #define SAD_FMT_CODE_LPCM 1
65 #define SAD_FMT_CODE_AC3 2
66 #define SAD_FMT_CODE_MPEG1 3
67 #define SAD_FMT_CODE_MP3 4
68 #define SAD_FMT_CODE_MPEG2 5
69 #define SAD_FMT_CODE_AAC_LC 6
70 #define SAD_FMT_CODE_DTS 7
71 #define SAD_FMT_CODE_ATRAC 8
72 #define SAD_FMT_CODE_ONE_BIT_AUDIO 9
73 #define SAD_FMT_CODE_ENHANCED_AC3 10
74 #define SAD_FMT_CODE_DTS_HD 11
75 #define SAD_FMT_CODE_MAT 12
76 #define SAD_FMT_CODE_DST 13
77 #define SAD_FMT_CODE_WMA_PRO 14
78 #define SAD_FMT_CODE_EXTENDED 15
79
80 #define SAD_BIT_DEPTH_MASK_16 1
81 #define SAD_BIT_DEPTH_MASK_20 (1 << 1)
82 #define SAD_BIT_DEPTH_MASK_24 (1 << 2)
83
84 #define SAD_SAMPLE_FREQ_MASK_32 1
85 #define SAD_SAMPLE_FREQ_MASK_44_1 (1 << 1)
86 #define SAD_SAMPLE_FREQ_MASK_48 (1 << 2)
87 #define SAD_SAMPLE_FREQ_MASK_88_2 (1 << 3)
88 #define SAD_SAMPLE_FREQ_MASK_96 (1 << 4)
89 #define SAD_SAMPLE_FREQ_MASK_176_4 (1 << 5)
90 #define SAD_SAMPLE_FREQ_MASK_192 (1 << 6)
91
92 #define SAD_FRAME_LENGTH_MASK_960 1
93 #define SAD_FRAME_LENGTH_MASK_1024 (1 << 1)
94
95 #define SAD_EXT_TYPE_MPEG4_HE_AAC 4
96 #define SAD_EXT_TYPE_MPEG4_HE_AACv2 5
97 #define SAD_EXT_TYPE_MPEG4_AAC_LC 6
98 #define SAD_EXT_TYPE_DRA 7
99 #define SAD_EXT_TYPE_MPEG4_HE_AAC_SURROUND 8
100 #define SAD_EXT_TYPE_MPEG4_AAC_LC_SURROUND 10
101 #define SAD_EXT_TYPE_MPEG_H_3D_AUDIO 11
102 #define SAD_EXT_TYPE_AC_4 12
103 #define SAD_EXT_TYPE_LPCM_3D_AUDIO 13
104
105 extern bool show_info;
106 extern bool show_colors;
107 extern bool show_warnings;
108 extern bool exit_on_fail;
109 extern bool exit_on_warn;
110 extern unsigned warnings;
111 extern unsigned reply_threshold;
112 extern time_t long_timeout;
113
114 struct remote {
115 bool recognized_op[256];
116 bool unrecognized_op[256];
117 unsigned prim_type;
118 __u16 phys_addr;
119 char osd_name[15];
120 char language[4];
121 __u8 cec_version;
122 __u8 rc_profile;
123 __u8 dev_features;
124 __u8 all_device_types;
125 __u32 vendor_id;
126 bool has_osd;
127 bool has_power_status;
128 bool has_image_view_on;
129 bool has_text_view_on;
130 bool in_standby;
131 bool has_remote_control_passthrough;
132 bool source_has_arc_rx;
133 bool sink_has_arc_tx;
134 bool arc_initiated;
135 bool has_sys_audio_mode_req;
136 bool has_set_sys_audio_mode;
137 bool has_sad;
138 __u8 supp_format_id;
139 __u8 supp_format_code;
140 __u8 volume;
141 __u8 mute;
142 bool has_aud_rate;
143 bool has_deck_ctl;
144 bool has_analogue_timer;
145 __u8 bcast_sys;
146 __u8 dig_bcast_sys;
147 bool has_rec_tv;
148 bool has_cdc;
149 };
150
151 struct node {
152 int fd;
153 const char *device;
154 bool has_cec20;
155 unsigned caps;
156 unsigned available_log_addrs;
157 unsigned num_log_addrs;
158 unsigned adap_la_mask;
159 __u8 log_addr[CEC_MAX_LOG_ADDRS];
160 unsigned remote_la_mask;
161 struct remote remote[16];
162 __u16 phys_addr;
163 bool in_standby;
164 __u8 prim_devtype;
165 time_t current_time;
166 };
167
168 struct remote_subtest {
169 const char *name;
170 const __u16 la_mask;
171 int (*const test_fn)(struct node *node, unsigned me, unsigned la, bool interactive);
172 bool in_standby;
173 bool for_cec20;
174 };
175
176 using vec_remote_subtests = std::vector<remote_subtest>;
177
178 #ifndef __FILE_NAME__
179 #define __FILE_NAME__ __FILE__
180 #endif
181
182 #define OK 0
183 #define FAIL 1
184 #define OK_PRESUMED 2
185 #define OK_NOT_SUPPORTED 3
186 #define OK_REFUSED 4
187 #define OK_UNEXPECTED 5
188 #define OK_EXPECTED_FAIL 6
189 #define NOTAPPLICABLE 7
190 #define FAIL_CRITICAL 8
191 #define DONT_CARE 255
192
193 #define CEC_LOG_ADDR_MASK_ALL 0xffff
194
195 #define COLOR_GREEN(s) "\033[32m" s "\033[0m"
196 #define COLOR_RED(s) "\033[1;31m" s "\033[0m"
197 #define COLOR_BOLD(s) "\033[1m" s "\033[0m"
198
199 #define info(fmt, args...) \
200 do { \
201 if (show_info) \
202 printf("\t\tinfo: " fmt, ##args); \
203 } while (0)
204
205 #define announce(fmt, args...) \
206 do { \
207 printf("\t\t>>> " fmt "\n", ##args); \
208 } while (0)
209
210 #define interactive_info(block, fmt, args...) \
211 do { \
212 if (interactive) { \
213 printf("\t\t>>> " fmt "\n", ##args); \
214 if (block) { \
215 printf("\t\t>>> Press ENTER to proceed.\n"); \
216 getchar(); \
217 } \
218 } \
219 } while(0)
220
221 #define warn(fmt, args...) \
222 ({ \
223 warnings++; \
224 if (show_warnings) \
225 printf("\t\%s: %s(%d): " fmt, \
226 show_colors ? COLOR_BOLD("warn") : "warn", \
227 __FILE_NAME__, __LINE__, ##args); \
228 if (exit_on_warn) \
229 std::exit(EXIT_FAILURE); \
230 0; \
231 })
232
233 #define warn_once(fmt, args...) \
234 do { \
235 static bool show; \
236 \
237 if (!show) { \
238 show = true; \
239 warn(fmt, ##args); \
240 } \
241 } while (0)
242
243 #define warn_on_test(test) \
244 do { \
245 if (test) \
246 warn("%s\n", #test); \
247 } while (0)
248
249 #define warn_once_on_test(test) \
250 do { \
251 if (test) \
252 warn_once("%s\n", #test); \
253 } while (0)
254
255 #define fail(fmt, args...) \
256 ({ \
257 printf("\t\t%s: %s(%d): " fmt, show_colors ? \
258 COLOR_RED("fail") : "fail", __FILE_NAME__, __LINE__, ##args); \
259 if (exit_on_fail) \
260 std::exit(EXIT_FAILURE); \
261 FAIL; \
262 })
263
264 #define fail_once(fmt, args...) \
265 do { \
266 static bool show; \
267 \
268 if (!show) { \
269 show = true; \
270 fail(fmt, ##args); \
271 } \
272 } while (0)
273
274 #define fail_or_warn(node, fmt, args...) \
275 ({ \
276 if ((node)->in_standby) \
277 warn(fmt, ##args); \
278 else \
279 fail(fmt, ##args); \
280 (node)->in_standby ? 0 : FAIL; \
281 })
282
283 #define fail_on_test(test) \
284 do { \
285 if (test) \
286 return fail("%s\n", #test); \
287 } while (0)
288
289 #define fail_on_test_v2(version, test) fail_on_test(version >= CEC_OP_CEC_VERSION_2_0 && (test))
290
291 #define fail_on_test_v2_warn(version, test) \
292 do { \
293 if (test) { \
294 if (version >= CEC_OP_CEC_VERSION_2_0) \
295 return fail("%s\n", #test); \
296 else \
297 warn("fails in CEC 2.0: %s\n", #test); \
298 } \
299 } while(0)
300
get_yn()301 static inline char get_yn()
302 {
303 char c;
304
305 while ((c = tolower(getchar())) != 'y' && c != 'n');
306 getchar();
307 return c;
308 }
309
question(const char * prompt)310 static inline bool question(const char* prompt)
311 {
312 printf("\t\t>>> %s (y/n) ", prompt);
313 return get_yn() == 'y';
314 }
315
316 int cec_named_ioctl(struct node *node, const char *name,
317 unsigned long int request, void *parm);
318
319 #define doioctl(n, r, p) cec_named_ioctl(n, #r, r, p)
320
321 const char *opcode2s(__u8 opcode);
322 std::string opcode2s(const struct cec_msg *msg);
323
is_tv(unsigned la,unsigned prim_type)324 static inline bool is_tv(unsigned la, unsigned prim_type)
325 {
326 return cec_has_tv(1 << la) ||
327 (cec_has_specific(1 << la) && prim_type == CEC_OP_PRIM_DEVTYPE_TV);
328 }
329
is_playback_or_rec(unsigned la)330 static inline bool is_playback_or_rec(unsigned la)
331 {
332 return cec_has_playback(1 << la) || cec_has_record(1 << la);
333 }
334
cec_msg_status_is_abort(const struct cec_msg * msg)335 static inline bool cec_msg_status_is_abort(const struct cec_msg *msg)
336 {
337 return msg->rx_status & CEC_RX_STATUS_FEATURE_ABORT;
338 }
339
abort_reason(const struct cec_msg * msg)340 static inline __u8 abort_reason(const struct cec_msg *msg)
341 {
342 return msg->msg[3];
343 }
344
unrecognized_op(const struct cec_msg * msg)345 static inline bool unrecognized_op(const struct cec_msg *msg)
346 {
347 if (!cec_msg_status_is_abort(msg))
348 return false;
349 if (abort_reason(msg) == CEC_OP_ABORT_UNRECOGNIZED_OP)
350 return true;
351 if (abort_reason(msg) == CEC_OP_ABORT_UNDETERMINED) {
352 warn("Opcode %x was undetermined and is treated as not supported.\n", msg->msg[2]);
353 return true;
354 }
355 return false;
356 }
357
refused(const struct cec_msg * msg)358 static inline bool refused(const struct cec_msg *msg)
359 {
360 return cec_msg_status_is_abort(msg) && abort_reason(msg) == CEC_OP_ABORT_REFUSED;
361 }
362
incorrect_mode(const struct cec_msg * msg)363 static inline bool incorrect_mode(const struct cec_msg *msg)
364 {
365 return cec_msg_status_is_abort(msg) && abort_reason(msg) == CEC_OP_ABORT_INCORRECT_MODE;
366 }
367
timed_out(const struct cec_msg * msg)368 static inline bool timed_out(const struct cec_msg *msg)
369 {
370 return msg->rx_status & CEC_RX_STATUS_TIMEOUT;
371 }
372
timed_out_or_abort(const struct cec_msg * msg)373 static inline bool timed_out_or_abort(const struct cec_msg *msg)
374 {
375 return timed_out(msg) || cec_msg_status_is_abort(msg);
376 }
377
response_time_ms(const struct cec_msg * msg)378 static inline unsigned response_time_ms(const struct cec_msg *msg)
379 {
380 unsigned ms = (msg->rx_ts - msg->tx_ts) / 1000000;
381
382 // Compensate for the time it took (approx.) to receive the
383 // message.
384 if (ms >= msg->len * 24)
385 return ms - msg->len * 24;
386 return 0;
387 }
388
389 bool transmit_timeout(struct node *node, struct cec_msg *msg,
390 unsigned timeout = 2000);
391
transmit(struct node * node,struct cec_msg * msg)392 static inline bool transmit(struct node *node, struct cec_msg *msg)
393 {
394 return transmit_timeout(node, msg, 0);
395 }
396
mode_set_follower(struct node * node)397 static inline void mode_set_follower(struct node *node)
398 {
399 __u32 mode = CEC_MODE_INITIATOR | CEC_MODE_FOLLOWER;
400
401 doioctl(node, CEC_S_MODE, &mode);
402 }
403
mode_set_initiator(struct node * node)404 static inline void mode_set_initiator(struct node *node)
405 {
406 __u32 mode = CEC_MODE_INITIATOR;
407
408 doioctl(node, CEC_S_MODE, &mode);
409 }
410
get_ts_ms()411 static inline unsigned get_ts_ms()
412 {
413 struct timespec timespec;
414
415 clock_gettime(CLOCK_MONOTONIC, ×pec);
416 return timespec.tv_sec * 1000ull + timespec.tv_nsec / 1000000;
417 }
418
419 const char *result_name(int res, bool show_colors);
420 const char *ok(int res);
421 const char *power_status2s(__u8 power_status);
422 const char *bcast_system2s(__u8 bcast_system);
423 const char *dig_bcast_system2s(__u8 bcast_system);
424 int check_0(const void *p, int len);
425 int util_receive(struct node *node, unsigned la, unsigned timeout,
426 struct cec_msg *msg, __u8 sent_msg,
427 __u8 reply1, __u8 reply2 = 0);
428 std::string safename(const char *name);
429 std::string current_ts();
430
431 // CEC adapter tests
432 void testAdapter(struct node &node, struct cec_log_addrs &laddrs,
433 const char *device);
434
435 // CEC fuzzing test
436 int testFuzzing(struct node &node, unsigned me, unsigned la);
437
438 // CEC core tests
439 int testCore(struct node *node);
440 int core_unknown(struct node *node, unsigned me, unsigned la, bool interactive);
441 int core_abort(struct node *node, unsigned me, unsigned la, bool interactive);
442 int system_info_polling(struct node *node, unsigned me, unsigned la, bool interactive);
443 int system_info_phys_addr(struct node *node, unsigned me, unsigned la, bool interactive);
444 int system_info_version(struct node *node, unsigned me, unsigned la, bool interactive);
445 int system_info_get_menu_lang(struct node *node, unsigned me, unsigned la, bool interactive);
446 int system_info_give_features(struct node *node, unsigned me, unsigned la, bool interactive);
447 int vendor_specific_commands_id(struct node *node, unsigned me, unsigned la, bool interactive);
448 int device_osd_transfer_give(struct node *node, unsigned me, unsigned la, bool interactive);
449
450 // CEC processing
451 int testProcessing(struct node *node, unsigned me);
452
453 // CEC testing
454 void collectTests(void);
455 void listTests(void);
456 int setExpectedResult(char *optarg, bool no_warnings);
457 void testRemote(struct node *node, unsigned me, unsigned la, unsigned test_tags,
458 bool interactive, bool show_ts);
459
460 // cec-test-tuner-record-timer.cpp
461 extern const vec_remote_subtests tuner_ctl_subtests;
462 extern const vec_remote_subtests one_touch_rec_subtests;
463 extern const vec_remote_subtests timer_prog_subtests;
464
465 // cec-test-audio.cpp
466 extern const vec_remote_subtests sac_subtests;
467 extern const vec_remote_subtests dal_subtests;
468 extern const vec_remote_subtests arc_subtests;
469 extern const vec_remote_subtests audio_rate_ctl_subtests;
470
471 // cec-test-power.cpp
472 bool util_interactive_ensure_power_state(struct node *node, unsigned me, unsigned la, bool interactive,
473 __u8 target_pwr);
474 int standby_resume_wakeup(struct node *node, unsigned me, unsigned la, bool interactive);
475 extern const vec_remote_subtests standby_subtests;
476 extern const vec_remote_subtests one_touch_play_subtests;
477 extern const vec_remote_subtests power_status_subtests;
478 extern const vec_remote_subtests standby_resume_subtests;
479
480 #endif
481