2
0

gen-code.pl 13 KB

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