add GPL v2+ SPDX header
[project/usbmode.git] / convert-modeswitch.pl
1 #!/usr/bin/perl
2 use strict;
3
4 my $msg_ctr = 0;
5 my %messages;
6 my %devices;
7
8 sub add_message {
9 my $msg = shift;
10 my $val = $messages{$msg};
11
12 defined($val) or do {
13 $val = $msg_ctr++;
14 $messages{$msg} = $val;
15 };
16
17 return $val;
18 }
19
20 sub add_device($) {
21 my $id = shift;
22 my $dev = {};
23 my $match;
24
25 $id =~ /^(\w{4}:\w{4})(:.*)?/ or do {
26 warn "Invalid device ID string $id\n";
27 return $dev;
28 };
29
30 $id = $1;
31 $match = $2 or $match = "*";
32
33 $devices{$id} or $devices{$id} = {};
34 $devices{$id}->{$match} = $dev;
35
36 return $dev;
37 }
38
39 sub add_hex {
40 $_[0] =~ s/^0x//;
41 return hex($_[0]);
42 }
43
44 sub add_mode {
45 $_[1] =~ s/^(\w+)Mode$/$1/;
46 return $_[1];
47 }
48
49 sub add_modeval {
50 return unless ($_[1] && $_[1] =~ /^\d+$/);
51 $_[0]->{"ModeValue"} = $_[1];
52 }
53
54 my $hex_option = [ undef, \&add_hex ];
55 my $msg_option = [ undef, \&add_message ];
56 my $mode_option = [ "Mode", \&add_mode ];
57 my $value_mode_option = [ "Mode", \&add_mode, \&add_modeval ];
58 my %options = (
59 TargetVendor => $hex_option,
60 TargetProductList => [ "TargetProduct", sub { return [ map(hex,split(/,/, $_[0])) ]; } ],
61 TargetProduct => [ "TargetProduct", sub { return [ hex($_[0]) ]; } ],
62 TargetClass => $hex_option,
63 MessageContent => $msg_option,
64 MessageContent2 => $msg_option,
65 MessageContent3 => $msg_option,
66 WaitBefore => [ ],
67 DetachStorageOnly => [ ],
68 MBIM => $mode_option,
69 HuaweiMode => $mode_option,
70 HuaweiNewMode => $mode_option,
71 QuantaMode => $mode_option,
72 BlackberryMode => $mode_option,
73 PantechMode => $value_mode_option,
74 OptionMode => $mode_option,
75 SierraMode => $mode_option,
76 SonyMode => $mode_option,
77 QisdaMode => $mode_option,
78 GCTMode => $mode_option,
79 KobilMode => $mode_option,
80 SequansMode => $mode_option,
81 MobileActionMode => $mode_option,
82 CiscoMode => $mode_option,
83 StandardEject => $mode_option,
84 NoDriverLoading => [],
85 MessageEndpoint => $hex_option,
86 ReleaseDelay => [],
87 NeedResponse => [],
88 ResponseEndpoint => $hex_option,
89 ResetUSB => [],
90 InquireDevice => [],
91 CheckSuccess => $hex_option,
92 Interface => $hex_option,
93 Configuration => $hex_option,
94 AltSetting => $hex_option,
95 );
96
97 sub parse_file($) {
98 my $file = shift;
99 my $id;
100
101 $id = $file;
102 $file =~ /\/?([^\/]+)$/ and $id = $1;
103
104 my $dev = add_device($id);
105
106 open FILE, "<$file" or die "Cannot open file '$file'\n";
107 while (<FILE>) {
108 chomp;
109 s/^\s*(.+?)\s*$/$1/;
110 s/#.+$//;
111 next unless /\w/;
112 /(\w+)\s*=\s*(.+)\s*/ or do {
113 warn "Invalid Line: $_";
114 next;
115 };
116
117 my ($var, $val) = ($1, $2);
118 $val =~ s/^"(.+)"$/$1/;
119
120 my $opt = $options{$var};
121 $opt or do {
122 warn "Unrecognized option $var in file $file\n";
123 next;
124 };
125
126 $opt->[2] and &{$opt->[2]}($dev, $val, $var);
127 $opt->[1] and $val = &{$opt->[1]}($val, $var);
128 $opt->[0] and $var = $opt->[0];
129 $dev->{$var} = $val;
130 }
131 }
132
133 foreach my $file (@ARGV) {
134 parse_file $file;
135 }
136
137 sub json_chr {
138 my $chr = shift;
139
140 $chr eq "\b" and return "\\b";
141 $chr eq "\n" and return "\\n";
142 $chr eq "\r" and return "\\r";
143 $chr eq "\t" and return "\\t";
144 $chr eq "\\" and return "\\\\";
145 $chr eq "\"" and return "\\\"";
146 $chr eq '/' and return "\\/";
147 return sprintf("\\u%04x", ord($chr));
148 };
149
150 sub json_str {
151 $_[0] =~ s/([\x00- \/"\\])/json_chr($1)/eg;
152 return $_[0];
153 }
154
155 sub json_val($$) {
156 my ($val, $type) = (shift, shift);
157 $type eq 'bool' and $val = $val > 0 ? "true" : "false";
158 $type eq 'string' and $val = "\"$val\"";
159 return $val;
160 }
161
162 sub dev_opt {
163 my ($val, $name, $type, $sep) = (shift, shift, shift, shift);
164 return unless defined($val);
165 if ($type =~ /array:(.+)/) {
166 $type = $1;
167 my @val = @$val;
168 undef $val;
169 foreach my $elem (@val) {
170 my $json = json_val($elem, $type);
171 next unless defined $json;
172 if (defined $val) {
173 $val = "$val, $json"
174 } else {
175 $val = $json;
176 }
177 }
178 $val = "[ $val ]";
179 } else {
180 $val = json_val($val, $type);
181 }
182 print "$$sep\t\t\t\t\"".json_str($name)."\": $val";
183 $$sep = ",\n";
184 }
185
186 print <<EOF;
187 {
188 "messages" : [
189 EOF
190 my $suffix = "";
191 foreach my $msg (sort { $messages{$a} <=> $messages{$b} } keys %messages) {
192 print "$suffix\t\t\"".json_str($msg)."\"";
193 $suffix = ",\n";
194 }
195 print <<EOF;
196
197 ],
198
199 "devices" : {
200 EOF
201 my $dev_sep = "";
202 foreach my $devid (sort keys %devices) {
203 my $dev = $devices{$devid};
204
205 print "$dev_sep\t\t\"".json_str($devid)."\": {\n";
206 $dev_sep = ",\n";
207
208 my $match_sep = "";
209 foreach my $match (sort keys %$dev) {
210 my $cur = $dev->{$match};
211 my $sep = "";
212
213 print "$match_sep\t\t\t\"".json_str($match)."\": {\n";
214 $match_sep = ",\n";
215
216 dev_opt($cur->{TargetVendor}, "t_vendor", "int", \$sep);
217 dev_opt($cur->{TargetProduct}, "t_product", "array:int", \$sep);
218 dev_opt($cur->{TargetClass}, "t_class", "int", \$sep);
219 dev_opt($cur->{DetachStorageOnly}, "detach_storage", "bool", \$sep);
220 dev_opt($cur->{Mode}, "mode", "string", \$sep);
221 dev_opt($cur->{ModeValue}, "modeval", "int", \$sep);
222 dev_opt($cur->{NoDriverLoading}, "no_driver", "bool", \$sep);
223 dev_opt($cur->{MessageEndpoint}, "msg_endpoint", "int", \$sep);
224 my $msg = [
225 $cur->{MessageContent},
226 $cur->{MessageContent2},
227 $cur->{MessageContent3}
228 ];
229 dev_opt($msg, "msg", "array:int", \$sep);
230 dev_opt($cur->{WaitBefore}, "wait", "int", \$sep);
231 dev_opt($cur->{ReleaseDelay}, "release_delay", "int", \$sep);
232 dev_opt($cur->{NeedResponse}, "response", "bool", \$sep);
233 dev_opt($cur->{ResponseEndpoint}, "response_endpoint", "int", \$sep);
234 dev_opt($cur->{ResetUSB}, "reset", "bool", \$sep);
235 dev_opt($cur->{InquireDevice}, "inquire", "int", \$sep);
236 dev_opt($cur->{CheckSuccess}, "check", "bool", \$sep);
237 dev_opt($cur->{Interface}, "interface", "int", \$sep);
238 dev_opt($cur->{Configuration}, "config", "int", \$sep);
239 dev_opt($cur->{AltSetting}, "alt", "int", \$sep);
240 print "\n\t\t\t}";
241 }
242 print "\n\t\t}"
243 }
244 print <<EOF;
245
246 }
247 }
248 EOF