diff options
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_cmd.c | 82 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_cmd.h | 17 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_main.c | 125 |
3 files changed, 117 insertions, 107 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index 770f260726bd..fcbfbd7585f8 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c | |||
@@ -410,3 +410,85 @@ out: | |||
410 | kfree(cmd); | 410 | kfree(cmd); |
411 | return ret; | 411 | return ret; |
412 | } | 412 | } |
413 | |||
414 | int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len, | ||
415 | unsigned int n_channels, unsigned int n_probes) | ||
416 | { | ||
417 | struct wl1251_cmd_scan *cmd; | ||
418 | int i, ret = 0; | ||
419 | |||
420 | wl1251_debug(DEBUG_CMD, "cmd scan"); | ||
421 | |||
422 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
423 | if (!cmd) | ||
424 | return -ENOMEM; | ||
425 | |||
426 | cmd->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); | ||
427 | cmd->params.rx_filter_options = cpu_to_le32(CFG_RX_PRSP_EN | | ||
428 | CFG_RX_MGMT_EN | | ||
429 | CFG_RX_BCN_EN); | ||
430 | cmd->params.scan_options = 0; | ||
431 | cmd->params.num_channels = n_channels; | ||
432 | cmd->params.num_probe_requests = n_probes; | ||
433 | cmd->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */ | ||
434 | cmd->params.tid_trigger = 0; | ||
435 | |||
436 | for (i = 0; i < n_channels; i++) { | ||
437 | cmd->channels[i].min_duration = | ||
438 | cpu_to_le32(WL1251_SCAN_MIN_DURATION); | ||
439 | cmd->channels[i].max_duration = | ||
440 | cpu_to_le32(WL1251_SCAN_MAX_DURATION); | ||
441 | memset(&cmd->channels[i].bssid_lsb, 0xff, 4); | ||
442 | memset(&cmd->channels[i].bssid_msb, 0xff, 2); | ||
443 | cmd->channels[i].early_termination = 0; | ||
444 | cmd->channels[i].tx_power_att = 0; | ||
445 | cmd->channels[i].channel = i + 1; | ||
446 | } | ||
447 | |||
448 | cmd->params.ssid_len = ssid_len; | ||
449 | if (ssid) | ||
450 | memcpy(cmd->params.ssid, ssid, ssid_len); | ||
451 | |||
452 | ret = wl1251_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd)); | ||
453 | if (ret < 0) { | ||
454 | wl1251_error("cmd scan failed: %d", ret); | ||
455 | goto out; | ||
456 | } | ||
457 | |||
458 | wl1251_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); | ||
459 | |||
460 | if (cmd->header.status != CMD_STATUS_SUCCESS) { | ||
461 | wl1251_error("cmd scan status wasn't success: %d", | ||
462 | cmd->header.status); | ||
463 | ret = -EIO; | ||
464 | goto out; | ||
465 | } | ||
466 | |||
467 | out: | ||
468 | kfree(cmd); | ||
469 | return ret; | ||
470 | } | ||
471 | |||
472 | int wl1251_cmd_trigger_scan_to(struct wl1251 *wl, u32 timeout) | ||
473 | { | ||
474 | struct wl1251_cmd_trigger_scan_to *cmd; | ||
475 | int ret; | ||
476 | |||
477 | wl1251_debug(DEBUG_CMD, "cmd trigger scan to"); | ||
478 | |||
479 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
480 | if (!cmd) | ||
481 | return -ENOMEM; | ||
482 | |||
483 | cmd->timeout = timeout; | ||
484 | |||
485 | ret = wl1251_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd)); | ||
486 | if (ret < 0) { | ||
487 | wl1251_error("cmd trigger scan to failed: %d", ret); | ||
488 | goto out; | ||
489 | } | ||
490 | |||
491 | out: | ||
492 | kfree(cmd); | ||
493 | return ret; | ||
494 | } | ||
diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.h b/drivers/net/wireless/wl12xx/wl1251_cmd.h index dff798ad0ef5..63ae3193f7c6 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.h | |||
@@ -43,6 +43,9 @@ int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, | |||
43 | size_t len); | 43 | size_t len); |
44 | int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id, | 44 | int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id, |
45 | void *buf, size_t buf_len); | 45 | void *buf, size_t buf_len); |
46 | int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len, | ||
47 | unsigned int n_channels, unsigned int n_probes); | ||
48 | int wl1251_cmd_trigger_scan_to(struct wl1251 *wl, u32 timeout); | ||
46 | 49 | ||
47 | /* unit ms */ | 50 | /* unit ms */ |
48 | #define WL1251_COMMAND_TIMEOUT 2000 | 51 | #define WL1251_COMMAND_TIMEOUT 2000 |
@@ -163,8 +166,10 @@ struct cmd_read_write_memory { | |||
163 | #define CMDMBOX_HEADER_LEN 4 | 166 | #define CMDMBOX_HEADER_LEN 4 |
164 | #define CMDMBOX_INFO_ELEM_HEADER_LEN 4 | 167 | #define CMDMBOX_INFO_ELEM_HEADER_LEN 4 |
165 | 168 | ||
169 | #define WL1251_SCAN_MIN_DURATION 30000 | ||
170 | #define WL1251_SCAN_MAX_DURATION 60000 | ||
166 | 171 | ||
167 | struct basic_scan_parameters { | 172 | struct wl1251_scan_parameters { |
168 | u32 rx_config_options; | 173 | u32 rx_config_options; |
169 | u32 rx_filter_options; | 174 | u32 rx_filter_options; |
170 | 175 | ||
@@ -189,11 +194,11 @@ struct basic_scan_parameters { | |||
189 | 194 | ||
190 | u8 tid_trigger; | 195 | u8 tid_trigger; |
191 | u8 ssid_len; | 196 | u8 ssid_len; |
192 | u32 ssid[8]; | 197 | u8 ssid[32]; |
193 | 198 | ||
194 | } __attribute__ ((packed)); | 199 | } __attribute__ ((packed)); |
195 | 200 | ||
196 | struct basic_scan_channel_parameters { | 201 | struct wl1251_scan_ch_parameters { |
197 | u32 min_duration; /* in TU */ | 202 | u32 min_duration; /* in TU */ |
198 | u32 max_duration; /* in TU */ | 203 | u32 max_duration; /* in TU */ |
199 | u32 bssid_lsb; | 204 | u32 bssid_lsb; |
@@ -213,11 +218,11 @@ struct basic_scan_channel_parameters { | |||
213 | /* SCAN parameters */ | 218 | /* SCAN parameters */ |
214 | #define SCAN_MAX_NUM_OF_CHANNELS 16 | 219 | #define SCAN_MAX_NUM_OF_CHANNELS 16 |
215 | 220 | ||
216 | struct cmd_scan { | 221 | struct wl1251_cmd_scan { |
217 | struct wl1251_cmd_header header; | 222 | struct wl1251_cmd_header header; |
218 | 223 | ||
219 | struct basic_scan_parameters params; | 224 | struct wl1251_scan_parameters params; |
220 | struct basic_scan_channel_parameters channels[SCAN_MAX_NUM_OF_CHANNELS]; | 225 | struct wl1251_scan_ch_parameters channels[SCAN_MAX_NUM_OF_CHANNELS]; |
221 | } __attribute__ ((packed)); | 226 | } __attribute__ ((packed)); |
222 | 227 | ||
223 | enum { | 228 | enum { |
diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 6cce86462fac..e038707294a5 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c | |||
@@ -903,111 +903,13 @@ static int wl1251_build_probe_req(struct wl1251 *wl, u8 *ssid, size_t ssid_len) | |||
903 | size); | 903 | size); |
904 | } | 904 | } |
905 | 905 | ||
906 | static int wl1251_hw_scan(struct wl1251 *wl, u8 *ssid, size_t len, | ||
907 | u8 active_scan, u8 high_prio, u8 num_channels, | ||
908 | u8 probe_requests) | ||
909 | { | ||
910 | struct wl1251_cmd_trigger_scan_to *trigger = NULL; | ||
911 | struct cmd_scan *params = NULL; | ||
912 | int i, ret; | ||
913 | u16 scan_options = 0; | ||
914 | |||
915 | if (wl->scanning) | ||
916 | return -EINVAL; | ||
917 | |||
918 | params = kzalloc(sizeof(*params), GFP_KERNEL); | ||
919 | if (!params) | ||
920 | return -ENOMEM; | ||
921 | |||
922 | params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); | ||
923 | params->params.rx_filter_options = | ||
924 | cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN); | ||
925 | |||
926 | /* High priority scan */ | ||
927 | if (!active_scan) | ||
928 | scan_options |= SCAN_PASSIVE; | ||
929 | if (high_prio) | ||
930 | scan_options |= SCAN_PRIORITY_HIGH; | ||
931 | params->params.scan_options = scan_options; | ||
932 | |||
933 | params->params.num_channels = num_channels; | ||
934 | params->params.num_probe_requests = probe_requests; | ||
935 | params->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */ | ||
936 | params->params.tid_trigger = 0; | ||
937 | |||
938 | for (i = 0; i < num_channels; i++) { | ||
939 | params->channels[i].min_duration = cpu_to_le32(30000); | ||
940 | params->channels[i].max_duration = cpu_to_le32(60000); | ||
941 | memset(¶ms->channels[i].bssid_lsb, 0xff, 4); | ||
942 | memset(¶ms->channels[i].bssid_msb, 0xff, 2); | ||
943 | params->channels[i].early_termination = 0; | ||
944 | params->channels[i].tx_power_att = 0; | ||
945 | params->channels[i].channel = i + 1; | ||
946 | memset(params->channels[i].pad, 0, 3); | ||
947 | } | ||
948 | |||
949 | for (i = num_channels; i < SCAN_MAX_NUM_OF_CHANNELS; i++) | ||
950 | memset(¶ms->channels[i], 0, | ||
951 | sizeof(struct basic_scan_channel_parameters)); | ||
952 | |||
953 | if (len && ssid) { | ||
954 | params->params.ssid_len = len; | ||
955 | memcpy(params->params.ssid, ssid, len); | ||
956 | } else { | ||
957 | params->params.ssid_len = 0; | ||
958 | memset(params->params.ssid, 0, 32); | ||
959 | } | ||
960 | |||
961 | ret = wl1251_build_probe_req(wl, ssid, len); | ||
962 | if (ret < 0) { | ||
963 | wl1251_error("PROBE request template failed"); | ||
964 | goto out; | ||
965 | } | ||
966 | |||
967 | trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); | ||
968 | if (!trigger) | ||
969 | goto out; | ||
970 | |||
971 | trigger->timeout = 0; | ||
972 | |||
973 | ret = wl1251_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, | ||
974 | sizeof(*trigger)); | ||
975 | if (ret < 0) { | ||
976 | wl1251_error("trigger scan to failed for hw scan"); | ||
977 | goto out; | ||
978 | } | ||
979 | |||
980 | wl1251_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); | ||
981 | |||
982 | wl->scanning = true; | ||
983 | |||
984 | ret = wl1251_cmd_send(wl, CMD_SCAN, params, sizeof(*params)); | ||
985 | if (ret < 0) | ||
986 | wl1251_error("SCAN failed"); | ||
987 | |||
988 | wl1251_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); | ||
989 | |||
990 | if (params->header.status != CMD_STATUS_SUCCESS) { | ||
991 | wl1251_error("TEST command answer error: %d", | ||
992 | params->header.status); | ||
993 | wl->scanning = false; | ||
994 | ret = -EIO; | ||
995 | goto out; | ||
996 | } | ||
997 | |||
998 | out: | ||
999 | kfree(params); | ||
1000 | return ret; | ||
1001 | |||
1002 | } | ||
1003 | |||
1004 | static int wl1251_op_hw_scan(struct ieee80211_hw *hw, | 906 | static int wl1251_op_hw_scan(struct ieee80211_hw *hw, |
1005 | struct cfg80211_scan_request *req) | 907 | struct cfg80211_scan_request *req) |
1006 | { | 908 | { |
1007 | struct wl1251 *wl = hw->priv; | 909 | struct wl1251 *wl = hw->priv; |
1008 | int ret; | ||
1009 | u8 *ssid = NULL; | ||
1010 | size_t ssid_len = 0; | 910 | size_t ssid_len = 0; |
911 | u8 *ssid = NULL; | ||
912 | int ret; | ||
1011 | 913 | ||
1012 | wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan"); | 914 | wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan"); |
1013 | 915 | ||
@@ -1018,12 +920,33 @@ static int wl1251_op_hw_scan(struct ieee80211_hw *hw, | |||
1018 | 920 | ||
1019 | mutex_lock(&wl->mutex); | 921 | mutex_lock(&wl->mutex); |
1020 | 922 | ||
923 | if (wl->scanning) { | ||
924 | wl1251_debug(DEBUG_SCAN, "scan already in progress"); | ||
925 | ret = -EINVAL; | ||
926 | goto out; | ||
927 | } | ||
928 | |||
1021 | ret = wl1251_ps_elp_wakeup(wl); | 929 | ret = wl1251_ps_elp_wakeup(wl); |
1022 | if (ret < 0) | 930 | if (ret < 0) |
1023 | goto out; | 931 | goto out; |
1024 | 932 | ||
1025 | ret = wl1251_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3); | 933 | ret = wl1251_build_probe_req(wl, ssid, ssid_len); |
934 | if (ret < 0) | ||
935 | wl1251_error("probe request template build failed"); | ||
936 | |||
937 | ret = wl1251_cmd_trigger_scan_to(wl, 0); | ||
938 | if (ret < 0) | ||
939 | goto out_sleep; | ||
940 | |||
941 | wl->scanning = true; | ||
1026 | 942 | ||
943 | ret = wl1251_cmd_scan(wl, ssid, ssid_len, 13, 3); | ||
944 | if (ret < 0) { | ||
945 | wl->scanning = false; | ||
946 | goto out_sleep; | ||
947 | } | ||
948 | |||
949 | out_sleep: | ||
1027 | wl1251_ps_elp_sleep(wl); | 950 | wl1251_ps_elp_sleep(wl); |
1028 | 951 | ||
1029 | out: | 952 | out: |