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