123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523 |
- #!/usr/bin/env perl
- use strict;
- use FindBin '$Bin';
- require "$Bin/gen-common.pm";
- our %tlv_types;
- our $ctl;
- my $data = get_json();
- my $varsize_field;
- my %tlv_get = (
- gint8 => "*(int8_t *) get_next(1)",
- guint8 => "*(uint8_t *) get_next(1)",
- gint16 => "le16_to_cpu(*(uint16_t *) get_next(2))",
- guint16 => "le16_to_cpu(*(uint16_t *) get_next(2))",
- gint32 => "le32_to_cpu(*(uint32_t *) get_next(4))",
- guint32 => "le32_to_cpu(*(uint32_t *) get_next(4))",
- gint64 => "le64_to_cpu(*(uint64_t *) get_next(8))",
- guint64 => "le64_to_cpu(*(uint64_t *) get_next(8))",
- gfloat => "({ uint32_t data = le32_to_cpu(*(uint32_t *) get_next(4)); float _val; memcpy(&_val, &data, sizeof(_val)); _val; })"
- );
- my %tlv_get_be = (
- gint16 => "be16_to_cpu(*(uint16_t *) get_next(2))",
- guint16 => "be16_to_cpu(*(uint16_t *) get_next(2))",
- gint32 => "be32_to_cpu(*(uint32_t *) get_next(4))",
- guint32 => "be32_to_cpu(*(uint32_t *) get_next(4))",
- gint64 => "be64_to_cpu(*(uint64_t *) get_next(8))",
- guint64 => "be64_to_cpu(*(uint64_t *) get_next(8))",
- );
- sub gen_tlv_parse_field($$$$) {
- my $var = shift;
- my $elem = shift;
- my $n_indent = shift;
- my $iterator = shift;
- my $data = "";
- my $indent = "\t" x ($n_indent + 3);
- my $use_iterator = 0;
- my $field = 0;
- my $type = $elem->{"format"};
- $varsize_field and die "Cannot place fields after a variable-sized field (var: $var, field: $varsize_field)\n";
- my $val;
- if ($elem->{endian} eq 'network') {
- $val = $tlv_get_be{$type};
- } else {
- $val = $tlv_get{$type};
- }
- if ($val) {
- return $indent."$var = $val;\n";
- } elsif ($type eq "array") {
- my $size;
- my $cur_varsize_field;
- my $var_data;
- my $var_iterator;
- if ($elem->{"fixed-size"}) {
- $size = $elem->{"fixed-size"};
- $data .= $indent."for ($iterator = 0; $iterator < $size; $iterator\++) {\n";
- ($var_data, $var_iterator) =
- gen_tlv_parse_field($var."[$iterator]", $elem->{"array-element"}, $n_indent + 1, "i$iterator");
- } else {
- my $prefix = $elem->{"size-prefix-format"};
- $prefix or $prefix = 'guint8';
- $size = $tlv_get{$prefix};
- die "Unknown size element type '$prefix'" if not defined $size;
- my $curvar = "$var\_n";
- if (rindex($var,"]") == length($var)-1) {
- $curvar = substr($var, 0, index($var, "["))."\_i";
- $data .= $indent."$curvar = 0;\n";
- }
- ($var_data, $var_iterator) =
- gen_tlv_parse_field($var."[$curvar]", $elem->{"array-element"}, $n_indent + 1, "i$iterator");
- $var_data .= $indent."\t$curvar++;\n";
- $data .= $indent."$iterator = $size;\n";
- $data .= $indent."$var = __qmi_alloc_static($iterator * sizeof($var\[0]));\n";
- $data .= $indent."while($iterator\-- > 0) {\n";
- }
- $var_iterator and $data .= $indent."\tunsigned int i$iterator;\n";
- $data .= $var_data;
- $data .= $indent."}\n";
- $varsize_field = $cur_varsize_field;
- return $data, 1;
- } elsif ($type eq "struct" or $type eq "sequence") {
- foreach my $field (@{$elem->{contents}}) {
- my $field_cname = gen_cname($field->{name});
- my ($var_data, $var_iterator) =
- gen_tlv_parse_field("$var.$field_cname", $field, $n_indent, $iterator);
- $data .= $var_data;
- $var_iterator and $use_iterator = 1;
- }
- return $data, $use_iterator;
- } elsif ($type eq "string") {
- my $size = $elem->{"fixed-size"};
- $size or do {
- my $prefix = $elem->{"size-prefix-format"};
- $prefix or do {
- $elem->{type} eq 'TLV' or $prefix = 'guint8';
- };
- if ($prefix) {
- $size = $tlv_get{$prefix};
- } else {
- $size = "cur_tlv_len - ofs";
- $varsize_field = $var;
- }
- };
- $data .= $indent."$iterator = $size;\n";
- my $maxsize = $elem->{"max-size"};
- $maxsize and do {
- $data .= $indent."if ($iterator > $maxsize)\n";
- $data .= $indent."\t$iterator = $maxsize;\n";
- };
- $data .= $indent.$var." = __qmi_copy_string(get_next($iterator), $iterator);\n";
- return $data, 1;
- } elsif ($type eq "guint-sized") {
- my $size = $elem->{"guint-size"};
- return $indent."$var = ({ uint64_t var; memcpy(&var, get_next($size), $size); le64_to_cpu(var); });\n";
- } else {
- die "Invalid type $type for variable $var";
- }
- }
- sub gen_tlv_type($$$) {
- my $cname = shift;
- my $elem = shift;
- my $idx = shift;
- my $idx_word = "found[".int($idx / 32)."]";
- my $idx_bit = "(1 << ".($idx % 32).")";
- my $type = $elem->{"format"};
- my $id = $elem->{"id"};
- my $data = "";
- undef $varsize_field;
- my $indent = "\t\t\t";
- $type or return undef;
- print <<EOF;
- case $id:
- if ($idx_word & $idx_bit)
- break;
- $idx_word |= $idx_bit;
- EOF
- my $val = $tlv_get{$type};
- if ($val) {
- print $indent."qmi_set(res, $cname, $val);\n";
- } elsif ($type eq "string") {
- my ($var_data, $var_iterator) =
- gen_tlv_parse_field("res->data.$cname", $elem, 0, "i");
- print "$var_data";
- } elsif ($type eq "array") {
- $elem->{"fixed-size"} and $data = $indent."res->set.$cname = 1;\n";
- my ($var_data, $var_iterator) =
- gen_tlv_parse_field("res->data.$cname", $elem, 0, "i");
- print "$data$var_data\n";
- } elsif ($type eq "sequence" or $type eq "struct") {
- my ($var_data, $var_iterator) =
- gen_tlv_parse_field("res->data.$cname", $elem, 0, "i");
- print $indent."res->set.$cname = 1;\n".$var_data;
- }
- print <<EOF;
- break;
- EOF
- }
- sub gen_parse_func($$)
- {
- my $name = shift;
- my $data = shift;
- my $type = "svc";
- $ctl and $type = "ctl";
- print gen_tlv_parse_func($name, $data)."\n";
- print <<EOF;
- {
- void *tlv_buf = &msg->$type.tlv;
- unsigned int tlv_len = le16_to_cpu(msg->$type.tlv_len);
- EOF
- if (gen_has_types($data)) {
- my $n_bits = scalar @$data;
- my $n_words = int(($n_bits + 31) / 32);
- my $i = 0;
- print <<EOF;
- struct tlv *tlv;
- int i;
- uint32_t found[$n_words] = {};
- memset(res, 0, sizeof(*res));
- __qmi_alloc_reset();
- while ((tlv = tlv_get_next(&tlv_buf, &tlv_len)) != NULL) {
- unsigned int cur_tlv_len = le16_to_cpu(tlv->len);
- unsigned int ofs = 0;
- switch(tlv->type) {
- EOF
- foreach my $field (@$data) {
- $field = gen_common_ref($field);
- my $cname = gen_cname($field->{name});
- gen_tlv_type($cname, $field, $i++);
- }
- print <<EOF;
- default:
- break;
- }
- }
- return 0;
- error_len:
- fprintf(stderr, "%s: Invalid TLV length in message, tlv=0x%02x, len=%d\\n",
- __func__, tlv->type, le16_to_cpu(tlv->len));
- return QMI_ERROR_INVALID_DATA;
- EOF
- } else {
- print <<EOF;
- return qmi_check_message_status(tlv_buf, tlv_len);
- EOF
- }
- print <<EOF;
- }
- EOF
- }
- sub gen_parse_ind_func($$)
- {
- my $name = shift;
- my $data = shift;
- my $type = "svc";
- $ctl and $type = "ctl";
- print gen_tlv_parse_func($name, $data)."\n";
- print <<EOF;
- {
- void *tlv_buf = &msg->$type.tlv;
- unsigned int tlv_len = le16_to_cpu(msg->$type.tlv_len);
- EOF
- if (gen_has_types($data)) {
- my $n_bits = scalar @$data;
- my $n_words = int(($n_bits + 31) / 32);
- my $i = 0;
- print <<EOF;
- struct tlv *tlv;
- int i;
- uint32_t found[$n_words] = {};
- memset(res, 0, sizeof(*res));
- __qmi_alloc_reset();
- while ((tlv = tlv_get_next(&tlv_buf, &tlv_len)) != NULL) {
- unsigned int cur_tlv_len = le16_to_cpu(tlv->len);
- unsigned int ofs = 0;
- switch(tlv->type) {
- EOF
- foreach my $field (@$data) {
- $field = gen_common_ref($field);
- my $cname = gen_cname($field->{name});
- gen_tlv_type($cname, $field, $i++);
- }
- print <<EOF;
- default:
- break;
- }
- }
- return 0;
- error_len:
- fprintf(stderr, "%s: Invalid TLV length in message, tlv=0x%02x, len=%d\\n",
- __func__, tlv->type, le16_to_cpu(tlv->len));
- return QMI_ERROR_INVALID_DATA;
- EOF
- } else {
- print <<EOF;
- return qmi_check_message_status(tlv_buf, tlv_len);
- EOF
- }
- print <<EOF;
- }
- EOF
- }
- my %tlv_set = (
- guint8 => sub { my $a = shift; my $b = shift; print "*(uint8_t *) $a = $b;\n" },
- guint16 => sub { my $a = shift; my $b = shift; print "*(uint16_t *) $a = cpu_to_le16($b);\n" },
- guint32 => sub { my $a = shift; my $b = shift; print "*(uint32_t *) $a = cpu_to_le32($b);\n" },
- );
- my %tlv_put = (
- gint8 => sub { my $a = shift; "put_tlv_var(uint8_t, $a, 1);\n" },
- guint8 => sub { my $a = shift; "put_tlv_var(uint8_t, $a, 1);\n" },
- gint16 => sub { my $a = shift; "put_tlv_var(uint16_t, cpu_to_le16($a), 2);\n" },
- guint16 => sub { my $a = shift; "put_tlv_var(uint16_t, cpu_to_le16($a), 2);\n" },
- gint32 => sub { my $a = shift; "put_tlv_var(uint32_t, cpu_to_le32($a), 4);\n" },
- guint32 => sub { my $a = shift; "put_tlv_var(uint32_t, cpu_to_le32($a), 4);\n" },
- gint64 => sub { my $a = shift; "put_tlv_var(uint64_t, cpu_to_le64($a), 8);\n" },
- guint64 => sub { my $a = shift; "put_tlv_var(uint64_t, cpu_to_le64($a), 8);\n" },
- );
- my %tlv_put_be = (
- gint16 => sub { my $a = shift; "put_tlv_var(uint16_t, cpu_to_be16($a), 2);\n" },
- guint16 => sub { my $a = shift; "put_tlv_var(uint16_t, cpu_to_be16($a), 2);\n" },
- gint32 => sub { my $a = shift; "put_tlv_var(uint32_t, cpu_to_be32($a), 4);\n" },
- guint32 => sub { my $a = shift; "put_tlv_var(uint32_t, cpu_to_be32($a), 4);\n" },
- gint64 => sub { my $a = shift; "put_tlv_var(uint64_t, cpu_to_be64($a), 8);\n" },
- guint64 => sub { my $a = shift; "put_tlv_var(uint64_t, cpu_to_be64($a), 8);\n" },
- );
- sub gen_tlv_val_set($$$$$)
- {
- my $cname = shift;
- my $elem = shift;
- my $indent = shift;
- my $iterator = shift;
- my $cond = shift;
- my $prev_cond;
- my $type = $elem->{format};
- my $data = "";
- my $put;
- if ($elem->{endian} eq 'network') {
- $put = $tlv_put_be{$type};
- } else {
- $put = $tlv_put{$type};
- }
- $put and return $indent.&$put($cname);
- $type eq 'array' and do {
- my $size = $elem->{"fixed-size"};
- $size or do {
- $cond and $$cond = $cname;
- $size = $cname."_n";
- my $prefix = $elem->{"size-prefix-format"};
- $prefix or $prefix = 'gint8';
- $put = $tlv_put{$prefix};
- $put or die "Unknown size prefix type $prefix\n";
- $data .= $indent.&$put($size);
- };
- $data .= $indent."for ($iterator = 0; $iterator < $size; $iterator++) {\n";
- my ($var_data, $var_iterator) =
- gen_tlv_val_set($cname."[$iterator]", $elem->{"array-element"}, "$indent\t", "i$iterator", undef);
- $var_iterator and $data .= $indent."\tunsigned int i$iterator;\n";
- $data .= $var_data;
- $data .= $indent."}\n";
- return $data, 1;
- };
- $type eq 'string' and do {
- $cond and $$cond = $cname;
- my $len = $elem->{"fixed-size"};
- $len or $len = "strlen($cname)";
- $data .= $indent."$iterator = $len;\n";
- $len = $elem->{"max-size"};
- $len and do {
- $data .= $indent."if ($iterator > $len)\n";
- $data .= $indent."\t$iterator = $len;\n";
- };
- my $prefix = $elem->{"size-prefix-format"};
- $prefix or do {
- $elem->{"type"} eq 'TLV' or $prefix = 'guint8';
- };
- $prefix and do {
- my $put = $tlv_put{$prefix} or die "Unknown size prefix format $prefix";
- $data .= $indent.&$put("$iterator");
- };
- $data .= $indent."strncpy(__qmi_alloc_static($iterator), $cname, $iterator);\n";
- return $data, 1;
- };
- ($type eq 'sequence' or $type eq 'struct') and do {
- my $use_iterator;
- foreach my $field (@{$elem->{contents}}) {
- my $field_cname = gen_cname($field->{name});
- my ($var_data, $var_iterator) =
- gen_tlv_val_set("$cname.$field_cname", $field, $indent, $iterator, undef);
- $var_iterator and $use_iterator = 1;
- $data .= $var_data;
- }
- return $data, $use_iterator;
- };
- die "Unknown type $type";
- }
- sub gen_tlv_attr_set($$)
- {
- my $cname = shift;
- my $elem = shift;
- my $indent = "\t";
- my $data = "";
- my $iterator = "";
- my $size_var = "";
- my $id = $elem->{id};
- my $cond = "req->set.$cname";
- my ($var_data, $use_iterator) =
- gen_tlv_val_set("req->data.$cname", $elem, "\t\t", "i", \$cond);
- $use_iterator and $iterator = "\t\tunsigned int i;\n";
- $data = <<EOF;
- if ($cond) {
- void *buf;
- unsigned int ofs;
- $iterator$size_var
- __qmi_alloc_reset();
- $var_data
- buf = __qmi_get_buf(&ofs);
- tlv_new(msg, $id, ofs, buf);
- }
- EOF
- print "$data";
- }
- sub gen_set_func($$)
- {
- my $name = shift;
- my $fields = shift;
- my $data = shift;
- my $type = "svc";
- my $service = $data->{service};
- my $id = $data->{id};
- $service eq 'CTL' and $type = 'ctl';
- print gen_tlv_set_func($name, $fields)."\n";
- print <<EOF;
- {
- qmi_init_request_message(msg, QMI_SERVICE_$service);
- msg->$type.message = cpu_to_le16($id);
- EOF
- foreach my $field (@$fields) {
- $field = gen_common_ref($field);
- my $cname = gen_cname($field->{name});
- gen_tlv_attr_set($cname, $field);
- }
- print <<EOF;
- return 0;
- }
- EOF
- }
- print <<EOF;
- /* generated by uqmi gen-code.pl */
- #include <stdio.h>
- #include <string.h>
- #include "qmi-message.h"
- #define get_next(_size) ({ void *_buf = &tlv->data[ofs]; ofs += _size; if (ofs > cur_tlv_len) goto error_len; _buf; })
- #define copy_tlv(_val, _size) \\
- do { \\
- unsigned int __size = _size; \\
- if (__size > 0) \\
- memcpy(__qmi_alloc_static(__size), _val, __size); \\
- } while (0);
- #define put_tlv_var(_type, _val, _size) \\
- do { \\
- _type __var = _val; \\
- copy_tlv(&__var, _size); \\
- } while(0)
- EOF
- gen_foreach_message_type($data, \&gen_set_func, \&gen_parse_func, \&gen_parse_ind_func);
|