1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright 2019 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 <inttypes.h>
10 #include <getopt.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <sys/time.h>
14 #include <dirent.h>
15 #include <fcntl.h>
16 #include <ctype.h>
17 #include <errno.h>
18 #include <sys/ioctl.h>
19 #include <stdarg.h>
20 #include <cstring>
21 #include <ctime>
22 #include <cerrno>
23 #include <string>
24 #include <vector>
25 #include <map>
26 #include <algorithm>
27 #include <linux/cec-funcs.h>
28 #include "cec-htng-funcs.h"
29 #include "cec-log.h"
30 #include "cec-parse.h"
31 
32 #define xstr(s) str(s)
33 #define str(s) #s
34 
args2digital_service_id(uint8_t service_id_method,uint8_t dig_bcast_system,uint16_t transport_id,uint16_t service_id,uint16_t orig_network_id,uint16_t program_number,uint8_t channel_number_fmt,uint16_t major,uint16_t minor)35 static struct cec_op_digital_service_id *args2digital_service_id(uint8_t service_id_method,
36 								 uint8_t dig_bcast_system,
37 								 uint16_t transport_id,
38 								 uint16_t service_id,
39 								 uint16_t orig_network_id,
40 								 uint16_t program_number,
41 								 uint8_t channel_number_fmt,
42 								 uint16_t major,
43 								 uint16_t minor)
44 {
45 	static struct cec_op_digital_service_id dsid;
46 
47 	dsid.service_id_method = service_id_method;
48 	dsid.dig_bcast_system = dig_bcast_system;
49 	if (service_id_method == CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL) {
50 		dsid.channel.channel_number_fmt = channel_number_fmt;
51 		dsid.channel.major = major;
52 		dsid.channel.minor = minor;
53 		return &dsid;
54 	}
55 	switch (dig_bcast_system) {
56 	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_GEN:
57 	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_CABLE:
58 	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_SAT:
59 	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_T:
60 		dsid.atsc.transport_id = transport_id;
61 		dsid.atsc.program_number = program_number;
62 		break;
63 	default:
64 		dsid.dvb.transport_id = transport_id;
65 		dsid.dvb.service_id = service_id;
66 		dsid.dvb.orig_network_id = orig_network_id;
67 		break;
68 	}
69 	return &dsid;
70 }
71 
args2ui_command(uint8_t ui_cmd,uint8_t has_opt_arg,uint8_t play_mode,uint8_t ui_function_media,uint8_t ui_function_select_av_input,uint8_t ui_function_select_audio_input,uint8_t ui_bcast_type,uint8_t ui_snd_pres_ctl,uint8_t channel_number_fmt,uint16_t major,uint16_t minor)72 static struct cec_op_ui_command *args2ui_command(uint8_t ui_cmd,
73 						 uint8_t has_opt_arg,
74 						 uint8_t play_mode,
75 						 uint8_t ui_function_media,
76 						 uint8_t ui_function_select_av_input,
77 						 uint8_t ui_function_select_audio_input,
78 						 uint8_t ui_bcast_type,
79 						 uint8_t ui_snd_pres_ctl,
80 						 uint8_t channel_number_fmt,
81 						 uint16_t major,
82 						 uint16_t minor)
83 {
84 	static struct cec_op_ui_command ui_command;
85 
86 	ui_command.ui_cmd = ui_cmd;
87 	ui_command.has_opt_arg = has_opt_arg;
88 	if (!has_opt_arg)
89 		return &ui_command;
90 	switch (ui_cmd) {
91 	case CEC_OP_UI_CMD_SELECT_BROADCAST_TYPE:
92 		ui_command.ui_broadcast_type = ui_bcast_type;
93 		break;
94 	case CEC_OP_UI_CMD_SELECT_SOUND_PRESENTATION:
95 		ui_command.ui_sound_presentation_control = ui_snd_pres_ctl;
96 		break;
97 	case CEC_OP_UI_CMD_PLAY_FUNCTION:
98 		ui_command.play_mode = play_mode;
99 		break;
100 	case CEC_OP_UI_CMD_TUNE_FUNCTION:
101 		ui_command.channel_identifier.channel_number_fmt = channel_number_fmt;
102 		ui_command.channel_identifier.major = major;
103 		ui_command.channel_identifier.minor = minor;
104 		break;
105 	case CEC_OP_UI_CMD_SELECT_MEDIA_FUNCTION:
106 		ui_command.ui_function_media = ui_function_media;
107 		break;
108 	case CEC_OP_UI_CMD_SELECT_AV_INPUT_FUNCTION:
109 		ui_command.ui_function_select_av_input = ui_function_select_av_input;
110 		break;
111 	case CEC_OP_UI_CMD_SELECT_AUDIO_INPUT_FUNCTION:
112 		ui_command.ui_function_select_audio_input = ui_function_select_audio_input;
113 		break;
114 	default:
115 		ui_command.has_opt_arg = false;
116 		break;
117 	}
118 	return &ui_command;
119 }
120 
args2short_descrs(uint32_t descriptor1,uint32_t descriptor2,uint32_t descriptor3,uint32_t descriptor4)121 static uint32_t *args2short_descrs(uint32_t descriptor1,
122 				uint32_t descriptor2,
123 				uint32_t descriptor3,
124 				uint32_t descriptor4)
125 {
126 	static uint32_t descriptors[4];
127 
128 	descriptors[0] = descriptor1;
129 	descriptors[1] = descriptor2;
130 	descriptors[2] = descriptor3;
131 	descriptors[3] = descriptor4;
132 	return descriptors;
133 }
134 
args2short_aud_fmt_ids(uint8_t audio_format_id1,uint8_t audio_format_id2,uint8_t audio_format_id3,uint8_t audio_format_id4)135 static uint8_t *args2short_aud_fmt_ids(uint8_t audio_format_id1,
136 				    uint8_t audio_format_id2,
137 				    uint8_t audio_format_id3,
138 				    uint8_t audio_format_id4)
139 {
140 	static uint8_t audio_format_ids[4];
141 
142 	audio_format_ids[0] = audio_format_id1;
143 	audio_format_ids[1] = audio_format_id2;
144 	audio_format_ids[2] = audio_format_id3;
145 	audio_format_ids[3] = audio_format_id4;
146 	return audio_format_ids;
147 }
148 
args2short_aud_fmt_codes(uint8_t audio_format_code1,uint8_t audio_format_code2,uint8_t audio_format_code3,uint8_t audio_format_code4)149 static uint8_t *args2short_aud_fmt_codes(uint8_t audio_format_code1,
150 				      uint8_t audio_format_code2,
151 				      uint8_t audio_format_code3,
152 				      uint8_t audio_format_code4)
153 {
154 	static uint8_t audio_format_codes[4];
155 
156 	audio_format_codes[0] = audio_format_code1;
157 	audio_format_codes[1] = audio_format_code2;
158 	audio_format_codes[2] = audio_format_code3;
159 	audio_format_codes[3] = audio_format_code4;
160 	return audio_format_codes;
161 }
162 
cec_parse_subopt(char ** subs,const char * const * subopts,char ** value)163 int cec_parse_subopt(char **subs, const char * const *subopts, char **value)
164 {
165 	int opt = getsubopt(subs, const_cast<char * const *>(subopts), value);
166 
167 	if (opt == -1) {
168 		fprintf(stderr, "Invalid suboptions specified\n");
169 		return -1;
170 	}
171 	if (*value == NULL) {
172 		fprintf(stderr, "No value given to suboption <%s>\n",
173 				subopts[opt]);
174 		return -1;
175 	}
176 	return opt;
177 }
178 
parse_enum(const char * value,const struct cec_arg * a)179 static unsigned parse_enum(const char *value, const struct cec_arg *a)
180 {
181 	if (isdigit(*value))
182 		return strtoul(value, NULL, 0);
183 	for (int i = 0; i < a->num_enum_values; i++) {
184 		if (!strcmp(value, a->values[i].type_name))
185 			return a->values[i].value;
186 	}
187 	return 0;
188 }
189 
cec_parse_phys_addr(const char * value)190 unsigned cec_parse_phys_addr(const char *value)
191 {
192 	unsigned p1, p2, p3, p4;
193 
194 	if (!std::strchr(value, '.'))
195 		return strtoul(value, NULL, 0);
196 	if (sscanf(value, "%x.%x.%x.%x", &p1, &p2, &p3, &p4) != 4) {
197 		fprintf(stderr, "Expected a physical address of the form x.x.x.x\n");
198 		return 0;
199 	}
200 	if (p1 > 0xf || p2 > 0xf || p3 > 0xf || p4 > 0xf) {
201 		fprintf(stderr, "Physical address components should never be larger than 0xf\n");
202 		return 0;
203 	}
204 	return (p1 << 12) | (p2 << 8) | (p3 << 4) | p4;
205 }
206 
parse_latency(const char * value)207 static unsigned parse_latency(const char *value)
208 {
209 	char *end;
210 	unsigned delay = strtoul(value, &end, 0);
211 
212 	if (!memcmp(end, "ms", 2))
213 		delay = (delay / 2) + 1;
214 	if (delay < 1)
215 		delay = 1;
216 	else if (delay > 251)
217 		delay = 251;
218 	return delay;
219 }
220 
221 
222 #define VENDOR_EXTRA \
223 	"  --vendor-command payload=<byte>[:<byte>]*\n" \
224 	"                                  Send VENDOR_COMMAND message (" xstr(CEC_MSG_VENDOR_COMMAND) ")\n" \
225 	"  --vendor-command-with-id vendor-id=<val>,cmd=<byte>[:<byte>]*\n" \
226 	"                                  Send VENDOR_COMMAND_WITH_ID message (" xstr(CEC_MSG_VENDOR_COMMAND_WITH_ID) ")\n" \
227 	"  --vendor-remote-button-down rc-code=<byte>[:<byte>]*\n" \
228 	"                                  Send VENDOR_REMOTE_BUTTON_DOWN message (" xstr(CEC_MSG_VENDOR_REMOTE_BUTTON_DOWN) ")\n"
229 
230 #include "cec-parse-src-gen.h"
231