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