• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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