1
2
3
4
5
6
7#include "wilc_wlan_if.h"
8#include "wilc_wlan.h"
9#include "wilc_wlan_cfg.h"
10#include "wilc_wfi_netdevice.h"
11
12enum cfg_cmd_type {
13 CFG_BYTE_CMD = 0,
14 CFG_HWORD_CMD = 1,
15 CFG_WORD_CMD = 2,
16 CFG_STR_CMD = 3,
17 CFG_BIN_CMD = 4
18};
19
20static const struct wilc_cfg_byte g_cfg_byte[] = {
21 {WID_STATUS, 0},
22 {WID_RSSI, 0},
23 {WID_LINKSPEED, 0},
24 {WID_NIL, 0}
25};
26
27static const struct wilc_cfg_hword g_cfg_hword[] = {
28 {WID_NIL, 0}
29};
30
31static const struct wilc_cfg_word g_cfg_word[] = {
32 {WID_FAILED_COUNT, 0},
33 {WID_RECEIVED_FRAGMENT_COUNT, 0},
34 {WID_SUCCESS_FRAME_COUNT, 0},
35 {WID_GET_INACTIVE_TIME, 0},
36 {WID_NIL, 0}
37
38};
39
40static const struct wilc_cfg_str g_cfg_str[] = {
41 {WID_FIRMWARE_VERSION, NULL},
42 {WID_MAC_ADDR, NULL},
43 {WID_ASSOC_RES_INFO, NULL},
44 {WID_NIL, NULL}
45};
46
47
48
49
50
51
52
53static int wilc_wlan_cfg_set_byte(u8 *frame, u32 offset, u16 id, u8 val8)
54{
55 u8 *buf;
56
57 if ((offset + 4) >= WILC_MAX_CFG_FRAME_SIZE)
58 return 0;
59
60 buf = &frame[offset];
61
62 buf[0] = (u8)id;
63 buf[1] = (u8)(id >> 8);
64 buf[2] = 1;
65 buf[3] = 0;
66 buf[4] = val8;
67 return 5;
68}
69
70static int wilc_wlan_cfg_set_hword(u8 *frame, u32 offset, u16 id, u16 val16)
71{
72 u8 *buf;
73
74 if ((offset + 5) >= WILC_MAX_CFG_FRAME_SIZE)
75 return 0;
76
77 buf = &frame[offset];
78
79 buf[0] = (u8)id;
80 buf[1] = (u8)(id >> 8);
81 buf[2] = 2;
82 buf[3] = 0;
83 buf[4] = (u8)val16;
84 buf[5] = (u8)(val16 >> 8);
85
86 return 6;
87}
88
89static int wilc_wlan_cfg_set_word(u8 *frame, u32 offset, u16 id, u32 val32)
90{
91 u8 *buf;
92
93 if ((offset + 7) >= WILC_MAX_CFG_FRAME_SIZE)
94 return 0;
95
96 buf = &frame[offset];
97
98 buf[0] = (u8)id;
99 buf[1] = (u8)(id >> 8);
100 buf[2] = 4;
101 buf[3] = 0;
102 buf[4] = (u8)val32;
103 buf[5] = (u8)(val32 >> 8);
104 buf[6] = (u8)(val32 >> 16);
105 buf[7] = (u8)(val32 >> 24);
106
107 return 8;
108}
109
110static int wilc_wlan_cfg_set_str(u8 *frame, u32 offset, u16 id, u8 *str,
111 u32 size)
112{
113 u8 *buf;
114
115 if ((offset + size + 4) >= WILC_MAX_CFG_FRAME_SIZE)
116 return 0;
117
118 buf = &frame[offset];
119
120 buf[0] = (u8)id;
121 buf[1] = (u8)(id >> 8);
122 buf[2] = (u8)size;
123 buf[3] = (u8)(size >> 8);
124
125 if (str && size != 0)
126 memcpy(&buf[4], str, size);
127
128 return (size + 4);
129}
130
131static int wilc_wlan_cfg_set_bin(u8 *frame, u32 offset, u16 id, u8 *b, u32 size)
132{
133 u8 *buf;
134 u32 i;
135 u8 checksum = 0;
136
137 if ((offset + size + 5) >= WILC_MAX_CFG_FRAME_SIZE)
138 return 0;
139
140 buf = &frame[offset];
141 buf[0] = (u8)id;
142 buf[1] = (u8)(id >> 8);
143 buf[2] = (u8)size;
144 buf[3] = (u8)(size >> 8);
145
146 if ((b) && size != 0) {
147 memcpy(&buf[4], b, size);
148 for (i = 0; i < size; i++)
149 checksum += buf[i + 4];
150 }
151
152 buf[size + 4] = checksum;
153
154 return (size + 5);
155}
156
157
158
159
160
161
162
163#define GET_WID_TYPE(wid) (((wid) >> 12) & 0x7)
164static void wilc_wlan_parse_response_frame(struct wilc *wl, u8 *info, int size)
165{
166 u16 wid;
167 u32 len = 0, i = 0;
168
169 while (size > 0) {
170 i = 0;
171 wid = get_unaligned_le16(info);
172
173 switch (GET_WID_TYPE(wid)) {
174 case WID_CHAR:
175 do {
176 if (wl->cfg.b[i].id == WID_NIL)
177 break;
178
179 if (wl->cfg.b[i].id == wid) {
180 wl->cfg.b[i].val = info[4];
181 break;
182 }
183 i++;
184 } while (1);
185 len = 3;
186 break;
187
188 case WID_SHORT:
189 do {
190 struct wilc_cfg_hword *hw = &wl->cfg.hw[i];
191
192 if (hw->id == WID_NIL)
193 break;
194
195 if (hw->id == wid) {
196 hw->val = get_unaligned_le16(&info[4]);
197 break;
198 }
199 i++;
200 } while (1);
201 len = 4;
202 break;
203
204 case WID_INT:
205 do {
206 struct wilc_cfg_word *w = &wl->cfg.w[i];
207
208 if (w->id == WID_NIL)
209 break;
210
211 if (w->id == wid) {
212 w->val = get_unaligned_le32(&info[4]);
213 break;
214 }
215 i++;
216 } while (1);
217 len = 6;
218 break;
219
220 case WID_STR:
221 do {
222 if (wl->cfg.s[i].id == WID_NIL)
223 break;
224
225 if (wl->cfg.s[i].id == wid) {
226 memcpy(wl->cfg.s[i].str, &info[2],
227 (info[2] + 2));
228 break;
229 }
230 i++;
231 } while (1);
232 len = 2 + info[2];
233 break;
234
235 default:
236 break;
237 }
238 size -= (2 + len);
239 info += (2 + len);
240 }
241}
242
243static void wilc_wlan_parse_info_frame(struct wilc *wl, u8 *info)
244{
245 u32 wid, len;
246
247 wid = get_unaligned_le16(info);
248
249 len = info[2];
250
251 if (len == 1 && wid == WID_STATUS) {
252 int i = 0;
253
254 do {
255 if (wl->cfg.b[i].id == WID_NIL)
256 break;
257
258 if (wl->cfg.b[i].id == wid) {
259 wl->cfg.b[i].val = info[3];
260 break;
261 }
262 i++;
263 } while (1);
264 }
265}
266
267
268
269
270
271
272
273int wilc_wlan_cfg_set_wid(u8 *frame, u32 offset, u16 id, u8 *buf, int size)
274{
275 u8 type = (id >> 12) & 0xf;
276 int ret = 0;
277
278 switch (type) {
279 case CFG_BYTE_CMD:
280 if (size >= 1)
281 ret = wilc_wlan_cfg_set_byte(frame, offset, id, *buf);
282 break;
283
284 case CFG_HWORD_CMD:
285 if (size >= 2)
286 ret = wilc_wlan_cfg_set_hword(frame, offset, id,
287 *((u16 *)buf));
288 break;
289
290 case CFG_WORD_CMD:
291 if (size >= 4)
292 ret = wilc_wlan_cfg_set_word(frame, offset, id,
293 *((u32 *)buf));
294 break;
295
296 case CFG_STR_CMD:
297 ret = wilc_wlan_cfg_set_str(frame, offset, id, buf, size);
298 break;
299
300 case CFG_BIN_CMD:
301 ret = wilc_wlan_cfg_set_bin(frame, offset, id, buf, size);
302 break;
303 }
304
305 return ret;
306}
307
308int wilc_wlan_cfg_get_wid(u8 *frame, u32 offset, u16 id)
309{
310 u8 *buf;
311
312 if ((offset + 2) >= WILC_MAX_CFG_FRAME_SIZE)
313 return 0;
314
315 buf = &frame[offset];
316
317 buf[0] = (u8)id;
318 buf[1] = (u8)(id >> 8);
319
320 return 2;
321}
322
323int wilc_wlan_cfg_get_wid_value(struct wilc *wl, u16 wid, u8 *buffer,
324 u32 buffer_size)
325{
326 u32 type = (wid >> 12) & 0xf;
327 int i, ret = 0;
328
329 i = 0;
330 if (type == CFG_BYTE_CMD) {
331 do {
332 if (wl->cfg.b[i].id == WID_NIL)
333 break;
334
335 if (wl->cfg.b[i].id == wid) {
336 memcpy(buffer, &wl->cfg.b[i].val, 1);
337 ret = 1;
338 break;
339 }
340 i++;
341 } while (1);
342 } else if (type == CFG_HWORD_CMD) {
343 do {
344 if (wl->cfg.hw[i].id == WID_NIL)
345 break;
346
347 if (wl->cfg.hw[i].id == wid) {
348 memcpy(buffer, &wl->cfg.hw[i].val, 2);
349 ret = 2;
350 break;
351 }
352 i++;
353 } while (1);
354 } else if (type == CFG_WORD_CMD) {
355 do {
356 if (wl->cfg.w[i].id == WID_NIL)
357 break;
358
359 if (wl->cfg.w[i].id == wid) {
360 memcpy(buffer, &wl->cfg.w[i].val, 4);
361 ret = 4;
362 break;
363 }
364 i++;
365 } while (1);
366 } else if (type == CFG_STR_CMD) {
367 do {
368 u32 id = wl->cfg.s[i].id;
369
370 if (id == WID_NIL)
371 break;
372
373 if (id == wid) {
374 u16 size = get_unaligned_le16(wl->cfg.s[i].str);
375
376 if (buffer_size >= size) {
377 memcpy(buffer, &wl->cfg.s[i].str[2],
378 size);
379 ret = size;
380 }
381 break;
382 }
383 i++;
384 } while (1);
385 }
386 return ret;
387}
388
389void wilc_wlan_cfg_indicate_rx(struct wilc *wilc, u8 *frame, int size,
390 struct wilc_cfg_rsp *rsp)
391{
392 u8 msg_type;
393 u8 msg_id;
394
395 msg_type = frame[0];
396 msg_id = frame[1];
397 frame += 4;
398 size -= 4;
399 rsp->type = 0;
400
401
402
403
404
405
406
407
408 switch (msg_type) {
409 case 'R':
410 wilc_wlan_parse_response_frame(wilc, frame, size);
411 rsp->type = WILC_CFG_RSP;
412 rsp->seq_no = msg_id;
413 break;
414
415 case 'I':
416 wilc_wlan_parse_info_frame(wilc, frame);
417 rsp->type = WILC_CFG_RSP_STATUS;
418 rsp->seq_no = msg_id;
419
420 wilc_gnrl_async_info_received(wilc, frame - 4, size + 4);
421 break;
422
423 case 'N':
424 wilc_network_info_received(wilc, frame - 4, size + 4);
425 break;
426
427 case 'S':
428 wilc_scan_complete_received(wilc, frame - 4, size + 4);
429 break;
430
431 default:
432 rsp->seq_no = msg_id;
433 break;
434 }
435}
436
437int wilc_wlan_cfg_init(struct wilc *wl)
438{
439 struct wilc_cfg_str_vals *str_vals;
440 int i = 0;
441
442 wl->cfg.b = kmemdup(g_cfg_byte, sizeof(g_cfg_byte), GFP_KERNEL);
443 if (!wl->cfg.b)
444 return -ENOMEM;
445
446 wl->cfg.hw = kmemdup(g_cfg_hword, sizeof(g_cfg_hword), GFP_KERNEL);
447 if (!wl->cfg.hw)
448 goto out_b;
449
450 wl->cfg.w = kmemdup(g_cfg_word, sizeof(g_cfg_word), GFP_KERNEL);
451 if (!wl->cfg.w)
452 goto out_hw;
453
454 wl->cfg.s = kmemdup(g_cfg_str, sizeof(g_cfg_str), GFP_KERNEL);
455 if (!wl->cfg.s)
456 goto out_w;
457
458 str_vals = kzalloc(sizeof(*str_vals), GFP_KERNEL);
459 if (!str_vals)
460 goto out_s;
461
462 wl->cfg.str_vals = str_vals;
463
464 wl->cfg.s[i].id = WID_FIRMWARE_VERSION;
465 wl->cfg.s[i].str = str_vals->firmware_version;
466 i++;
467 wl->cfg.s[i].id = WID_MAC_ADDR;
468 wl->cfg.s[i].str = str_vals->mac_address;
469 i++;
470 wl->cfg.s[i].id = WID_ASSOC_RES_INFO;
471 wl->cfg.s[i].str = str_vals->assoc_rsp;
472 i++;
473 wl->cfg.s[i].id = WID_NIL;
474 wl->cfg.s[i].str = NULL;
475 return 0;
476
477out_s:
478 kfree(wl->cfg.s);
479out_w:
480 kfree(wl->cfg.w);
481out_hw:
482 kfree(wl->cfg.hw);
483out_b:
484 kfree(wl->cfg.b);
485 return -ENOMEM;
486}
487
488void wilc_wlan_cfg_deinit(struct wilc *wl)
489{
490 kfree(wl->cfg.b);
491 kfree(wl->cfg.hw);
492 kfree(wl->cfg.w);
493 kfree(wl->cfg.s);
494 kfree(wl->cfg.str_vals);
495}
496