4b495cbef48165e680da405b57e5d5665b3dc20b
[cascardo/linux.git] / drivers / staging / ks7010 / ks7010_config.c
1 #include <linux/kernel.h>
2 #include <linux/mmc/sdio_func.h>
3
4 #include "ks_wlan.h"
5 #include "ks_hostif.h"
6 #include "ks_wlan_ioctl.h"
7
8 static int wep_on_off;
9 #define WEP_OFF         0
10 #define WEP_ON_64BIT    1
11 #define WEP_ON_128BIT   2
12
13 static int wep_type;
14 #define WEP_KEY_CHARACTER 0
15 #define WEP_KEY_HEX       1
16
17 static
18 void analyze_character_wep_key(struct ks_wlan_parameter *param,
19                                int wep_key_index, char *value)
20 {
21         int i;
22         unsigned char wep_key[26], key_length;
23
24         key_length = (wep_on_off == WEP_ON_64BIT) ? 5 : 13;
25         /* 64bit key_length = 5; 128bit key_length = 13; */
26
27         for (i = 0; i < key_length; i++) {
28                 wep_key[i] = value[i];
29         }
30
31         if (wep_key_index < 0 || wep_key_index > 3)
32                 return;
33
34         param->wep_key[wep_key_index].size = key_length;
35         for (i = 0; i < (param->wep_key[wep_key_index].size); i++) {
36                 param->wep_key[wep_key_index].val[i] = wep_key[i];
37         }
38 }
39
40 static
41 void analyze_hex_wep_key(struct ks_wlan_parameter *param, int wep_key_index,
42                          char *value)
43 {
44         unsigned char wep_end[26], i, j, key_length;
45
46         key_length = (wep_on_off == WEP_ON_64BIT) ? 10 : 26;
47         /* 64bit key_length = 10; 128bit key_length = 26; */
48
49         for (i = 0; i < key_length; i++) {
50                 wep_end[i] = value[i];
51                 if (i % 2) {
52                         /* Odd */
53                         for (j = 0x00; j < 0x10; j++) {
54                                 if (j < 0x0a) {
55                                         if (wep_end[i] == j + 0x30)
56                                                 wep_end[i] = j;
57                                 } else {
58                                         if ((wep_end[i] ==
59                                              j + 0x37) | (wep_end[i] ==
60                                                           j + 0x57))
61                                                 wep_end[i] = j;
62                                 }
63                         }
64                 } else {
65                         /* Even */
66                         for (j = 0x00; j < 0x10; j++) {
67                                 if (j < 0x0a) {
68                                         if (wep_end[i] == j + 0x30) {
69                                                 wep_end[i] = j * 16;
70                                         }
71                                 } else {
72                                         if ((wep_end[i] ==
73                                              j + 0x37) | (wep_end[i] ==
74                                                           j + 0x57))
75                                                 wep_end[i] = j * 16;
76                                 }
77                         }
78                 }
79         }
80
81         for (i = 0; i < key_length / 2; i++) {
82                 wep_end[i] = wep_end[i * 2] + wep_end[(i * 2) + 1];
83         }
84
85         if (wep_key_index < 0 || wep_key_index > 3)
86                 return;
87
88         param->wep_key[wep_key_index].size = key_length / 2;
89         for (i = 0; i < (param->wep_key[wep_key_index].size); i++) {
90                 param->wep_key[wep_key_index].val[i] = wep_end[i];
91         }
92
93 }
94
95 static
96 int rate_set_configuration(struct ks_wlan_private *priv, char *value)
97 {
98         int rc = 0;
99
100         priv->reg.tx_rate = TX_RATE_FIXED;
101         priv->reg.rate_set.size = 1;
102
103         switch (*value) {
104         case '1':       /* 1M 11M 12M 18M */
105                 if (*(value + 1) == '8') {
106                         priv->reg.rate_set.body[0] = TX_RATE_18M;
107                 } else if (*(value + 1) == '2') {
108                         priv->reg.rate_set.body[0] = TX_RATE_12M | BASIC_RATE;
109                 } else if (*(value + 1) == '1') {
110                         priv->reg.rate_set.body[0] = TX_RATE_11M | BASIC_RATE;
111                 } else {
112                         priv->reg.rate_set.body[0] = TX_RATE_1M | BASIC_RATE;
113                 }
114                 break;
115         case '2':       /* 2M 24M */
116                 if (*(value + 1) == '4') {
117                         priv->reg.rate_set.body[0] = TX_RATE_24M | BASIC_RATE;
118                 } else {
119                         priv->reg.rate_set.body[0] = TX_RATE_2M | BASIC_RATE;
120                 }
121                 break;
122         case '3':       /* 36M */
123                 priv->reg.rate_set.body[0] = TX_RATE_36M;
124                 break;
125         case '4':       /* 48M */
126                 priv->reg.rate_set.body[0] = TX_RATE_48M;
127                 break;
128         case '5':       /* 5.5M 54M */
129                 if (*(value + 1) == '4') {
130                         priv->reg.rate_set.body[0] = TX_RATE_54M;
131                 } else {
132                         priv->reg.rate_set.body[0] = TX_RATE_5M | BASIC_RATE;
133                 }
134                 break;
135         case '6':       /* 6M */
136                 priv->reg.rate_set.body[0] = TX_RATE_6M | BASIC_RATE;
137                 break;
138         case '9':       /* 9M */
139                 priv->reg.rate_set.body[0] = TX_RATE_9M;
140                 break;
141         case 'K':
142                 priv->reg.rate_set.body[6] = TX_RATE_36M;
143                 priv->reg.rate_set.body[5] = TX_RATE_18M;
144                 priv->reg.rate_set.body[4] = TX_RATE_24M | BASIC_RATE;
145                 priv->reg.rate_set.body[3] = TX_RATE_12M | BASIC_RATE;
146                 priv->reg.rate_set.body[2] = TX_RATE_6M | BASIC_RATE;
147                 priv->reg.rate_set.body[1] = TX_RATE_11M | BASIC_RATE;
148                 priv->reg.rate_set.body[0] = TX_RATE_2M | BASIC_RATE;
149                 priv->reg.tx_rate = TX_RATE_FULL_AUTO;
150                 priv->reg.rate_set.size = 7;
151                 break;
152         default:
153                 priv->reg.rate_set.body[11] = TX_RATE_54M;
154                 priv->reg.rate_set.body[10] = TX_RATE_48M;
155                 priv->reg.rate_set.body[9] = TX_RATE_36M;
156                 priv->reg.rate_set.body[8] = TX_RATE_18M;
157                 priv->reg.rate_set.body[7] = TX_RATE_9M;
158                 priv->reg.rate_set.body[6] = TX_RATE_24M | BASIC_RATE;
159                 priv->reg.rate_set.body[5] = TX_RATE_12M | BASIC_RATE;
160                 priv->reg.rate_set.body[4] = TX_RATE_6M | BASIC_RATE;
161                 priv->reg.rate_set.body[3] = TX_RATE_11M | BASIC_RATE;
162                 priv->reg.rate_set.body[2] = TX_RATE_5M | BASIC_RATE;
163                 priv->reg.rate_set.body[1] = TX_RATE_2M | BASIC_RATE;
164                 priv->reg.rate_set.body[0] = TX_RATE_1M | BASIC_RATE;
165                 priv->reg.tx_rate = TX_RATE_FULL_AUTO;
166                 priv->reg.rate_set.size = 12;
167                 break;
168         }
169         return rc;
170 }
171
172 #include <linux/firmware.h>
173 int ks_wlan_read_config_file(struct ks_wlan_private *priv)
174 {
175         struct {
176                 const int key_len;
177                 const char *key;
178                 const char *val;
179         } cfg_tbl[] = {
180                 {15, "BeaconLostCount", "20"},                  /* 0 */
181                 {7, "Channel", "1"},                            /* 1 */
182                 {17, "FragmentThreshold", "2346"},              /* 2 */
183                 {13, "OperationMode", "Infrastructure"},        /* 3 */
184                 {19, "PowerManagementMode", "ACTIVE"},          /* 4 */
185                 {12, "RTSThreshold", "2347"},                   /* 5 */
186                 {4, "SSID", "default"},                         /* 6 */
187                 {6, "TxRate", "Auto"},                          /* 7 */
188                 {23, "AuthenticationAlgorithm", ""},            /* 8 */
189                 {12, "WepKeyValue1", ""},                       /* 9 */
190                 {12, "WepKeyValue2", ""},                       /* 10 */
191                 {12, "WepKeyValue3", ""},                       /* 11 */
192                 {12, "WepKeyValue4", ""},                       /* 12 */
193                 {8, "WepIndex", "1"},                           /* 13 */
194                 {7, "WepType", "STRING"},                       /* 14 */
195                 {3, "Wep", "OFF"},                              /* 15 */
196                 {13, "PREAMBLE_TYPE", "LONG"},                  /* 16 */
197                 {8, "ScanType", "ACTIVE_SCAN"},                 /* 17 */
198                 {8, "ROM_FILE", ROM_FILE},                      /* 18 */
199                 {7, "PhyType", "BG_MODE"},                      /* 19 */
200                 {7, "CtsMode", "FALSE"},                        /* 20 */
201                 {19, "PhyInformationTimer", "0"},               /* 21 */
202                 {0, "", ""},
203         };
204
205         const struct firmware *fw_entry;
206         struct device *dev = NULL;
207         char cfg_file[] = CFG_FILE;
208         char *cur_p, *end_p;
209         char wk_buff[256], *wk_p;
210
211         /* Initialize Variable */
212         priv->reg.operation_mode = MODE_INFRASTRUCTURE; /* Infrastructure */
213         priv->reg.channel = 10; /* 10 */
214         memset(priv->reg.bssid, 0x0, ETH_ALEN); /* BSSID */
215         priv->reg.ssid.body[0] = '\0';  /* SSID */
216         priv->reg.ssid.size = 0;        /* SSID size */
217         priv->reg.tx_rate = TX_RATE_AUTO;       /* TxRate Fully Auto */
218         priv->reg.preamble = LONG_PREAMBLE;     /* Preamble = LONG */
219         priv->reg.powermgt = POWMGT_ACTIVE_MODE;        /* POWMGT_ACTIVE_MODE */
220         priv->reg.scan_type = ACTIVE_SCAN;      /* Active */
221         priv->reg.beacon_lost_count = 20;       /* Beacon Lost Count */
222         priv->reg.rts = 2347UL; /* RTS Threashold */
223         priv->reg.fragment = 2346UL;    /* Fragmentation Threashold */
224
225         strcpy(&priv->reg.rom_file[0], ROM_FILE);
226
227         priv->skb = NULL;
228
229         priv->reg.authenticate_type = AUTH_TYPE_OPEN_SYSTEM;    /* AuthenticationAlgorithm */
230
231         priv->reg.privacy_invoked = 0x00;       /* WEP */
232         priv->reg.wep_index = 0;
233         memset(&priv->reg.wep_key[0], 0, sizeof(priv->reg.wep_key[0]));
234         memset(&priv->reg.wep_key[1], 0, sizeof(priv->reg.wep_key[0]));
235         memset(&priv->reg.wep_key[2], 0, sizeof(priv->reg.wep_key[0]));
236         memset(&priv->reg.wep_key[3], 0, sizeof(priv->reg.wep_key[0]));
237
238         priv->reg.phy_type = D_11BG_COMPATIBLE_MODE;
239         priv->reg.cts_mode = CTS_MODE_FALSE;
240         priv->reg.phy_info_timer = 0;
241         priv->reg.rate_set.body[11] = TX_RATE_54M;
242         priv->reg.rate_set.body[10] = TX_RATE_48M;
243         priv->reg.rate_set.body[9] = TX_RATE_36M;
244         priv->reg.rate_set.body[8] = TX_RATE_18M;
245         priv->reg.rate_set.body[7] = TX_RATE_9M;
246         priv->reg.rate_set.body[6] = TX_RATE_24M | BASIC_RATE;
247         priv->reg.rate_set.body[5] = TX_RATE_12M | BASIC_RATE;
248         priv->reg.rate_set.body[4] = TX_RATE_6M | BASIC_RATE;
249         priv->reg.rate_set.body[3] = TX_RATE_11M | BASIC_RATE;
250         priv->reg.rate_set.body[2] = TX_RATE_5M | BASIC_RATE;
251         priv->reg.rate_set.body[1] = TX_RATE_2M | BASIC_RATE;
252         priv->reg.rate_set.body[0] = TX_RATE_1M | BASIC_RATE;
253         priv->reg.tx_rate = TX_RATE_FULL_AUTO;
254         priv->reg.rate_set.size = 12;
255
256         dev = &priv->ks_wlan_hw.sdio_card->func->dev;
257         /* If no cfg file, stay with the defaults */
258         if (request_firmware_direct(&fw_entry, cfg_file, dev))
259                 return 0;
260
261         DPRINTK(4, "success request_firmware() file=%s size=%zu\n", cfg_file,
262                 fw_entry->size);
263         cur_p = fw_entry->data;
264         end_p = cur_p + fw_entry->size;
265         *end_p = '\0';
266
267         while (cur_p < end_p) {
268                 int i, j, len;
269
270                 len = end_p - cur_p;
271                 for (i = 0; cfg_tbl[i].key_len != 0; i++) {
272                         if (*cur_p == '#') {
273                                 break;
274                         }
275                         if (len < cfg_tbl[i].key_len) {
276                                 continue;
277                         }
278                         if (!strncmp(cfg_tbl[i].key, cur_p, cfg_tbl[i].key_len)) {
279                                 break;
280                         }
281                 }
282                 if ((*cur_p == '#') || (cfg_tbl[i].key_len == 0)) {
283                         while (*cur_p != '\n') {
284                                 if (cur_p >= end_p) {
285                                         break;
286                                 }
287                                 cur_p++;
288                         }
289                         cur_p++;
290                 } else {
291                         cur_p += cfg_tbl[i].key_len;
292                         if (*cur_p != '=') {
293                                 while (*cur_p != '\n') {
294                                         if (cur_p >= end_p) {
295                                                 break;
296                                         }
297                                         cur_p++;
298                                 }
299                                 continue;
300                         }
301                         cur_p++;
302
303                         for (j = 0, wk_p = cur_p; *wk_p != '\n' && wk_p < end_p;
304                              j++, wk_p++) {
305                                 wk_buff[j] = *wk_p;
306                         }
307                         wk_buff[j] = '\0';
308                         cur_p = wk_p;
309                         DPRINTK(4, "%s=%s\n", cfg_tbl[i].key, wk_buff);
310                         wk_p = wk_buff;
311
312                         switch (i) {
313                         case 0: /* "BeaconLostCount", "10" */
314                                 priv->reg.beacon_lost_count =
315                                     simple_strtol(wk_buff, NULL, 10);
316                                 break;
317                         case 1: /* "Channel", "1" */
318                                 priv->reg.channel =
319                                     simple_strtol(wk_buff, NULL, 10);
320                                 break;
321                         case 2: /* "FragmentThreshold","2346" */
322                                 j = simple_strtol(wk_buff, NULL, 10);
323                                 priv->reg.fragment = (unsigned long)j;
324                                 break;
325                         case 3: /* "OperationMode","Infrastructure" */
326                                 switch (*wk_buff) {
327                                 case 'P':
328                                         priv->reg.operation_mode =
329                                             MODE_PSEUDO_ADHOC;
330                                         break;
331                                 case 'I':
332                                         priv->reg.operation_mode =
333                                             MODE_INFRASTRUCTURE;
334                                         break;
335                                 case '8':
336                                         priv->reg.operation_mode = MODE_ADHOC;
337                                         break;
338                                 default:
339                                         priv->reg.operation_mode =
340                                             MODE_INFRASTRUCTURE;
341                                 }
342                                 break;
343                         case 4: /* "PowerManagementMode","POWER_ACTIVE" */
344                                 if (!strncmp(wk_buff, "SAVE1", 5)) {
345                                         priv->reg.powermgt = POWMGT_SAVE1_MODE;
346                                 } else if (!strncmp(wk_buff, "SAVE2", 5)) {
347                                         priv->reg.powermgt = POWMGT_SAVE2_MODE;
348                                 } else {
349                                         priv->reg.powermgt = POWMGT_ACTIVE_MODE;
350                                 }
351                                 break;
352                         case 5: /* "RTSThreshold","2347" */
353                                 j = simple_strtol(wk_buff, NULL, 10);
354                                 priv->reg.rts = (unsigned long)j;
355                                 break;
356                         case 6: /* "SSID","" */
357                                 if (*wk_p != '"')
358                                         break;
359                                 wk_p++;
360                                 for (j = 0; *wk_p != '"'; j++) {
361                                         if (wk_p == '\0') {
362                                                 break;
363                                         }
364                                         priv->reg.ssid.body[j] = *wk_p++;
365                                 }
366                                 priv->reg.ssid.body[j] = '\0';
367                                 priv->reg.ssid.size = j;
368                                 wk_p++;
369                                 break;
370                         case 7: /* "TxRate","Auto" */
371                                 rate_set_configuration(priv, wk_p);
372                                 break;
373                         case 8: /* "AuthenticationAlgorithm","OPEN_SYSTEM" */
374                                 switch (*wk_p) {
375                                 case 'O':       /* Authenticate System : Open System */
376                                         priv->reg.authenticate_type =
377                                             AUTH_TYPE_OPEN_SYSTEM;
378                                         break;
379                                 case 'S':       /* Authenticate System : Shared Key */
380                                         priv->reg.authenticate_type =
381                                             AUTH_TYPE_SHARED_KEY;
382                                         break;
383                                 }
384                                 break;
385                         case 9: /* "WepKeyValue1","" */
386                         case 10:        /* "WepKeyValue2","" */
387                         case 11:        /* "WepKeyValue3","" */
388                         case 12:        /* "WepKeyValue4","" */
389                                 if (wep_on_off != WEP_OFF) {
390                                         switch (wep_type) {
391                                         case WEP_KEY_CHARACTER:
392                                                 analyze_character_wep_key
393                                                     (&priv->reg, (i - 9), wk_p);
394                                                 break;
395                                         case WEP_KEY_HEX:
396                                                 analyze_hex_wep_key(&priv->reg,
397                                                                     (i - 9),
398                                                                     wk_p);
399                                                 break;
400                                         }
401                                 }
402                                 break;
403                         case 13:        /* "WepIndex","1"->0 (So, Zero Origin) */
404                                 priv->reg.wep_index =
405                                     simple_strtol(wk_buff, NULL, 10) - 1;
406                                 break;
407                         case 14:        /* "WepType","STRING" */
408                                 if (!strncmp(wk_buff, "STRING", 6)) {
409                                         wep_type = WEP_KEY_CHARACTER;
410                                 } else {
411                                         wep_type = WEP_KEY_HEX;
412                                 }
413                                 break;
414                         case 15:        /* "Wep","OFF" */
415                                 if (!strncmp(wk_buff, "OFF", 3)) {
416                                         priv->reg.privacy_invoked = 0x00;
417                                         wep_on_off = WEP_OFF;
418                                 } else {        /* 64bit or 128bit */
419                                         priv->reg.privacy_invoked = 0x01;
420                                         if (*wk_buff == '6') {  /* 64bit */
421                                                 wep_on_off = WEP_ON_64BIT;
422                                         } else {        /* 128bit */
423                                                 wep_on_off = WEP_ON_128BIT;
424                                         }
425                                 }
426                                 break;
427                         case 16:        /* "PREAMBLE_TYPE","LONG" */
428                                 if (!strncmp(wk_buff, "SHORT", 5)) {
429                                         priv->reg.preamble = SHORT_PREAMBLE;
430                                 } else {        /* "LONG" */
431                                         priv->reg.preamble = LONG_PREAMBLE;
432                                 }
433                                 break;
434                         case 17:        /* "ScanType","ACTIVE_SCAN" */
435                                 if (!strncmp(wk_buff, "PASSIVE_SCAN", 12)) {
436                                         priv->reg.scan_type = PASSIVE_SCAN;
437                                 } else {        /* "ACTIVE_SCAN" */
438                                         priv->reg.scan_type = ACTIVE_SCAN;
439                                 }
440                                 break;
441                         case 18:        // "ROM_FILE",ROMFILE
442                                 if (*wk_p != '"')
443                                         break;
444                                 wk_p++;
445                                 for (j = 0; *wk_p != '"'; j++) {
446                                         if (wk_p == '\0') {
447                                                 break;
448                                         }
449                                         priv->reg.rom_file[j] = *wk_p++;
450                                 }
451                                 priv->reg.rom_file[j] = '\0';
452                                 wk_p++;
453                                 break;
454                         case 19:        /*"PhyType", "BG_MODE" */
455                                 if (!strncmp(wk_buff, "B_MODE", 6)) {
456                                         priv->reg.phy_type = D_11B_ONLY_MODE;
457                                 } else if (!strncmp(wk_buff, "G_MODE", 6)) {
458                                         priv->reg.phy_type = D_11G_ONLY_MODE;
459                                 } else {
460                                         priv->reg.phy_type =
461                                             D_11BG_COMPATIBLE_MODE;
462                                 }
463                                 break;
464                         case 20:        /* "CtsMode", "FALSE" */
465                                 if (!strncmp(wk_buff, "TRUE", 4)) {
466                                         priv->reg.cts_mode = CTS_MODE_TRUE;
467                                 } else {
468                                         priv->reg.cts_mode = CTS_MODE_FALSE;
469                                 }
470                                 break;
471                         case 21:        /* "PhyInformationTimer", "0" */
472                                 j = simple_strtol(wk_buff, NULL, 10);
473                                 priv->reg.phy_info_timer = (uint16_t) j;
474                                 break;
475                         default:
476                                 break;
477                         }
478                         if (cur_p >= end_p) {
479                                 break;
480                         }
481                         cur_p++;
482                 }
483
484         }
485         release_firmware(fw_entry);
486
487         DPRINTK(3,
488                 "\n    operation_mode = %d\n    channel = %d\n    ssid = %s\n    tx_rate = %d\n \
489    preamble = %d\n    powermgt = %d\n    scan_type = %d\n    beacon_lost_count = %d\n    rts = %d\n \
490    fragment = %d\n    privacy_invoked = %d\n    wep_type = %d\n    wep_on_off = %d\n    wep_index = %d\n    romfile = %s\n",
491                 priv->reg.operation_mode, priv->reg.channel, &priv->reg.ssid.body[0], priv->reg.tx_rate, priv->reg.preamble, priv->reg.powermgt, priv->reg.scan_type, priv->reg.beacon_lost_count, priv->reg.rts, priv->reg.fragment, priv->reg.privacy_invoked, wep_type, wep_on_off,
492                 priv->reg.wep_index, &priv->reg.rom_file[0]
493             );
494         DPRINTK(3,
495                 "\n    phy_type = %d\n    cts_mode = %d\n    tx_rate = %d\n    phy_info_timer = %d\n",
496                 priv->reg.phy_type, priv->reg.cts_mode, priv->reg.tx_rate,
497                 priv->reg.phy_info_timer);
498
499         return (0);
500 }