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