Commit | Line | Data |
---|---|---|
635d2b00 GKH |
1 | /***************************************************************************** |
2 | ||
3 | (c) Cambridge Silicon Radio Limited 2010 | |
4 | All rights reserved and confidential information of CSR | |
5 | ||
6 | Refer to LICENSE.txt included with this source for details | |
7 | on the license terms. | |
8 | ||
9 | *****************************************************************************/ | |
10 | ||
11 | #include <linux/module.h> | |
980b5a2b | 12 | #include <linux/types.h> |
55a27055 | 13 | #include <linux/slab.h> |
635d2b00 GKH |
14 | #include "csr_sched.h" |
15 | #include "csr_msgconv.h" | |
d63123fc | 16 | #include "csr_macro.h" |
635d2b00 GKH |
17 | |
18 | static CsrMsgConvEntry *converter; | |
19 | ||
8c87f69a | 20 | CsrMsgConvPrimEntry *CsrMsgConvFind(u16 primType) |
635d2b00 GKH |
21 | { |
22 | CsrMsgConvPrimEntry *ptr = NULL; | |
23 | ||
24 | if (converter) | |
25 | { | |
26 | ptr = converter->profile_converters; | |
27 | while (ptr) | |
28 | { | |
29 | if (ptr->primType == primType) | |
30 | { | |
31 | break; | |
32 | } | |
33 | else | |
34 | { | |
35 | ptr = ptr->next; | |
36 | } | |
37 | } | |
38 | } | |
39 | ||
40 | return ptr; | |
41 | } | |
42 | ||
8c87f69a | 43 | static const CsrMsgConvMsgEntry *find_msg_converter(CsrMsgConvPrimEntry *ptr, u16 msgType) |
635d2b00 GKH |
44 | { |
45 | const CsrMsgConvMsgEntry *cv = ptr->conv; | |
46 | if (ptr->lookupFunc) | |
47 | { | |
48 | return (const CsrMsgConvMsgEntry *) ptr->lookupFunc((CsrMsgConvMsgEntry *) cv, msgType); | |
49 | } | |
50 | ||
51 | while (cv) | |
52 | { | |
53 | if (cv->serFunc == NULL) | |
54 | { | |
55 | /* We've reached the end of the chain */ | |
56 | cv = NULL; | |
57 | break; | |
58 | } | |
59 | ||
60 | if (cv->msgType == msgType) | |
61 | { | |
62 | break; | |
63 | } | |
64 | else | |
65 | { | |
66 | cv++; | |
67 | } | |
68 | } | |
69 | ||
70 | return cv; | |
71 | } | |
72 | ||
8c87f69a | 73 | static void *deserialize_data(u16 primType, |
d4fda8db | 74 | size_t length, |
7e6f5794 | 75 | u8 *data) |
635d2b00 GKH |
76 | { |
77 | CsrMsgConvPrimEntry *ptr; | |
7e6f5794 | 78 | u8 *ret; |
635d2b00 GKH |
79 | |
80 | ptr = CsrMsgConvFind(primType); | |
81 | ||
82 | if (ptr) | |
83 | { | |
84 | const CsrMsgConvMsgEntry *cv; | |
8c87f69a | 85 | u16 msgId = 0; |
d4fda8db | 86 | size_t offset = 0; |
635d2b00 GKH |
87 | CsrUint16Des(&msgId, data, &offset); |
88 | ||
89 | cv = find_msg_converter(ptr, msgId); | |
90 | if (cv) | |
91 | { | |
92 | ret = cv->deserFunc(data, length); | |
93 | } | |
94 | else | |
95 | { | |
96 | ret = NULL; | |
97 | } | |
98 | } | |
99 | else | |
100 | { | |
101 | ret = NULL; | |
102 | } | |
103 | ||
104 | return ret; | |
105 | } | |
106 | ||
d4fda8db | 107 | static size_t sizeof_message(u16 primType, void *msg) |
635d2b00 GKH |
108 | { |
109 | CsrMsgConvPrimEntry *ptr = CsrMsgConvFind(primType); | |
d4fda8db | 110 | size_t ret; |
635d2b00 GKH |
111 | |
112 | if (ptr) | |
113 | { | |
114 | const CsrMsgConvMsgEntry *cv; | |
8c87f69a | 115 | u16 msgId = *(u16 *) msg; |
635d2b00 GKH |
116 | |
117 | cv = find_msg_converter(ptr, msgId); | |
118 | if (cv) | |
119 | { | |
120 | ret = cv->sizeofFunc(msg); | |
121 | } | |
122 | else | |
123 | { | |
124 | ret = 0; | |
125 | } | |
126 | } | |
127 | else | |
128 | { | |
129 | ret = 0; | |
130 | } | |
131 | ||
132 | return ret; | |
133 | } | |
134 | ||
5379b13d | 135 | static u8 free_message(u16 primType, u8 *data) |
635d2b00 GKH |
136 | { |
137 | CsrMsgConvPrimEntry *ptr; | |
5379b13d | 138 | u8 ret; |
635d2b00 GKH |
139 | |
140 | ptr = CsrMsgConvFind(primType); | |
141 | ||
142 | if (ptr) | |
143 | { | |
144 | const CsrMsgConvMsgEntry *cv; | |
8c87f69a | 145 | u16 msgId = *(u16 *) data; |
635d2b00 GKH |
146 | |
147 | cv = find_msg_converter(ptr, msgId); | |
148 | if (cv) | |
149 | { | |
150 | cv->freeFunc(data); | |
151 | ret = TRUE; | |
152 | } | |
153 | else | |
154 | { | |
155 | ret = FALSE; | |
156 | } | |
157 | } | |
158 | else | |
159 | { | |
160 | ret = FALSE; | |
161 | } | |
162 | ||
163 | return ret; | |
164 | } | |
165 | ||
8c87f69a | 166 | static u8 *serialize_message(u16 primType, |
635d2b00 | 167 | void *msg, |
d4fda8db | 168 | size_t *length, |
7e6f5794 | 169 | u8 *buffer) |
635d2b00 GKH |
170 | { |
171 | CsrMsgConvPrimEntry *ptr; | |
7e6f5794 | 172 | u8 *ret; |
635d2b00 GKH |
173 | |
174 | ptr = CsrMsgConvFind(primType); | |
175 | ||
176 | *length = 0; | |
177 | ||
178 | if (ptr) | |
179 | { | |
180 | const CsrMsgConvMsgEntry *cv; | |
181 | ||
8c87f69a | 182 | cv = find_msg_converter(ptr, *(u16 *) msg); |
635d2b00 GKH |
183 | if (cv) |
184 | { | |
185 | ret = cv->serFunc(buffer, length, msg); | |
186 | } | |
187 | else | |
188 | { | |
189 | ret = NULL; | |
190 | } | |
191 | } | |
192 | else | |
193 | { | |
194 | ret = NULL; | |
195 | } | |
196 | ||
197 | return ret; | |
198 | } | |
199 | ||
d4fda8db | 200 | size_t CsrMsgConvSizeof(u16 primType, void *msg) |
635d2b00 GKH |
201 | { |
202 | return sizeof_message(primType, msg); | |
203 | } | |
204 | ||
d4fda8db | 205 | u8 *CsrMsgConvSerialize(u8 *buffer, size_t maxBufferOffset, size_t *offset, u16 primType, void *msg) |
635d2b00 GKH |
206 | { |
207 | if (converter) | |
208 | { | |
d4fda8db | 209 | size_t serializedLength; |
7e6f5794 GKH |
210 | u8 *bufSerialized; |
211 | u8 *bufOffset = &buffer[*offset]; | |
635d2b00 GKH |
212 | bufSerialized = converter->serialize_message(primType, msg, &serializedLength, bufOffset); |
213 | *offset += serializedLength; | |
214 | return bufSerialized; | |
215 | } | |
216 | else | |
217 | { | |
218 | return NULL; | |
219 | } | |
220 | } | |
221 | ||
222 | /* Insert profile converter at head of converter list. */ | |
8c87f69a | 223 | void CsrMsgConvInsert(u16 primType, const CsrMsgConvMsgEntry *ce) |
635d2b00 GKH |
224 | { |
225 | CsrMsgConvPrimEntry *pc; | |
226 | pc = CsrMsgConvFind(primType); | |
227 | ||
228 | if (pc) | |
229 | { | |
230 | /* Already registered. Do nothing */ | |
231 | } | |
232 | else | |
233 | { | |
786eeeb3 | 234 | pc = kmalloc(sizeof(*pc), GFP_KERNEL); |
635d2b00 GKH |
235 | pc->primType = primType; |
236 | pc->conv = ce; | |
237 | pc->lookupFunc = NULL; | |
238 | pc->next = converter->profile_converters; | |
239 | converter->profile_converters = pc; | |
240 | } | |
241 | } | |
242 | EXPORT_SYMBOL_GPL(CsrMsgConvInsert); | |
243 | ||
8c87f69a | 244 | CsrMsgConvMsgEntry *CsrMsgConvFindEntry(u16 primType, u16 msgType) |
635d2b00 GKH |
245 | { |
246 | CsrMsgConvPrimEntry *ptr = CsrMsgConvFind(primType); | |
247 | if (ptr) | |
248 | { | |
249 | return (CsrMsgConvMsgEntry *) find_msg_converter(ptr, msgType); | |
250 | } | |
251 | return NULL; | |
252 | } | |
253 | EXPORT_SYMBOL_GPL(CsrMsgConvFindEntry); | |
254 | ||
8c87f69a | 255 | CsrMsgConvMsgEntry *CsrMsgConvFindEntryByMsg(u16 primType, const void *msg) |
635d2b00 GKH |
256 | { |
257 | CsrMsgConvPrimEntry *ptr = CsrMsgConvFind(primType); | |
258 | if (ptr && msg) | |
259 | { | |
8c87f69a | 260 | u16 msgType = *((u16 *) msg); |
635d2b00 GKH |
261 | return (CsrMsgConvMsgEntry *) find_msg_converter(ptr, msgType); |
262 | } | |
263 | return NULL; | |
264 | } | |
265 | ||
8c87f69a | 266 | void CsrMsgConvCustomLookupRegister(u16 primType, CsrMsgCustomLookupFunc *lookupFunc) |
635d2b00 GKH |
267 | { |
268 | CsrMsgConvPrimEntry *ptr = CsrMsgConvFind(primType); | |
269 | if (ptr) | |
270 | { | |
271 | ptr->lookupFunc = lookupFunc; | |
272 | } | |
273 | } | |
274 | EXPORT_SYMBOL_GPL(CsrMsgConvCustomLookupRegister); | |
275 | ||
276 | CsrMsgConvEntry *CsrMsgConvInit(void) | |
277 | { | |
278 | if (!converter) | |
279 | { | |
786eeeb3 | 280 | converter = kmalloc(sizeof(CsrMsgConvEntry), GFP_KERNEL); |
635d2b00 GKH |
281 | |
282 | converter->profile_converters = NULL; | |
283 | converter->free_message = free_message; | |
284 | converter->sizeof_message = sizeof_message; | |
285 | converter->serialize_message = serialize_message; | |
286 | converter->deserialize_data = deserialize_data; | |
287 | } | |
288 | ||
289 | return converter; | |
290 | } | |
291 | EXPORT_SYMBOL_GPL(CsrMsgConvInit); |