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