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