• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/uqmi/data/gen-code.pl

  1 #!/usr/bin/env perl
  2 use strict;
  3 
  4 use FindBin '$Bin';
  5 require "$Bin/gen-common.pm";
  6 
  7 our %tlv_types;
  8 our $ctl;
  9 
 10 my $data = get_json();
 11 my $varsize_field;
 12 
 13 my %tlv_get = (
 14         gint8 => "*(int8_t *) get_next(1)",
 15         guint8 => "*(uint8_t *) get_next(1)",
 16         gint16 => "le16_to_cpu(*(uint16_t *) get_next(2))",
 17         guint16 => "le16_to_cpu(*(uint16_t *) get_next(2))",
 18         gint32 => "le32_to_cpu(*(uint32_t *) get_next(4))",
 19         guint32 => "le32_to_cpu(*(uint32_t *) get_next(4))",
 20         gint64 => "le64_to_cpu(*(uint64_t *) get_next(8))",
 21         guint64 => "le64_to_cpu(*(uint64_t *) get_next(8))",
 22         gfloat => "({ uint32_t data = le32_to_cpu(*(uint32_t *) get_next(4)); float _val; memcpy(&_val, &data, sizeof(_val)); _val; })"
 23 );
 24 
 25 my %tlv_get_be = (
 26         gint16 => "be16_to_cpu(*(uint16_t *) get_next(2))",
 27         guint16 => "be16_to_cpu(*(uint16_t *) get_next(2))",
 28         gint32 => "be32_to_cpu(*(uint32_t *) get_next(4))",
 29         guint32 => "be32_to_cpu(*(uint32_t *) get_next(4))",
 30         gint64 => "be64_to_cpu(*(uint64_t *) get_next(8))",
 31         guint64 => "be64_to_cpu(*(uint64_t *) get_next(8))",
 32 );
 33 
 34 sub gen_tlv_parse_field($$$$) {
 35         my $var = shift;
 36         my $elem = shift;
 37         my $n_indent = shift;
 38         my $iterator = shift;
 39         my $data = "";
 40 
 41         my $indent = "\t" x ($n_indent + 3);
 42         my $use_iterator = 0;
 43         my $field = 0;
 44 
 45         my $type = $elem->{"format"};
 46 
 47         $varsize_field and die "Cannot place fields after a variable-sized field (var: $var, field: $varsize_field)\n";
 48 
 49         my $val;
 50         if ($elem->{endian} eq 'network') {
 51                 $val = $tlv_get_be{$type};
 52         } else {
 53                 $val = $tlv_get{$type};
 54         }
 55 
 56         if ($val) {
 57                 return $indent."$var = $val;\n";
 58         } elsif ($type eq "array") {
 59                 my $size;
 60                 my $cur_varsize_field;
 61                 my $var_data;
 62                 my $var_iterator;
 63 
 64                 if ($elem->{"fixed-size"}) {
 65                         $size = $elem->{"fixed-size"};
 66                         $data .= $indent."for ($iterator = 0; $iterator < $size; $iterator\++) {\n";
 67 
 68                         ($var_data, $var_iterator) =
 69                                 gen_tlv_parse_field($var."[$iterator]", $elem->{"array-element"}, $n_indent + 1, "i$iterator");
 70 
 71                 } else {
 72                         my $prefix = $elem->{"size-prefix-format"};
 73                         $prefix or $prefix = 'guint8';
 74 
 75                         $size = $tlv_get{$prefix};
 76                         die "Unknown size element type '$prefix'" if not defined $size;
 77 
 78                         my $curvar = "$var\_n";
 79                         if (rindex($var,"]") == length($var)-1) {
 80                                 $curvar = substr($var, 0, index($var, "["))."\_i";
 81                                 $data .= $indent."$curvar = 0;\n";
 82                         }
 83                         ($var_data, $var_iterator) =
 84                                 gen_tlv_parse_field($var."[$curvar]", $elem->{"array-element"}, $n_indent + 1, "i$iterator");
 85 
 86                         $var_data .= $indent."\t$curvar++;\n";
 87                         $data .= $indent."$iterator = $size;\n";
 88                         $data .= $indent."$var = __qmi_alloc_static($iterator * sizeof($var\[0]));\n";
 89                         $data .= $indent."while($iterator\-- > 0) {\n";
 90                 }
 91 
 92                 $var_iterator and $data .= $indent."\tunsigned int i$iterator;\n";
 93                 $data .= $var_data;
 94                 $data .= $indent."}\n";
 95 
 96                 $varsize_field = $cur_varsize_field;
 97 
 98                 return $data, 1;
 99         } elsif ($type eq "struct" or $type eq "sequence") {
100                 foreach my $field (@{$elem->{contents}}) {
101                         my $field_cname = gen_cname($field->{name});
102                         my ($var_data, $var_iterator) =
103                                 gen_tlv_parse_field("$var.$field_cname", $field, $n_indent, $iterator);
104 
105                         $data .= $var_data;
106                         $var_iterator and $use_iterator = 1;
107                 }
108                 return $data, $use_iterator;
109         } elsif ($type eq "string") {
110                 my $size = $elem->{"fixed-size"};
111                 $size or do {
112                         my $prefix = $elem->{"size-prefix-format"};
113                         $prefix or do {
114                                 $elem->{type} eq 'TLV' or $prefix = 'guint8';
115                         };
116 
117                         if ($prefix) {
118                                 $size = $tlv_get{$prefix};
119                         } else {
120                                 $size = "cur_tlv_len - ofs";
121                                 $varsize_field = $var;
122                         }
123                 };
124 
125                 $data .= $indent."$iterator = $size;\n";
126                 my $maxsize = $elem->{"max-size"};
127                 $maxsize and do {
128                         $data .= $indent."if ($iterator > $maxsize)\n";
129                         $data .= $indent."\t$iterator = $maxsize;\n";
130                 };
131                 $data .= $indent.$var." = __qmi_copy_string(get_next($iterator), $iterator);\n";
132                 return $data, 1;
133         } elsif ($type eq "guint-sized") {
134                 my $size = $elem->{"guint-size"};
135                 return $indent."$var = ({ uint64_t var; memcpy(&var, get_next($size), $size); le64_to_cpu(var); });\n";
136         } else {
137                 die "Invalid type $type for variable $var";
138         }
139 }
140 
141 sub gen_tlv_type($$$) {
142         my $cname = shift;
143         my $elem = shift;
144         my $idx = shift;
145         my $idx_word = "found[".int($idx / 32)."]";
146         my $idx_bit = "(1 << ".($idx % 32).")";
147 
148         my $type = $elem->{"format"};
149         my $id = $elem->{"id"};
150         my $data = "";
151         undef $varsize_field;
152         my $indent = "\t\t\t";
153 
154         $type or return undef;
155 
156         print <<EOF;
157                 case $id:
158                         if ($idx_word & $idx_bit)
159                                 break;
160 
161                         $idx_word |= $idx_bit;
162 EOF
163 
164         my $val = $tlv_get{$type};
165         if ($val) {
166                 print $indent."qmi_set(res, $cname, $val);\n";
167         } elsif ($type eq "string") {
168                 my ($var_data, $var_iterator) =
169                         gen_tlv_parse_field("res->data.$cname", $elem, 0, "i");
170                 print "$var_data";
171         } elsif ($type eq "array") {
172                 $elem->{"fixed-size"} and $data = $indent."res->set.$cname = 1;\n";
173                 my ($var_data, $var_iterator) =
174                         gen_tlv_parse_field("res->data.$cname", $elem, 0, "i");
175                 print "$data$var_data\n";
176         } elsif ($type eq "sequence" or $type eq "struct") {
177                 my ($var_data, $var_iterator) =
178                         gen_tlv_parse_field("res->data.$cname", $elem, 0, "i");
179 
180                 print $indent."res->set.$cname = 1;\n".$var_data;
181         }
182         print <<EOF;
183                         break;
184 
185 EOF
186 }
187 
188 sub gen_parse_func($$)
189 {
190         my $name = shift;
191         my $data = shift;
192 
193         my $type = "svc";
194         $ctl and $type = "ctl";
195 
196         print gen_tlv_parse_func($name, $data)."\n";
197         print <<EOF;
198 {
199         void *tlv_buf = &msg->$type.tlv;
200         unsigned int tlv_len = le16_to_cpu(msg->$type.tlv_len);
201 EOF
202 
203         if (gen_has_types($data)) {
204                 my $n_bits = scalar @$data;
205                 my $n_words = int(($n_bits + 31) / 32);
206                 my $i = 0;
207 
208                 print <<EOF;
209         struct tlv *tlv;
210         int i;
211         uint32_t found[$n_words] = {};
212 
213         memset(res, 0, sizeof(*res));
214 
215         __qmi_alloc_reset();
216         while ((tlv = tlv_get_next(&tlv_buf, &tlv_len)) != NULL) {
217                 unsigned int cur_tlv_len = le16_to_cpu(tlv->len);
218                 unsigned int ofs = 0;
219 
220                 switch(tlv->type) {
221 EOF
222                 foreach my $field (@$data) {
223                         $field = gen_common_ref($field);
224                         my $cname = gen_cname($field->{name});
225                         gen_tlv_type($cname, $field, $i++);
226                 }
227 
228                 print <<EOF;
229                 default:
230                         break;
231                 }
232         }
233 
234         return 0;
235 
236 error_len:
237         fprintf(stderr, "%s: Invalid TLV length in message, tlv=0x%02x, len=%d\\n",
238                 __func__, tlv->type, le16_to_cpu(tlv->len));
239         return QMI_ERROR_INVALID_DATA;
240 EOF
241         } else {
242                 print <<EOF;
243 
244         return qmi_check_message_status(tlv_buf, tlv_len);
245 EOF
246         }
247 
248         print <<EOF;
249 }
250 
251 EOF
252 }
253 
254 sub gen_parse_ind_func($$)
255 {
256         my $name = shift;
257         my $data = shift;
258 
259         my $type = "svc";
260         $ctl and $type = "ctl";
261 
262         print gen_tlv_parse_func($name, $data)."\n";
263         print <<EOF;
264 {
265         void *tlv_buf = &msg->$type.tlv;
266         unsigned int tlv_len = le16_to_cpu(msg->$type.tlv_len);
267 EOF
268 
269         if (gen_has_types($data)) {
270                 my $n_bits = scalar @$data;
271                 my $n_words = int(($n_bits + 31) / 32);
272                 my $i = 0;
273 
274                 print <<EOF;
275         struct tlv *tlv;
276         int i;
277         uint32_t found[$n_words] = {};
278 
279         memset(res, 0, sizeof(*res));
280 
281         __qmi_alloc_reset();
282         while ((tlv = tlv_get_next(&tlv_buf, &tlv_len)) != NULL) {
283                 unsigned int cur_tlv_len = le16_to_cpu(tlv->len);
284                 unsigned int ofs = 0;
285 
286                 switch(tlv->type) {
287 EOF
288                 foreach my $field (@$data) {
289                         $field = gen_common_ref($field);
290                         my $cname = gen_cname($field->{name});
291                         gen_tlv_type($cname, $field, $i++);
292                 }
293 
294                 print <<EOF;
295                 default:
296                         break;
297                 }
298         }
299 
300         return 0;
301 
302 error_len:
303         fprintf(stderr, "%s: Invalid TLV length in message, tlv=0x%02x, len=%d\\n",
304                 __func__, tlv->type, le16_to_cpu(tlv->len));
305         return QMI_ERROR_INVALID_DATA;
306 EOF
307         } else {
308                 print <<EOF;
309 
310         return qmi_check_message_status(tlv_buf, tlv_len);
311 EOF
312         }
313 
314         print <<EOF;
315 }
316 
317 EOF
318 }
319 
320 my %tlv_set = (
321         guint8 => sub { my $a = shift; my $b = shift; print "*(uint8_t *) $a = $b;\n" },
322         guint16 => sub { my $a = shift; my $b = shift; print "*(uint16_t *) $a = cpu_to_le16($b);\n" },
323         guint32 => sub { my $a = shift; my $b = shift; print "*(uint32_t *) $a = cpu_to_le32($b);\n" },
324 );
325 
326 my %tlv_put = (
327         gint8 => sub { my $a = shift; "put_tlv_var(uint8_t, $a, 1);\n" },
328         guint8 => sub { my $a = shift; "put_tlv_var(uint8_t, $a, 1);\n" },
329         gint16 => sub { my $a = shift; "put_tlv_var(uint16_t, cpu_to_le16($a), 2);\n" },
330         guint16 => sub { my $a = shift; "put_tlv_var(uint16_t, cpu_to_le16($a), 2);\n" },
331         gint32 => sub { my $a = shift; "put_tlv_var(uint32_t, cpu_to_le32($a), 4);\n" },
332         guint32 => sub { my $a = shift; "put_tlv_var(uint32_t, cpu_to_le32($a), 4);\n" },
333         gint64 => sub { my $a = shift; "put_tlv_var(uint64_t, cpu_to_le64($a), 8);\n" },
334         guint64 => sub { my $a = shift; "put_tlv_var(uint64_t, cpu_to_le64($a), 8);\n" },
335 );
336 
337 my %tlv_put_be = (
338         gint16 => sub { my $a = shift; "put_tlv_var(uint16_t, cpu_to_be16($a), 2);\n" },
339         guint16 => sub { my $a = shift; "put_tlv_var(uint16_t, cpu_to_be16($a), 2);\n" },
340         gint32 => sub { my $a = shift; "put_tlv_var(uint32_t, cpu_to_be32($a), 4);\n" },
341         guint32 => sub { my $a = shift; "put_tlv_var(uint32_t, cpu_to_be32($a), 4);\n" },
342         gint64 => sub { my $a = shift; "put_tlv_var(uint64_t, cpu_to_be64($a), 8);\n" },
343         guint64 => sub { my $a = shift; "put_tlv_var(uint64_t, cpu_to_be64($a), 8);\n" },
344 );
345 
346 sub gen_tlv_val_set($$$$$)
347 {
348         my $cname = shift;
349         my $elem = shift;
350         my $indent = shift;
351         my $iterator = shift;
352         my $cond = shift;
353         my $prev_cond;
354 
355         my $type = $elem->{format};
356         my $data = "";
357 
358         my $put;
359         if ($elem->{endian} eq 'network') {
360                 $put = $tlv_put_be{$type};
361         } else {
362                 $put = $tlv_put{$type};
363         }
364         $put and return $indent.&$put($cname);
365 
366         $type eq 'array' and do {
367                 my $size = $elem->{"fixed-size"};
368 
369                 $size or do {
370                         $cond and $$cond = $cname;
371                         $size = $cname."_n";
372 
373                         my $prefix = $elem->{"size-prefix-format"};
374                         $prefix or $prefix = 'gint8';
375 
376                         $put = $tlv_put{$prefix};
377                         $put or die "Unknown size prefix type $prefix\n";
378 
379                         $data .= $indent.&$put($size);
380                 };
381 
382                 $data .= $indent."for ($iterator = 0; $iterator < $size; $iterator++) {\n";
383                 my ($var_data, $var_iterator) =
384                         gen_tlv_val_set($cname."[$iterator]", $elem->{"array-element"}, "$indent\t", "i$iterator", undef);
385 
386                 $var_iterator and $data .= $indent."\tunsigned int i$iterator;\n";
387                 $data .= $var_data;
388                 $data .= $indent."}\n";
389 
390                 return $data, 1;
391         };
392 
393         $type eq 'string' and do {
394                 $cond and $$cond = $cname;
395 
396                 my $len = $elem->{"fixed-size"};
397                 $len or $len = "strlen($cname)";
398 
399                 $data .= $indent."$iterator = $len;\n";
400 
401                 $len = $elem->{"max-size"};
402                 $len and do {
403                         $data .= $indent."if ($iterator > $len)\n";
404                         $data .= $indent."\t$iterator = $len;\n";
405                 };
406 
407                 my $prefix = $elem->{"size-prefix-format"};
408                 $prefix or do {
409                         $elem->{"type"} eq 'TLV' or $prefix = 'guint8';
410                 };
411 
412                 $prefix and do {
413                         my $put = $tlv_put{$prefix} or die "Unknown size prefix format $prefix";
414                         $data .= $indent.&$put("$iterator");
415                 };
416 
417                 $data .= $indent."strncpy(__qmi_alloc_static($iterator), $cname, $iterator);\n";
418 
419                 return $data, 1;
420         };
421 
422         ($type eq 'sequence' or $type eq 'struct') and do {
423                 my $use_iterator;
424 
425                 foreach my $field (@{$elem->{contents}}) {
426                 my $field_cname = gen_cname($field->{name});
427                         my ($var_data, $var_iterator) =
428                                 gen_tlv_val_set("$cname.$field_cname", $field, $indent, $iterator, undef);
429 
430                         $var_iterator and $use_iterator = 1;
431                         $data .= $var_data;
432                 }
433                 return $data, $use_iterator;
434         };
435 
436         die "Unknown type $type";
437 }
438 
439 sub gen_tlv_attr_set($$)
440 {
441         my $cname = shift;
442         my $elem = shift;
443         my $indent = "\t";
444         my $data = "";
445         my $iterator = "";
446         my $size_var = "";
447         my $id = $elem->{id};
448 
449         my $cond = "req->set.$cname";
450         my ($var_data, $use_iterator) =
451                 gen_tlv_val_set("req->data.$cname", $elem, "\t\t", "i", \$cond);
452         $use_iterator and $iterator = "\t\tunsigned int i;\n";
453 
454         $data = <<EOF;
455         if ($cond) {
456                 void *buf;
457                 unsigned int ofs;
458 $iterator$size_var
459                 __qmi_alloc_reset();
460 $var_data
461                 buf = __qmi_get_buf(&ofs);
462                 tlv_new(msg, $id, ofs, buf);
463         }
464 
465 EOF
466         print "$data";
467 }
468 
469 sub gen_set_func($$)
470 {
471         my $name = shift;
472         my $fields = shift;
473         my $data = shift;
474 
475         my $type = "svc";
476         my $service = $data->{service};
477         my $id = $data->{id};
478 
479         $service eq 'CTL' and $type = 'ctl';
480 
481         print gen_tlv_set_func($name, $fields)."\n";
482         print <<EOF;
483 {
484         qmi_init_request_message(msg, QMI_SERVICE_$service);
485         msg->$type.message = cpu_to_le16($id);
486 
487 EOF
488         foreach my $field (@$fields) {
489                 $field = gen_common_ref($field);
490                 my $cname = gen_cname($field->{name});
491                 gen_tlv_attr_set($cname, $field);
492         }
493 
494         print <<EOF;
495         return 0;
496 }
497 
498 EOF
499 }
500 
501 print <<EOF;
502 /* generated by uqmi gen-code.pl */
503 #include <stdio.h>
504 #include <string.h>
505 #include "qmi-message.h"
506 
507 #define get_next(_size) ({ void *_buf = &tlv->data[ofs]; ofs += _size; if (ofs > cur_tlv_len) goto error_len; _buf; })
508 #define copy_tlv(_val, _size) \\
509         do { \\
510                 unsigned int __size = _size; \\
511                 if (__size > 0) \\
512                         memcpy(__qmi_alloc_static(__size), _val, __size); \\
513         } while (0);
514 
515 #define put_tlv_var(_type, _val, _size) \\
516         do { \\
517                 _type __var = _val; \\
518                 copy_tlv(&__var, _size); \\
519         } while(0)
520 
521 EOF
522 
523 gen_foreach_message_type($data, \&gen_set_func, \&gen_parse_func, \&gen_parse_ind_func);

This page was automatically generated by LXR 0.3.1.  •  OpenWrt