diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx/wl1271_cmd.c')
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_cmd.c | 473 |
1 files changed, 322 insertions, 151 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 2a4351ff54dc..e7832f3318eb 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c | |||
@@ -26,10 +26,12 @@ | |||
26 | #include <linux/crc7.h> | 26 | #include <linux/crc7.h> |
27 | #include <linux/spi/spi.h> | 27 | #include <linux/spi/spi.h> |
28 | #include <linux/etherdevice.h> | 28 | #include <linux/etherdevice.h> |
29 | #include <linux/slab.h> | ||
29 | 30 | ||
30 | #include "wl1271.h" | 31 | #include "wl1271.h" |
31 | #include "wl1271_reg.h" | 32 | #include "wl1271_reg.h" |
32 | #include "wl1271_spi.h" | 33 | #include "wl1271_spi.h" |
34 | #include "wl1271_io.h" | ||
33 | #include "wl1271_acx.h" | 35 | #include "wl1271_acx.h" |
34 | #include "wl12xx_80211.h" | 36 | #include "wl12xx_80211.h" |
35 | #include "wl1271_cmd.h" | 37 | #include "wl1271_cmd.h" |
@@ -42,26 +44,28 @@ | |||
42 | * @buf: buffer containing the command, must work with dma | 44 | * @buf: buffer containing the command, must work with dma |
43 | * @len: length of the buffer | 45 | * @len: length of the buffer |
44 | */ | 46 | */ |
45 | int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len) | 47 | int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, |
48 | size_t res_len) | ||
46 | { | 49 | { |
47 | struct wl1271_cmd_header *cmd; | 50 | struct wl1271_cmd_header *cmd; |
48 | unsigned long timeout; | 51 | unsigned long timeout; |
49 | u32 intr; | 52 | u32 intr; |
50 | int ret = 0; | 53 | int ret = 0; |
54 | u16 status; | ||
51 | 55 | ||
52 | cmd = buf; | 56 | cmd = buf; |
53 | cmd->id = id; | 57 | cmd->id = cpu_to_le16(id); |
54 | cmd->status = 0; | 58 | cmd->status = 0; |
55 | 59 | ||
56 | WARN_ON(len % 4 != 0); | 60 | WARN_ON(len % 4 != 0); |
57 | 61 | ||
58 | wl1271_spi_mem_write(wl, wl->cmd_box_addr, buf, len); | 62 | wl1271_write(wl, wl->cmd_box_addr, buf, len, false); |
59 | 63 | ||
60 | wl1271_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); | 64 | wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); |
61 | 65 | ||
62 | timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT); | 66 | timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT); |
63 | 67 | ||
64 | intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); | 68 | intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); |
65 | while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) { | 69 | while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) { |
66 | if (time_after(jiffies, timeout)) { | 70 | if (time_after(jiffies, timeout)) { |
67 | wl1271_error("command complete timeout"); | 71 | wl1271_error("command complete timeout"); |
@@ -71,17 +75,28 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len) | |||
71 | 75 | ||
72 | msleep(1); | 76 | msleep(1); |
73 | 77 | ||
74 | intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); | 78 | intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); |
75 | } | 79 | } |
76 | 80 | ||
77 | wl1271_reg_write32(wl, ACX_REG_INTERRUPT_ACK, | 81 | /* read back the status code of the command */ |
78 | WL1271_ACX_INTR_CMD_COMPLETE); | 82 | if (res_len == 0) |
83 | res_len = sizeof(struct wl1271_cmd_header); | ||
84 | wl1271_read(wl, wl->cmd_box_addr, cmd, res_len, false); | ||
85 | |||
86 | status = le16_to_cpu(cmd->status); | ||
87 | if (status != CMD_STATUS_SUCCESS) { | ||
88 | wl1271_error("command execute failure %d", status); | ||
89 | ret = -EIO; | ||
90 | } | ||
91 | |||
92 | wl1271_write32(wl, ACX_REG_INTERRUPT_ACK, | ||
93 | WL1271_ACX_INTR_CMD_COMPLETE); | ||
79 | 94 | ||
80 | out: | 95 | out: |
81 | return ret; | 96 | return ret; |
82 | } | 97 | } |
83 | 98 | ||
84 | int wl1271_cmd_cal_channel_tune(struct wl1271 *wl) | 99 | static int wl1271_cmd_cal_channel_tune(struct wl1271 *wl) |
85 | { | 100 | { |
86 | struct wl1271_cmd_cal_channel_tune *cmd; | 101 | struct wl1271_cmd_cal_channel_tune *cmd; |
87 | int ret = 0; | 102 | int ret = 0; |
@@ -104,7 +119,7 @@ int wl1271_cmd_cal_channel_tune(struct wl1271 *wl) | |||
104 | return ret; | 119 | return ret; |
105 | } | 120 | } |
106 | 121 | ||
107 | int wl1271_cmd_cal_update_ref_point(struct wl1271 *wl) | 122 | static int wl1271_cmd_cal_update_ref_point(struct wl1271 *wl) |
108 | { | 123 | { |
109 | struct wl1271_cmd_cal_update_ref_point *cmd; | 124 | struct wl1271_cmd_cal_update_ref_point *cmd; |
110 | int ret = 0; | 125 | int ret = 0; |
@@ -129,7 +144,7 @@ int wl1271_cmd_cal_update_ref_point(struct wl1271 *wl) | |||
129 | return ret; | 144 | return ret; |
130 | } | 145 | } |
131 | 146 | ||
132 | int wl1271_cmd_cal_p2g(struct wl1271 *wl) | 147 | static int wl1271_cmd_cal_p2g(struct wl1271 *wl) |
133 | { | 148 | { |
134 | struct wl1271_cmd_cal_p2g *cmd; | 149 | struct wl1271_cmd_cal_p2g *cmd; |
135 | int ret = 0; | 150 | int ret = 0; |
@@ -150,7 +165,7 @@ int wl1271_cmd_cal_p2g(struct wl1271 *wl) | |||
150 | return ret; | 165 | return ret; |
151 | } | 166 | } |
152 | 167 | ||
153 | int wl1271_cmd_cal(struct wl1271 *wl) | 168 | static int wl1271_cmd_cal(struct wl1271 *wl) |
154 | { | 169 | { |
155 | /* | 170 | /* |
156 | * FIXME: we must make sure that we're not sleeping when calibration | 171 | * FIXME: we must make sure that we're not sleeping when calibration |
@@ -175,11 +190,68 @@ int wl1271_cmd_cal(struct wl1271 *wl) | |||
175 | return ret; | 190 | return ret; |
176 | } | 191 | } |
177 | 192 | ||
178 | int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval, | 193 | int wl1271_cmd_general_parms(struct wl1271 *wl) |
179 | u16 beacon_interval, u8 wait) | 194 | { |
195 | struct wl1271_general_parms_cmd *gen_parms; | ||
196 | int ret; | ||
197 | |||
198 | if (!wl->nvs) | ||
199 | return -ENODEV; | ||
200 | |||
201 | gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); | ||
202 | if (!gen_parms) | ||
203 | return -ENOMEM; | ||
204 | |||
205 | gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM; | ||
206 | |||
207 | memcpy(gen_parms->params, wl->nvs->general_params, | ||
208 | WL1271_NVS_GENERAL_PARAMS_SIZE); | ||
209 | |||
210 | ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0); | ||
211 | if (ret < 0) | ||
212 | wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); | ||
213 | |||
214 | kfree(gen_parms); | ||
215 | return ret; | ||
216 | } | ||
217 | |||
218 | int wl1271_cmd_radio_parms(struct wl1271 *wl) | ||
219 | { | ||
220 | struct wl1271_radio_parms_cmd *radio_parms; | ||
221 | struct conf_radio_parms *rparam = &wl->conf.init.radioparam; | ||
222 | int ret; | ||
223 | |||
224 | if (!wl->nvs) | ||
225 | return -ENODEV; | ||
226 | |||
227 | radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL); | ||
228 | if (!radio_parms) | ||
229 | return -ENOMEM; | ||
230 | |||
231 | radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; | ||
232 | |||
233 | memcpy(radio_parms->stat_radio_params, wl->nvs->stat_radio_params, | ||
234 | WL1271_NVS_STAT_RADIO_PARAMS_SIZE); | ||
235 | memcpy(radio_parms->dyn_radio_params, | ||
236 | wl->nvs->dyn_radio_params[rparam->fem], | ||
237 | WL1271_NVS_DYN_RADIO_PARAMS_SIZE); | ||
238 | |||
239 | /* FIXME: current NVS is missing 5GHz parameters */ | ||
240 | |||
241 | wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", | ||
242 | radio_parms, sizeof(*radio_parms)); | ||
243 | |||
244 | ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0); | ||
245 | if (ret < 0) | ||
246 | wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed"); | ||
247 | |||
248 | kfree(radio_parms); | ||
249 | return ret; | ||
250 | } | ||
251 | |||
252 | int wl1271_cmd_join(struct wl1271 *wl) | ||
180 | { | 253 | { |
181 | static bool do_cal = true; | 254 | static bool do_cal = true; |
182 | unsigned long timeout; | ||
183 | struct wl1271_cmd_join *join; | 255 | struct wl1271_cmd_join *join; |
184 | int ret, i; | 256 | int ret, i; |
185 | u8 *bssid; | 257 | u8 *bssid; |
@@ -193,7 +265,6 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval, | |||
193 | do_cal = false; | 265 | do_cal = false; |
194 | } | 266 | } |
195 | 267 | ||
196 | |||
197 | join = kzalloc(sizeof(*join), GFP_KERNEL); | 268 | join = kzalloc(sizeof(*join), GFP_KERNEL); |
198 | if (!join) { | 269 | if (!join) { |
199 | ret = -ENOMEM; | 270 | ret = -ENOMEM; |
@@ -207,15 +278,34 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval, | |||
207 | for (i = 0; i < ETH_ALEN; i++) | 278 | for (i = 0; i < ETH_ALEN; i++) |
208 | bssid[i] = wl->bssid[ETH_ALEN - i - 1]; | 279 | bssid[i] = wl->bssid[ETH_ALEN - i - 1]; |
209 | 280 | ||
210 | join->rx_config_options = wl->rx_config; | 281 | join->rx_config_options = cpu_to_le32(wl->rx_config); |
211 | join->rx_filter_options = wl->rx_filter; | 282 | join->rx_filter_options = cpu_to_le32(wl->rx_filter); |
283 | join->bss_type = wl->bss_type; | ||
284 | |||
285 | /* | ||
286 | * FIXME: disable temporarily all filters because after commit | ||
287 | * 9cef8737 "mac80211: fix managed mode BSSID handling" broke | ||
288 | * association. The filter logic needs to be implemented properly | ||
289 | * and once that is done, this hack can be removed. | ||
290 | */ | ||
291 | join->rx_config_options = cpu_to_le32(0); | ||
292 | join->rx_filter_options = cpu_to_le32(WL1271_DEFAULT_RX_FILTER); | ||
293 | |||
294 | if (wl->band == IEEE80211_BAND_2GHZ) | ||
295 | join->basic_rate_set = cpu_to_le32(CONF_HW_BIT_RATE_1MBPS | | ||
296 | CONF_HW_BIT_RATE_2MBPS | | ||
297 | CONF_HW_BIT_RATE_5_5MBPS | | ||
298 | CONF_HW_BIT_RATE_11MBPS); | ||
299 | else { | ||
300 | join->bss_type |= WL1271_JOIN_CMD_BSS_TYPE_5GHZ; | ||
301 | join->basic_rate_set = cpu_to_le32(CONF_HW_BIT_RATE_6MBPS | | ||
302 | CONF_HW_BIT_RATE_12MBPS | | ||
303 | CONF_HW_BIT_RATE_24MBPS); | ||
304 | } | ||
212 | 305 | ||
213 | join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | | 306 | join->beacon_interval = cpu_to_le16(WL1271_DEFAULT_BEACON_INT); |
214 | RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; | 307 | join->dtim_interval = WL1271_DEFAULT_DTIM_PERIOD; |
215 | 308 | ||
216 | join->beacon_interval = beacon_interval; | ||
217 | join->dtim_interval = dtim_interval; | ||
218 | join->bss_type = bss_type; | ||
219 | join->channel = wl->channel; | 309 | join->channel = wl->channel; |
220 | join->ssid_len = wl->ssid_len; | 310 | join->ssid_len = wl->ssid_len; |
221 | memcpy(join->ssid, wl->ssid, wl->ssid_len); | 311 | memcpy(join->ssid, wl->ssid, wl->ssid_len); |
@@ -228,21 +318,22 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval, | |||
228 | 318 | ||
229 | join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET; | 319 | join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET; |
230 | 320 | ||
321 | /* reset TX security counters */ | ||
322 | wl->tx_security_last_seq = 0; | ||
323 | wl->tx_security_seq_16 = 0; | ||
324 | wl->tx_security_seq_32 = 0; | ||
231 | 325 | ||
232 | ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); | 326 | ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join), 0); |
233 | if (ret < 0) { | 327 | if (ret < 0) { |
234 | wl1271_error("failed to initiate cmd join"); | 328 | wl1271_error("failed to initiate cmd join"); |
235 | goto out_free; | 329 | goto out_free; |
236 | } | 330 | } |
237 | 331 | ||
238 | timeout = msecs_to_jiffies(JOIN_TIMEOUT); | ||
239 | |||
240 | /* | 332 | /* |
241 | * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to | 333 | * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to |
242 | * simplify locking we just sleep instead, for now | 334 | * simplify locking we just sleep instead, for now |
243 | */ | 335 | */ |
244 | if (wait) | 336 | msleep(10); |
245 | msleep(10); | ||
246 | 337 | ||
247 | out_free: | 338 | out_free: |
248 | kfree(join); | 339 | kfree(join); |
@@ -262,34 +353,21 @@ out: | |||
262 | int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer) | 353 | int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer) |
263 | { | 354 | { |
264 | int ret; | 355 | int ret; |
356 | size_t res_len = 0; | ||
265 | 357 | ||
266 | wl1271_debug(DEBUG_CMD, "cmd test"); | 358 | wl1271_debug(DEBUG_CMD, "cmd test"); |
267 | 359 | ||
268 | ret = wl1271_cmd_send(wl, CMD_TEST, buf, buf_len); | 360 | if (answer) |
361 | res_len = buf_len; | ||
362 | |||
363 | ret = wl1271_cmd_send(wl, CMD_TEST, buf, buf_len, res_len); | ||
269 | 364 | ||
270 | if (ret < 0) { | 365 | if (ret < 0) { |
271 | wl1271_warning("TEST command failed"); | 366 | wl1271_warning("TEST command failed"); |
272 | return ret; | 367 | return ret; |
273 | } | 368 | } |
274 | 369 | ||
275 | if (answer) { | 370 | return ret; |
276 | struct wl1271_command *cmd_answer; | ||
277 | |||
278 | /* | ||
279 | * The test command got in, we can read the answer. | ||
280 | * The answer would be a wl1271_command, where the | ||
281 | * parameter array contains the actual answer. | ||
282 | */ | ||
283 | wl1271_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len); | ||
284 | |||
285 | cmd_answer = buf; | ||
286 | |||
287 | if (cmd_answer->header.status != CMD_STATUS_SUCCESS) | ||
288 | wl1271_error("TEST command answer error: %d", | ||
289 | cmd_answer->header.status); | ||
290 | } | ||
291 | |||
292 | return 0; | ||
293 | } | 371 | } |
294 | 372 | ||
295 | /** | 373 | /** |
@@ -307,26 +385,15 @@ int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len) | |||
307 | 385 | ||
308 | wl1271_debug(DEBUG_CMD, "cmd interrogate"); | 386 | wl1271_debug(DEBUG_CMD, "cmd interrogate"); |
309 | 387 | ||
310 | acx->id = id; | 388 | acx->id = cpu_to_le16(id); |
311 | 389 | ||
312 | /* payload length, does not include any headers */ | 390 | /* payload length, does not include any headers */ |
313 | acx->len = len - sizeof(*acx); | 391 | acx->len = cpu_to_le16(len - sizeof(*acx)); |
314 | 392 | ||
315 | ret = wl1271_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx)); | 393 | ret = wl1271_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx), len); |
316 | if (ret < 0) { | 394 | if (ret < 0) |
317 | wl1271_error("INTERROGATE command failed"); | 395 | wl1271_error("INTERROGATE command failed"); |
318 | goto out; | ||
319 | } | ||
320 | |||
321 | /* the interrogate command got in, we can read the answer */ | ||
322 | wl1271_spi_mem_read(wl, wl->cmd_box_addr, buf, len); | ||
323 | |||
324 | acx = buf; | ||
325 | if (acx->cmd.status != CMD_STATUS_SUCCESS) | ||
326 | wl1271_error("INTERROGATE command error: %d", | ||
327 | acx->cmd.status); | ||
328 | 396 | ||
329 | out: | ||
330 | return ret; | 397 | return ret; |
331 | } | 398 | } |
332 | 399 | ||
@@ -345,12 +412,12 @@ int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len) | |||
345 | 412 | ||
346 | wl1271_debug(DEBUG_CMD, "cmd configure"); | 413 | wl1271_debug(DEBUG_CMD, "cmd configure"); |
347 | 414 | ||
348 | acx->id = id; | 415 | acx->id = cpu_to_le16(id); |
349 | 416 | ||
350 | /* payload length, does not include any headers */ | 417 | /* payload length, does not include any headers */ |
351 | acx->len = len - sizeof(*acx); | 418 | acx->len = cpu_to_le16(len - sizeof(*acx)); |
352 | 419 | ||
353 | ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len); | 420 | ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len, 0); |
354 | if (ret < 0) { | 421 | if (ret < 0) { |
355 | wl1271_warning("CONFIGURE command NOK"); | 422 | wl1271_warning("CONFIGURE command NOK"); |
356 | return ret; | 423 | return ret; |
@@ -359,7 +426,7 @@ int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len) | |||
359 | return 0; | 426 | return 0; |
360 | } | 427 | } |
361 | 428 | ||
362 | int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable) | 429 | int wl1271_cmd_data_path(struct wl1271 *wl, bool enable) |
363 | { | 430 | { |
364 | struct cmd_enabledisable_path *cmd; | 431 | struct cmd_enabledisable_path *cmd; |
365 | int ret; | 432 | int ret; |
@@ -373,7 +440,8 @@ int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable) | |||
373 | goto out; | 440 | goto out; |
374 | } | 441 | } |
375 | 442 | ||
376 | cmd->channel = channel; | 443 | /* the channel here is only used for calibration, so hardcoded to 1 */ |
444 | cmd->channel = 1; | ||
377 | 445 | ||
378 | if (enable) { | 446 | if (enable) { |
379 | cmd_rx = CMD_ENABLE_RX; | 447 | cmd_rx = CMD_ENABLE_RX; |
@@ -383,39 +451,38 @@ int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable) | |||
383 | cmd_tx = CMD_DISABLE_TX; | 451 | cmd_tx = CMD_DISABLE_TX; |
384 | } | 452 | } |
385 | 453 | ||
386 | ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd)); | 454 | ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd), 0); |
387 | if (ret < 0) { | 455 | if (ret < 0) { |
388 | wl1271_error("rx %s cmd for channel %d failed", | 456 | wl1271_error("rx %s cmd for channel %d failed", |
389 | enable ? "start" : "stop", channel); | 457 | enable ? "start" : "stop", cmd->channel); |
390 | goto out; | 458 | goto out; |
391 | } | 459 | } |
392 | 460 | ||
393 | wl1271_debug(DEBUG_BOOT, "rx %s cmd channel %d", | 461 | wl1271_debug(DEBUG_BOOT, "rx %s cmd channel %d", |
394 | enable ? "start" : "stop", channel); | 462 | enable ? "start" : "stop", cmd->channel); |
395 | 463 | ||
396 | ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd)); | 464 | ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd), 0); |
397 | if (ret < 0) { | 465 | if (ret < 0) { |
398 | wl1271_error("tx %s cmd for channel %d failed", | 466 | wl1271_error("tx %s cmd for channel %d failed", |
399 | enable ? "start" : "stop", channel); | 467 | enable ? "start" : "stop", cmd->channel); |
400 | return ret; | 468 | return ret; |
401 | } | 469 | } |
402 | 470 | ||
403 | wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d", | 471 | wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d", |
404 | enable ? "start" : "stop", channel); | 472 | enable ? "start" : "stop", cmd->channel); |
405 | 473 | ||
406 | out: | 474 | out: |
407 | kfree(cmd); | 475 | kfree(cmd); |
408 | return ret; | 476 | return ret; |
409 | } | 477 | } |
410 | 478 | ||
411 | int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode) | 479 | int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send) |
412 | { | 480 | { |
413 | struct wl1271_cmd_ps_params *ps_params = NULL; | 481 | struct wl1271_cmd_ps_params *ps_params = NULL; |
414 | int ret = 0; | 482 | int ret = 0; |
415 | 483 | ||
416 | /* FIXME: this should be in ps.c */ | 484 | /* FIXME: this should be in ps.c */ |
417 | ret = wl1271_acx_wake_up_conditions(wl, WAKE_UP_EVENT_DTIM_BITMAP, | 485 | ret = wl1271_acx_wake_up_conditions(wl); |
418 | wl->listen_int); | ||
419 | if (ret < 0) { | 486 | if (ret < 0) { |
420 | wl1271_error("couldn't set wake up conditions"); | 487 | wl1271_error("couldn't set wake up conditions"); |
421 | goto out; | 488 | goto out; |
@@ -430,13 +497,13 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode) | |||
430 | } | 497 | } |
431 | 498 | ||
432 | ps_params->ps_mode = ps_mode; | 499 | ps_params->ps_mode = ps_mode; |
433 | ps_params->send_null_data = 1; | 500 | ps_params->send_null_data = send; |
434 | ps_params->retries = 5; | 501 | ps_params->retries = 5; |
435 | ps_params->hang_over_period = 128; | 502 | ps_params->hang_over_period = 128; |
436 | ps_params->null_data_rate = 1; /* 1 Mbps */ | 503 | ps_params->null_data_rate = cpu_to_le32(1); /* 1 Mbps */ |
437 | 504 | ||
438 | ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params, | 505 | ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params, |
439 | sizeof(*ps_params)); | 506 | sizeof(*ps_params), 0); |
440 | if (ret < 0) { | 507 | if (ret < 0) { |
441 | wl1271_error("cmd set_ps_mode failed"); | 508 | wl1271_error("cmd set_ps_mode failed"); |
442 | goto out; | 509 | goto out; |
@@ -464,22 +531,17 @@ int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, | |||
464 | WARN_ON(len > MAX_READ_SIZE); | 531 | WARN_ON(len > MAX_READ_SIZE); |
465 | len = min_t(size_t, len, MAX_READ_SIZE); | 532 | len = min_t(size_t, len, MAX_READ_SIZE); |
466 | 533 | ||
467 | cmd->addr = addr; | 534 | cmd->addr = cpu_to_le32(addr); |
468 | cmd->size = len; | 535 | cmd->size = cpu_to_le32(len); |
469 | 536 | ||
470 | ret = wl1271_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd)); | 537 | ret = wl1271_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd), |
538 | sizeof(*cmd)); | ||
471 | if (ret < 0) { | 539 | if (ret < 0) { |
472 | wl1271_error("read memory command failed: %d", ret); | 540 | wl1271_error("read memory command failed: %d", ret); |
473 | goto out; | 541 | goto out; |
474 | } | 542 | } |
475 | 543 | ||
476 | /* the read command got in, we can now read the answer */ | 544 | /* the read command got in */ |
477 | wl1271_spi_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); | ||
478 | |||
479 | if (cmd->header.status != CMD_STATUS_SUCCESS) | ||
480 | wl1271_error("error in read command result: %d", | ||
481 | cmd->header.status); | ||
482 | |||
483 | memcpy(answer, cmd->value, len); | 545 | memcpy(answer, cmd->value, len); |
484 | 546 | ||
485 | out: | 547 | out: |
@@ -488,16 +550,33 @@ out: | |||
488 | } | 550 | } |
489 | 551 | ||
490 | int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, | 552 | int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, |
491 | u8 active_scan, u8 high_prio, u8 num_channels, | 553 | u8 active_scan, u8 high_prio, u8 band, |
492 | u8 probe_requests) | 554 | u8 probe_requests) |
493 | { | 555 | { |
494 | 556 | ||
495 | struct wl1271_cmd_trigger_scan_to *trigger = NULL; | 557 | struct wl1271_cmd_trigger_scan_to *trigger = NULL; |
496 | struct wl1271_cmd_scan *params = NULL; | 558 | struct wl1271_cmd_scan *params = NULL; |
497 | int i, ret; | 559 | struct ieee80211_channel *channels; |
560 | int i, j, n_ch, ret; | ||
498 | u16 scan_options = 0; | 561 | u16 scan_options = 0; |
562 | u8 ieee_band; | ||
563 | |||
564 | if (band == WL1271_SCAN_BAND_2_4_GHZ) | ||
565 | ieee_band = IEEE80211_BAND_2GHZ; | ||
566 | else if (band == WL1271_SCAN_BAND_DUAL && wl1271_11a_enabled()) | ||
567 | ieee_band = IEEE80211_BAND_2GHZ; | ||
568 | else if (band == WL1271_SCAN_BAND_5_GHZ && wl1271_11a_enabled()) | ||
569 | ieee_band = IEEE80211_BAND_5GHZ; | ||
570 | else | ||
571 | return -EINVAL; | ||
572 | |||
573 | if (wl->hw->wiphy->bands[ieee_band]->channels == NULL) | ||
574 | return -EINVAL; | ||
499 | 575 | ||
500 | if (wl->scanning) | 576 | channels = wl->hw->wiphy->bands[ieee_band]->channels; |
577 | n_ch = wl->hw->wiphy->bands[ieee_band]->n_channels; | ||
578 | |||
579 | if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) | ||
501 | return -EINVAL; | 580 | return -EINVAL; |
502 | 581 | ||
503 | params = kzalloc(sizeof(*params), GFP_KERNEL); | 582 | params = kzalloc(sizeof(*params), GFP_KERNEL); |
@@ -512,32 +591,43 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, | |||
512 | scan_options |= WL1271_SCAN_OPT_PASSIVE; | 591 | scan_options |= WL1271_SCAN_OPT_PASSIVE; |
513 | if (high_prio) | 592 | if (high_prio) |
514 | scan_options |= WL1271_SCAN_OPT_PRIORITY_HIGH; | 593 | scan_options |= WL1271_SCAN_OPT_PRIORITY_HIGH; |
515 | params->params.scan_options = scan_options; | 594 | params->params.scan_options = cpu_to_le16(scan_options); |
516 | 595 | ||
517 | params->params.num_channels = num_channels; | ||
518 | params->params.num_probe_requests = probe_requests; | 596 | params->params.num_probe_requests = probe_requests; |
519 | params->params.tx_rate = cpu_to_le32(RATE_MASK_2MBPS); | 597 | /* Let the fw autodetect suitable tx_rate for probes */ |
598 | params->params.tx_rate = 0; | ||
520 | params->params.tid_trigger = 0; | 599 | params->params.tid_trigger = 0; |
521 | params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; | 600 | params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; |
522 | 601 | ||
523 | for (i = 0; i < num_channels; i++) { | 602 | if (band == WL1271_SCAN_BAND_DUAL) |
524 | params->channels[i].min_duration = | 603 | params->params.band = WL1271_SCAN_BAND_2_4_GHZ; |
525 | cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION); | 604 | else |
526 | params->channels[i].max_duration = | 605 | params->params.band = band; |
527 | cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION); | 606 | |
528 | memset(¶ms->channels[i].bssid_lsb, 0xff, 4); | 607 | for (i = 0, j = 0; i < n_ch && i < WL1271_SCAN_MAX_CHANNELS; i++) { |
529 | memset(¶ms->channels[i].bssid_msb, 0xff, 2); | 608 | if (!(channels[i].flags & IEEE80211_CHAN_DISABLED)) { |
530 | params->channels[i].early_termination = 0; | 609 | params->channels[j].min_duration = |
531 | params->channels[i].tx_power_att = WL1271_SCAN_CURRENT_TX_PWR; | 610 | cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION); |
532 | params->channels[i].channel = i + 1; | 611 | params->channels[j].max_duration = |
612 | cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION); | ||
613 | memset(¶ms->channels[j].bssid_lsb, 0xff, 4); | ||
614 | memset(¶ms->channels[j].bssid_msb, 0xff, 2); | ||
615 | params->channels[j].early_termination = 0; | ||
616 | params->channels[j].tx_power_att = | ||
617 | WL1271_SCAN_CURRENT_TX_PWR; | ||
618 | params->channels[j].channel = channels[i].hw_value; | ||
619 | j++; | ||
620 | } | ||
533 | } | 621 | } |
534 | 622 | ||
623 | params->params.num_channels = j; | ||
624 | |||
535 | if (len && ssid) { | 625 | if (len && ssid) { |
536 | params->params.ssid_len = len; | 626 | params->params.ssid_len = len; |
537 | memcpy(params->params.ssid, ssid, len); | 627 | memcpy(params->params.ssid, ssid, len); |
538 | } | 628 | } |
539 | 629 | ||
540 | ret = wl1271_cmd_build_probe_req(wl, ssid, len); | 630 | ret = wl1271_cmd_build_probe_req(wl, ssid, len, ieee_band); |
541 | if (ret < 0) { | 631 | if (ret < 0) { |
542 | wl1271_error("PROBE request template failed"); | 632 | wl1271_error("PROBE request template failed"); |
543 | goto out; | 633 | goto out; |
@@ -553,7 +643,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, | |||
553 | trigger->timeout = 0; | 643 | trigger->timeout = 0; |
554 | 644 | ||
555 | ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, | 645 | ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, |
556 | sizeof(*trigger)); | 646 | sizeof(*trigger), 0); |
557 | if (ret < 0) { | 647 | if (ret < 0) { |
558 | wl1271_error("trigger scan to failed for hw scan"); | 648 | wl1271_error("trigger scan to failed for hw scan"); |
559 | goto out; | 649 | goto out; |
@@ -561,21 +651,25 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, | |||
561 | 651 | ||
562 | wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); | 652 | wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); |
563 | 653 | ||
564 | wl->scanning = true; | 654 | set_bit(WL1271_FLAG_SCANNING, &wl->flags); |
655 | if (wl1271_11a_enabled()) { | ||
656 | wl->scan.state = band; | ||
657 | if (band == WL1271_SCAN_BAND_DUAL) { | ||
658 | wl->scan.active = active_scan; | ||
659 | wl->scan.high_prio = high_prio; | ||
660 | wl->scan.probe_requests = probe_requests; | ||
661 | if (len && ssid) { | ||
662 | wl->scan.ssid_len = len; | ||
663 | memcpy(wl->scan.ssid, ssid, len); | ||
664 | } else | ||
665 | wl->scan.ssid_len = 0; | ||
666 | } | ||
667 | } | ||
565 | 668 | ||
566 | ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params)); | 669 | ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params), 0); |
567 | if (ret < 0) { | 670 | if (ret < 0) { |
568 | wl1271_error("SCAN failed"); | 671 | wl1271_error("SCAN failed"); |
569 | goto out; | 672 | clear_bit(WL1271_FLAG_SCANNING, &wl->flags); |
570 | } | ||
571 | |||
572 | wl1271_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); | ||
573 | |||
574 | if (params->header.status != CMD_STATUS_SUCCESS) { | ||
575 | wl1271_error("Scan command error: %d", | ||
576 | params->header.status); | ||
577 | wl->scanning = false; | ||
578 | ret = -EIO; | ||
579 | goto out; | 673 | goto out; |
580 | } | 674 | } |
581 | 675 | ||
@@ -603,14 +697,14 @@ int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, | |||
603 | 697 | ||
604 | cmd->len = cpu_to_le16(buf_len); | 698 | cmd->len = cpu_to_le16(buf_len); |
605 | cmd->template_type = template_id; | 699 | cmd->template_type = template_id; |
606 | cmd->enabled_rates = ACX_RATE_MASK_UNSPECIFIED; | 700 | cmd->enabled_rates = cpu_to_le32(wl->conf.tx.rc_conf.enabled_rates); |
607 | cmd->short_retry_limit = ACX_RATE_RETRY_LIMIT; | 701 | cmd->short_retry_limit = wl->conf.tx.rc_conf.short_retry_limit; |
608 | cmd->long_retry_limit = ACX_RATE_RETRY_LIMIT; | 702 | cmd->long_retry_limit = wl->conf.tx.rc_conf.long_retry_limit; |
609 | 703 | ||
610 | if (buf) | 704 | if (buf) |
611 | memcpy(cmd->template_data, buf, buf_len); | 705 | memcpy(cmd->template_data, buf, buf_len); |
612 | 706 | ||
613 | ret = wl1271_cmd_send(wl, CMD_SET_TEMPLATE, cmd, sizeof(*cmd)); | 707 | ret = wl1271_cmd_send(wl, CMD_SET_TEMPLATE, cmd, sizeof(*cmd), 0); |
614 | if (ret < 0) { | 708 | if (ret < 0) { |
615 | wl1271_warning("cmd set_template failed: %d", ret); | 709 | wl1271_warning("cmd set_template failed: %d", ret); |
616 | goto out_free; | 710 | goto out_free; |
@@ -623,30 +717,62 @@ out: | |||
623 | return ret; | 717 | return ret; |
624 | } | 718 | } |
625 | 719 | ||
626 | static int wl1271_build_basic_rates(char *rates) | 720 | static int wl1271_build_basic_rates(u8 *rates, u8 band) |
627 | { | 721 | { |
628 | u8 index = 0; | 722 | u8 index = 0; |
629 | 723 | ||
630 | rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; | 724 | if (band == IEEE80211_BAND_2GHZ) { |
631 | rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; | 725 | rates[index++] = |
632 | rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; | 726 | IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; |
633 | rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; | 727 | rates[index++] = |
728 | IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; | ||
729 | rates[index++] = | ||
730 | IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; | ||
731 | rates[index++] = | ||
732 | IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; | ||
733 | } else if (band == IEEE80211_BAND_5GHZ) { | ||
734 | rates[index++] = | ||
735 | IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_6MB; | ||
736 | rates[index++] = | ||
737 | IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_12MB; | ||
738 | rates[index++] = | ||
739 | IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB; | ||
740 | } else { | ||
741 | wl1271_error("build_basic_rates invalid band: %d", band); | ||
742 | } | ||
634 | 743 | ||
635 | return index; | 744 | return index; |
636 | } | 745 | } |
637 | 746 | ||
638 | static int wl1271_build_extended_rates(char *rates) | 747 | static int wl1271_build_extended_rates(u8 *rates, u8 band) |
639 | { | 748 | { |
640 | u8 index = 0; | 749 | u8 index = 0; |
641 | 750 | ||
642 | rates[index++] = IEEE80211_OFDM_RATE_6MB; | 751 | if (band == IEEE80211_BAND_2GHZ) { |
643 | rates[index++] = IEEE80211_OFDM_RATE_9MB; | 752 | rates[index++] = IEEE80211_OFDM_RATE_6MB; |
644 | rates[index++] = IEEE80211_OFDM_RATE_12MB; | 753 | rates[index++] = IEEE80211_OFDM_RATE_9MB; |
645 | rates[index++] = IEEE80211_OFDM_RATE_18MB; | 754 | rates[index++] = IEEE80211_OFDM_RATE_12MB; |
646 | rates[index++] = IEEE80211_OFDM_RATE_24MB; | 755 | rates[index++] = IEEE80211_OFDM_RATE_18MB; |
647 | rates[index++] = IEEE80211_OFDM_RATE_36MB; | 756 | rates[index++] = IEEE80211_OFDM_RATE_24MB; |
648 | rates[index++] = IEEE80211_OFDM_RATE_48MB; | 757 | rates[index++] = IEEE80211_OFDM_RATE_36MB; |
649 | rates[index++] = IEEE80211_OFDM_RATE_54MB; | 758 | rates[index++] = IEEE80211_OFDM_RATE_48MB; |
759 | rates[index++] = IEEE80211_OFDM_RATE_54MB; | ||
760 | } else if (band == IEEE80211_BAND_5GHZ) { | ||
761 | rates[index++] = | ||
762 | IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_9MB; | ||
763 | rates[index++] = | ||
764 | IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_18MB; | ||
765 | rates[index++] = | ||
766 | IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB; | ||
767 | rates[index++] = | ||
768 | IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_36MB; | ||
769 | rates[index++] = | ||
770 | IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_48MB; | ||
771 | rates[index++] = | ||
772 | IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_54MB; | ||
773 | } else { | ||
774 | wl1271_error("build_basic_rates invalid band: %d", band); | ||
775 | } | ||
650 | 776 | ||
651 | return index; | 777 | return index; |
652 | } | 778 | } |
@@ -665,7 +791,8 @@ int wl1271_cmd_build_null_data(struct wl1271 *wl) | |||
665 | 791 | ||
666 | memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); | 792 | memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); |
667 | template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | | 793 | template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | |
668 | IEEE80211_STYPE_NULLFUNC); | 794 | IEEE80211_STYPE_NULLFUNC | |
795 | IEEE80211_FCTL_TODS); | ||
669 | 796 | ||
670 | return wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, &template, | 797 | return wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, &template, |
671 | sizeof(template)); | 798 | sizeof(template)); |
@@ -678,7 +805,10 @@ int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid) | |||
678 | 805 | ||
679 | memcpy(template.bssid, wl->bssid, ETH_ALEN); | 806 | memcpy(template.bssid, wl->bssid, ETH_ALEN); |
680 | memcpy(template.ta, wl->mac_addr, ETH_ALEN); | 807 | memcpy(template.ta, wl->mac_addr, ETH_ALEN); |
681 | template.aid = aid; | 808 | |
809 | /* aid in PS-Poll has its two MSBs each set to 1 */ | ||
810 | template.aid = cpu_to_le16(1 << 15 | 1 << 14 | aid); | ||
811 | |||
682 | template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); | 812 | template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); |
683 | 813 | ||
684 | return wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, &template, | 814 | return wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, &template, |
@@ -686,12 +816,14 @@ int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid) | |||
686 | 816 | ||
687 | } | 817 | } |
688 | 818 | ||
689 | int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len) | 819 | int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len, |
820 | u8 band) | ||
690 | { | 821 | { |
691 | struct wl12xx_probe_req_template template; | 822 | struct wl12xx_probe_req_template template; |
692 | struct wl12xx_ie_rates *rates; | 823 | struct wl12xx_ie_rates *rates; |
693 | char *ptr; | 824 | char *ptr; |
694 | u16 size; | 825 | u16 size; |
826 | int ret; | ||
695 | 827 | ||
696 | ptr = (char *)&template; | 828 | ptr = (char *)&template; |
697 | size = sizeof(struct ieee80211_header); | 829 | size = sizeof(struct ieee80211_header); |
@@ -713,20 +845,25 @@ int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len) | |||
713 | /* Basic Rates */ | 845 | /* Basic Rates */ |
714 | rates = (struct wl12xx_ie_rates *)ptr; | 846 | rates = (struct wl12xx_ie_rates *)ptr; |
715 | rates->header.id = WLAN_EID_SUPP_RATES; | 847 | rates->header.id = WLAN_EID_SUPP_RATES; |
716 | rates->header.len = wl1271_build_basic_rates(rates->rates); | 848 | rates->header.len = wl1271_build_basic_rates(rates->rates, band); |
717 | size += sizeof(struct wl12xx_ie_header) + rates->header.len; | 849 | size += sizeof(struct wl12xx_ie_header) + rates->header.len; |
718 | ptr += sizeof(struct wl12xx_ie_header) + rates->header.len; | 850 | ptr += sizeof(struct wl12xx_ie_header) + rates->header.len; |
719 | 851 | ||
720 | /* Extended rates */ | 852 | /* Extended rates */ |
721 | rates = (struct wl12xx_ie_rates *)ptr; | 853 | rates = (struct wl12xx_ie_rates *)ptr; |
722 | rates->header.id = WLAN_EID_EXT_SUPP_RATES; | 854 | rates->header.id = WLAN_EID_EXT_SUPP_RATES; |
723 | rates->header.len = wl1271_build_extended_rates(rates->rates); | 855 | rates->header.len = wl1271_build_extended_rates(rates->rates, band); |
724 | size += sizeof(struct wl12xx_ie_header) + rates->header.len; | 856 | size += sizeof(struct wl12xx_ie_header) + rates->header.len; |
725 | 857 | ||
726 | wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size); | 858 | wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size); |
727 | 859 | ||
728 | return wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, | 860 | if (band == IEEE80211_BAND_2GHZ) |
729 | &template, size); | 861 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, |
862 | &template, size); | ||
863 | else | ||
864 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, | ||
865 | &template, size); | ||
866 | return ret; | ||
730 | } | 867 | } |
731 | 868 | ||
732 | int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id) | 869 | int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id) |
@@ -743,10 +880,10 @@ int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id) | |||
743 | } | 880 | } |
744 | 881 | ||
745 | cmd->id = id; | 882 | cmd->id = id; |
746 | cmd->key_action = KEY_SET_ID; | 883 | cmd->key_action = cpu_to_le16(KEY_SET_ID); |
747 | cmd->key_type = KEY_WEP; | 884 | cmd->key_type = KEY_WEP; |
748 | 885 | ||
749 | ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd)); | 886 | ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); |
750 | if (ret < 0) { | 887 | if (ret < 0) { |
751 | wl1271_warning("cmd set_default_wep_key failed: %d", ret); | 888 | wl1271_warning("cmd set_default_wep_key failed: %d", ret); |
752 | goto out; | 889 | goto out; |
@@ -759,7 +896,8 @@ out: | |||
759 | } | 896 | } |
760 | 897 | ||
761 | int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, | 898 | int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, |
762 | u8 key_size, const u8 *key, const u8 *addr) | 899 | u8 key_size, const u8 *key, const u8 *addr, |
900 | u32 tx_seq_32, u16 tx_seq_16) | ||
763 | { | 901 | { |
764 | struct wl1271_cmd_set_keys *cmd; | 902 | struct wl1271_cmd_set_keys *cmd; |
765 | int ret = 0; | 903 | int ret = 0; |
@@ -773,16 +911,18 @@ int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, | |||
773 | if (key_type != KEY_WEP) | 911 | if (key_type != KEY_WEP) |
774 | memcpy(cmd->addr, addr, ETH_ALEN); | 912 | memcpy(cmd->addr, addr, ETH_ALEN); |
775 | 913 | ||
776 | cmd->key_action = action; | 914 | cmd->key_action = cpu_to_le16(action); |
777 | cmd->key_size = key_size; | 915 | cmd->key_size = key_size; |
778 | cmd->key_type = key_type; | 916 | cmd->key_type = key_type; |
779 | 917 | ||
918 | cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16); | ||
919 | cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32); | ||
920 | |||
780 | /* we have only one SSID profile */ | 921 | /* we have only one SSID profile */ |
781 | cmd->ssid_profile = 0; | 922 | cmd->ssid_profile = 0; |
782 | 923 | ||
783 | cmd->id = id; | 924 | cmd->id = id; |
784 | 925 | ||
785 | /* FIXME: this is from wl1251, needs to be checked */ | ||
786 | if (key_type == KEY_TKIP) { | 926 | if (key_type == KEY_TKIP) { |
787 | /* | 927 | /* |
788 | * We get the key in the following form: | 928 | * We get the key in the following form: |
@@ -800,10 +940,10 @@ int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, | |||
800 | 940 | ||
801 | wl1271_dump(DEBUG_CRYPT, "TARGET KEY: ", cmd, sizeof(*cmd)); | 941 | wl1271_dump(DEBUG_CRYPT, "TARGET KEY: ", cmd, sizeof(*cmd)); |
802 | 942 | ||
803 | ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd)); | 943 | ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); |
804 | if (ret < 0) { | 944 | if (ret < 0) { |
805 | wl1271_warning("could not set keys"); | 945 | wl1271_warning("could not set keys"); |
806 | goto out; | 946 | goto out; |
807 | } | 947 | } |
808 | 948 | ||
809 | out: | 949 | out: |
@@ -811,3 +951,34 @@ out: | |||
811 | 951 | ||
812 | return ret; | 952 | return ret; |
813 | } | 953 | } |
954 | |||
955 | int wl1271_cmd_disconnect(struct wl1271 *wl) | ||
956 | { | ||
957 | struct wl1271_cmd_disconnect *cmd; | ||
958 | int ret = 0; | ||
959 | |||
960 | wl1271_debug(DEBUG_CMD, "cmd disconnect"); | ||
961 | |||
962 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
963 | if (!cmd) { | ||
964 | ret = -ENOMEM; | ||
965 | goto out; | ||
966 | } | ||
967 | |||
968 | cmd->rx_config_options = cpu_to_le32(wl->rx_config); | ||
969 | cmd->rx_filter_options = cpu_to_le32(wl->rx_filter); | ||
970 | /* disconnect reason is not used in immediate disconnections */ | ||
971 | cmd->type = DISCONNECT_IMMEDIATE; | ||
972 | |||
973 | ret = wl1271_cmd_send(wl, CMD_DISCONNECT, cmd, sizeof(*cmd), 0); | ||
974 | if (ret < 0) { | ||
975 | wl1271_error("failed to send disconnect command"); | ||
976 | goto out_free; | ||
977 | } | ||
978 | |||
979 | out_free: | ||
980 | kfree(cmd); | ||
981 | |||
982 | out: | ||
983 | return ret; | ||
984 | } | ||