aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/libertas/cmd.c7
-rw-r--r--drivers/net/wireless/libertas/cmdresp.c17
-rw-r--r--drivers/net/wireless/libertas/decl.h4
-rw-r--r--drivers/net/wireless/libertas/defs.h11
-rw-r--r--drivers/net/wireless/libertas/dev.h16
-rw-r--r--drivers/net/wireless/libertas/fw.c9
-rw-r--r--drivers/net/wireless/libertas/hostcmd.h8
-rw-r--r--drivers/net/wireless/libertas/join.c203
-rw-r--r--drivers/net/wireless/libertas/join.h2
-rw-r--r--drivers/net/wireless/libertas/main.c57
-rw-r--r--drivers/net/wireless/libertas/rx.c9
-rw-r--r--drivers/net/wireless/libertas/scan.c54
-rw-r--r--drivers/net/wireless/libertas/scan.h4
-rw-r--r--drivers/net/wireless/libertas/wext.c163
14 files changed, 241 insertions, 323 deletions
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index c96ced963d69..c3fc074b6e3a 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -607,17 +607,14 @@ static int wlan_cmd_802_11_data_rate(wlan_private * priv,
607 607
608 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_data_rate) + 608 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_data_rate) +
609 S_DS_GEN); 609 S_DS_GEN);
610
611 cmd->command = cpu_to_le16(CMD_802_11_DATA_RATE); 610 cmd->command = cpu_to_le16(CMD_802_11_DATA_RATE);
612
613 memset(pdatarate, 0, sizeof(struct cmd_ds_802_11_data_rate)); 611 memset(pdatarate, 0, sizeof(struct cmd_ds_802_11_data_rate));
614
615 pdatarate->action = cpu_to_le16(cmd_action); 612 pdatarate->action = cpu_to_le16(cmd_action);
616 613
617 if (cmd_action == CMD_ACT_SET_TX_FIX_RATE) { 614 if (cmd_action == CMD_ACT_SET_TX_FIX_RATE) {
618 pdatarate->datarate[0] = libertas_data_rate_to_index(adapter->datarate); 615 pdatarate->rates[0] = libertas_data_rate_to_fw_index(adapter->cur_rate);
619 lbs_deb_cmd("Setting FW for fixed rate 0x%02X\n", 616 lbs_deb_cmd("Setting FW for fixed rate 0x%02X\n",
620 adapter->datarate); 617 adapter->cur_rate);
621 } else if (cmd_action == CMD_ACT_SET_TX_AUTO) { 618 } else if (cmd_action == CMD_ACT_SET_TX_AUTO) {
622 lbs_deb_cmd("Setting FW for AUTO rate\n"); 619 lbs_deb_cmd("Setting FW for AUTO rate\n");
623 } 620 }
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index d90279269e7b..577c434089b0 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -430,21 +430,18 @@ static int wlan_ret_802_11_data_rate(wlan_private * priv,
430{ 430{
431 struct cmd_ds_802_11_data_rate *pdatarate = &resp->params.drate; 431 struct cmd_ds_802_11_data_rate *pdatarate = &resp->params.drate;
432 wlan_adapter *adapter = priv->adapter; 432 wlan_adapter *adapter = priv->adapter;
433 u8 dot11datarate;
434 433
435 lbs_deb_enter(LBS_DEB_CMD); 434 lbs_deb_enter(LBS_DEB_CMD);
436 435
437 lbs_dbg_hex("DATA_RATE_RESP: data_rate- ", 436 lbs_dbg_hex("DATA_RATE_RESP: data_rate- ", (u8 *) pdatarate,
438 (u8 *) pdatarate, sizeof(struct cmd_ds_802_11_data_rate)); 437 sizeof(struct cmd_ds_802_11_data_rate));
439 438
440 dot11datarate = pdatarate->datarate[0]; 439 /* FIXME: get actual rates FW can do if this command actually returns
441 if (pdatarate->action == cpu_to_le16(CMD_ACT_GET_TX_RATE)) { 440 * all data rates supported.
442 memcpy(adapter->libertas_supported_rates, pdatarate->datarate, 441 */
443 sizeof(adapter->libertas_supported_rates)); 442 adapter->cur_rate = libertas_fw_index_to_data_rate(pdatarate->rates[0]);
444 }
445 adapter->datarate = libertas_index_to_data_rate(dot11datarate);
446 443
447 lbs_deb_enter(LBS_DEB_CMD); 444 lbs_deb_leave(LBS_DEB_CMD);
448 return 0; 445 return 0;
449} 446}
450 447
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index 846e79a77f67..129b021d35fd 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -44,8 +44,8 @@ int libertas_execute_next_command(wlan_private * priv);
44int libertas_process_event(wlan_private * priv); 44int libertas_process_event(wlan_private * priv);
45void libertas_interrupt(struct net_device *); 45void libertas_interrupt(struct net_device *);
46int libertas_set_radio_control(wlan_private * priv); 46int libertas_set_radio_control(wlan_private * priv);
47u32 libertas_index_to_data_rate(u8 index); 47u32 libertas_fw_index_to_data_rate(u8 index);
48u8 libertas_data_rate_to_index(u32 rate); 48u8 libertas_data_rate_to_fw_index(u32 rate);
49void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen); 49void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen);
50 50
51void libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb); 51void libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb);
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
index 862292913c2c..a1c6dae1ba46 100644
--- a/drivers/net/wireless/libertas/defs.h
+++ b/drivers/net/wireless/libertas/defs.h
@@ -246,10 +246,7 @@ static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len)
246 ((((int)(AVG) * (N -1)) + ((u16)(SNRNF) * \ 246 ((((int)(AVG) * (N -1)) + ((u16)(SNRNF) * \
247 AVG_SCALE)) / N)) 247 AVG_SCALE)) / N))
248 248
249#define B_SUPPORTED_RATES 8 249#define MAX_RATES 14
250#define G_SUPPORTED_RATES 14
251
252#define WLAN_SUPPORTED_RATES 14
253 250
254#define MAX_LEDS 8 251#define MAX_LEDS 8
255 252
@@ -263,11 +260,7 @@ typedef struct _wlan_adapter wlan_adapter;
263extern const char libertas_driver_version[]; 260extern const char libertas_driver_version[];
264extern u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE]; 261extern u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE];
265 262
266extern u8 libertas_supported_rates[G_SUPPORTED_RATES]; 263extern u8 libertas_bg_rates[MAX_RATES];
267
268extern u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES];
269
270extern u8 libertas_adhoc_rates_b[4];
271 264
272/** ENUM definition*/ 265/** ENUM definition*/
273/** SNRNF_TYPE */ 266/** SNRNF_TYPE */
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index c6fb703f665b..6acb8fb8733e 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -72,10 +72,8 @@ struct current_bss_params {
72 u8 band; 72 u8 band;
73 /** channel */ 73 /** channel */
74 u8 channel; 74 u8 channel;
75 /** number of rates supported */ 75 /** zero-terminated array of supported data rates */
76 int numofrates; 76 u8 rates[MAX_RATES + 1];
77 /** supported rates*/
78 u8 datarates[WLAN_SUPPORTED_RATES];
79}; 77};
80 78
81/** sleep_params */ 79/** sleep_params */
@@ -296,9 +294,6 @@ struct _wlan_adapter {
296 u32 fragthsd; 294 u32 fragthsd;
297 u32 rtsthsd; 295 u32 rtsthsd;
298 296
299 u32 datarate;
300 u8 is_datarate_auto;
301
302 u16 listeninterval; 297 u16 listeninterval;
303 u16 prescan; 298 u16 prescan;
304 u8 txretrycount; 299 u8 txretrycount;
@@ -364,10 +359,9 @@ struct _wlan_adapter {
364 u8 radioon; 359 u8 radioon;
365 u32 preamble; 360 u32 preamble;
366 361
367 /** Multi bands Parameter*/ 362 /** data rate stuff */
368 u8 libertas_supported_rates[G_SUPPORTED_RATES]; 363 u8 cur_rate;
369 364 u8 auto_rate;
370 /** Blue Tooth Co-existence Arbitration */
371 365
372 /** sleep_params */ 366 /** sleep_params */
373 struct sleep_params sp; 367 struct sleep_params sp;
diff --git a/drivers/net/wireless/libertas/fw.c b/drivers/net/wireless/libertas/fw.c
index d214692eb209..6c259878da96 100644
--- a/drivers/net/wireless/libertas/fw.c
+++ b/drivers/net/wireless/libertas/fw.c
@@ -214,7 +214,10 @@ static void wlan_init_adapter(wlan_private * priv)
214 adapter->txantenna = RF_ANTENNA_2; 214 adapter->txantenna = RF_ANTENNA_2;
215 adapter->rxantenna = RF_ANTENNA_AUTO; 215 adapter->rxantenna = RF_ANTENNA_AUTO;
216 216
217 adapter->is_datarate_auto = 1; 217 adapter->auto_rate = 1;
218 adapter->cur_rate = 0;
219 adapter->adhoc_grate_enabled = 0;
220
218 adapter->beaconperiod = MRVDRV_BEACON_INTERVAL; 221 adapter->beaconperiod = MRVDRV_BEACON_INTERVAL;
219 222
220 // set default capabilities 223 // set default capabilities
@@ -229,10 +232,6 @@ static void wlan_init_adapter(wlan_private * priv)
229 adapter->needtowakeup = 0; 232 adapter->needtowakeup = 0;
230 adapter->locallisteninterval = 0; /* default value in firmware will be used */ 233 adapter->locallisteninterval = 0; /* default value in firmware will be used */
231 234
232 adapter->datarate = 0; // Initially indicate the rate as auto
233
234 adapter->adhoc_grate_enabled = 0;
235
236 adapter->intcounter = 0; 235 adapter->intcounter = 0;
237 236
238 adapter->currenttxskb = NULL; 237 adapter->currenttxskb = NULL;
diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h
index 76c5fdeb256a..44cf39c8d1b8 100644
--- a/drivers/net/wireless/libertas/hostcmd.h
+++ b/drivers/net/wireless/libertas/hostcmd.h
@@ -428,8 +428,8 @@ struct PS_CMD_ConfirmSleep {
428 428
429struct cmd_ds_802_11_data_rate { 429struct cmd_ds_802_11_data_rate {
430 __le16 action; 430 __le16 action;
431 __le16 reserverd; 431 __le16 reserved;
432 u8 datarate[G_SUPPORTED_RATES]; 432 u8 rates[MAX_RATES];
433}; 433};
434 434
435struct cmd_ds_802_11_rate_adapt_rateset { 435struct cmd_ds_802_11_rate_adapt_rateset {
@@ -447,7 +447,7 @@ struct cmd_ds_802_11_ad_hoc_start {
447 union ieeetypes_phyparamset phyparamset; 447 union ieeetypes_phyparamset phyparamset;
448 __le16 probedelay; 448 __le16 probedelay;
449 __le16 capability; 449 __le16 capability;
450 u8 datarate[G_SUPPORTED_RATES]; 450 u8 rates[MAX_RATES];
451 u8 tlv_memory_size_pad[100]; 451 u8 tlv_memory_size_pad[100];
452} __attribute__ ((packed)); 452} __attribute__ ((packed));
453 453
@@ -462,7 +462,7 @@ struct adhoc_bssdesc {
462 union ieeetypes_phyparamset phyparamset; 462 union ieeetypes_phyparamset phyparamset;
463 union IEEEtypes_ssparamset ssparamset; 463 union IEEEtypes_ssparamset ssparamset;
464 __le16 capability; 464 __le16 capability;
465 u8 datarates[G_SUPPORTED_RATES]; 465 u8 rates[MAX_RATES];
466 466
467 /* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the 467 /* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the
468 * Adhoc join command and will cause a binary layout mismatch with 468 * Adhoc join command and will cause a binary layout mismatch with
diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c
index 381739d6ed96..78e398d6f5f3 100644
--- a/drivers/net/wireless/libertas/join.c
+++ b/drivers/net/wireless/libertas/join.c
@@ -17,8 +17,12 @@
17#include "dev.h" 17#include "dev.h"
18#include "assoc.h" 18#include "assoc.h"
19 19
20/* Supported rates for ad-hoc B mode */
21u8 adhoc_rates_b[5] = { 0x02, 0x04, 0x0b, 0x16, 0x00 };
22
23
20/** 24/**
21 * @brief This function finds out the common rates between rate1 and rate2. 25 * @brief This function finds common rates between rate1 and card rates.
22 * 26 *
23 * It will fill common rates in rate1 as output if found. 27 * It will fill common rates in rate1 as output if found.
24 * 28 *
@@ -27,61 +31,87 @@
27 * 31 *
28 * @param adapter A pointer to wlan_adapter structure 32 * @param adapter A pointer to wlan_adapter structure
29 * @param rate1 the buffer which keeps input and output 33 * @param rate1 the buffer which keeps input and output
30 * @param rate1_size the size of rate1 buffer 34 * @param rate1_size the size of rate1 buffer; new size of buffer on return
31 * @param rate2 the buffer which keeps rate2
32 * @param rate2_size the size of rate2 buffer.
33 * 35 *
34 * @return 0 or -1 36 * @return 0 or -1
35 */ 37 */
36static int get_common_rates(wlan_adapter * adapter, u8 * rate1, 38static int get_common_rates(wlan_adapter * adapter, u8 * rates, u16 *rates_size)
37 int rate1_size, u8 * rate2, int rate2_size)
38{ 39{
39 u8 *ptr = rate1; 40 u8 *card_rates = libertas_bg_rates;
40 int ret = 0; 41 size_t num_card_rates = sizeof(libertas_bg_rates);
42 int ret = 0, i, j;
41 u8 tmp[30]; 43 u8 tmp[30];
42 int i; 44 size_t tmp_size = 0;
43 45
44 memset(&tmp, 0, sizeof(tmp)); 46 /* For each rate in card_rates that exists in rate1, copy to tmp */
45 memcpy(&tmp, rate1, min_t(size_t, rate1_size, sizeof(tmp))); 47 for (i = 0; card_rates[i] && (i < num_card_rates); i++) {
46 memset(rate1, 0, rate1_size); 48 for (j = 0; rates[j] && (j < *rates_size); j++) {
47 49 if (rates[j] == card_rates[i])
48 /* Mask the top bit of the original values */ 50 tmp[tmp_size++] = card_rates[i];
49 for (i = 0; tmp[i] && i < sizeof(tmp); i++)
50 tmp[i] &= 0x7F;
51
52 for (i = 0; rate2[i] && i < rate2_size; i++) {
53 /* Check for Card Rate in tmp, excluding the top bit */
54 if (strchr(tmp, rate2[i] & 0x7F)) {
55 /* values match, so copy the Card Rate to rate1 */
56 *rate1++ = rate2[i];
57 } 51 }
58 } 52 }
59 53
60 lbs_dbg_hex("rate1 (AP) rates:", tmp, sizeof(tmp)); 54 lbs_dbg_hex("rate1 (AP) rates:", rates, *rates_size);
61 lbs_dbg_hex("rate2 (Card) rates:", rate2, rate2_size); 55 lbs_dbg_hex("rate2 (Card) rates:", card_rates, num_card_rates);
62 lbs_dbg_hex("Common rates:", ptr, rate1_size); 56 lbs_dbg_hex("Common rates:", tmp, tmp_size);
63 lbs_deb_join("Tx datarate is set to 0x%X\n", adapter->datarate); 57 lbs_deb_join("Tx datarate is currently 0x%X\n", adapter->cur_rate);
64 58
65 if (!adapter->is_datarate_auto) { 59 if (!adapter->auto_rate) {
66 while (*ptr) { 60 for (i = 0; i < tmp_size; i++) {
67 if ((*ptr & 0x7f) == adapter->datarate) { 61 if (tmp[i] == adapter->cur_rate)
68 ret = 0;
69 goto done; 62 goto done;
70 }
71 ptr++;
72 } 63 }
73 lbs_pr_alert( "Previously set fixed data rate %#x isn't " 64 lbs_pr_alert("Previously set fixed data rate %#x isn't "
74 "compatible with the network.\n", adapter->datarate); 65 "compatible with the network.\n", adapter->cur_rate);
75
76 ret = -1; 66 ret = -1;
77 goto done; 67 goto done;
78 } 68 }
79
80 ret = 0; 69 ret = 0;
70
81done: 71done:
72 memset(rates, 0, *rates_size);
73 *rates_size = min_t(int, tmp_size, *rates_size);
74 memcpy(rates, tmp, *rates_size);
82 return ret; 75 return ret;
83} 76}
84 77
78
79/**
80 * @brief Sets the MSB on basic rates as the firmware requires
81 *
82 * Scan through an array and set the MSB for basic data rates.
83 *
84 * @param rates buffer of data rates
85 * @param len size of buffer
86 */
87static void libertas_set_basic_rate_flags(u8 * rates, size_t len)
88{
89 int i;
90
91 for (i = 0; i < len; i++) {
92 if (rates[i] == 0x02 || rates[i] == 0x04 ||
93 rates[i] == 0x0b || rates[i] == 0x16)
94 rates[i] |= 0x80;
95 }
96}
97
98/**
99 * @brief Unsets the MSB on basic rates
100 *
101 * Scan through an array and unset the MSB for basic data rates.
102 *
103 * @param rates buffer of data rates
104 * @param len size of buffer
105 */
106void libertas_unset_basic_rate_flags(u8 * rates, size_t len)
107{
108 int i;
109
110 for (i = 0; i < len; i++)
111 rates[i] &= 0x7f;
112}
113
114
85int libertas_send_deauth(wlan_private * priv) 115int libertas_send_deauth(wlan_private * priv)
86{ 116{
87 wlan_adapter *adapter = priv->adapter; 117 wlan_adapter *adapter = priv->adapter;
@@ -330,9 +360,7 @@ int libertas_cmd_80211_associate(wlan_private * priv,
330 int ret = 0; 360 int ret = 0;
331 struct assoc_request * assoc_req = pdata_buf; 361 struct assoc_request * assoc_req = pdata_buf;
332 struct bss_descriptor * bss = &assoc_req->bss; 362 struct bss_descriptor * bss = &assoc_req->bss;
333 u8 *card_rates;
334 u8 *pos; 363 u8 *pos;
335 int card_rates_size;
336 u16 tmpcap, tmplen; 364 u16 tmpcap, tmplen;
337 struct mrvlietypes_ssidparamset *ssid; 365 struct mrvlietypes_ssidparamset *ssid;
338 struct mrvlietypes_phyparamset *phy; 366 struct mrvlietypes_phyparamset *phy;
@@ -386,23 +414,24 @@ int libertas_cmd_80211_associate(wlan_private * priv,
386 414
387 rates = (struct mrvlietypes_ratesparamset *) pos; 415 rates = (struct mrvlietypes_ratesparamset *) pos;
388 rates->header.type = cpu_to_le16(TLV_TYPE_RATES); 416 rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
389 417 memcpy(&rates->rates, &bss->rates, MAX_RATES);
390 memcpy(&rates->rates, &bss->libertas_supported_rates, WLAN_SUPPORTED_RATES); 418 tmplen = MAX_RATES;
391 419 if (get_common_rates(adapter, rates->rates, &tmplen)) {
392 card_rates = libertas_supported_rates;
393 card_rates_size = sizeof(libertas_supported_rates);
394
395 if (get_common_rates(adapter, rates->rates, WLAN_SUPPORTED_RATES,
396 card_rates, card_rates_size)) {
397 ret = -1; 420 ret = -1;
398 goto done; 421 goto done;
399 } 422 }
400
401 tmplen = min_t(size_t, strlen(rates->rates), WLAN_SUPPORTED_RATES);
402 adapter->curbssparams.numofrates = tmplen;
403
404 pos += sizeof(rates->header) + tmplen; 423 pos += sizeof(rates->header) + tmplen;
405 rates->header.len = cpu_to_le16(tmplen); 424 rates->header.len = cpu_to_le16(tmplen);
425 lbs_deb_join("ASSOC_CMD: num rates = %u\n", tmplen);
426
427 /* Copy the infra. association rates into Current BSS state structure */
428 memset(&adapter->curbssparams.rates, 0, sizeof(adapter->curbssparams.rates));
429 memcpy(&adapter->curbssparams.rates, &rates->rates, tmplen);
430
431 /* Set MSB on basic rates as the firmware requires, but _after_
432 * copying to current bss rates.
433 */
434 libertas_set_basic_rate_flags(rates->rates, tmplen);
406 435
407 if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) { 436 if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
408 rsn = (struct mrvlietypes_rsnparamset *) pos; 437 rsn = (struct mrvlietypes_rsnparamset *) pos;
@@ -419,14 +448,6 @@ int libertas_cmd_80211_associate(wlan_private * priv,
419 /* update curbssparams */ 448 /* update curbssparams */
420 adapter->curbssparams.channel = bss->phyparamset.dsparamset.currentchan; 449 adapter->curbssparams.channel = bss->phyparamset.dsparamset.currentchan;
421 450
422 /* Copy the infra. association rates into Current BSS state structure */
423 memcpy(&adapter->curbssparams.datarates, &rates->rates,
424 min_t(size_t, sizeof(adapter->curbssparams.datarates),
425 cpu_to_le16(rates->header.len)));
426
427 lbs_deb_join("ASSOC_CMD: rates->header.len = %d\n",
428 cpu_to_le16(rates->header.len));
429
430 if (libertas_parse_dnld_countryinfo_11d(priv, bss)) { 451 if (libertas_parse_dnld_countryinfo_11d(priv, bss)) {
431 ret = -1; 452 ret = -1;
432 goto done; 453 goto done;
@@ -454,9 +475,9 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
454 struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads; 475 struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads;
455 int ret = 0; 476 int ret = 0;
456 int cmdappendsize = 0; 477 int cmdappendsize = 0;
457 int i;
458 struct assoc_request * assoc_req = pdata_buf; 478 struct assoc_request * assoc_req = pdata_buf;
459 u16 tmpcap = 0; 479 u16 tmpcap = 0;
480 size_t ratesize = 0;
460 481
461 lbs_deb_enter(LBS_DEB_JOIN); 482 lbs_deb_enter(LBS_DEB_JOIN);
462 483
@@ -526,28 +547,26 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
526 /* probedelay */ 547 /* probedelay */
527 adhs->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); 548 adhs->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
528 549
529 memset(adhs->datarate, 0, sizeof(adhs->datarate)); 550 memset(adhs->rates, 0, sizeof(adhs->rates));
530
531 if (adapter->adhoc_grate_enabled) { 551 if (adapter->adhoc_grate_enabled) {
532 memcpy(adhs->datarate, libertas_adhoc_rates_g, 552 ratesize = min(sizeof(adhs->rates), sizeof(libertas_bg_rates));
533 min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_g))); 553 memcpy(adhs->rates, libertas_bg_rates, ratesize);
534 } else { 554 } else {
535 memcpy(adhs->datarate, libertas_adhoc_rates_b, 555 ratesize = min(sizeof(adhs->rates), sizeof(adhoc_rates_b));
536 min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_b))); 556 memcpy(adhs->rates, adhoc_rates_b, ratesize);
537 } 557 }
538 558
539 /* Find the last non zero */
540 for (i = 0; i < sizeof(adhs->datarate) && adhs->datarate[i]; i++) ;
541
542 adapter->curbssparams.numofrates = i;
543
544 /* Copy the ad-hoc creating rates into Current BSS state structure */ 559 /* Copy the ad-hoc creating rates into Current BSS state structure */
545 memcpy(&adapter->curbssparams.datarates, 560 memset(&adapter->curbssparams.rates, 0, sizeof(adapter->curbssparams.rates));
546 &adhs->datarate, adapter->curbssparams.numofrates); 561 memcpy(&adapter->curbssparams.rates, &adhs->rates, ratesize);
562
563 /* Set MSB on basic rates as the firmware requires, but _after_
564 * copying to current bss rates.
565 */
566 libertas_set_basic_rate_flags(adhs->rates, ratesize);
547 567
548 lbs_deb_join("ADHOC_S_CMD: rates=%02x %02x %02x %02x \n", 568 lbs_deb_join("ADHOC_S_CMD: rates=%02x %02x %02x %02x \n",
549 adhs->datarate[0], adhs->datarate[1], 569 adhs->rates[0], adhs->rates[1], adhs->rates[2], adhs->rates[3]);
550 adhs->datarate[2], adhs->datarate[3]);
551 570
552 lbs_deb_join("ADHOC_S_CMD: AD HOC Start command is ready\n"); 571 lbs_deb_join("ADHOC_S_CMD: AD HOC Start command is ready\n");
553 572
@@ -584,9 +603,7 @@ int libertas_cmd_80211_ad_hoc_join(wlan_private * priv,
584 struct bss_descriptor *bss = &assoc_req->bss; 603 struct bss_descriptor *bss = &assoc_req->bss;
585 int cmdappendsize = 0; 604 int cmdappendsize = 0;
586 int ret = 0; 605 int ret = 0;
587 u8 *card_rates; 606 u16 ratesize = 0;
588 int card_rates_size;
589 int i;
590 607
591 lbs_deb_enter(LBS_DEB_JOIN); 608 lbs_deb_enter(LBS_DEB_JOIN);
592 609
@@ -619,36 +636,26 @@ int libertas_cmd_80211_ad_hoc_join(wlan_private * priv,
619 /* probedelay */ 636 /* probedelay */
620 join_cmd->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); 637 join_cmd->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
621 638
622 /* Copy Data rates from the rates recorded in scan response */
623 memset(join_cmd->bss.datarates, 0, sizeof(join_cmd->bss.datarates));
624 memcpy(join_cmd->bss.datarates, bss->datarates,
625 min(sizeof(join_cmd->bss.datarates), sizeof(bss->datarates)));
626
627 card_rates = libertas_supported_rates;
628 card_rates_size = sizeof(libertas_supported_rates);
629
630 adapter->curbssparams.channel = bss->channel; 639 adapter->curbssparams.channel = bss->channel;
631 640
632 if (get_common_rates(adapter, join_cmd->bss.datarates, 641 /* Copy Data rates from the rates recorded in scan response */
633 sizeof(join_cmd->bss.datarates), 642 memset(join_cmd->bss.rates, 0, sizeof(join_cmd->bss.rates));
634 card_rates, card_rates_size)) { 643 ratesize = min_t(u16, sizeof(join_cmd->bss.rates), MAX_RATES);
644 memcpy(join_cmd->bss.rates, bss->rates, ratesize);
645 if (get_common_rates(adapter, join_cmd->bss.rates, &ratesize)) {
635 lbs_deb_join("ADHOC_J_CMD: get_common_rates returns error.\n"); 646 lbs_deb_join("ADHOC_J_CMD: get_common_rates returns error.\n");
636 ret = -1; 647 ret = -1;
637 goto done; 648 goto done;
638 } 649 }
639 650
640 /* Find the last non zero */ 651 /* Copy the ad-hoc creating rates into Current BSS state structure */
641 for (i = 0; i < sizeof(join_cmd->bss.datarates) 652 memset(&adapter->curbssparams.rates, 0, sizeof(adapter->curbssparams.rates));
642 && join_cmd->bss.datarates[i]; i++) ; 653 memcpy(&adapter->curbssparams.rates, join_cmd->bss.rates, ratesize);
643
644 adapter->curbssparams.numofrates = i;
645 654
646 /* 655 /* Set MSB on basic rates as the firmware requires, but _after_
647 * Copy the adhoc joining rates to Current BSS State structure 656 * copying to current bss rates.
648 */ 657 */
649 memcpy(adapter->curbssparams.datarates, 658 libertas_set_basic_rate_flags(join_cmd->bss.rates, ratesize);
650 join_cmd->bss.datarates,
651 adapter->curbssparams.numofrates);
652 659
653 join_cmd->bss.ssparamset.ibssparamset.atimwindow = 660 join_cmd->bss.ssparamset.ibssparamset.atimwindow =
654 cpu_to_le16(bss->atimwindow); 661 cpu_to_le16(bss->atimwindow);
diff --git a/drivers/net/wireless/libertas/join.h b/drivers/net/wireless/libertas/join.h
index d522630ff8cf..8ea5ae30f4ab 100644
--- a/drivers/net/wireless/libertas/join.h
+++ b/drivers/net/wireless/libertas/join.h
@@ -53,4 +53,6 @@ extern int libertas_do_adhocstop_ioctl(wlan_private * priv);
53 53
54int wlan_associate(wlan_private * priv, struct assoc_request * assoc_req); 54int wlan_associate(wlan_private * priv, struct assoc_request * assoc_req);
55 55
56void libertas_unset_basic_rate_flags(u8 * rates, size_t len);
57
56#endif 58#endif
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 26948595d952..03217f5537ad 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -150,29 +150,60 @@ static struct region_cfp_table region_cfp_table[] = {
150}; 150};
151 151
152/** 152/**
153 * the rates supported 153 * the table to keep region code
154 */ 154 */
155u8 libertas_supported_rates[G_SUPPORTED_RATES] = 155u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
156 { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c, 156 { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 };
1570 };
158 157
159/** 158/**
160 * the rates supported for ad-hoc G mode 159 * 802.11b/g supported bitrates (in 500Kb/s units)
161 */ 160 */
162u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES] = 161u8 libertas_bg_rates[MAX_RATES] =
163 { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c, 162 { 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
1640 }; 1630x00, 0x00 };
165 164
166/** 165/**
167 * the rates supported for ad-hoc B mode 166 * FW rate table. FW refers to rates by their index in this table, not by the
167 * rate value itself. Values of 0x00 are
168 * reserved positions.
168 */ 169 */
169u8 libertas_adhoc_rates_b[4] = { 0x82, 0x84, 0x8b, 0x96 }; 170static u8 fw_data_rates[MAX_RATES] =
171 { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12,
172 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00
173};
170 174
171/** 175/**
172 * the table to keep region code 176 * @brief use index to get the data rate
177 *
178 * @param idx The index of data rate
179 * @return data rate or 0
173 */ 180 */
174u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE] = 181u32 libertas_fw_index_to_data_rate(u8 idx)
175 { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 }; 182{
183 if (idx >= sizeof(fw_data_rates))
184 idx = 0;
185 return fw_data_rates[idx];
186}
187
188/**
189 * @brief use rate to get the index
190 *
191 * @param rate data rate
192 * @return index or 0
193 */
194u8 libertas_data_rate_to_fw_index(u32 rate)
195{
196 u8 i;
197
198 if (!rate)
199 return 0;
200
201 for (i = 0; i < sizeof(fw_data_rates); i++) {
202 if (rate == fw_data_rates[i])
203 return i;
204 }
205 return 0;
206}
176 207
177/** 208/**
178 * Attributes exported through sysfs 209 * Attributes exported through sysfs
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
index 769c86fb9509..e78636d6651a 100644
--- a/drivers/net/wireless/libertas/rx.c
+++ b/drivers/net/wireless/libertas/rx.c
@@ -260,8 +260,8 @@ int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb)
260 /* Take the data rate from the rxpd structure 260 /* Take the data rate from the rxpd structure
261 * only if the rate is auto 261 * only if the rate is auto
262 */ 262 */
263 if (adapter->is_datarate_auto) 263 if (adapter->auto_rate)
264 adapter->datarate = libertas_index_to_data_rate(p_rx_pd->rx_rate); 264 adapter->cur_rate = libertas_fw_index_to_data_rate(p_rx_pd->rx_rate);
265 265
266 wlan_compute_rssi(priv, p_rx_pd); 266 wlan_compute_rssi(priv, p_rx_pd);
267 267
@@ -424,9 +424,8 @@ static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb)
424 /* Take the data rate from the rxpd structure 424 /* Take the data rate from the rxpd structure
425 * only if the rate is auto 425 * only if the rate is auto
426 */ 426 */
427 if (adapter->is_datarate_auto) { 427 if (adapter->auto_rate)
428 adapter->datarate = libertas_index_to_data_rate(prxpd->rx_rate); 428 adapter->cur_rate = libertas_fw_index_to_data_rate(prxpd->rx_rate);
429 }
430 429
431 wlan_compute_rssi(priv, prxpd); 430 wlan_compute_rssi(priv, prxpd);
432 431
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
index 2cac47fc4cd9..790e9888ea2b 100644
--- a/drivers/net/wireless/libertas/scan.c
+++ b/drivers/net/wireless/libertas/scan.c
@@ -17,6 +17,7 @@
17#include "decl.h" 17#include "decl.h"
18#include "dev.h" 18#include "dev.h"
19#include "scan.h" 19#include "scan.h"
20#include "join.h"
20 21
21//! Approximate amount of data needed to pass a scan result back to iwlist 22//! Approximate amount of data needed to pass a scan result back to iwlist
22#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \ 23#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \
@@ -904,22 +905,14 @@ static int libertas_process_bss(struct bss_descriptor * bss,
904 struct ieeetypes_dsparamset *pDS; 905 struct ieeetypes_dsparamset *pDS;
905 struct ieeetypes_cfparamset *pCF; 906 struct ieeetypes_cfparamset *pCF;
906 struct ieeetypes_ibssparamset *pibss; 907 struct ieeetypes_ibssparamset *pibss;
907 u8 *pos, *end;
908 u8 *pRate;
909 u8 bytestocopy;
910 u8 ratesize;
911 u16 beaconsize;
912 u8 founddatarateie;
913 int ret;
914
915 struct ieeetypes_countryinfoset *pcountryinfo; 908 struct ieeetypes_countryinfoset *pcountryinfo;
909 u8 *pos, *end, *p;
910 u8 n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0;
911 u16 beaconsize = 0;
912 int ret;
916 913
917 lbs_deb_enter(LBS_DEB_ASSOC); 914 lbs_deb_enter(LBS_DEB_ASSOC);
918 915
919 founddatarateie = 0;
920 ratesize = 0;
921 beaconsize = 0;
922
923 if (*bytesleft >= sizeof(beaconsize)) { 916 if (*bytesleft >= sizeof(beaconsize)) {
924 /* Extract & convert beacon size from the command buffer */ 917 /* Extract & convert beacon size from the command buffer */
925 beaconsize = le16_to_cpup((void *)*pbeaconinfo); 918 beaconsize = le16_to_cpup((void *)*pbeaconinfo);
@@ -1005,11 +998,9 @@ static int libertas_process_bss(struct bss_descriptor * bss,
1005 break; 998 break;
1006 999
1007 case MFIE_TYPE_RATES: 1000 case MFIE_TYPE_RATES:
1008 memcpy(bss->datarates, elem->data, elem->len); 1001 n_basic_rates = min_t(u8, MAX_RATES, elem->len);
1009 memmove(bss->libertas_supported_rates, elem->data, 1002 memcpy(bss->rates, elem->data, n_basic_rates);
1010 elem->len); 1003 got_basic_rates = 1;
1011 ratesize = elem->len;
1012 founddatarateie = 1;
1013 break; 1004 break;
1014 1005
1015 case MFIE_TYPE_FH_SET: 1006 case MFIE_TYPE_FH_SET:
@@ -1070,22 +1061,15 @@ static int libertas_process_bss(struct bss_descriptor * bss,
1070 * already found. Data rate IE should come before 1061 * already found. Data rate IE should come before
1071 * extended supported rate IE 1062 * extended supported rate IE
1072 */ 1063 */
1073 if (!founddatarateie) 1064 if (!got_basic_rates)
1074 break; 1065 break;
1075 1066
1076 if ((elem->len + ratesize) > WLAN_SUPPORTED_RATES) { 1067 n_ex_rates = elem->len;
1077 bytestocopy = 1068 if (n_basic_rates + n_ex_rates > MAX_RATES)
1078 (WLAN_SUPPORTED_RATES - ratesize); 1069 n_ex_rates = MAX_RATES - n_basic_rates;
1079 } else {
1080 bytestocopy = elem->len;
1081 }
1082 1070
1083 pRate = (u8 *) bss->datarates; 1071 p = bss->rates + n_basic_rates;
1084 pRate += ratesize; 1072 memcpy(p, elem->data, n_ex_rates);
1085 memmove(pRate, elem->data, bytestocopy);
1086 pRate = (u8 *) bss->libertas_supported_rates;
1087 pRate += ratesize;
1088 memmove(pRate, elem->data, bytestocopy);
1089 break; 1073 break;
1090 1074
1091 case MFIE_TYPE_GENERIC: 1075 case MFIE_TYPE_GENERIC:
@@ -1123,6 +1107,7 @@ static int libertas_process_bss(struct bss_descriptor * bss,
1123 1107
1124 /* Timestamp */ 1108 /* Timestamp */
1125 bss->last_scanned = jiffies; 1109 bss->last_scanned = jiffies;
1110 libertas_unset_basic_rate_flags(bss->rates, sizeof(bss->rates));
1126 1111
1127 ret = 0; 1112 ret = 0;
1128 1113
@@ -1530,12 +1515,9 @@ static inline char *libertas_translate_scan(wlan_private *priv,
1530 iwe.u.bitrate.disabled = 0; 1515 iwe.u.bitrate.disabled = 0;
1531 iwe.u.bitrate.value = 0; 1516 iwe.u.bitrate.value = 0;
1532 1517
1533 for (j = 0; j < sizeof(bss->libertas_supported_rates); j++) { 1518 for (j = 0; bss->rates[j] && (j < sizeof(bss->rates)); j++) {
1534 u8 rate = bss->libertas_supported_rates[j]; 1519 /* Bit rate given in 500 kb/s units */
1535 if (rate == 0) 1520 iwe.u.bitrate.value = bss->rates[j] * 500000;
1536 break; /* no more rates */
1537 /* Bit rate given in 500 kb/s units (+ 0x80) */
1538 iwe.u.bitrate.value = (rate & 0x7f) * 500000;
1539 current_val = iwe_stream_add_value(start, current_val, 1521 current_val = iwe_stream_add_value(start, current_val,
1540 stop, &iwe, IW_EV_PARAM_LEN); 1522 stop, &iwe, IW_EV_PARAM_LEN);
1541 } 1523 }
diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h
index 23c539c22634..8c3508b3257f 100644
--- a/drivers/net/wireless/libertas/scan.h
+++ b/drivers/net/wireless/libertas/scan.h
@@ -152,14 +152,14 @@ struct bss_descriptor {
152 u32 atimwindow; 152 u32 atimwindow;
153 153
154 u8 mode; 154 u8 mode;
155 u8 libertas_supported_rates[WLAN_SUPPORTED_RATES]; 155 /* zero-terminated array of supported data rates */
156 u8 rates[MAX_RATES + 1];
156 157
157 __le64 timestamp; //!< TSF value included in the beacon/probe response 158 __le64 timestamp; //!< TSF value included in the beacon/probe response
158 unsigned long last_scanned; 159 unsigned long last_scanned;
159 160
160 union ieeetypes_phyparamset phyparamset; 161 union ieeetypes_phyparamset phyparamset;
161 union IEEEtypes_ssparamset ssparamset; 162 union IEEEtypes_ssparamset ssparamset;
162 u8 datarates[WLAN_SUPPORTED_RATES];
163 163
164 u64 networktsf; //!< TSF timestamp from the current firmware TSF 164 u64 networktsf; //!< TSF timestamp from the current firmware TSF
165 165
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
index 115f02c010a1..0b805e32993a 100644
--- a/drivers/net/wireless/libertas/wext.c
+++ b/drivers/net/wireless/libertas/wext.c
@@ -22,14 +22,6 @@
22 22
23 23
24/** 24/**
25 * the rates supported by the card
26 */
27static u8 libertas_wlan_data_rates[WLAN_SUPPORTED_RATES] =
28 { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12,
29 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00
30};
31
32/**
33 * @brief Convert mw value to dbm value 25 * @brief Convert mw value to dbm value
34 * 26 *
35 * @param mw the value of mw 27 * @param mw the value of mw
@@ -187,57 +179,21 @@ int wlan_radio_ioctl(wlan_private * priv, u8 option)
187} 179}
188 180
189/** 181/**
190 * @brief Copy rates 182 * @brief Copy active data rates based on adapter mode and status
191 *
192 * @param dest A pointer to Dest Buf
193 * @param src A pointer to Src Buf
194 * @param len The len of Src Buf
195 * @return Number of rates copyed
196 */
197static inline int copyrates(u8 * dest, int pos, u8 * src, int len)
198{
199 int i;
200
201 for (i = 0; i < len && src[i]; i++, pos++) {
202 if (pos >= sizeof(u8) * WLAN_SUPPORTED_RATES)
203 break;
204 dest[pos] = src[i];
205 }
206
207 return pos;
208}
209
210/**
211 * @brief Get active data rates
212 * 183 *
213 * @param adapter A pointer to wlan_adapter structure 184 * @param adapter A pointer to wlan_adapter structure
214 * @param rate The buf to return the active rates 185 * @param rate The buf to return the active rates
215 * @return The number of rates
216 */ 186 */
217static int get_active_data_rates(wlan_adapter * adapter, 187static void copy_active_data_rates(wlan_adapter * adapter, u8 * rates)
218 u8* rates)
219{ 188{
220 int k = 0;
221
222 lbs_deb_enter(LBS_DEB_WEXT); 189 lbs_deb_enter(LBS_DEB_WEXT);
223 190
224 if (adapter->connect_status != LIBERTAS_CONNECTED) { 191 if (adapter->connect_status != LIBERTAS_CONNECTED)
225 if (adapter->mode == IW_MODE_INFRA) { 192 memcpy(rates, libertas_bg_rates, MAX_RATES);
226 lbs_deb_wext("infra\n"); 193 else
227 k = copyrates(rates, k, libertas_supported_rates, 194 memcpy(rates, adapter->curbssparams.rates, MAX_RATES);
228 sizeof(libertas_supported_rates));
229 } else {
230 lbs_deb_wext("Adhoc G\n");
231 k = copyrates(rates, k, libertas_adhoc_rates_g,
232 sizeof(libertas_adhoc_rates_g));
233 }
234 } else {
235 k = copyrates(rates, 0, adapter->curbssparams.datarates,
236 adapter->curbssparams.numofrates);
237 }
238 195
239 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", k); 196 lbs_deb_leave(LBS_DEB_WEXT);
240 return k;
241} 197}
242 198
243static int wlan_get_name(struct net_device *dev, struct iw_request_info *info, 199static int wlan_get_name(struct net_device *dev, struct iw_request_info *info,
@@ -673,7 +629,7 @@ static int wlan_get_range(struct net_device *dev, struct iw_request_info *info,
673 wlan_adapter *adapter = priv->adapter; 629 wlan_adapter *adapter = priv->adapter;
674 struct iw_range *range = (struct iw_range *)extra; 630 struct iw_range *range = (struct iw_range *)extra;
675 struct chan_freq_power *cfp; 631 struct chan_freq_power *cfp;
676 u8 rates[WLAN_SUPPORTED_RATES]; 632 u8 rates[MAX_RATES + 1];
677 633
678 u8 flag = 0; 634 u8 flag = 0;
679 635
@@ -686,12 +642,10 @@ static int wlan_get_range(struct net_device *dev, struct iw_request_info *info,
686 range->max_nwid = 0; 642 range->max_nwid = 0;
687 643
688 memset(rates, 0, sizeof(rates)); 644 memset(rates, 0, sizeof(rates));
689 range->num_bitrates = get_active_data_rates(adapter, rates); 645 copy_active_data_rates(adapter, rates);
690 646 range->num_bitrates = strnlen(rates, IW_MAX_BITRATES);
691 for (i = 0; i < min_t(__u8, range->num_bitrates, IW_MAX_BITRATES) && rates[i]; 647 for (i = 0; i < range->num_bitrates; i++)
692 i++) { 648 range->bitrate[i] = rates[i] * 500000;
693 range->bitrate[i] = (rates[i] & 0x7f) * 500000;
694 }
695 range->num_bitrates = i; 649 range->num_bitrates = i;
696 lbs_deb_wext("IW_MAX_BITRATES %d, num_bitrates %d\n", IW_MAX_BITRATES, 650 lbs_deb_wext("IW_MAX_BITRATES %d, num_bitrates %d\n", IW_MAX_BITRATES,
697 range->num_bitrates); 651 range->num_bitrates);
@@ -1080,88 +1034,46 @@ out:
1080 return ret; 1034 return ret;
1081} 1035}
1082 1036
1083/**
1084 * @brief use index to get the data rate
1085 *
1086 * @param index The index of data rate
1087 * @return data rate or 0
1088 */
1089u32 libertas_index_to_data_rate(u8 index)
1090{
1091 if (index >= sizeof(libertas_wlan_data_rates))
1092 index = 0;
1093
1094 return libertas_wlan_data_rates[index];
1095}
1096
1097/**
1098 * @brief use rate to get the index
1099 *
1100 * @param rate data rate
1101 * @return index or 0
1102 */
1103u8 libertas_data_rate_to_index(u32 rate)
1104{
1105 u8 *ptr;
1106
1107 if (rate)
1108 if ((ptr = memchr(libertas_wlan_data_rates, (u8) rate,
1109 sizeof(libertas_wlan_data_rates))))
1110 return (ptr - libertas_wlan_data_rates);
1111
1112 return 0;
1113}
1114
1115static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info, 1037static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info,
1116 struct iw_param *vwrq, char *extra) 1038 struct iw_param *vwrq, char *extra)
1117{ 1039{
1118 wlan_private *priv = dev->priv; 1040 wlan_private *priv = dev->priv;
1119 wlan_adapter *adapter = priv->adapter; 1041 wlan_adapter *adapter = priv->adapter;
1120 u32 data_rate; 1042 u32 new_rate;
1121 u16 action; 1043 u16 action;
1122 int ret = 0; 1044 int ret = -EINVAL;
1123 u8 rates[WLAN_SUPPORTED_RATES]; 1045 u8 rates[MAX_RATES + 1];
1124 u8 *rate;
1125 1046
1126 lbs_deb_enter(LBS_DEB_WEXT); 1047 lbs_deb_enter(LBS_DEB_WEXT);
1127
1128 lbs_deb_wext("vwrq->value %d\n", vwrq->value); 1048 lbs_deb_wext("vwrq->value %d\n", vwrq->value);
1129 1049
1050 /* Auto rate? */
1130 if (vwrq->value == -1) { 1051 if (vwrq->value == -1) {
1131 action = CMD_ACT_SET_TX_AUTO; // Auto 1052 action = CMD_ACT_SET_TX_AUTO;
1132 adapter->is_datarate_auto = 1; 1053 adapter->auto_rate = 1;
1133 adapter->datarate = 0; 1054 adapter->cur_rate = 0;
1134 } else { 1055 } else {
1135 if (vwrq->value % 100000) { 1056 if (vwrq->value % 100000)
1136 return -EINVAL; 1057 goto out;
1137 }
1138
1139 data_rate = vwrq->value / 500000;
1140 1058
1141 memset(rates, 0, sizeof(rates)); 1059 memset(rates, 0, sizeof(rates));
1142 get_active_data_rates(adapter, rates); 1060 copy_active_data_rates(adapter, rates);
1143 rate = rates; 1061 new_rate = vwrq->value / 500000;
1144 while (*rate) { 1062 if (!memchr(rates, new_rate, sizeof(rates))) {
1145 lbs_deb_wext("rate=0x%X, wanted data_rate 0x%X\n", *rate, 1063 lbs_pr_alert("fixed data rate 0x%X out of range\n",
1146 data_rate); 1064 new_rate);
1147 if ((*rate & 0x7f) == (data_rate & 0x7f)) 1065 goto out;
1148 break;
1149 rate++;
1150 }
1151 if (!*rate) {
1152 lbs_pr_alert("fixed data rate 0x%X out "
1153 "of range\n", data_rate);
1154 return -EINVAL;
1155 } 1066 }
1156 1067
1157 adapter->datarate = data_rate; 1068 adapter->cur_rate = new_rate;
1158 action = CMD_ACT_SET_TX_FIX_RATE; 1069 action = CMD_ACT_SET_TX_FIX_RATE;
1159 adapter->is_datarate_auto = 0; 1070 adapter->auto_rate = 0;
1160 } 1071 }
1161 1072
1162 ret = libertas_prepare_and_send_command(priv, CMD_802_11_DATA_RATE, 1073 ret = libertas_prepare_and_send_command(priv, CMD_802_11_DATA_RATE,
1163 action, CMD_OPTION_WAITFORRSP, 0, NULL); 1074 action, CMD_OPTION_WAITFORRSP, 0, NULL);
1164 1075
1076out:
1165 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); 1077 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1166 return ret; 1078 return ret;
1167} 1079}
@@ -1174,14 +1086,19 @@ static int wlan_get_rate(struct net_device *dev, struct iw_request_info *info,
1174 1086
1175 lbs_deb_enter(LBS_DEB_WEXT); 1087 lbs_deb_enter(LBS_DEB_WEXT);
1176 1088
1177 if (adapter->is_datarate_auto) { 1089 if (adapter->connect_status == LIBERTAS_CONNECTED) {
1178 vwrq->fixed = 0; 1090 vwrq->value = adapter->cur_rate * 500000;
1091
1092 if (adapter->auto_rate)
1093 vwrq->fixed = 0;
1094 else
1095 vwrq->fixed = 1;
1096
1179 } else { 1097 } else {
1180 vwrq->fixed = 1; 1098 vwrq->fixed = 0;
1099 vwrq->value = 0;
1181 } 1100 }
1182 1101
1183 vwrq->value = adapter->datarate * 500000;
1184
1185 lbs_deb_leave(LBS_DEB_WEXT); 1102 lbs_deb_leave(LBS_DEB_WEXT);
1186 return 0; 1103 return 0;
1187} 1104}