5 require "$Bin/gen-common.pm";
10 my $data = get_json();
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))",
25 gint16 => "be16_to_cpu(*(uint16_t *) get_next(2))",
26 guint16 => "be16_to_cpu(*(uint16_t *) get_next(2))",
27 gint32 => "be32_to_cpu(*(uint32_t *) get_next(4))",
28 guint32 => "be32_to_cpu(*(uint32_t *) get_next(4))",
29 gint64 => "be64_to_cpu(*(uint64_t *) get_next(8))",
30 guint64 => "be64_to_cpu(*(uint64_t *) get_next(8))",
33 sub gen_tlv_parse_field($$$$) {
40 my $indent = "\t" x ($n_indent + 3);
44 my $type = $elem->{"format"};
46 $varsize_field and die "Cannot place fields after a variable-sized field (var: $var, field: $varsize_field)\n";
49 if ($elem->{endian} eq 'network') {
50 $val = $tlv_get_be{$type};
52 $val = $tlv_get{$type};
56 return $indent."$var = $val;\n";
57 } elsif ($type eq "array") {
59 my $cur_varsize_field;
63 if ($elem->{"fixed-size"}) {
64 $size = $elem->{"fixed-size"};
65 $data .= $indent."for ($iterator = 0; $iterator < $size; $iterator\++) {\n";
67 ($var_data, $var_iterator) =
68 gen_tlv_parse_field($var."[$iterator]", $elem->{"array-element"}, $n_indent + 1, "i$iterator");
71 my $prefix = $elem->{"size-prefix-format"};
72 $prefix or $prefix = 'guint8';
74 $size = $tlv_get{$prefix};
75 die "Unknown size element type '$prefix'" if not defined $size;
77 ($var_data, $var_iterator) =
78 gen_tlv_parse_field($var."[$var\_n]", $elem->{"array-element"}, $n_indent + 1, "i$iterator");
80 $var_data .= $indent."\t$var\_n++;\n";
81 $data .= $indent."$iterator = $size;\n";
82 $data .= $indent."$var = __qmi_alloc_static($iterator * sizeof($var\[0]));\n";
83 $data .= $indent."while($iterator\-- > 0) {\n";
86 $var_iterator and $data .= $indent."\tint i$iterator;\n";
88 $data .= $indent."}\n";
90 $varsize_field = $cur_varsize_field;
93 } elsif ($type eq "struct" or $type eq "sequence") {
94 foreach my $field (@{$elem->{contents}}) {
95 my $field_cname = gen_cname($field->{name});
96 my ($var_data, $var_iterator) =
97 gen_tlv_parse_field("$var.$field_cname", $field, $n_indent, $iterator);
100 $var_iterator and $use_iterator = 1;
102 return $data, $use_iterator;
103 } elsif ($type eq "string") {
104 my $size = $elem->{"fixed-size"};
106 my $prefix = $elem->{"size-prefix-format"};
108 $elem->{type} eq 'TLV' or $prefix = 'guint8';
112 $size = $tlv_get{$prefix};
114 $size = "cur_tlv_len - ofs";
115 $varsize_field = $var;
119 $data .= $indent."$iterator = $size;\n";
120 my $maxsize = $elem->{"max-size"};
122 $data .= $indent."if ($iterator > $maxsize)\n";
123 $data .= $indent."\t$iterator = $maxsize;\n";
125 $data .= $indent.$var." = __qmi_copy_string(get_next($iterator), $iterator);\n";
127 } elsif ($type eq "guint-sized") {
128 my $size = $elem->{"guint-size"};
129 return $indent."$var = ({ uint64_t var; memcpy(&var, get_next($size), $size); le64_to_cpu(var); });\n";
131 die "Invalid type $type for variable $var";
135 sub gen_tlv_type($$$) {
139 my $idx_word = "found[".int($idx / 32)."]";
140 my $idx_bit = "(1 << ".($idx % 32).")";
142 my $type = $elem->{"format"};
143 my $id = $elem->{"id"};
145 undef $varsize_field;
146 my $indent = "\t\t\t";
148 $type or return undef;
152 if ($idx_word & $idx_bit)
155 $idx_word |= $idx_bit;
158 my $val = $tlv_get{$type};
160 print $indent."qmi_set(res, $cname, $val);\n";
161 } elsif ($type eq "string") {
162 my ($var_data, $var_iterator) =
163 gen_tlv_parse_field("res->data.$cname", $elem, 0, "i");
165 } elsif ($type eq "array") {
166 $elem->{"fixed-size"} and $data = $indent."res->set.$cname = 1;\n";
167 my ($var_data, $var_iterator) =
168 gen_tlv_parse_field("res->data.$cname", $elem, 0, "i");
169 print "$data$var_data\n";
170 } elsif ($type eq "sequence" or $type eq "struct") {
171 my ($var_data, $var_iterator) =
172 gen_tlv_parse_field("res->data.$cname", $elem, 0, "i");
174 print $indent."res->set.$cname = 1;\n".$var_data;
182 sub gen_parse_func($$)
188 $ctl and $type = "ctl";
190 print gen_tlv_parse_func($name, $data)."\n";
193 void *tlv_buf = &msg->$type.tlv;
194 int tlv_len = le16_to_cpu(msg->$type.tlv_len);
197 if (gen_has_types($data)) {
198 my $n_bits = scalar @$data;
199 my $n_words = int(($n_bits + 31) / 32);
205 uint32_t found[$n_words] = {};
207 memset(res, 0, sizeof(*res));
210 while ((tlv = tlv_get_next(&tlv_buf, &tlv_len)) != NULL) {
211 unsigned int cur_tlv_len = le16_to_cpu(tlv->len);
212 unsigned int ofs = 0;
216 foreach my $field (@$data) {
217 my $cname = gen_cname($field->{name});
218 gen_tlv_type($cname, $field, $i++);
230 fprintf(stderr, "%s: Invalid TLV length in message, tlv=0x%02x, len=%d\\n",
231 __func__, tlv->type, le16_to_cpu(tlv->len));
232 return QMI_ERROR_INVALID_DATA;
237 return qmi_check_message_status(tlv_buf, tlv_len);
248 guint8 => sub { my $a = shift; my $b = shift; print "*(uint8_t *) $a = $b;\n" },
249 guint16 => sub { my $a = shift; my $b = shift; print "*(uint16_t *) $a = cpu_to_le16($b);\n" },
250 guint32 => sub { my $a = shift; my $b = shift; print "*(uint32_t *) $a = cpu_to_le32($b);\n" },
254 gint8 => sub { my $a = shift; "put_tlv_var(uint8_t, $a, 1);\n" },
255 guint8 => sub { my $a = shift; "put_tlv_var(uint8_t, $a, 1);\n" },
256 gint16 => sub { my $a = shift; "put_tlv_var(uint16_t, cpu_to_le16($a), 2);\n" },
257 guint16 => sub { my $a = shift; "put_tlv_var(uint16_t, cpu_to_le16($a), 2);\n" },
258 gint32 => sub { my $a = shift; "put_tlv_var(uint32_t, cpu_to_le32($a), 4);\n" },
259 guint32 => sub { my $a = shift; "put_tlv_var(uint32_t, cpu_to_le32($a), 4);\n" },
260 gint64 => sub { my $a = shift; "put_tlv_var(uint64_t, cpu_to_le64($a), 8);\n" },
261 guint64 => sub { my $a = shift; "put_tlv_var(uint64_t, cpu_to_le64($a), 8);\n" },
265 gint16 => sub { my $a = shift; "put_tlv_var(uint16_t, cpu_to_be16($a), 2);\n" },
266 guint16 => sub { my $a = shift; "put_tlv_var(uint16_t, cpu_to_be16($a), 2);\n" },
267 gint32 => sub { my $a = shift; "put_tlv_var(uint32_t, cpu_to_be32($a), 4);\n" },
268 guint32 => sub { my $a = shift; "put_tlv_var(uint32_t, cpu_to_be32($a), 4);\n" },
269 gint64 => sub { my $a = shift; "put_tlv_var(uint64_t, cpu_to_be64($a), 8);\n" },
270 guint64 => sub { my $a = shift; "put_tlv_var(uint64_t, cpu_to_be64($a), 8);\n" },
273 sub gen_tlv_val_set($$$$$)
278 my $iterator = shift;
282 my $type = $elem->{format};
286 if ($elem->{endian} eq 'network') {
287 $put = $tlv_put_be{$type};
289 $put = $tlv_put{$type};
291 $put and return $indent.&$put($cname);
293 $type eq 'array' and do {
294 my $size = $elem->{"fixed-size"};
297 $cond and $$cond = $cname;
300 my $prefix = $elem->{"size-prefix-format"};
301 $prefix or $prefix = 'gint8';
303 $put = $tlv_put{$prefix};
304 $put or die "Unknown size prefix type $prefix\n";
306 $data .= $indent.&$put($size);
309 $data .= $indent."for ($iterator = 0; $iterator < $size; $iterator++) {\n";
310 my ($var_data, $var_iterator) =
311 gen_tlv_val_set($cname."[$iterator]", $elem->{"array-element"}, "$indent\t", "i$iterator", undef);
313 $var_iterator and $data .= $indent."\tint i$iterator;\n";
315 $data .= $indent."}\n";
320 $type eq 'string' and do {
321 $cond and $$cond = $cname;
323 my $len = $elem->{"fixed-size"};
324 $len or $len = "strlen($cname)";
326 $data .= $indent."$iterator = $len;\n";
328 $len = $elem->{"max-size"};
330 $data .= $indent."if ($iterator > $len)\n";
331 $data .= $indent."\t$iterator = $len;\n";
334 my $prefix = $elem->{"size-prefix-format"};
336 $elem->{"type"} eq 'TLV' or $prefix = 'guint8';
340 my $put = $tlv_put{$prefix} or die "Unknown size prefix format $prefix";
341 $data .= $indent.&$put("$iterator");
344 $data .= $indent."strncpy(__qmi_alloc_static($iterator), $cname, $iterator);\n";
349 ($type eq 'sequence' or $type eq 'struct') and do {
352 foreach my $field (@{$elem->{contents}}) {
353 my $field_cname = gen_cname($field->{name});
354 my ($var_data, $var_iterator) =
355 gen_tlv_val_set("$cname.$field_cname", $field, $indent, $iterator, undef);
357 $var_iterator and $use_iterator = 1;
360 return $data, $use_iterator;
363 die "Unknown type $type";
366 sub gen_tlv_attr_set($$)
374 my $id = $elem->{id};
376 my $cond = "req->set.$cname";
377 my ($var_data, $use_iterator) =
378 gen_tlv_val_set("req->data.$cname", $elem, "\t\t", "i", \$cond);
379 $use_iterator and $iterator = "\t\tint i;\n";
388 buf = __qmi_get_buf(&ofs);
389 tlv_new(msg, $id, ofs, buf);
403 my $service = $data->{service};
404 my $id = $data->{id};
406 $service eq 'CTL' and $type = 'ctl';
408 print gen_tlv_set_func($name, $fields)."\n";
411 qmi_init_request_message(msg, QMI_SERVICE_$service);
412 msg->$type.message = cpu_to_le16($id);
415 foreach my $field (@$fields) {
416 my $cname = gen_cname($field->{name});
417 gen_tlv_attr_set($cname, $field);
428 /* generated by uqmi gen-code.pl */
431 #include "qmi-message.h"
433 #define get_next(_size) ({ void *_buf = &tlv->data[ofs]; ofs += _size; if (ofs > cur_tlv_len) goto error_len; _buf; })
434 #define copy_tlv(_val, _size) \\
436 int __size = _size; \\
438 memcpy(__qmi_alloc_static(__size), _val, __size); \\
441 #define put_tlv_var(_type, _val, _size) \\
443 _type __var = _val; \\
444 copy_tlv(&__var, _size); \\
449 gen_foreach_message_type($data, \&gen_set_func, \&gen_parse_func);