diff --git a/Makefile b/Makefile index 2713e1c..64540fd 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ CFLAGS := -Wall -g -O2 LDFLAGS := prefix := /usr/local -SRCS := accessor.c parser.c qmic.c +SRCS := accessor.c kernel.c parser.c qmic.c OBJS := $(SRCS:.c=.o) $(OUT): $(OBJS) diff --git a/accessor.c b/accessor.c index d9436d8..8c1facb 100644 --- a/accessor.c +++ b/accessor.c @@ -162,7 +162,7 @@ static void qmi_message_emit_simple_prototype(FILE *fp, const char *message, struct qmi_message_member *qmm) { - if (qmm->array) { + if (qmm->array_size) { fprintf(fp, "int %1$s_%2$s_set_%3$s(struct %1$s_%2$s *%2$s, %4$s *val, size_t count);\n", package, message, qmm->name, sz_simple_types[qmm->type]); @@ -183,12 +183,12 @@ static void qmi_message_emit_simple_accessors(FILE *fp, const char *message, struct qmi_message_member *qmm) { - if (qmm->array) { + if (qmm->array_size) { fprintf(fp, "int %1$s_%2$s_set_%3$s(struct %1$s_%2$s *%2$s, %4$s *val, size_t count)\n" "{\n" " return qmi_tlv_set_array((struct qmi_tlv*)%2$s, %5$d, %6$d, val, count, sizeof(%4$s));\n" "}\n\n", - package, message, qmm->name, sz_simple_types[qmm->type], qmm->id, qmm->array); + package, message, qmm->name, sz_simple_types[qmm->type], qmm->id, qmm->array_size); fprintf(fp, "%4$s *%1$s_%2$s_get_%3$s(struct %1$s_%2$s *%2$s, size_t *count)\n" "{\n" @@ -206,7 +206,7 @@ static void qmi_message_emit_simple_accessors(FILE *fp, " *count = len;\n" " return ptr;\n" "}\n\n", - package, message, qmm->name, sz_simple_types[qmm->type], qmm->id, qmm->array); + package, message, qmm->name, sz_simple_types[qmm->type], qmm->id, qmm->array_size); } else { fprintf(fp, "int %1$s_%2$s_set_%3$s(struct %1$s_%2$s *%2$s, %4$s val)\n" "{\n" @@ -238,7 +238,7 @@ static void qmi_message_emit_string_prototype(FILE *fp, const char *message, struct qmi_message_member *qmm) { - if (qmm->array) { + if (qmm->array_size) { fprintf(stderr, "Dont' know how to encode string arrays yet"); exit(1); } else { @@ -301,7 +301,7 @@ static void qmi_message_source(FILE *fp, const char *package) qmi_message_emit_string_accessors(fp, package, qm->name, qmm); break; case TYPE_STRUCT: - qmi_struct_emit_accessors(fp, package, qm->name, qmm->name, qmm->id, qmm->array, qmm->qmi_struct); + qmi_struct_emit_accessors(fp, package, qm->name, qmm->name, qmm->id, qmm->array_size, qmm->qmi_struct); break; }; } @@ -333,7 +333,7 @@ static void qmi_message_header(FILE *fp, const char *package) qmi_message_emit_string_prototype(fp, package, qm->name, qmm); break; case TYPE_STRUCT: - qmi_struct_emit_prototype(fp, package, qm->name, qmm->name, qmm->array, qmm->qmi_struct); + qmi_struct_emit_prototype(fp, package, qm->name, qmm->name, qmm->array_size, qmm->qmi_struct); break; }; } diff --git a/kernel.c b/kernel.c new file mode 100644 index 0000000..a8007ae --- /dev/null +++ b/kernel.c @@ -0,0 +1,328 @@ +#include +#include + +#include "qmic.h" + +static const char *sz_native_types[] = { + [TYPE_U8] = "uint8_t", + [TYPE_U16] = "uint16_t", + [TYPE_U32] = "uint32_t", + [TYPE_U64] = "uint64_t", +}; + +static const char *sz_data_types[] = { + [TYPE_U8] = "QMI_UNSIGNED_1_BYTE", + [TYPE_U16] = "QMI_UNSIGNED_2_BYTE", + [TYPE_U32] = "QMI_UNSIGNED_4_BYTE", + [TYPE_U64] = "QMI_UNSIGNED_8_BYTE" +}; + +static void emit_struct_definition(FILE *fp, const char *package, + struct qmi_struct *qs) +{ + struct qmi_struct_member *qsm; + + fprintf(fp, "struct %s_%s {\n", package, qs->name); + + list_for_each_entry(qsm, &qs->members, node) { + switch (qsm->type) { + case TYPE_U8: + case TYPE_U16: + case TYPE_U32: + case TYPE_U64: + fprintf(fp, "\t%s %s;\n", sz_native_types[qsm->type], qsm->name); + break; + } + } + + fprintf(fp, "};\n"); + fprintf(fp, "\n"); +} + +static void emit_struct_native_ei(FILE *fp, const char *package, + struct qmi_struct *qs, + struct qmi_struct_member *qsm) +{ + fprintf(fp, "\t{\n" + "\t\t.data_type = %4$s,\n" + "\t\t.elem_len = 1,\n" + "\t\t.elem_size = sizeof(%5$s),\n" + "\t\t.offset = offsetof(struct %1$s_%2$s, %3$s),\n" + "\t},\n", + package, qs->name, qsm->name, + sz_data_types[qsm->type], sz_native_types[qsm->type]); +} + +static void emit_struct_ei(FILE *fp, const char *package, struct qmi_struct *qs) +{ + struct qmi_struct_member *qsm; + + fprintf(fp, "struct qmi_elem_info %s_%s_ei[] = {\n", package, qs->name); + + list_for_each_entry(qsm, &qs->members, node) { + switch (qsm->type) { + case TYPE_U8: + case TYPE_U16: + case TYPE_U32: + case TYPE_U64: + emit_struct_native_ei(fp, package, qs, qsm); + break; + } + } + + fprintf(fp, "\t{}\n"); + fprintf(fp, "};\n"); + fprintf(fp, "\n"); +} + +static void emit_native_type(FILE *fp, const char *package, struct qmi_message *qm, + struct qmi_message_member *qmm) +{ + static const char *sz_types[] = { + [TYPE_U8] = "uint8_t", + [TYPE_U16] = "uint16_t", + [TYPE_U32] = "uint32_t", + [TYPE_U64] = "uint64_t", + }; + + if (!qmm->required) + fprintf(fp, "\tbool %s_valid;\n", qmm->name); + + if (qmm->array_size) { + fprintf(fp, "\tuint32_t %s_len;\n", qmm->name); + fprintf(fp, "\t%s %s[%d];\n", sz_types[qmm->type], + qmm->name, qmm->array_size); + } else { + fprintf(fp, "\t%s %s;\n", sz_types[qmm->type], + qmm->name); + } +} + +static void emit_struct_type(FILE *fp, const char *package, struct qmi_message *qm, + struct qmi_message_member *qmm) +{ + struct qmi_struct *qs = qmm->qmi_struct; + if (!qmm->required) + fprintf(fp, "\tbool %s_valid;\n", qmm->name); + + if (qmm->array_size) { + fprintf(fp, "\tuint32_t %s_len;\n", qmm->name); + fprintf(fp, "\tstruct %s_%s %s[%d];\n", package, qs->name, + qmm->name, qmm->array_size); + } else { + fprintf(fp, "\tstruct %s_%s %s;\n", package, qs->name, qmm->name); + } +} + +static void emit_msg_struct(FILE *fp, const char *package, struct qmi_message *qm) +{ + struct qmi_message_member *qmm; + + fprintf(fp, "struct %1$s_%2$s {\n", package, qm->name); + + list_for_each_entry(qmm, &qm->members, node) { + switch (qmm->type) { + case TYPE_U8: + case TYPE_U16: + case TYPE_U32: + case TYPE_U64: + emit_native_type(fp, package, qm, qmm); + break; + case TYPE_STRING: + fprintf(fp, "\tuint32_t %s_len;\n", qmm->name); + fprintf(fp, "\tchar %s[256];\n", qmm->name); + break; + case TYPE_STRUCT: + emit_struct_type(fp, package, qm, qmm); + break; + } + } + + fprintf(fp, "};\n"); + fprintf(fp, "\n"); +} + +static void emit_native_ei(FILE *fp, const char *package, struct qmi_message *qm, + struct qmi_message_member *qmm) +{ + if (!qmm->required) { + fprintf(fp, "\t{\n" + "\t\t.data_type = QMI_OPT_FLAG,\n" + "\t\t.elem_len = 1,\n" + "\t\t.elem_size = sizeof(bool),\n" + "\t\t.tlv_type = %4$d,\n" + "\t\t.offset = offsetof(struct %1$s_%2$s, %3$s_valid),\n" + "\t},\n", + package, qm->name, qmm->name, qmm->id); + } + + if (qmm->array_size) { + fprintf(fp, "\t{\n" + "\t\t.data_type = QMI_DATA_LEN,\n" + "\t\t.elem_len = 1,\n" + "\t\t.elem_size = sizeof(%5$s),\n" + "\t\t.tlv_type = %4$d,\n" + "\t\t.offset = offsetof(struct %1$s_%2$s, %3$s_len),\n" + "\t},\n", + package, qm->name, qmm->name, qmm->id, + qmm->array_size >= 256 ? "uint16_t" : "uint8_t"); + fprintf(fp, "\t{\n" + "\t\t.data_type = QMI_UNSIGNED_1_BYTE,\n" + "\t\t.elem_len = %5$d,\n" + "\t\t.elem_size = sizeof(%6$s),\n" + "\t\t.array_type = VAR_LEN_ARRAY,\n" + "\t\t.tlv_type = %4$d,\n" + "\t\t.offset = offsetof(struct %1$s_%2$s, %3$s),\n" + "\t},\n", + package, qm->name, qmm->name, qmm->id, qmm->array_size, + sz_native_types[qmm->type]); + } else { + fprintf(fp, "\t{\n" + "\t\t.data_type = %5$s,\n" + "\t\t.elem_len = 1,\n" + "\t\t.elem_size = sizeof(%6$s),\n" + "\t\t.tlv_type = %4$d,\n" + "\t\t.offset = offsetof(struct %1$s_%2$s, %3$s),\n" + "\t},\n", + package, qm->name, qmm->name, qmm->id, + sz_data_types[qmm->type], + sz_native_types[qmm->type]); + } +} + +static void emit_struct_ref_ei(FILE *fp, const char *package, struct qmi_message *qm, + struct qmi_message_member *qmm) +{ + struct qmi_struct *qs = qmm->qmi_struct; + + if (!qmm->required) { + fprintf(fp, "\t{\n" + "\t\t.data_type = QMI_OPT_FLAG,\n" + "\t\t.elem_len = 1,\n" + "\t\t.elem_size = sizeof(bool),\n" + "\t\t.tlv_type = %4$d,\n" + "\t\t.offset = offsetof(struct %1$s_%2$s, %3$s_valid),\n" + "\t},\n", + package, qm->name, qmm->name, qmm->id); + } + + if (qmm->array_size) { + fprintf(fp, "\t{\n" + "\t\t.data_type = QMI_DATA_LEN,\n" + "\t\t.elem_len = 1,\n" + "\t\t.elem_size = sizeof(%5$s),\n" + "\t\t.tlv_type = %4$d,\n" + "\t\t.offset = offsetof(struct %1$s_%2$s, %3$s_len),\n" + "\t},\n", + package, qm->name, qmm->name, qmm->id, + qmm->array_size >= 256 ? "uint16_t" : "uint8_t"); + + fprintf(fp, "\t{\n" + "\t\t.data_type = QMI_STRUCT,\n" + "\t\t.elem_len = %6$d,\n" + "\t\t.elem_size = sizeof(struct %1$s_%5$s),\n" + "\t\t.array_type = VAR_LEN_ARRAY,\n" + "\t\t.tlv_type = %4$d,\n" + "\t\t.offset = offsetof(struct %1$s_%2$s, %3$s),\n" + "\t\t.ei_array = %1$s_%5$s_ei,\n" + "\t},\n", + package, qm->name, qmm->name, qmm->id, qs->name, qmm->array_size); + } else { + fprintf(fp, "\t{\n" + "\t\t.data_type = QMI_STRUCT,\n" + "\t\t.elem_len = 1,\n" + "\t\t.elem_size = sizeof(struct %1$s_%5$s),\n" + "\t\t.tlv_type = %4$d,\n" + "\t\t.offset = offsetof(struct %1$s_%2$s, %3$s),\n" + "\t\t.ei_array = %1$s_%5$s_ei,\n" + "\t},\n", + package, qm->name, qmm->name, qmm->id, qs->name); + } +} + +static void emit_elem_info_array_decl(FILE *fp, const char *package, struct qmi_message *qm) +{ + fprintf(fp, "extern struct qmi_elem_info %1$s_%2$s_ei[];\n", + package, qm->name); +} + +static void emit_elem_info_array(FILE *fp, const char *package, struct qmi_message *qm) +{ + struct qmi_message_member *qmm; + + fprintf(fp, "struct qmi_elem_info %1$s_%2$s_ei[] = {\n", + package, qm->name); + + list_for_each_entry(qmm, &qm->members, node) { + switch (qmm->type) { + case TYPE_U8: + case TYPE_U16: + case TYPE_U32: + case TYPE_U64: + emit_native_ei(fp, package, qm, qmm); + break; + case TYPE_STRUCT: + emit_struct_ref_ei(fp, package, qm, qmm); + break; + case TYPE_STRING: + fprintf(fp, "\t{\n" + "\t\t.data_type = QMI_STRING,\n" + "\t\t.elem_len = 256,\n" + "\t\t.elem_size = sizeof(char),\n" + "\t\t.array_type = VAR_LEN_ARRAY,\n" + "\t\t.tlv_type = %4$d,\n" + "\t\t.offset = offsetof(struct %1$s_%2$s, %3$s)\n" + "\t},\n", + package, qm->name, qmm->name, qmm->id); + break; + } + } + fprintf(fp, "\t{}\n"); + fprintf(fp, "};\n"); + fprintf(fp, "\n"); +} + +static void emit_h_file_header(FILE *fp) +{ + fprintf(fp, "#include \n" + "#include \n" + "\n" + "#include \"libqrtr.h\"\n" + "\n"); +}; + +void kernel_emit_c(FILE *fp, const char *package) +{ + struct qmi_message *qm; + struct qmi_struct *qs; + + emit_source_includes(fp, package); + + list_for_each_entry(qs, &qmi_structs, node) + emit_struct_ei(fp, package, qs); + + list_for_each_entry(qm, &qmi_messages, node) + emit_elem_info_array(fp, package, qm); +} + +void kernel_emit_h(FILE *fp, const char *package) +{ + struct qmi_message *qm; + struct qmi_struct *qs; + + guard_header(fp, package); + emit_h_file_header(fp); + qmi_const_header(fp); + + list_for_each_entry(qs, &qmi_structs, node) + emit_struct_definition(fp, package, qs); + + list_for_each_entry(qm, &qmi_messages, node) + emit_msg_struct(fp, package, qm); + + list_for_each_entry(qm, &qmi_messages, node) + emit_elem_info_array_decl(fp, package, qm); + fprintf(fp, "\n"); + + guard_footer(fp); +} diff --git a/parser.c b/parser.c index e3ccc9b..4378ced 100644 --- a/parser.c +++ b/parser.c @@ -280,20 +280,19 @@ static void qmi_message_parse(enum message_type message_type) struct token type_tok; struct token num_tok; struct token id_tok; - unsigned array; + unsigned int array_size; + bool array_fixed = false; bool required; token_expect(TOK_ID, &msg_id_tok); token_expect('{', NULL); - qm = malloc(sizeof(struct qmi_message)); + qm = calloc(1, sizeof(struct qmi_message)); qm->name = msg_id_tok.str; qm->type = message_type; list_init(&qm->members); while (!token_accept('}', NULL)) { - array = 0; - if (token_accept(TOK_REQUIRED, NULL)) required = true; else if (token_accept(TOK_OPTIONAL, NULL)) @@ -305,28 +304,31 @@ static void qmi_message_parse(enum message_type message_type) token_expect(TOK_ID, &id_tok); if (token_accept('[', NULL)) { - array = 1; - if (token_accept(TOK_NUM, &num_tok)) { - if (num_tok.num & 0xffff0000) - array = 4; - else if (num_tok.num & 0xff00) - array = 2; - } - + token_expect(TOK_NUM, &num_tok); + array_size = num_tok.num; token_expect(']', NULL); + + array_fixed = true; + } else if(token_accept('(', NULL)) { + token_expect(TOK_NUM, &num_tok); + array_size = num_tok.num; + token_expect(')', NULL); + } else { + array_size = 0; } token_expect('=', NULL); token_expect(TOK_NUM, &num_tok); token_expect(';', NULL); - qmm = malloc(sizeof(struct qmi_message_member)); + qmm = calloc(1, sizeof(struct qmi_message_member)); qmm->name = id_tok.str; qmm->type = type_tok.num; qmm->qmi_struct = type_tok.qmi_struct; qmm->id = num_tok.num; qmm->required = required; - qmm->array = array; + qmm->array_size = array_size; + qmm->array_fixed = array_fixed; list_add(&qm->members, &qmm->node); } diff --git a/qmic.c b/qmic.c index bcbc22f..f542f82 100644 --- a/qmic.c +++ b/qmic.c @@ -66,7 +66,7 @@ static void usage(void) { extern const char *__progname; - fprintf(stderr, "Usage: %s -a\n", __progname); + fprintf(stderr, "Usage: %s [-ak]\n", __progname); exit(1); } @@ -78,9 +78,12 @@ int main(int argc, char **argv) int method = 0; int opt; - while ((opt = getopt(argc, argv, "a")) != -1) { + while ((opt = getopt(argc, argv, "ak")) != -1) { switch (opt) { case 'a': + method = 0; + break; + case 'k': method = 1; break; default: @@ -88,9 +91,6 @@ int main(int argc, char **argv) } } - if (!method) - usage(); - qmi_parse(); snprintf(fname, sizeof(fname), "qmi_%s.c", qmi_package); @@ -103,8 +103,16 @@ int main(int argc, char **argv) if (!hfp) err(1, "failed to open %s", fname); - accessor_emit_c(sfp, qmi_package); - accessor_emit_h(hfp, qmi_package); + switch (method) { + case 0: + accessor_emit_c(sfp, qmi_package); + accessor_emit_h(hfp, qmi_package); + break; + case 1: + kernel_emit_c(sfp, qmi_package); + kernel_emit_h(hfp, qmi_package); + break; + } fclose(hfp); fclose(sfp); diff --git a/qmic.h b/qmic.h index 8b7c991..482be4c 100644 --- a/qmic.h +++ b/qmic.h @@ -39,7 +39,8 @@ struct qmi_message_member { struct qmi_struct *qmi_struct; int id; bool required; - unsigned array; + unsigned array_size; + bool array_fixed; struct list_head node; }; @@ -83,4 +84,7 @@ void qmi_const_header(FILE *fp); void accessor_emit_c(FILE *fp, const char *package); void accessor_emit_h(FILE *fp, const char *package); +void kernel_emit_c(FILE *fp, const char *package); +void kernel_emit_h(FILE *fp, const char *package); + #endif