aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/libertas
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2007-08-02 11:40:45 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 19:49:48 -0400
commit8c5127657549d055ac9d709cdea73902a6ef392c (patch)
tree33e72a0b55165d51652a002ab6929857f0e2facc /drivers/net/wireless/libertas
parente52414728b930f0adcbc38c6498dd03b3568fe99 (diff)
[PATCH] libertas: simplify and clean up data rate handling
Remove unused/duplicated fields and consolidate static data rate arrays, for example the libertas_supported_rates[] and datarates[] arrays in the bss_descriptor structure, and the libertas_supported_rates field in the wlan_adapter structure. Introduce libertas_fw_index_to_data_rate and libertas_data_rate_to_fw_index functions and use them everywhere firmware requires a rate index rather than a rate array. The firmware requires the 4 basic rates to have the MSB set, but most other stuff doesn't, like WEXT and mesh ioctls. Therefore, only set the MSB on basic rates when pushing rate arrays to firmware instead of doing a ton of (rate & 0x7f) everywhere. Signed-off-by: Dan Williams <dcbw@redhat.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/libertas')
-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}