1 // SPDX-License-Identifier: (LGPL-2.1-only OR BSD-3-Clause)
2 /*
3 * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
4 */
5
6 #include <string>
7
8 #include <unistd.h>
9
10 #include <linux/cec-funcs.h>
11
12 #include "cec-htng-funcs.h"
13 #include "cec-info.h"
14 #include "cec-log.h"
15 #include "compiler.h"
16
17 static const struct cec_arg arg_u8 = {
18 CEC_ARG_TYPE_U8,
19 };
20
21 static const struct cec_arg arg_u16 = {
22 CEC_ARG_TYPE_U16,
23 };
24
25 static const struct cec_arg arg_u32 = {
26 CEC_ARG_TYPE_U32,
27 };
28
29 static const struct cec_arg arg_string = {
30 CEC_ARG_TYPE_STRING,
31 };
32
log_arg(const struct cec_arg * arg,const char * arg_name,__u32 val)33 static void log_arg(const struct cec_arg *arg, const char *arg_name, __u32 val)
34 {
35 unsigned i;
36
37 switch (arg->type) {
38 case CEC_ARG_TYPE_ENUM:
39 for (i = 0; i < arg->num_enum_values; i++) {
40 if (arg->values[i].value == val) {
41 printf("\t%s: %s (0x%02x)\n", arg_name,
42 arg->values[i].type_name, val);
43 return;
44 }
45 }
46 fallthrough;
47 case CEC_ARG_TYPE_U8:
48 if (!strcmp(arg_name, "video-latency") ||
49 !strcmp(arg_name, "audio-out-delay")) {
50 printf("\t%s: %u (0x%02x, %d ms)\n", arg_name, val, val,
51 (val - 1) * 2);
52 } else if (!strcmp(arg_name, "abort-msg")) {
53 if (cec_opcode2s(val))
54 printf("\t%s: %u (0x%02x, %s)\n",
55 arg_name, val, val, cec_opcode2s(val));
56 else
57 printf("\t%s: %u (0x%02x)\n", arg_name, val, val);
58 } else {
59 printf("\t%s: %u (0x%02x)\n", arg_name, val, val);
60 }
61 return;
62 case CEC_ARG_TYPE_U16:
63 if (strstr(arg_name, "phys-addr"))
64 printf("\t%s: %x.%x.%x.%x\n", arg_name, cec_phys_addr_exp(val));
65 else
66 printf("\t%s: %u (0x%04x)\n", arg_name, val, val);
67 return;
68 case CEC_ARG_TYPE_U32:
69 printf("\t%s: %u (0x%08x)\n", arg_name, val, val);
70 return;
71 default:
72 break;
73 }
74 printf("\t%s: unknown type\n", arg_name);
75 }
76
log_arg(const struct cec_arg * arg,const char * arg_name,const char * s)77 static void log_arg(const struct cec_arg *arg, const char *arg_name,
78 const char *s)
79 {
80 switch (arg->type) {
81 case CEC_ARG_TYPE_STRING:
82 printf("\t%s: %s\n", arg_name, s);
83 return;
84 default:
85 break;
86 }
87 printf("\t%s: unknown type\n", arg_name);
88 }
89
90 static const struct cec_arg_enum_values type_rec_src_type[] = {
91 { "own", CEC_OP_RECORD_SRC_OWN },
92 { "digital", CEC_OP_RECORD_SRC_DIGITAL },
93 { "analog", CEC_OP_RECORD_SRC_ANALOG },
94 { "ext-plug", CEC_OP_RECORD_SRC_EXT_PLUG },
95 { "ext-phys-addr", CEC_OP_RECORD_SRC_EXT_PHYS_ADDR },
96 };
97
98 static const struct cec_arg arg_rec_src_type = {
99 CEC_ARG_TYPE_ENUM, 5, type_rec_src_type
100 };
101
102 static void log_digital(const char *arg_name, const struct cec_op_digital_service_id *digital);
103 static void log_rec_src(const char *arg_name, const struct cec_op_record_src *rec_src);
104 static void log_tuner_dev_info(const char *arg_name, const struct cec_op_tuner_device_info *tuner_dev_info);
105 static void log_features(const struct cec_arg *arg, const char *arg_name, const __u8 *p);
106 static void log_ui_command(const char *arg_name, const struct cec_op_ui_command *ui_cmd);
107 static void log_vendor_id(const char *arg_name, __u32 vendor_id);
108 static void log_descriptors(const char *arg_name, unsigned num, const __u32 *descriptors);
109 static void log_u8_array(const char *arg_name, unsigned num, const __u8 *vals);
110 static void log_unknown_msg(const struct cec_msg *msg);
111 static void log_htng_unknown_msg(const struct cec_msg *msg);
112
113 #include "cec-log-gen.h"
114
cec_log_msg_args(unsigned int index)115 const struct cec_msg_args *cec_log_msg_args(unsigned int index)
116 {
117 if (index >= sizeof(messages) / sizeof(messages[0]))
118 return nullptr;
119 return &messages[index];
120 }
121
log_digital(const char * arg_name,const struct cec_op_digital_service_id * digital)122 static void log_digital(const char *arg_name, const struct cec_op_digital_service_id *digital)
123 {
124 log_arg(&arg_service_id_method, "service-id-method", digital->service_id_method);
125 log_arg(&arg_dig_bcast_system, "dig-bcast-system", digital->dig_bcast_system);
126 if (digital->service_id_method == CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL) {
127 log_arg(&arg_channel_number_fmt, "channel-number-fmt", digital->channel.channel_number_fmt);
128 log_arg(&arg_u16, "major", digital->channel.major);
129 log_arg(&arg_u16, "minor", digital->channel.minor);
130 return;
131 }
132
133 switch (digital->dig_bcast_system) {
134 case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_GEN:
135 case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_CABLE:
136 case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_SAT:
137 case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_T:
138 log_arg(&arg_u16, "transport-id", digital->atsc.transport_id);
139 log_arg(&arg_u16, "program-number", digital->atsc.program_number);
140 break;
141 default:
142 log_arg(&arg_u16, "transport-id", digital->dvb.transport_id);
143 log_arg(&arg_u16, "service-id", digital->dvb.service_id);
144 log_arg(&arg_u16, "orig-network-id", digital->dvb.orig_network_id);
145 break;
146 }
147 }
148
log_rec_src(const char * arg_name,const struct cec_op_record_src * rec_src)149 static void log_rec_src(const char *arg_name, const struct cec_op_record_src *rec_src)
150 {
151 log_arg(&arg_rec_src_type, "rec-src-type", rec_src->type);
152 switch (rec_src->type) {
153 case CEC_OP_RECORD_SRC_OWN:
154 default:
155 break;
156 case CEC_OP_RECORD_SRC_DIGITAL:
157 log_digital(arg_name, &rec_src->digital);
158 break;
159 case CEC_OP_RECORD_SRC_ANALOG:
160 log_arg(&arg_ana_bcast_type, "ana-bcast-type", rec_src->analog.ana_bcast_type);
161 log_arg(&arg_u16, "ana-freq", rec_src->analog.ana_freq);
162 log_arg(&arg_bcast_system, "bcast-system", rec_src->analog.bcast_system);
163 break;
164 case CEC_OP_RECORD_SRC_EXT_PLUG:
165 log_arg(&arg_u8, "plug", rec_src->ext_plug.plug);
166 break;
167 case CEC_OP_RECORD_SRC_EXT_PHYS_ADDR:
168 log_arg(&arg_u16, "phys-addr", rec_src->ext_phys_addr.phys_addr);
169 break;
170 }
171 }
172
log_tuner_dev_info(const char * arg_name,const struct cec_op_tuner_device_info * tuner_dev_info)173 static void log_tuner_dev_info(const char *arg_name, const struct cec_op_tuner_device_info *tuner_dev_info)
174 {
175 log_arg(&arg_rec_flag, "rec-flag", tuner_dev_info->rec_flag);
176 log_arg(&arg_tuner_display_info, "tuner-display-info", tuner_dev_info->tuner_display_info);
177 if (tuner_dev_info->is_analog) {
178 log_arg(&arg_ana_bcast_type, "ana-bcast-type", tuner_dev_info->analog.ana_bcast_type);
179 log_arg(&arg_u16, "ana-freq", tuner_dev_info->analog.ana_freq);
180 log_arg(&arg_bcast_system, "bcast-system", tuner_dev_info->analog.bcast_system);
181 } else {
182 log_digital(arg_name, &tuner_dev_info->digital);
183 }
184 }
185
log_features(const struct cec_arg * arg,const char * arg_name,const __u8 * p)186 static void log_features(const struct cec_arg *arg,
187 const char *arg_name, const __u8 *p)
188 {
189 do {
190 log_arg(arg, arg_name, static_cast<__u32>((*p) & ~CEC_OP_FEAT_EXT));
191 } while ((*p++) & CEC_OP_FEAT_EXT);
192 }
193
log_ui_command(const char * arg_name,const struct cec_op_ui_command * ui_cmd)194 static void log_ui_command(const char *arg_name,
195 const struct cec_op_ui_command *ui_cmd)
196 {
197 log_arg(&arg_ui_cmd, arg_name, ui_cmd->ui_cmd);
198 if (!ui_cmd->has_opt_arg)
199 return;
200 switch (ui_cmd->ui_cmd) {
201 case CEC_OP_UI_CMD_SELECT_BROADCAST_TYPE:
202 log_arg(&arg_ui_bcast_type, "ui-broadcast-type",
203 ui_cmd->ui_broadcast_type);
204 break;
205 case CEC_OP_UI_CMD_SELECT_SOUND_PRESENTATION:
206 log_arg(&arg_ui_snd_pres_ctl, "ui-sound-presentation-control",
207 ui_cmd->ui_sound_presentation_control);
208 break;
209 case CEC_OP_UI_CMD_PLAY_FUNCTION:
210 log_arg(&arg_u8, "play-mode", ui_cmd->play_mode);
211 break;
212 case CEC_OP_UI_CMD_TUNE_FUNCTION:
213 log_arg(&arg_channel_number_fmt, "channel-number-fmt",
214 ui_cmd->channel_identifier.channel_number_fmt);
215 log_arg(&arg_u16, "major", ui_cmd->channel_identifier.major);
216 log_arg(&arg_u16, "minor", ui_cmd->channel_identifier.minor);
217 break;
218 case CEC_OP_UI_CMD_SELECT_MEDIA_FUNCTION:
219 log_arg(&arg_u8, "ui-function-media", ui_cmd->ui_function_media);
220 break;
221 case CEC_OP_UI_CMD_SELECT_AV_INPUT_FUNCTION:
222 log_arg(&arg_u8, "ui-function-select-av-input", ui_cmd->ui_function_select_av_input);
223 break;
224 case CEC_OP_UI_CMD_SELECT_AUDIO_INPUT_FUNCTION:
225 log_arg(&arg_u8, "ui-function-select-audio-input", ui_cmd->ui_function_select_audio_input);
226 break;
227 }
228 }
229
log_vendor_id(const char * arg_name,__u32 vendor_id)230 static void log_vendor_id(const char *arg_name, __u32 vendor_id)
231 {
232 const char *vendor = cec_vendor2s(vendor_id);
233
234 if (vendor)
235 printf("\t%s: 0x%06x (%s)\n", arg_name, vendor_id, vendor);
236 else
237 printf("\t%s: 0x%06x, %u\n", arg_name, vendor_id, vendor_id);
238 }
239
log_descriptors(const char * arg_name,unsigned num,const __u32 * descriptors)240 static void log_descriptors(const char *arg_name, unsigned num, const __u32 *descriptors)
241 {
242 for (unsigned i = 0; i < num; i++)
243 log_arg(&arg_u32, arg_name, descriptors[i]);
244 }
245
log_u8_array(const char * arg_name,unsigned num,const __u8 * vals)246 static void log_u8_array(const char *arg_name, unsigned num, const __u8 *vals)
247 {
248 for (unsigned i = 0; i < num; i++)
249 log_arg(&arg_u8, arg_name, vals[i]);
250 }
251
log_htng_unknown_msg(const struct cec_msg * msg)252 static void log_htng_unknown_msg(const struct cec_msg *msg)
253 {
254 __u32 vendor_id;
255 const __u8 *bytes;
256 __u8 size;
257 unsigned i;
258
259 cec_ops_vendor_command_with_id(msg, &vendor_id, &size, &bytes);
260 printf("VENDOR_COMMAND_WITH_ID (0x%02x):\n",
261 CEC_MSG_VENDOR_COMMAND_WITH_ID);
262 log_vendor_id("vendor-id", vendor_id);
263 printf("\tvendor-specific-data:");
264 for (i = 0; i < size; i++)
265 printf(" 0x%02x", bytes[i]);
266 printf("\n");
267 }
268
log_unknown_msg(const struct cec_msg * msg)269 static void log_unknown_msg(const struct cec_msg *msg)
270 {
271 __u32 vendor_id;
272 __u16 phys_addr;
273 const __u8 *bytes;
274 __u8 size;
275 unsigned i;
276
277 switch (msg->msg[1]) {
278 case CEC_MSG_VENDOR_COMMAND:
279 printf("VENDOR_COMMAND (0x%02x):\n",
280 CEC_MSG_VENDOR_COMMAND);
281 cec_ops_vendor_command(msg, &size, &bytes);
282 printf("\tvendor-specific-data:");
283 for (i = 0; i < size; i++)
284 printf(" 0x%02x", bytes[i]);
285 printf("\n");
286 break;
287 case CEC_MSG_VENDOR_COMMAND_WITH_ID:
288 cec_ops_vendor_command_with_id(msg, &vendor_id, &size, &bytes);
289 switch (vendor_id) {
290 case VENDOR_ID_HTNG:
291 log_htng_msg(msg);
292 break;
293 default:
294 printf("VENDOR_COMMAND_WITH_ID (0x%02x):\n",
295 CEC_MSG_VENDOR_COMMAND_WITH_ID);
296 log_vendor_id("vendor-id", vendor_id);
297 printf("\tvendor-specific-data:");
298 for (i = 0; i < size; i++)
299 printf(" 0x%02x", bytes[i]);
300 printf("\n");
301 break;
302 }
303 break;
304 case CEC_MSG_VENDOR_REMOTE_BUTTON_DOWN:
305 printf("VENDOR_REMOTE_BUTTON_DOWN (0x%02x):\n",
306 CEC_MSG_VENDOR_REMOTE_BUTTON_DOWN);
307 cec_ops_vendor_remote_button_down(msg, &size, &bytes);
308 printf("\tvendor-specific-rc-code:");
309 for (i = 0; i < size; i++)
310 printf(" 0x%02x", bytes[i]);
311 printf("\n");
312 break;
313 case CEC_MSG_CDC_MESSAGE:
314 phys_addr = (msg->msg[2] << 8) | msg->msg[3];
315
316 printf("CDC_MESSAGE (0x%02x): 0x%02x:\n",
317 CEC_MSG_CDC_MESSAGE, msg->msg[4]);
318 log_arg(&arg_u16, "phys-addr", phys_addr);
319 printf("\tpayload:");
320 for (i = 5; i < msg->len; i++)
321 printf(" 0x%02x", msg->msg[i]);
322 printf("\n");
323 break;
324 default:
325 printf("UNKNOWN (0x%02x)%s", msg->msg[1], msg->len > 2 ? ":\n\tpayload:" : "");
326 for (i = 2; i < msg->len; i++)
327 printf(" 0x%02x", msg->msg[i]);
328 printf("\n");
329 break;
330 }
331 }
332
cec_log_ui_cmd_string(__u8 ui_cmd)333 const char *cec_log_ui_cmd_string(__u8 ui_cmd)
334 {
335 for (unsigned i = 0; i < arg_ui_cmd.num_enum_values; i++) {
336 if (type_ui_cmd[i].value == ui_cmd)
337 return type_ui_cmd[i].type_name;
338 }
339 return nullptr;
340 }
341