1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
|
/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _QMI_ENCDEC_H_
#define _QMI_ENCDEC_H_
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/list.h>
#include <linux/socket.h>
#include <linux/gfp.h>
#define QMI_REQUEST_CONTROL_FLAG 0x00
#define QMI_RESPONSE_CONTROL_FLAG 0x02
#define QMI_INDICATION_CONTROL_FLAG 0x04
#define QMI_HEADER_SIZE 7
/**
* elem_type - Enum to identify the data type of elements in a data
* structure.
*/
enum elem_type {
QMI_OPT_FLAG = 1,
QMI_DATA_LEN,
QMI_UNSIGNED_1_BYTE,
QMI_UNSIGNED_2_BYTE,
QMI_UNSIGNED_4_BYTE,
QMI_UNSIGNED_8_BYTE,
QMI_SIGNED_2_BYTE_ENUM,
QMI_SIGNED_4_BYTE_ENUM,
QMI_STRUCT,
QMI_STRING,
QMI_EOTI,
};
/**
* array_type - Enum to identify if an element in a data structure is
* an array. If so, then is it a static length array or a
* variable length array.
*/
enum array_type {
NO_ARRAY = 0,
STATIC_ARRAY = 1,
VAR_LEN_ARRAY = 2,
};
/**
* elem_info - Data structure to specify information about an element
* in a data structure. An array of this data structure
* can be used to specify info about a complex data
* structure to be encoded/decoded.
*
* @data_type: Data type of this element.
* @elem_len: Array length of this element, if an array.
* @elem_size: Size of a single instance of this data type.
* @is_array: Array type of this element.
* @tlv_type: QMI message specific type to identify which element
* is present in an incoming message.
* @offset: To identify the address of the first instance of this
* element in the data structure.
* @ei_array: Array to provide information about the nested structure
* within a data structure to be encoded/decoded.
*/
struct elem_info {
enum elem_type data_type;
uint32_t elem_len;
uint32_t elem_size;
enum array_type is_array;
uint8_t tlv_type;
uint32_t offset;
struct elem_info *ei_array;
};
/**
* @msg_desc - Describe about the main/outer structure to be
* encoded/decoded.
*
* @max_msg_len: Maximum possible length of the QMI message.
* @ei_array: Array to provide information about a data structure.
*/
struct msg_desc {
uint16_t msg_id;
int max_msg_len;
struct elem_info *ei_array;
};
struct qmi_header {
unsigned char cntl_flag;
uint16_t txn_id;
uint16_t msg_id;
uint16_t msg_len;
} __attribute__((__packed__));
static inline void encode_qmi_header(unsigned char *buf,
unsigned char cntl_flag, uint16_t txn_id,
uint16_t msg_id, uint16_t msg_len)
{
struct qmi_header *hdr = (struct qmi_header *)buf;
hdr->cntl_flag = cntl_flag;
hdr->txn_id = txn_id;
hdr->msg_id = msg_id;
hdr->msg_len = msg_len;
}
static inline void decode_qmi_header(unsigned char *buf,
unsigned char *cntl_flag, uint16_t *txn_id,
uint16_t *msg_id, uint16_t *msg_len)
{
struct qmi_header *hdr = (struct qmi_header *)buf;
*cntl_flag = hdr->cntl_flag;
*txn_id = hdr->txn_id;
*msg_id = hdr->msg_id;
*msg_len = hdr->msg_len;
}
#ifdef CONFIG_QMI_ENCDEC
/**
* qmi_kernel_encode() - Encode to QMI message wire format
* @desc: Pointer to structure descriptor.
* @out_buf: Buffer to hold the encoded QMI message.
* @out_buf_len: Length of the out buffer.
* @in_c_struct: C Structure to be encoded.
*
* @return: size of encoded message on success, < 0 on error.
*/
int qmi_kernel_encode(struct msg_desc *desc,
void *out_buf, uint32_t out_buf_len,
void *in_c_struct);
/**
* qmi_kernel_decode() - Decode to C Structure format
* @desc: Pointer to structure descriptor.
* @out_c_struct: Buffer to hold the decoded C structure.
* @in_buf: Buffer containg the QMI message to be decoded.
* @in_buf_len: Length of the incoming QMI message.
*
* @return: 0 on success, < 0 on error.
*/
int qmi_kernel_decode(struct msg_desc *desc, void *out_c_struct,
void *in_buf, uint32_t in_buf_len);
/**
* qmi_verify_max_msg_len() - Verify the maximum length of a QMI message
* @desc: Pointer to structure descriptor.
*
* @return: true if the maximum message length embedded in structure
* descriptor matches the calculated value, else false.
*/
bool qmi_verify_max_msg_len(struct msg_desc *desc);
#else
static inline int qmi_kernel_encode(struct msg_desc *desc,
void *out_buf, uint32_t out_buf_len,
void *in_c_struct)
{
return -EOPNOTSUPP;
}
static inline int qmi_kernel_decode(struct msg_desc *desc,
void *out_c_struct,
void *in_buf, uint32_t in_buf_len)
{
return -EOPNOTSUPP;
}
static inline bool qmi_verify_max_msg_len(struct msg_desc *desc)
{
return false;
}
#endif
#endif
|