Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
b376704b
Commit
b376704b
authored
May 13, 2011
by
John W. Linville
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'for-linville' of
git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx
parents
1159024d
9439064c
Changes
10
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
728 additions
and
16 deletions
+728
-16
drivers/net/wireless/wl12xx/boot.c
drivers/net/wireless/wl12xx/boot.c
+3
-1
drivers/net/wireless/wl12xx/conf.h
drivers/net/wireless/wl12xx/conf.h
+21
-0
drivers/net/wireless/wl12xx/debugfs.c
drivers/net/wireless/wl12xx/debugfs.c
+1
-0
drivers/net/wireless/wl12xx/event.c
drivers/net/wireless/wl12xx/event.c
+23
-0
drivers/net/wireless/wl12xx/main.c
drivers/net/wireless/wl12xx/main.c
+247
-13
drivers/net/wireless/wl12xx/ps.h
drivers/net/wireless/wl12xx/ps.h
+2
-0
drivers/net/wireless/wl12xx/scan.c
drivers/net/wireless/wl12xx/scan.c
+243
-0
drivers/net/wireless/wl12xx/scan.h
drivers/net/wireless/wl12xx/scan.h
+114
-0
drivers/net/wireless/wl12xx/sdio.c
drivers/net/wireless/wl12xx/sdio.c
+63
-1
drivers/net/wireless/wl12xx/wl12xx.h
drivers/net/wireless/wl12xx/wl12xx.h
+11
-1
No files found.
drivers/net/wireless/wl12xx/boot.c
View file @
b376704b
...
...
@@ -478,7 +478,9 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
DISCONNECT_EVENT_COMPLETE_ID
|
RSSI_SNR_TRIGGER_0_EVENT_ID
|
PSPOLL_DELIVERY_FAILURE_EVENT_ID
|
SOFT_GEMINI_SENSE_EVENT_ID
;
SOFT_GEMINI_SENSE_EVENT_ID
|
PERIODIC_SCAN_REPORT_EVENT_ID
|
PERIODIC_SCAN_COMPLETE_EVENT_ID
;
if
(
wl
->
bss_type
==
BSS_TYPE_AP_BSS
)
wl
->
event_mask
|=
STA_REMOVE_COMPLETE_EVENT_ID
;
...
...
drivers/net/wireless/wl12xx/conf.h
View file @
b376704b
...
...
@@ -1147,6 +1147,26 @@ struct conf_scan_settings {
};
struct
conf_sched_scan_settings
{
/* minimum time to wait on the channel for active scans (in TUs) */
u16
min_dwell_time_active
;
/* maximum time to wait on the channel for active scans (in TUs) */
u16
max_dwell_time_active
;
/* time to wait on the channel for passive scans (in TUs) */
u32
dwell_time_passive
;
/* number of probe requests to send on each channel in active scans */
u8
num_probe_reqs
;
/* RSSI threshold to be used for filtering */
s8
rssi_threshold
;
/* SNR threshold to be used for filtering */
s8
snr_threshold
;
};
/* these are number of channels on the band divided by two, rounded up */
#define CONF_TX_PWR_COMPENSATION_LEN_2 7
#define CONF_TX_PWR_COMPENSATION_LEN_5 18
...
...
@@ -1234,6 +1254,7 @@ struct conf_drv_settings {
struct
conf_pm_config_settings
pm_config
;
struct
conf_roam_trigger_settings
roam_trigger
;
struct
conf_scan_settings
scan
;
struct
conf_sched_scan_settings
sched_scan
;
struct
conf_rf_settings
rf
;
struct
conf_ht_setting
ht
;
struct
conf_memory_settings
mem_wl127x
;
...
...
drivers/net/wireless/wl12xx/debugfs.c
View file @
b376704b
...
...
@@ -377,6 +377,7 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,
DRIVER_STATE_PRINT_HEX
(
platform_quirks
);
DRIVER_STATE_PRINT_HEX
(
chip
.
id
);
DRIVER_STATE_PRINT_STR
(
chip
.
fw_ver_str
);
DRIVER_STATE_PRINT_INT
(
sched_scanning
);
#undef DRIVER_STATE_PRINT_INT
#undef DRIVER_STATE_PRINT_LONG
...
...
drivers/net/wireless/wl12xx/event.c
View file @
b376704b
...
...
@@ -135,6 +135,13 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
/* enable beacon early termination */
ret
=
wl1271_acx_bet_enable
(
wl
,
true
);
if
(
ret
<
0
)
break
;
if
(
wl
->
ps_compl
)
{
complete
(
wl
->
ps_compl
);
wl
->
ps_compl
=
NULL
;
}
break
;
default:
break
;
...
...
@@ -188,6 +195,22 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
wl1271_scan_stm
(
wl
);
}
if
(
vector
&
PERIODIC_SCAN_REPORT_EVENT_ID
)
{
wl1271_debug
(
DEBUG_EVENT
,
"PERIODIC_SCAN_REPORT_EVENT "
"(status 0x%0x)"
,
mbox
->
scheduled_scan_status
);
wl1271_scan_sched_scan_results
(
wl
);
}
if
(
vector
&
PERIODIC_SCAN_COMPLETE_EVENT_ID
)
{
wl1271_debug
(
DEBUG_EVENT
,
"PERIODIC_SCAN_COMPLETE_EVENT "
"(status 0x%0x)"
,
mbox
->
scheduled_scan_status
);
if
(
wl
->
sched_scanning
)
{
wl1271_scan_sched_scan_stop
(
wl
);
ieee80211_sched_scan_stopped
(
wl
->
hw
);
}
}
/* disable dynamic PS when requested by the firmware */
if
(
vector
&
SOFT_GEMINI_SENSE_EVENT_ID
&&
wl
->
bss_type
==
BSS_TYPE_STA_BSS
)
{
...
...
drivers/net/wireless/wl12xx/main.c
View file @
b376704b
...
...
@@ -257,12 +257,16 @@ static struct conf_drv_settings default_conf = {
.
wake_up_event
=
CONF_WAKE_UP_EVENT_DTIM
,
.
listen_interval
=
1
,
.
bcn_filt_mode
=
CONF_BCN_FILT_MODE_ENABLED
,
.
bcn_filt_ie_count
=
1
,
.
bcn_filt_ie_count
=
2
,
.
bcn_filt_ie
=
{
[
0
]
=
{
.
ie
=
WLAN_EID_CHANNEL_SWITCH
,
.
rule
=
CONF_BCN_RULE_PASS_ON_APPEARANCE
,
}
},
[
1
]
=
{
.
ie
=
WLAN_EID_HT_INFORMATION
,
.
rule
=
CONF_BCN_RULE_PASS_ON_CHANGE
,
},
},
.
synch_fail_thold
=
10
,
.
bss_lose_timeout
=
100
,
...
...
@@ -302,6 +306,15 @@ static struct conf_drv_settings default_conf = {
.
max_dwell_time_passive
=
100000
,
.
num_probe_reqs
=
2
,
},
.
sched_scan
=
{
/* sched_scan requires dwell times in TU instead of TU/1000 */
.
min_dwell_time_active
=
8
,
.
max_dwell_time_active
=
30
,
.
dwell_time_passive
=
100
,
.
num_probe_reqs
=
2
,
.
rssi_threshold
=
-
90
,
.
snr_threshold
=
0
,
},
.
rf
=
{
.
tx_per_channel_power_compensation_2
=
{
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
...
...
@@ -975,6 +988,11 @@ static void wl1271_recovery_work(struct work_struct *work)
/* Prevent spurious TX during FW restart */
ieee80211_stop_queues
(
wl
->
hw
);
if
(
wl
->
sched_scanning
)
{
ieee80211_sched_scan_stopped
(
wl
->
hw
);
wl
->
sched_scanning
=
false
;
}
/* reboot the chipset */
__wl1271_op_remove_interface
(
wl
,
false
);
ieee80211_restart_hw
(
wl
->
hw
);
...
...
@@ -1332,6 +1350,150 @@ static struct notifier_block wl1271_dev_notifier = {
.
notifier_call
=
wl1271_dev_notify
,
};
static
int
wl1271_configure_suspend
(
struct
wl1271
*
wl
)
{
int
ret
;
if
(
wl
->
bss_type
!=
BSS_TYPE_STA_BSS
)
return
0
;
mutex_lock
(
&
wl
->
mutex
);
ret
=
wl1271_ps_elp_wakeup
(
wl
);
if
(
ret
<
0
)
goto
out_unlock
;
/* enter psm if needed*/
if
(
!
test_bit
(
WL1271_FLAG_PSM
,
&
wl
->
flags
))
{
DECLARE_COMPLETION_ONSTACK
(
compl
);
wl
->
ps_compl
=
&
compl
;
ret
=
wl1271_ps_set_mode
(
wl
,
STATION_POWER_SAVE_MODE
,
wl
->
basic_rate
,
true
);
if
(
ret
<
0
)
goto
out_sleep
;
/* we must unlock here so we will be able to get events */
wl1271_ps_elp_sleep
(
wl
);
mutex_unlock
(
&
wl
->
mutex
);
ret
=
wait_for_completion_timeout
(
&
compl
,
msecs_to_jiffies
(
WL1271_PS_COMPLETE_TIMEOUT
));
if
(
ret
<=
0
)
{
wl1271_warning
(
"couldn't enter ps mode!"
);
ret
=
-
EBUSY
;
goto
out
;
}
/* take mutex again, and wakeup */
mutex_lock
(
&
wl
->
mutex
);
ret
=
wl1271_ps_elp_wakeup
(
wl
);
if
(
ret
<
0
)
goto
out_unlock
;
}
out_sleep:
wl1271_ps_elp_sleep
(
wl
);
out_unlock:
mutex_unlock
(
&
wl
->
mutex
);
out:
return
ret
;
}
static
void
wl1271_configure_resume
(
struct
wl1271
*
wl
)
{
int
ret
;
if
(
wl
->
bss_type
!=
BSS_TYPE_STA_BSS
)
return
;
mutex_lock
(
&
wl
->
mutex
);
ret
=
wl1271_ps_elp_wakeup
(
wl
);
if
(
ret
<
0
)
goto
out
;
/* exit psm if it wasn't configured */
if
(
!
test_bit
(
WL1271_FLAG_PSM_REQUESTED
,
&
wl
->
flags
))
wl1271_ps_set_mode
(
wl
,
STATION_ACTIVE_MODE
,
wl
->
basic_rate
,
true
);
wl1271_ps_elp_sleep
(
wl
);
out:
mutex_unlock
(
&
wl
->
mutex
);
}
static
int
wl1271_op_suspend
(
struct
ieee80211_hw
*
hw
,
struct
cfg80211_wowlan
*
wow
)
{
struct
wl1271
*
wl
=
hw
->
priv
;
wl1271_debug
(
DEBUG_MAC80211
,
"mac80211 suspend wow=%d"
,
!!
wow
);
wl
->
wow_enabled
=
!!
wow
;
if
(
wl
->
wow_enabled
)
{
int
ret
;
ret
=
wl1271_configure_suspend
(
wl
);
if
(
ret
<
0
)
{
wl1271_warning
(
"couldn't prepare device to suspend"
);
return
ret
;
}
/* flush any remaining work */
wl1271_debug
(
DEBUG_MAC80211
,
"flushing remaining works"
);
flush_delayed_work
(
&
wl
->
scan_complete_work
);
/*
* disable and re-enable interrupts in order to flush
* the threaded_irq
*/
wl1271_disable_interrupts
(
wl
);
/*
* set suspended flag to avoid triggering a new threaded_irq
* work. no need for spinlock as interrupts are disabled.
*/
set_bit
(
WL1271_FLAG_SUSPENDED
,
&
wl
->
flags
);
wl1271_enable_interrupts
(
wl
);
flush_work
(
&
wl
->
tx_work
);
flush_delayed_work
(
&
wl
->
pspoll_work
);
flush_delayed_work
(
&
wl
->
elp_work
);
}
return
0
;
}
static
int
wl1271_op_resume
(
struct
ieee80211_hw
*
hw
)
{
struct
wl1271
*
wl
=
hw
->
priv
;
wl1271_debug
(
DEBUG_MAC80211
,
"mac80211 resume wow=%d"
,
wl
->
wow_enabled
);
/*
* re-enable irq_work enqueuing, and call irq_work directly if
* there is a pending work.
*/
if
(
wl
->
wow_enabled
)
{
struct
wl1271
*
wl
=
hw
->
priv
;
unsigned
long
flags
;
bool
run_irq_work
=
false
;
spin_lock_irqsave
(
&
wl
->
wl_lock
,
flags
);
clear_bit
(
WL1271_FLAG_SUSPENDED
,
&
wl
->
flags
);
if
(
test_and_clear_bit
(
WL1271_FLAG_PENDING_WORK
,
&
wl
->
flags
))
run_irq_work
=
true
;
spin_unlock_irqrestore
(
&
wl
->
wl_lock
,
flags
);
if
(
run_irq_work
)
{
wl1271_debug
(
DEBUG_MAC80211
,
"run postponed irq_work directly"
);
wl1271_irq
(
0
,
wl
);
wl1271_enable_interrupts
(
wl
);
}
wl1271_configure_resume
(
wl
);
}
return
0
;
}
static
int
wl1271_op_start
(
struct
ieee80211_hw
*
hw
)
{
wl1271_debug
(
DEBUG_MAC80211
,
"mac80211 start"
);
...
...
@@ -1563,6 +1725,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
memset
(
wl
->
ap_hlid_map
,
0
,
sizeof
(
wl
->
ap_hlid_map
));
wl
->
ap_fw_ps_map
=
0
;
wl
->
ap_ps_map
=
0
;
wl
->
sched_scanning
=
false
;
/*
* this is performed after the cancel_work calls and the associated
...
...
@@ -1765,6 +1928,13 @@ static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
wl
->
session_counter
++
;
if
(
wl
->
session_counter
>=
SESSION_COUNTER_MAX
)
wl
->
session_counter
=
0
;
/* The current firmware only supports sched_scan in idle */
if
(
wl
->
sched_scanning
)
{
wl1271_scan_sched_scan_stop
(
wl
);
ieee80211_sched_scan_stopped
(
wl
->
hw
);
}
ret
=
wl1271_dummy_join
(
wl
);
if
(
ret
<
0
)
goto
out
;
...
...
@@ -2317,6 +2487,60 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
return
ret
;
}
static
int
wl1271_op_sched_scan_start
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
,
struct
cfg80211_sched_scan_request
*
req
,
struct
ieee80211_sched_scan_ies
*
ies
)
{
struct
wl1271
*
wl
=
hw
->
priv
;
int
ret
;
wl1271_debug
(
DEBUG_MAC80211
,
"wl1271_op_sched_scan_start"
);
mutex_lock
(
&
wl
->
mutex
);
ret
=
wl1271_ps_elp_wakeup
(
wl
);
if
(
ret
<
0
)
goto
out
;
ret
=
wl1271_scan_sched_scan_config
(
wl
,
req
,
ies
);
if
(
ret
<
0
)
goto
out_sleep
;
ret
=
wl1271_scan_sched_scan_start
(
wl
);
if
(
ret
<
0
)
goto
out_sleep
;
wl
->
sched_scanning
=
true
;
out_sleep:
wl1271_ps_elp_sleep
(
wl
);
out:
mutex_unlock
(
&
wl
->
mutex
);
return
ret
;
}
static
void
wl1271_op_sched_scan_stop
(
struct
ieee80211_hw
*
hw
,
struct
ieee80211_vif
*
vif
)
{
struct
wl1271
*
wl
=
hw
->
priv
;
int
ret
;
wl1271_debug
(
DEBUG_MAC80211
,
"wl1271_op_sched_scan_stop"
);
mutex_lock
(
&
wl
->
mutex
);
ret
=
wl1271_ps_elp_wakeup
(
wl
);
if
(
ret
<
0
)
goto
out
;
wl1271_scan_sched_scan_stop
(
wl
);
wl1271_ps_elp_sleep
(
wl
);
out:
mutex_unlock
(
&
wl
->
mutex
);
}
static
int
wl1271_op_set_frag_threshold
(
struct
ieee80211_hw
*
hw
,
u32
value
)
{
struct
wl1271
*
wl
=
hw
->
priv
;
...
...
@@ -2376,20 +2600,24 @@ static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
static
int
wl1271_ssid_set
(
struct
wl1271
*
wl
,
struct
sk_buff
*
skb
,
int
offset
)
{
u8
*
ptr
=
skb
->
data
+
offset
;
u8
ssid_len
;
const
u8
*
ptr
=
cfg80211_find_ie
(
WLAN_EID_SSID
,
skb
->
data
+
offset
,
skb
->
len
-
offset
);
/* find the location of the ssid in the beacon */
while
(
ptr
<
skb
->
data
+
skb
->
len
)
{
if
(
ptr
[
0
]
==
WLAN_EID_SSID
)
{
wl
->
ssid_len
=
ptr
[
1
];
memcpy
(
wl
->
ssid
,
ptr
+
2
,
wl
->
ssid_len
);
return
0
;
if
(
!
ptr
)
{
wl1271_error
(
"No SSID in IEs!"
);
return
-
ENOENT
;
}
ptr
+=
(
ptr
[
1
]
+
2
);
ssid_len
=
ptr
[
1
];
if
(
ssid_len
>
IEEE80211_MAX_SSID_LEN
)
{
wl1271_error
(
"SSID is too long!"
);
return
-
EINVAL
;
}
wl1271_error
(
"No SSID in IEs!
\n
"
);
return
-
ENOENT
;
wl
->
ssid_len
=
ssid_len
;
memcpy
(
wl
->
ssid
,
ptr
+
2
,
ssid_len
);
return
0
;
}
static
int
wl1271_bss_erp_info_changed
(
struct
wl1271
*
wl
,
...
...
@@ -3422,12 +3650,16 @@ static const struct ieee80211_ops wl1271_ops = {
.
stop
=
wl1271_op_stop
,
.
add_interface
=
wl1271_op_add_interface
,
.
remove_interface
=
wl1271_op_remove_interface
,
.
suspend
=
wl1271_op_suspend
,
.
resume
=
wl1271_op_resume
,
.
config
=
wl1271_op_config
,
.
prepare_multicast
=
wl1271_op_prepare_multicast
,
.
configure_filter
=
wl1271_op_configure_filter
,
.
tx
=
wl1271_op_tx
,
.
set_key
=
wl1271_op_set_key
,
.
hw_scan
=
wl1271_op_hw_scan
,
.
sched_scan_start
=
wl1271_op_sched_scan_start
,
.
sched_scan_stop
=
wl1271_op_sched_scan_stop
,
.
bss_info_changed
=
wl1271_op_bss_info_changed
,
.
set_frag_threshold
=
wl1271_op_set_frag_threshold
,
.
set_rts_threshold
=
wl1271_op_set_rts_threshold
,
...
...
@@ -3626,6 +3858,7 @@ int wl1271_init_ieee80211(struct wl1271 *wl)
IEEE80211_HW_CONNECTION_MONITOR
|
IEEE80211_HW_SUPPORTS_CQM_RSSI
|
IEEE80211_HW_REPORTS_TX_ACK_STATUS
|
IEEE80211_HW_SPECTRUM_MGMT
|
IEEE80211_HW_AP_LINK_PS
;
wl
->
hw
->
wiphy
->
cipher_suites
=
cipher_suites
;
...
...
@@ -3747,6 +3980,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
wl
->
ap_fw_ps_map
=
0
;
wl
->
quirks
=
0
;
wl
->
platform_quirks
=
0
;
wl
->
sched_scanning
=
false
;
memset
(
wl
->
tx_frames_map
,
0
,
sizeof
(
wl
->
tx_frames_map
));
for
(
i
=
0
;
i
<
ACX_TX_DESCRIPTORS
;
i
++
)
...
...
drivers/net/wireless/wl12xx/ps.h
View file @
b376704b
...
...
@@ -35,4 +35,6 @@ void wl1271_elp_work(struct work_struct *work);
void
wl1271_ps_link_start
(
struct
wl1271
*
wl
,
u8
hlid
,
bool
clean_queues
);
void
wl1271_ps_link_end
(
struct
wl1271
*
wl
,
u8
hlid
);
#define WL1271_PS_COMPLETE_TIMEOUT 500
#endif
/* __WL1271_PS_H__ */
drivers/net/wireless/wl12xx/scan.c
View file @
b376704b
...
...
@@ -320,3 +320,246 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
return
0
;
}
static
int
wl1271_scan_get_sched_scan_channels
(
struct
wl1271
*
wl
,
struct
cfg80211_sched_scan_request
*
req
,
struct
conn_scan_ch_params
*
channels
,
u32
band
,
bool
radar
,
bool
passive
,
int
start
)
{
struct
conf_sched_scan_settings
*
c
=
&
wl
->
conf
.
sched_scan
;
int
i
,
j
;
u32
flags
;
for
(
i
=
0
,
j
=
start
;
i
<
req
->
n_channels
&&
j
<
MAX_CHANNELS_ALL_BANDS
;
i
++
)
{
flags
=
req
->
channels
[
i
]
->
flags
;
if
(
!
(
flags
&
IEEE80211_CHAN_DISABLED
)
&&
((
flags
&
IEEE80211_CHAN_PASSIVE_SCAN
)
==
passive
)
&&
((
flags
&
IEEE80211_CHAN_RADAR
)
==
radar
)
&&
(
req
->
channels
[
i
]
->
band
==
band
))
{
wl1271_debug
(
DEBUG_SCAN
,
"band %d, center_freq %d "
,
req
->
channels
[
i
]
->
band
,
req
->
channels
[
i
]
->
center_freq
);
wl1271_debug
(
DEBUG_SCAN
,
"hw_value %d, flags %X"
,
req
->
channels
[
i
]
->
hw_value
,
req
->
channels
[
i
]
->
flags
);
wl1271_debug
(
DEBUG_SCAN
,
"max_power %d"
,
req
->
channels
[
i
]
->
max_power
);
if
(
flags
&
IEEE80211_CHAN_PASSIVE_SCAN
)
{
channels
[
j
].
passive_duration
=
cpu_to_le16
(
c
->
dwell_time_passive
);
}
else
{
channels
[
j
].
min_duration
=
cpu_to_le16
(
c
->
min_dwell_time_active
);
channels
[
j
].
max_duration
=
cpu_to_le16
(
c
->
max_dwell_time_active
);
}
channels
[
j
].
tx_power_att
=
req
->
channels
[
j
]
->
max_power
;
channels
[
j
].
channel
=
req
->
channels
[
i
]
->
hw_value
;
j
++
;
}
}
return
j
-
start
;
}
static
int
wl1271_scan_sched_scan_channels
(
struct
wl1271
*
wl
,
struct
cfg80211_sched_scan_request
*
req
,
struct
wl1271_cmd_sched_scan_config
*
cfg
)
{
int
idx
=
0
;
cfg
->
passive
[
0
]
=
wl1271_scan_get_sched_scan_channels
(
wl
,
req
,
cfg
->
channels
,
IEEE80211_BAND_2GHZ
,
false
,
true
,
idx
);
idx
+=
cfg
->
passive
[
0
];
cfg
->
active
[
0
]
=
wl1271_scan_get_sched_scan_channels
(
wl
,
req
,
cfg
->
channels
,
IEEE80211_BAND_2GHZ
,
false
,
false
,
idx
);
idx
+=
cfg
->
active
[
0
];
cfg
->
passive
[
1
]
=
wl1271_scan_get_sched_scan_channels
(
wl
,
req
,
cfg
->
channels
,
IEEE80211_BAND_5GHZ
,
false
,
true
,
idx
);
idx
+=
cfg
->
passive
[
1
];
cfg
->
active
[
1
]
=
wl1271_scan_get_sched_scan_channels
(
wl
,
req
,
cfg
->
channels
,
IEEE80211_BAND_5GHZ
,
false
,
false
,
14
);
idx
+=
cfg
->
active
[
1
];
cfg
->
dfs
=
wl1271_scan_get_sched_scan_channels
(
wl
,
req
,
cfg
->
channels
,
IEEE80211_BAND_5GHZ
,
true
,
false
,
idx
);
idx
+=
cfg
->
dfs
;
wl1271_debug
(
DEBUG_SCAN
,
" 2.4GHz: active %d passive %d"
,
cfg
->
active
[
0
],
cfg
->
passive
[
0
]);
wl1271_debug
(
DEBUG_SCAN
,
" 5GHz: active %d passive %d"
,
cfg
->
active
[
1
],
cfg
->
passive
[
1
]);
return
idx
;
}
int
wl1271_scan_sched_scan_config
(
struct
wl1271
*
wl
,
struct
cfg80211_sched_scan_request
*
req
,
struct
ieee80211_sched_scan_ies
*
ies
)
{
struct
wl1271_cmd_sched_scan_config
*
cfg
=
NULL
;
struct
conf_sched_scan_settings
*
c
=
&
wl
->
conf
.
sched_scan
;
int
i
,
total_channels
,
ret
;
wl1271_debug
(
DEBUG_CMD
,
"cmd sched_scan scan config"
);
cfg
=
kzalloc
(
sizeof
(
*
cfg
),
GFP_KERNEL
);
if
(
!
cfg
)
return
-
ENOMEM
;
cfg
->
rssi_threshold
=
c
->
rssi_threshold
;
cfg
->
snr_threshold
=
c
->
snr_threshold
;
cfg
->
n_probe_reqs
=
c
->
num_probe_reqs
;
/* cycles set to 0 it means infinite (until manually stopped) */
cfg
->
cycles
=
0
;
/* report APs when at least 1 is found */
cfg
->
report_after
=
1
;
/* don't stop scanning automatically when something is found */
cfg
->
terminate
=
0
;
cfg
->
tag
=
WL1271_SCAN_DEFAULT_TAG
;
/* don't filter on BSS type */
cfg
->
bss_type
=
SCAN_BSS_TYPE_ANY
;
/* currently NL80211 supports only a single interval */
for
(
i
=
0
;
i
<
SCAN_MAX_CYCLE_INTERVALS
;
i
++
)
cfg
->
intervals
[
i
]
=
cpu_to_le32
(
req
->
interval
);
if
(
req
->
ssids
[
0
].
ssid_len
&&
req
->
ssids
[
0
].
ssid
)
{
cfg
->
filter_type
=
SCAN_SSID_FILTER_SPECIFIC
;
cfg
->
ssid_len
=
req
->
ssids
[
0
].
ssid_len
;
memcpy
(
cfg
->
ssid
,
req
->
ssids
[
0
].
ssid
,
req
->
ssids
[
0
].
ssid_len
);
}
else
{
cfg
->
filter_type
=
SCAN_SSID_FILTER_ANY
;
cfg
->
ssid_len
=
0
;
}
total_channels
=
wl1271_scan_sched_scan_channels
(
wl
,
req
,
cfg
);
if
(
total_channels
==
0
)
{
wl1271_error
(
"scan channel list is empty"
);
ret
=
-
EINVAL
;
goto
out
;
}
if
(
cfg
->
active
[
0
])
{
ret
=
wl1271_cmd_build_probe_req
(
wl
,
req
->
ssids
[
0
].
ssid
,
req
->
ssids
[
0
].
ssid_len
,
ies
->
ie
[
IEEE80211_BAND_2GHZ
],
ies
->
len
[
IEEE80211_BAND_2GHZ
],
IEEE80211_BAND_2GHZ
);
if
(
ret
<
0
)
{
wl1271_error
(
"2.4GHz PROBE request template failed"
);
goto
out
;
}
}
if
(
cfg
->
active
[
1
])
{
ret
=
wl1271_cmd_build_probe_req
(
wl
,
req
->
ssids
[
0
].
ssid
,
req
->
ssids
[
0
].
ssid_len
,
ies
->
ie
[
IEEE80211_BAND_5GHZ
],
ies
->
len
[
IEEE80211_BAND_5GHZ
],
IEEE80211_BAND_5GHZ
);
if
(
ret
<
0
)
{
wl1271_error
(
"5GHz PROBE request template failed"
);
goto
out
;
}
}
wl1271_dump
(
DEBUG_SCAN
,
"SCAN_CFG: "
,
cfg
,
sizeof
(
*
cfg
));
ret
=
wl1271_cmd_send
(
wl
,
CMD_CONNECTION_SCAN_CFG
,
cfg
,
sizeof
(
*
cfg
),
0
);
if
(
ret
<
0
)
{
wl1271_error
(
"SCAN configuration failed"
);
goto
out
;
}
out:
kfree
(
cfg
);
return
ret
;
}
int
wl1271_scan_sched_scan_start
(
struct
wl1271
*
wl
)
{
struct
wl1271_cmd_sched_scan_start
*
start
;
int
ret
=
0
;
wl1271_debug
(
DEBUG_CMD
,
"cmd periodic scan start"
);
if
(
wl
->
bss_type
!=
BSS_TYPE_STA_BSS
)
return
-
EOPNOTSUPP
;
if
(
!
test_bit
(
WL1271_FLAG_IDLE
,
&
wl
->
flags
))
return
-
EBUSY
;
start
=
kzalloc
(
sizeof
(
*
start
),
GFP_KERNEL
);
if
(
!
start
)
return
-
ENOMEM
;
start
->
tag
=
WL1271_SCAN_DEFAULT_TAG
;
ret
=
wl1271_cmd_send
(
wl
,
CMD_START_PERIODIC_SCAN
,
start
,
sizeof
(
*
start
),
0
);
if
(
ret
<
0
)
{
wl1271_error
(
"failed to send scan start command"
);
goto
out_free
;
}
out_free:
kfree
(
start
);
return
ret
;
}
void
wl1271_scan_sched_scan_results
(
struct
wl1271
*
wl
)
{
wl1271_debug
(
DEBUG_SCAN
,
"got periodic scan results"
);
ieee80211_sched_scan_results
(
wl
->
hw
);
}
void
wl1271_scan_sched_scan_stop
(
struct
wl1271
*
wl
)
{
struct
wl1271_cmd_sched_scan_stop
*
stop
;
int
ret
=
0
;
wl1271_debug
(
DEBUG_CMD
,
"cmd periodic scan stop"
);
/* FIXME: what to do if alloc'ing to stop fails? */
stop
=
kzalloc
(
sizeof
(
*
stop
),
GFP_KERNEL
);
if
(
!
stop
)
{
wl1271_error
(
"failed to alloc memory to send sched scan stop"
);
return
;
}
stop
->
tag
=
WL1271_SCAN_DEFAULT_TAG
;
ret
=
wl1271_cmd_send
(
wl
,
CMD_STOP_PERIODIC_SCAN
,
stop
,
sizeof
(
*
stop
),
0
);
if
(
ret
<
0
)
{
wl1271_error
(
"failed to send sched scan stop command"
);
goto
out_free
;
}
wl
->
sched_scanning
=
false
;
out_free:
kfree
(
stop
);
}
drivers/net/wireless/wl12xx/scan.h
View file @
b376704b
...
...
@@ -33,6 +33,12 @@ int wl1271_scan_build_probe_req(struct wl1271 *wl,
const
u8
*
ie
,
size_t
ie_len
,
u8
band
);
void
wl1271_scan_stm
(
struct
wl1271
*
wl
);
void
wl1271_scan_complete_work
(
struct
work_struct
*
work
);
int
wl1271_scan_sched_scan_config
(
struct
wl1271
*
wl
,
struct
cfg80211_sched_scan_request
*
req
,
struct
ieee80211_sched_scan_ies
*
ies
);
int
wl1271_scan_sched_scan_start
(
struct
wl1271
*
wl
);
void
wl1271_scan_sched_scan_stop
(
struct
wl1271
*
wl
);
void
wl1271_scan_sched_scan_results
(
struct
wl1271
*
wl
);
#define WL1271_SCAN_MAX_CHANNELS 24
#define WL1271_SCAN_DEFAULT_TAG 1
...
...
@@ -106,4 +112,112 @@ struct wl1271_cmd_trigger_scan_to {
__le32
timeout
;
}
__packed
;
#define MAX_CHANNELS_ALL_BANDS 41
#define SCAN_MAX_CYCLE_INTERVALS 16
#define SCAN_MAX_BANDS 3
enum
{
SCAN_CHANNEL_TYPE_2GHZ_PASSIVE
,
SCAN_CHANNEL_TYPE_2GHZ_ACTIVE
,
SCAN_CHANNEL_TYPE_5GHZ_PASSIVE
,
SCAN_CHANNEL_TYPE_5GHZ_ACTIVE
,
SCAN_CHANNEL_TYPE_5GHZ_DFS
,
};
enum
{
SCAN_SSID_FILTER_ANY
=
0
,
SCAN_SSID_FILTER_SPECIFIC
=
1
,
SCAN_SSID_FILTER_LIST
=
2
,
SCAN_SSID_FILTER_DISABLED
=
3
};
enum
{
SCAN_BSS_TYPE_INDEPENDENT
,
SCAN_BSS_TYPE_INFRASTRUCTURE
,
SCAN_BSS_TYPE_ANY
,
};
struct
conn_scan_ch_params
{
__le16
min_duration
;
__le16
max_duration
;
__le16
passive_duration
;
u8
channel
;
u8
tx_power_att
;
/* bit 0: DFS channel; bit 1: DFS enabled */
u8
flags
;
u8
padding
[
3
];
}
__packed
;
struct
wl1271_cmd_sched_scan_config
{
struct
wl1271_cmd_header
header
;
__le32
intervals
[
SCAN_MAX_CYCLE_INTERVALS
];
s8
rssi_threshold
;
/* for filtering (in dBm) */
s8
snr_threshold
;
/* for filtering (in dB) */
u8
cycles
;
/* maximum number of scan cycles */
u8
report_after
;
/* report when this number of results are received */
u8
terminate
;
/* stop scanning after reporting */
u8
tag
;
u8
bss_type
;
/* for filtering */
u8
filter_type
;
u8
ssid_len
;
/* For SCAN_SSID_FILTER_SPECIFIC */
u8
ssid
[
IW_ESSID_MAX_SIZE
];
u8
n_probe_reqs
;
/* Number of probes requests per channel */
u8
passive
[
SCAN_MAX_BANDS
];
u8
active
[
SCAN_MAX_BANDS
];
u8
dfs
;
u8
padding
[
3
];
struct
conn_scan_ch_params
channels
[
MAX_CHANNELS_ALL_BANDS
];
}
__packed
;
#define SCHED_SCAN_MAX_SSIDS 8
enum
{
SCAN_SSID_TYPE_PUBLIC
=
0
,
SCAN_SSID_TYPE_HIDDEN
=
1
,
};
struct
wl1271_ssid
{
u8
type
;
u8
len
;
u8
ssid
[
IW_ESSID_MAX_SIZE
];
/* u8 padding[2]; */
}
__packed
;
struct
wl1271_cmd_sched_scan_ssid_list
{
struct
wl1271_cmd_header
header
;
u8
n_ssids
;
struct
wl1271_ssid
ssids
[
SCHED_SCAN_MAX_SSIDS
];
u8
padding
[
3
];
}
__packed
;
struct
wl1271_cmd_sched_scan_start
{
struct
wl1271_cmd_header
header
;
u8
tag
;
u8
padding
[
3
];
}
__packed
;
struct
wl1271_cmd_sched_scan_stop
{
struct
wl1271_cmd_header
header
;
u8
tag
;
u8
padding
[
3
];
}
__packed
;
#endif
/* __WL1271_SCAN_H__ */
drivers/net/wireless/wl12xx/sdio.c
View file @
b376704b
...
...
@@ -82,6 +82,16 @@ static irqreturn_t wl1271_hardirq(int irq, void *cookie)
complete
(
wl
->
elp_compl
);
wl
->
elp_compl
=
NULL
;
}
if
(
test_bit
(
WL1271_FLAG_SUSPENDED
,
&
wl
->
flags
))
{
/* don't enqueue a work right now. mark it as pending */
set_bit
(
WL1271_FLAG_PENDING_WORK
,
&
wl
->
flags
);
wl1271_debug
(
DEBUG_IRQ
,
"should not enqueue work"
);
disable_irq_nosync
(
wl
->
irq
);
pm_wakeup_event
(
wl1271_sdio_wl_to_dev
(
wl
),
0
);
spin_unlock_irqrestore
(
&
wl
->
wl_lock
,
flags
);
return
IRQ_HANDLED
;
}
spin_unlock_irqrestore
(
&
wl
->
wl_lock
,
flags
);
return
IRQ_WAKE_THREAD
;
...
...
@@ -221,6 +231,7 @@ static int __devinit wl1271_probe(struct sdio_func *func,
const
struct
wl12xx_platform_data
*
wlan_data
;
struct
wl1271
*
wl
;
unsigned
long
irqflags
;
mmc_pm_flag_t
mmcflags
;
int
ret
;
/* We are only able to handle the wlan function */
...
...
@@ -267,8 +278,18 @@ static int __devinit wl1271_probe(struct sdio_func *func,
goto
out_free
;
}
enable_irq_wake
(
wl
->
irq
);
device_init_wakeup
(
wl1271_sdio_wl_to_dev
(
wl
),
1
);
disable_irq
(
wl
->
irq
);
/* if sdio can keep power while host is suspended, enable wow */
mmcflags
=
sdio_get_host_pm_caps
(
func
);
wl1271_debug
(
DEBUG_SDIO
,
"sdio PM caps = 0x%x"
,
mmcflags
);
if
(
mmcflags
&
MMC_PM_KEEP_POWER
)
hw
->
wiphy
->
wowlan
.
flags
=
WIPHY_WOWLAN_ANY
;
ret
=
wl1271_init_ieee80211
(
wl
);
if
(
ret
)
goto
out_irq
;
...
...
@@ -303,6 +324,8 @@ static void __devexit wl1271_remove(struct sdio_func *func)
pm_runtime_get_noresume
(
&
func
->
dev
);
wl1271_unregister_hw
(
wl
);
device_init_wakeup
(
wl1271_sdio_wl_to_dev
(
wl
),
0
);
disable_irq_wake
(
wl
->
irq
);
free_irq
(
wl
->
irq
,
wl
);
wl1271_free_hw
(
wl
);
}
...
...
@@ -311,11 +334,50 @@ static int wl1271_suspend(struct device *dev)
{
/* Tell MMC/SDIO core it's OK to power down the card
* (if it isn't already), but not to remove it completely */
return
0
;
struct
sdio_func
*
func
=
dev_to_sdio_func
(
dev
);
struct
wl1271
*
wl
=
sdio_get_drvdata
(
func
);
mmc_pm_flag_t
sdio_flags
;
int
ret
=
0
;
wl1271_debug
(
DEBUG_MAC80211
,
"wl1271 suspend. wow_enabled: %d"
,
wl
->
wow_enabled
);
/* check whether sdio should keep power */
if
(
wl
->
wow_enabled
)
{
sdio_flags
=
sdio_get_host_pm_caps
(
func
);
if
(
!
(
sdio_flags
&
MMC_PM_KEEP_POWER
))
{
wl1271_error
(
"can't keep power while host "
"is suspended"
);
ret
=
-
EINVAL
;
goto
out
;
}
/* keep power while host suspended */
ret
=
sdio_set_host_pm_flags
(
func
,
MMC_PM_KEEP_POWER
);
if
(
ret
)
{
wl1271_error
(
"error while trying to keep power"
);
goto
out
;
}
/* release host */
sdio_release_host
(
func
);
}
out:
return
ret
;
}
static
int
wl1271_resume
(
struct
device
*
dev
)
{
struct
sdio_func
*
func
=
dev_to_sdio_func
(
dev
);
struct
wl1271
*
wl
=
sdio_get_drvdata
(
func
);
wl1271_debug
(
DEBUG_MAC80211
,
"wl1271 resume"
);
if
(
wl
->
wow_enabled
)
{
/* claim back host */
sdio_claim_host
(
func
);
}
return
0
;
}
...
...
drivers/net/wireless/wl12xx/wl12xx.h
View file @
b376704b
...
...
@@ -351,13 +351,14 @@ enum wl12xx_flags {
WL1271_FLAG_PSM_REQUESTED
,
WL1271_FLAG_IRQ_RUNNING
,
WL1271_FLAG_IDLE
,
WL1271_FLAG_IDLE_REQUESTED
,
WL1271_FLAG_PSPOLL_FAILURE
,
WL1271_FLAG_STA_STATE_SENT
,
WL1271_FLAG_FW_TX_BUSY
,
WL1271_FLAG_AP_STARTED
,
WL1271_FLAG_IF_INITIALIZED
,
WL1271_FLAG_DUMMY_PACKET_PENDING
,
WL1271_FLAG_SUSPENDED
,
WL1271_FLAG_PENDING_WORK
,
};
struct
wl1271_link
{
...
...
@@ -480,6 +481,8 @@ struct wl1271 {
struct
wl1271_scan
scan
;
struct
delayed_work
scan_complete_work
;
bool
sched_scanning
;
/* probe-req template for the current AP */
struct
sk_buff
*
probereq
;
...
...
@@ -510,6 +513,7 @@ struct wl1271 {
unsigned
int
rx_filter
;
struct
completion
*
elp_compl
;
struct
completion
*
ps_compl
;
struct
delayed_work
elp_work
;
struct
delayed_work
pspoll_work
;
...
...
@@ -563,6 +567,12 @@ struct wl1271 {
int
tcxo_clock
;
/*
* wowlan trigger was configured during suspend.
* (currently, only "ANY" trigger is supported)
*/
bool
wow_enabled
;
/*
* AP-mode - links indexed by HLID. The global and broadcast links
* are always active.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment