mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 05:02:12 +00:00
Merge branch 'for-linville' of git://github.com/kvalo/ath6kl
This commit is contained in:
commit
640f5950a7
@ -1,12 +1,29 @@
|
||||
config ATH6KL
|
||||
tristate "Atheros ath6kl support"
|
||||
tristate "Atheros mobile chipsets support"
|
||||
|
||||
config ATH6KL_SDIO
|
||||
tristate "Atheros ath6kl SDIO support"
|
||||
depends on ATH6KL
|
||||
depends on MMC
|
||||
depends on CFG80211
|
||||
---help---
|
||||
This module adds support for wireless adapters based on
|
||||
Atheros AR6003 chipset running over SDIO. If you choose to
|
||||
build it as a module, it will be called ath6kl. Pls note
|
||||
that AR6002 and AR6001 are not supported by this driver.
|
||||
Atheros AR6003 and AR6004 chipsets running over SDIO. If you
|
||||
choose to build it as a module, it will be called ath6kl_sdio.
|
||||
Please note that AR6002 and AR6001 are not supported by this
|
||||
driver.
|
||||
|
||||
config ATH6KL_USB
|
||||
tristate "Atheros ath6kl USB support"
|
||||
depends on ATH6KL
|
||||
depends on USB
|
||||
depends on CFG80211
|
||||
depends on EXPERIMENTAL
|
||||
---help---
|
||||
This module adds support for wireless adapters based on
|
||||
Atheros AR6004 chipset running over USB. This is still under
|
||||
implementation and it isn't functional. If you choose to
|
||||
build it as a module, it will be called ath6kl_usb.
|
||||
|
||||
config ATH6KL_DEBUG
|
||||
bool "Atheros ath6kl debugging"
|
||||
|
@ -21,17 +21,30 @@
|
||||
# Author(s): ="Atheros"
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
obj-$(CONFIG_ATH6KL) := ath6kl.o
|
||||
ath6kl-y += debug.o
|
||||
ath6kl-y += hif.o
|
||||
ath6kl-y += htc.o
|
||||
ath6kl-y += bmi.o
|
||||
ath6kl-y += cfg80211.o
|
||||
ath6kl-y += init.o
|
||||
ath6kl-y += main.o
|
||||
ath6kl-y += txrx.o
|
||||
ath6kl-y += wmi.o
|
||||
ath6kl-y += sdio.o
|
||||
ath6kl-$(CONFIG_NL80211_TESTMODE) += testmode.o
|
||||
obj-$(CONFIG_ATH6KL_SDIO) := ath6kl_sdio.o
|
||||
ath6kl_sdio-y += debug.o
|
||||
ath6kl_sdio-y += hif.o
|
||||
ath6kl_sdio-y += htc.o
|
||||
ath6kl_sdio-y += bmi.o
|
||||
ath6kl_sdio-y += cfg80211.o
|
||||
ath6kl_sdio-y += init.o
|
||||
ath6kl_sdio-y += main.o
|
||||
ath6kl_sdio-y += txrx.o
|
||||
ath6kl_sdio-y += wmi.o
|
||||
ath6kl_sdio-y += sdio.o
|
||||
ath6kl_sdio-$(CONFIG_NL80211_TESTMODE) += testmode.o
|
||||
|
||||
obj-$(CONFIG_ATH6KL_USB) += ath6kl_usb.o
|
||||
ath6kl_usb-y += debug.o
|
||||
ath6kl_usb-y += hif.o
|
||||
ath6kl_usb-y += htc.o
|
||||
ath6kl_usb-y += bmi.o
|
||||
ath6kl_usb-y += cfg80211.o
|
||||
ath6kl_usb-y += init.o
|
||||
ath6kl_usb-y += main.o
|
||||
ath6kl_usb-y += txrx.o
|
||||
ath6kl_usb-y += wmi.o
|
||||
ath6kl_usb-y += usb.o
|
||||
ath6kl_usb-$(CONFIG_NL80211_TESTMODE) += testmode.o
|
||||
|
||||
ccflags-y += -D__CHECK_ENDIAN__
|
||||
|
@ -19,165 +19,6 @@
|
||||
#include "target.h"
|
||||
#include "debug.h"
|
||||
|
||||
static int ath6kl_get_bmi_cmd_credits(struct ath6kl *ar)
|
||||
{
|
||||
u32 addr;
|
||||
unsigned long timeout;
|
||||
int ret;
|
||||
|
||||
ar->bmi.cmd_credits = 0;
|
||||
|
||||
/* Read the counter register to get the command credits */
|
||||
addr = COUNT_DEC_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 4;
|
||||
|
||||
timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT);
|
||||
while (time_before(jiffies, timeout) && !ar->bmi.cmd_credits) {
|
||||
|
||||
/*
|
||||
* Hit the credit counter with a 4-byte access, the first byte
|
||||
* read will hit the counter and cause a decrement, while the
|
||||
* remaining 3 bytes has no effect. The rationale behind this
|
||||
* is to make all HIF accesses 4-byte aligned.
|
||||
*/
|
||||
ret = hif_read_write_sync(ar, addr,
|
||||
(u8 *)&ar->bmi.cmd_credits, 4,
|
||||
HIF_RD_SYNC_BYTE_INC);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to decrement the command credit count register: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* The counter is only 8 bits.
|
||||
* Ignore anything in the upper 3 bytes
|
||||
*/
|
||||
ar->bmi.cmd_credits &= 0xFF;
|
||||
}
|
||||
|
||||
if (!ar->bmi.cmd_credits) {
|
||||
ath6kl_err("bmi communication timeout\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kl_bmi_get_rx_lkahd(struct ath6kl *ar)
|
||||
{
|
||||
unsigned long timeout;
|
||||
u32 rx_word = 0;
|
||||
int ret = 0;
|
||||
|
||||
timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT);
|
||||
while (time_before(jiffies, timeout) && !rx_word) {
|
||||
ret = hif_read_write_sync(ar, RX_LOOKAHEAD_VALID_ADDRESS,
|
||||
(u8 *)&rx_word, sizeof(rx_word),
|
||||
HIF_RD_SYNC_BYTE_INC);
|
||||
if (ret) {
|
||||
ath6kl_err("unable to read RX_LOOKAHEAD_VALID\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* all we really want is one bit */
|
||||
rx_word &= (1 << ENDPOINT1);
|
||||
}
|
||||
|
||||
if (!rx_word) {
|
||||
ath6kl_err("bmi_recv_buf FIFO empty\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath6kl_bmi_send_buf(struct ath6kl *ar, u8 *buf, u32 len)
|
||||
{
|
||||
int ret;
|
||||
u32 addr;
|
||||
|
||||
ret = ath6kl_get_bmi_cmd_credits(ar);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
addr = ar->mbox_info.htc_addr;
|
||||
|
||||
ret = hif_read_write_sync(ar, addr, buf, len,
|
||||
HIF_WR_SYNC_BYTE_INC);
|
||||
if (ret)
|
||||
ath6kl_err("unable to send the bmi data to the device\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath6kl_bmi_recv_buf(struct ath6kl *ar, u8 *buf, u32 len)
|
||||
{
|
||||
int ret;
|
||||
u32 addr;
|
||||
|
||||
/*
|
||||
* During normal bootup, small reads may be required.
|
||||
* Rather than issue an HIF Read and then wait as the Target
|
||||
* adds successive bytes to the FIFO, we wait here until
|
||||
* we know that response data is available.
|
||||
*
|
||||
* This allows us to cleanly timeout on an unexpected
|
||||
* Target failure rather than risk problems at the HIF level.
|
||||
* In particular, this avoids SDIO timeouts and possibly garbage
|
||||
* data on some host controllers. And on an interconnect
|
||||
* such as Compact Flash (as well as some SDIO masters) which
|
||||
* does not provide any indication on data timeout, it avoids
|
||||
* a potential hang or garbage response.
|
||||
*
|
||||
* Synchronization is more difficult for reads larger than the
|
||||
* size of the MBOX FIFO (128B), because the Target is unable
|
||||
* to push the 129th byte of data until AFTER the Host posts an
|
||||
* HIF Read and removes some FIFO data. So for large reads the
|
||||
* Host proceeds to post an HIF Read BEFORE all the data is
|
||||
* actually available to read. Fortunately, large BMI reads do
|
||||
* not occur in practice -- they're supported for debug/development.
|
||||
*
|
||||
* So Host/Target BMI synchronization is divided into these cases:
|
||||
* CASE 1: length < 4
|
||||
* Should not happen
|
||||
*
|
||||
* CASE 2: 4 <= length <= 128
|
||||
* Wait for first 4 bytes to be in FIFO
|
||||
* If CONSERVATIVE_BMI_READ is enabled, also wait for
|
||||
* a BMI command credit, which indicates that the ENTIRE
|
||||
* response is available in the the FIFO
|
||||
*
|
||||
* CASE 3: length > 128
|
||||
* Wait for the first 4 bytes to be in FIFO
|
||||
*
|
||||
* For most uses, a small timeout should be sufficient and we will
|
||||
* usually see a response quickly; but there may be some unusual
|
||||
* (debug) cases of BMI_EXECUTE where we want an larger timeout.
|
||||
* For now, we use an unbounded busy loop while waiting for
|
||||
* BMI_EXECUTE.
|
||||
*
|
||||
* If BMI_EXECUTE ever needs to support longer-latency execution,
|
||||
* especially in production, this code needs to be enhanced to sleep
|
||||
* and yield. Also note that BMI_COMMUNICATION_TIMEOUT is currently
|
||||
* a function of Host processor speed.
|
||||
*/
|
||||
if (len >= 4) { /* NB: Currently, always true */
|
||||
ret = ath6kl_bmi_get_rx_lkahd(ar);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
addr = ar->mbox_info.htc_addr;
|
||||
ret = hif_read_write_sync(ar, addr, buf, len,
|
||||
HIF_RD_SYNC_BYTE_INC);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to read the bmi data from the device: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath6kl_bmi_done(struct ath6kl *ar)
|
||||
{
|
||||
int ret;
|
||||
@ -190,7 +31,7 @@ int ath6kl_bmi_done(struct ath6kl *ar)
|
||||
|
||||
ar->bmi.done_sent = true;
|
||||
|
||||
ret = ath6kl_bmi_send_buf(ar, (u8 *)&cid, sizeof(cid));
|
||||
ret = ath6kl_hif_bmi_write(ar, (u8 *)&cid, sizeof(cid));
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to send bmi done: %d\n", ret);
|
||||
return ret;
|
||||
@ -210,14 +51,20 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar,
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
ret = ath6kl_bmi_send_buf(ar, (u8 *)&cid, sizeof(cid));
|
||||
ret = ath6kl_hif_bmi_write(ar, (u8 *)&cid, sizeof(cid));
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to send get target info: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ath6kl_bmi_recv_buf(ar, (u8 *)&targ_info->version,
|
||||
sizeof(targ_info->version));
|
||||
if (ar->hif_type == ATH6KL_HIF_TYPE_USB) {
|
||||
ret = ath6kl_hif_bmi_read(ar, (u8 *)targ_info,
|
||||
sizeof(*targ_info));
|
||||
} else {
|
||||
ret = ath6kl_hif_bmi_read(ar, (u8 *)&targ_info->version,
|
||||
sizeof(targ_info->version));
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to recv target info: %d\n", ret);
|
||||
return ret;
|
||||
@ -225,7 +72,7 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar,
|
||||
|
||||
if (le32_to_cpu(targ_info->version) == TARGET_VERSION_SENTINAL) {
|
||||
/* Determine how many bytes are in the Target's targ_info */
|
||||
ret = ath6kl_bmi_recv_buf(ar,
|
||||
ret = ath6kl_hif_bmi_read(ar,
|
||||
(u8 *)&targ_info->byte_count,
|
||||
sizeof(targ_info->byte_count));
|
||||
if (ret) {
|
||||
@ -244,7 +91,7 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar,
|
||||
}
|
||||
|
||||
/* Read the remainder of the targ_info */
|
||||
ret = ath6kl_bmi_recv_buf(ar,
|
||||
ret = ath6kl_hif_bmi_read(ar,
|
||||
((u8 *)targ_info) +
|
||||
sizeof(targ_info->byte_count),
|
||||
sizeof(*targ_info) -
|
||||
@ -276,8 +123,8 @@ int ath6kl_bmi_read(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
size = BMI_DATASZ_MAX + sizeof(cid) + sizeof(addr) + sizeof(len);
|
||||
if (size > MAX_BMI_CMDBUF_SZ) {
|
||||
size = ar->bmi.max_data_size + sizeof(cid) + sizeof(addr) + sizeof(len);
|
||||
if (size > ar->bmi.max_cmd_size) {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -290,8 +137,8 @@ int ath6kl_bmi_read(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
|
||||
len_remain = len;
|
||||
|
||||
while (len_remain) {
|
||||
rx_len = (len_remain < BMI_DATASZ_MAX) ?
|
||||
len_remain : BMI_DATASZ_MAX;
|
||||
rx_len = (len_remain < ar->bmi.max_data_size) ?
|
||||
len_remain : ar->bmi.max_data_size;
|
||||
offset = 0;
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
|
||||
offset += sizeof(cid);
|
||||
@ -300,13 +147,13 @@ int ath6kl_bmi_read(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &rx_len, sizeof(rx_len));
|
||||
offset += sizeof(len);
|
||||
|
||||
ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
|
||||
ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to write to the device: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, rx_len);
|
||||
ret = ath6kl_hif_bmi_read(ar, ar->bmi.cmd_buf, rx_len);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to read from the device: %d\n",
|
||||
ret);
|
||||
@ -326,7 +173,7 @@ int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
|
||||
u32 offset;
|
||||
u32 len_remain, tx_len;
|
||||
const u32 header = sizeof(cid) + sizeof(addr) + sizeof(len);
|
||||
u8 aligned_buf[BMI_DATASZ_MAX];
|
||||
u8 aligned_buf[400];
|
||||
u8 *src;
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
@ -334,12 +181,15 @@ int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
if ((BMI_DATASZ_MAX + header) > MAX_BMI_CMDBUF_SZ) {
|
||||
if ((ar->bmi.max_data_size + header) > ar->bmi.max_cmd_size) {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(ar->bmi.cmd_buf, 0, BMI_DATASZ_MAX + header);
|
||||
if (WARN_ON(ar->bmi.max_data_size > sizeof(aligned_buf)))
|
||||
return -E2BIG;
|
||||
|
||||
memset(ar->bmi.cmd_buf, 0, ar->bmi.max_data_size + header);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_BMI,
|
||||
"bmi write memory: addr: 0x%x, len: %d\n", addr, len);
|
||||
@ -348,7 +198,7 @@ int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
|
||||
while (len_remain) {
|
||||
src = &buf[len - len_remain];
|
||||
|
||||
if (len_remain < (BMI_DATASZ_MAX - header)) {
|
||||
if (len_remain < (ar->bmi.max_data_size - header)) {
|
||||
if (len_remain & 3) {
|
||||
/* align it with 4 bytes */
|
||||
len_remain = len_remain +
|
||||
@ -358,7 +208,7 @@ int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
|
||||
}
|
||||
tx_len = len_remain;
|
||||
} else {
|
||||
tx_len = (BMI_DATASZ_MAX - header);
|
||||
tx_len = (ar->bmi.max_data_size - header);
|
||||
}
|
||||
|
||||
offset = 0;
|
||||
@ -371,7 +221,7 @@ int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), src, tx_len);
|
||||
offset += tx_len;
|
||||
|
||||
ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
|
||||
ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to write to the device: %d\n",
|
||||
ret);
|
||||
@ -396,7 +246,7 @@ int ath6kl_bmi_execute(struct ath6kl *ar, u32 addr, u32 *param)
|
||||
}
|
||||
|
||||
size = sizeof(cid) + sizeof(addr) + sizeof(param);
|
||||
if (size > MAX_BMI_CMDBUF_SZ) {
|
||||
if (size > ar->bmi.max_cmd_size) {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -413,13 +263,13 @@ int ath6kl_bmi_execute(struct ath6kl *ar, u32 addr, u32 *param)
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), param, sizeof(*param));
|
||||
offset += sizeof(*param);
|
||||
|
||||
ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
|
||||
ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to write to the device: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, sizeof(*param));
|
||||
ret = ath6kl_hif_bmi_read(ar, ar->bmi.cmd_buf, sizeof(*param));
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to read from the device: %d\n", ret);
|
||||
return ret;
|
||||
@ -443,7 +293,7 @@ int ath6kl_bmi_set_app_start(struct ath6kl *ar, u32 addr)
|
||||
}
|
||||
|
||||
size = sizeof(cid) + sizeof(addr);
|
||||
if (size > MAX_BMI_CMDBUF_SZ) {
|
||||
if (size > ar->bmi.max_cmd_size) {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -457,7 +307,7 @@ int ath6kl_bmi_set_app_start(struct ath6kl *ar, u32 addr)
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
|
||||
offset += sizeof(addr);
|
||||
|
||||
ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
|
||||
ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to write to the device: %d\n", ret);
|
||||
return ret;
|
||||
@ -479,7 +329,7 @@ int ath6kl_bmi_reg_read(struct ath6kl *ar, u32 addr, u32 *param)
|
||||
}
|
||||
|
||||
size = sizeof(cid) + sizeof(addr);
|
||||
if (size > MAX_BMI_CMDBUF_SZ) {
|
||||
if (size > ar->bmi.max_cmd_size) {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -493,13 +343,13 @@ int ath6kl_bmi_reg_read(struct ath6kl *ar, u32 addr, u32 *param)
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
|
||||
offset += sizeof(addr);
|
||||
|
||||
ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
|
||||
ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to write to the device: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, sizeof(*param));
|
||||
ret = ath6kl_hif_bmi_read(ar, ar->bmi.cmd_buf, sizeof(*param));
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to read from the device: %d\n", ret);
|
||||
return ret;
|
||||
@ -522,7 +372,7 @@ int ath6kl_bmi_reg_write(struct ath6kl *ar, u32 addr, u32 param)
|
||||
}
|
||||
|
||||
size = sizeof(cid) + sizeof(addr) + sizeof(param);
|
||||
if (size > MAX_BMI_CMDBUF_SZ) {
|
||||
if (size > ar->bmi.max_cmd_size) {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -540,7 +390,7 @@ int ath6kl_bmi_reg_write(struct ath6kl *ar, u32 addr, u32 param)
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), ¶m, sizeof(param));
|
||||
offset += sizeof(param);
|
||||
|
||||
ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
|
||||
ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to write to the device: %d\n", ret);
|
||||
return ret;
|
||||
@ -563,8 +413,8 @@ int ath6kl_bmi_lz_data(struct ath6kl *ar, u8 *buf, u32 len)
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
size = BMI_DATASZ_MAX + header;
|
||||
if (size > MAX_BMI_CMDBUF_SZ) {
|
||||
size = ar->bmi.max_data_size + header;
|
||||
if (size > ar->bmi.max_cmd_size) {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -575,8 +425,8 @@ int ath6kl_bmi_lz_data(struct ath6kl *ar, u8 *buf, u32 len)
|
||||
|
||||
len_remain = len;
|
||||
while (len_remain) {
|
||||
tx_len = (len_remain < (BMI_DATASZ_MAX - header)) ?
|
||||
len_remain : (BMI_DATASZ_MAX - header);
|
||||
tx_len = (len_remain < (ar->bmi.max_data_size - header)) ?
|
||||
len_remain : (ar->bmi.max_data_size - header);
|
||||
|
||||
offset = 0;
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
|
||||
@ -587,7 +437,7 @@ int ath6kl_bmi_lz_data(struct ath6kl *ar, u8 *buf, u32 len)
|
||||
tx_len);
|
||||
offset += tx_len;
|
||||
|
||||
ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
|
||||
ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to write to the device: %d\n",
|
||||
ret);
|
||||
@ -613,7 +463,7 @@ int ath6kl_bmi_lz_stream_start(struct ath6kl *ar, u32 addr)
|
||||
}
|
||||
|
||||
size = sizeof(cid) + sizeof(addr);
|
||||
if (size > MAX_BMI_CMDBUF_SZ) {
|
||||
if (size > ar->bmi.max_cmd_size) {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -629,7 +479,7 @@ int ath6kl_bmi_lz_stream_start(struct ath6kl *ar, u32 addr)
|
||||
memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
|
||||
offset += sizeof(addr);
|
||||
|
||||
ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
|
||||
ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to start LZ stream to the device: %d\n",
|
||||
ret);
|
||||
@ -677,8 +527,13 @@ void ath6kl_bmi_reset(struct ath6kl *ar)
|
||||
|
||||
int ath6kl_bmi_init(struct ath6kl *ar)
|
||||
{
|
||||
ar->bmi.cmd_buf = kzalloc(MAX_BMI_CMDBUF_SZ, GFP_ATOMIC);
|
||||
if (WARN_ON(ar->bmi.max_data_size == 0))
|
||||
return -EINVAL;
|
||||
|
||||
/* cmd + addr + len + data_size */
|
||||
ar->bmi.max_cmd_size = ar->bmi.max_data_size + (sizeof(u32) * 3);
|
||||
|
||||
ar->bmi.cmd_buf = kzalloc(ar->bmi.max_cmd_size, GFP_ATOMIC);
|
||||
if (!ar->bmi.cmd_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -44,12 +44,6 @@
|
||||
* BMI handles all required Target-side cache flushing.
|
||||
*/
|
||||
|
||||
#define MAX_BMI_CMDBUF_SZ (BMI_DATASZ_MAX + \
|
||||
(sizeof(u32) * 3 /* cmd + addr + len */))
|
||||
|
||||
/* Maximum data size used for BMI transfers */
|
||||
#define BMI_DATASZ_MAX 256
|
||||
|
||||
/* BMI Commands */
|
||||
|
||||
#define BMI_NO_COMMAND 0
|
||||
|
@ -23,10 +23,8 @@
|
||||
#include "testmode.h"
|
||||
|
||||
static unsigned int ath6kl_p2p;
|
||||
static unsigned int multi_norm_if_support;
|
||||
|
||||
module_param(ath6kl_p2p, uint, 0644);
|
||||
module_param(multi_norm_if_support, uint, 0644);
|
||||
|
||||
#define RATETAB_ENT(_rate, _rateid, _flags) { \
|
||||
.bitrate = (_rate), \
|
||||
@ -127,6 +125,37 @@ static struct ieee80211_supported_band ath6kl_band_5ghz = {
|
||||
|
||||
#define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */
|
||||
|
||||
/* returns true if scheduled scan was stopped */
|
||||
static bool __ath6kl_cfg80211_sscan_stop(struct ath6kl_vif *vif)
|
||||
{
|
||||
struct ath6kl *ar = vif->ar;
|
||||
|
||||
if (ar->state != ATH6KL_STATE_SCHED_SCAN)
|
||||
return false;
|
||||
|
||||
del_timer_sync(&vif->sched_scan_timer);
|
||||
|
||||
ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
ATH6KL_HOST_MODE_AWAKE);
|
||||
|
||||
ar->state = ATH6KL_STATE_ON;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ath6kl_cfg80211_sscan_disable(struct ath6kl_vif *vif)
|
||||
{
|
||||
struct ath6kl *ar = vif->ar;
|
||||
bool stopped;
|
||||
|
||||
stopped = __ath6kl_cfg80211_sscan_stop(vif);
|
||||
|
||||
if (!stopped)
|
||||
return;
|
||||
|
||||
cfg80211_sched_scan_stopped(ar->wiphy);
|
||||
}
|
||||
|
||||
static int ath6kl_set_wpa_version(struct ath6kl_vif *vif,
|
||||
enum nl80211_wpa_versions wpa_version)
|
||||
{
|
||||
@ -205,6 +234,10 @@ static int ath6kl_set_cipher(struct ath6kl_vif *vif, u32 cipher, bool ucast)
|
||||
*ar_cipher = AES_CRYPT;
|
||||
*ar_cipher_len = 0;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_SMS4:
|
||||
*ar_cipher = WAPI_CRYPT;
|
||||
*ar_cipher_len = 0;
|
||||
break;
|
||||
default:
|
||||
ath6kl_err("cipher 0x%x not supported\n", cipher);
|
||||
return -ENOTSUPP;
|
||||
@ -355,7 +388,7 @@ static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type,
|
||||
|
||||
if (type == NL80211_IFTYPE_STATION ||
|
||||
type == NL80211_IFTYPE_AP || type == NL80211_IFTYPE_ADHOC) {
|
||||
for (i = 0; i < MAX_NUM_VIF; i++) {
|
||||
for (i = 0; i < ar->vif_max; i++) {
|
||||
if ((ar->avail_idx_map >> i) & BIT(0)) {
|
||||
*if_idx = i;
|
||||
return true;
|
||||
@ -365,7 +398,7 @@ static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type,
|
||||
|
||||
if (type == NL80211_IFTYPE_P2P_CLIENT ||
|
||||
type == NL80211_IFTYPE_P2P_GO) {
|
||||
for (i = ar->max_norm_iface; i < MAX_NUM_VIF; i++) {
|
||||
for (i = ar->max_norm_iface; i < ar->vif_max; i++) {
|
||||
if ((ar->avail_idx_map >> i) & BIT(0)) {
|
||||
*if_idx = i;
|
||||
return true;
|
||||
@ -382,6 +415,9 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct ath6kl *ar = ath6kl_priv(dev);
|
||||
struct ath6kl_vif *vif = netdev_priv(dev);
|
||||
int status;
|
||||
u8 nw_subtype = (ar->p2p) ? SUBTYPE_P2PDEV : SUBTYPE_NONE;
|
||||
|
||||
ath6kl_cfg80211_sscan_disable(vif);
|
||||
|
||||
vif->sme_state = SME_CONNECTING;
|
||||
|
||||
@ -427,9 +463,12 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
|
||||
|
||||
if (sme->ie && (sme->ie_len > 0)) {
|
||||
status = ath6kl_set_assoc_req_ies(vif, sme->ie, sme->ie_len);
|
||||
if (status)
|
||||
if (status) {
|
||||
up(&ar->sem);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
} else
|
||||
ar->connect_ctrl_flags &= ~CONNECT_WPS_FLAG;
|
||||
|
||||
if (test_bit(CONNECTED, &vif->flags) &&
|
||||
vif->ssid_len == sme->ssid_len &&
|
||||
@ -519,6 +558,9 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
|
||||
|
||||
vif->nw_type = vif->next_mode;
|
||||
|
||||
if (vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)
|
||||
nw_subtype = SUBTYPE_P2PCLIENT;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
|
||||
"%s: connect called with authmode %d dot11 auth %d"
|
||||
" PW crypto %d PW crypto len %d GRP crypto %d"
|
||||
@ -536,7 +578,7 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
|
||||
vif->grp_crypto, vif->grp_crypto_len,
|
||||
vif->ssid_len, vif->ssid,
|
||||
vif->req_bssid, vif->ch_hint,
|
||||
ar->connect_ctrl_flags);
|
||||
ar->connect_ctrl_flags, nw_subtype);
|
||||
|
||||
up(&ar->sem);
|
||||
|
||||
@ -563,17 +605,28 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kl_add_bss_if_needed(struct ath6kl_vif *vif, const u8 *bssid,
|
||||
static int ath6kl_add_bss_if_needed(struct ath6kl_vif *vif,
|
||||
enum network_type nw_type,
|
||||
const u8 *bssid,
|
||||
struct ieee80211_channel *chan,
|
||||
const u8 *beacon_ie, size_t beacon_ie_len)
|
||||
{
|
||||
struct ath6kl *ar = vif->ar;
|
||||
struct cfg80211_bss *bss;
|
||||
u16 cap_mask, cap_val;
|
||||
u8 *ie;
|
||||
|
||||
if (nw_type & ADHOC_NETWORK) {
|
||||
cap_mask = WLAN_CAPABILITY_IBSS;
|
||||
cap_val = WLAN_CAPABILITY_IBSS;
|
||||
} else {
|
||||
cap_mask = WLAN_CAPABILITY_ESS;
|
||||
cap_val = WLAN_CAPABILITY_ESS;
|
||||
}
|
||||
|
||||
bss = cfg80211_get_bss(ar->wiphy, chan, bssid,
|
||||
vif->ssid, vif->ssid_len, WLAN_CAPABILITY_ESS,
|
||||
WLAN_CAPABILITY_ESS);
|
||||
vif->ssid, vif->ssid_len,
|
||||
cap_mask, cap_val);
|
||||
if (bss == NULL) {
|
||||
/*
|
||||
* Since cfg80211 may not yet know about the BSS,
|
||||
@ -591,13 +644,12 @@ static int ath6kl_add_bss_if_needed(struct ath6kl_vif *vif, const u8 *bssid,
|
||||
memcpy(ie + 2, vif->ssid, vif->ssid_len);
|
||||
memcpy(ie + 2 + vif->ssid_len, beacon_ie, beacon_ie_len);
|
||||
bss = cfg80211_inform_bss(ar->wiphy, chan,
|
||||
bssid, 0, WLAN_CAPABILITY_ESS, 100,
|
||||
bssid, 0, cap_val, 100,
|
||||
ie, 2 + vif->ssid_len + beacon_ie_len,
|
||||
0, GFP_KERNEL);
|
||||
if (bss)
|
||||
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added dummy bss for "
|
||||
"%pM prior to indicating connect/roamed "
|
||||
"event\n", bssid);
|
||||
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added bss %pM to "
|
||||
"cfg80211\n", bssid);
|
||||
kfree(ie);
|
||||
} else
|
||||
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss "
|
||||
@ -660,16 +712,16 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
|
||||
|
||||
chan = ieee80211_get_channel(ar->wiphy, (int) channel);
|
||||
|
||||
|
||||
if (nw_type & ADHOC_NETWORK) {
|
||||
cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
|
||||
if (ath6kl_add_bss_if_needed(vif, nw_type, bssid, chan, assoc_info,
|
||||
beacon_ie_len) < 0) {
|
||||
ath6kl_err("could not add cfg80211 bss entry\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ath6kl_add_bss_if_needed(vif, bssid, chan, assoc_info,
|
||||
beacon_ie_len) < 0) {
|
||||
ath6kl_err("could not add cfg80211 bss entry for "
|
||||
"connect/roamed notification\n");
|
||||
if (nw_type & ADHOC_NETWORK) {
|
||||
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n",
|
||||
nw_type & ADHOC_CREATOR ? "creator" : "joiner");
|
||||
cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -691,12 +743,14 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
|
||||
static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy,
|
||||
struct net_device *dev, u16 reason_code)
|
||||
{
|
||||
struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev);
|
||||
struct ath6kl *ar = ath6kl_priv(dev);
|
||||
struct ath6kl_vif *vif = netdev_priv(dev);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__,
|
||||
reason_code);
|
||||
|
||||
ath6kl_cfg80211_sscan_disable(vif);
|
||||
|
||||
if (!ath6kl_cfg80211_ready(vif))
|
||||
return -EIO;
|
||||
|
||||
@ -789,7 +843,7 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
|
||||
static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
|
||||
struct cfg80211_scan_request *request)
|
||||
{
|
||||
struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
|
||||
struct ath6kl *ar = ath6kl_priv(ndev);
|
||||
struct ath6kl_vif *vif = netdev_priv(ndev);
|
||||
s8 n_channels = 0;
|
||||
u16 *channels = NULL;
|
||||
@ -799,6 +853,8 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
|
||||
if (!ath6kl_cfg80211_ready(vif))
|
||||
return -EIO;
|
||||
|
||||
ath6kl_cfg80211_sscan_disable(vif);
|
||||
|
||||
if (!ar->usr_bss_filter) {
|
||||
clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
|
||||
ret = ath6kl_wmi_bssfilter_cmd(
|
||||
@ -824,6 +880,10 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
|
||||
request->ssids[i].ssid);
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: we should clear the IE in fw if it's not set so just
|
||||
* remove the check altogether
|
||||
*/
|
||||
if (request->ie) {
|
||||
ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
WMI_FRAME_PROBE_REQ,
|
||||
@ -860,9 +920,25 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
|
||||
if (test_bit(CONNECTED, &vif->flags))
|
||||
force_fg_scan = 1;
|
||||
|
||||
ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx, WMI_LONG_SCAN,
|
||||
force_fg_scan, false, 0, 0, n_channels,
|
||||
channels);
|
||||
if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
|
||||
ar->fw_capabilities)) {
|
||||
/*
|
||||
* If capable of doing P2P mgmt operations using
|
||||
* station interface, send additional information like
|
||||
* supported rates to advertise and xmit rates for
|
||||
* probe requests
|
||||
*/
|
||||
ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
WMI_LONG_SCAN, force_fg_scan,
|
||||
false, 0, 0, n_channels,
|
||||
channels, request->no_cck,
|
||||
request->rates);
|
||||
} else {
|
||||
ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
WMI_LONG_SCAN, force_fg_scan,
|
||||
false, 0, 0, n_channels,
|
||||
channels);
|
||||
}
|
||||
if (ret)
|
||||
ath6kl_err("wmi_startscan_cmd failed\n");
|
||||
else
|
||||
@ -905,7 +981,7 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
|
||||
const u8 *mac_addr,
|
||||
struct key_params *params)
|
||||
{
|
||||
struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
|
||||
struct ath6kl *ar = ath6kl_priv(ndev);
|
||||
struct ath6kl_vif *vif = netdev_priv(ndev);
|
||||
struct ath6kl_key *key = NULL;
|
||||
u8 key_usage;
|
||||
@ -937,13 +1013,19 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
|
||||
key_usage = GROUP_USAGE;
|
||||
|
||||
if (params) {
|
||||
int seq_len = params->seq_len;
|
||||
if (params->cipher == WLAN_CIPHER_SUITE_SMS4 &&
|
||||
seq_len > ATH6KL_KEY_SEQ_LEN) {
|
||||
/* Only first half of the WPI PN is configured */
|
||||
seq_len = ATH6KL_KEY_SEQ_LEN;
|
||||
}
|
||||
if (params->key_len > WLAN_MAX_KEY_LEN ||
|
||||
params->seq_len > sizeof(key->seq))
|
||||
seq_len > sizeof(key->seq))
|
||||
return -EINVAL;
|
||||
|
||||
key->key_len = params->key_len;
|
||||
memcpy(key->key, params->key, key->key_len);
|
||||
key->seq_len = params->seq_len;
|
||||
key->seq_len = seq_len;
|
||||
memcpy(key->seq, params->seq, key->seq_len);
|
||||
key->cipher = params->cipher;
|
||||
}
|
||||
@ -961,6 +1043,9 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
key_type = AES_CRYPT;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_SMS4:
|
||||
key_type = WAPI_CRYPT;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
@ -976,10 +1061,9 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
|
||||
__func__, key_index, key->key_len, key_type,
|
||||
key_usage, key->seq_len);
|
||||
|
||||
vif->def_txkey_index = key_index;
|
||||
|
||||
if (vif->nw_type == AP_NETWORK && !pairwise &&
|
||||
(key_type == TKIP_CRYPT || key_type == AES_CRYPT) && params) {
|
||||
(key_type == TKIP_CRYPT || key_type == AES_CRYPT ||
|
||||
key_type == WAPI_CRYPT) && params) {
|
||||
ar->ap_mode_bkey.valid = true;
|
||||
ar->ap_mode_bkey.key_index = key_index;
|
||||
ar->ap_mode_bkey.key_type = key_type;
|
||||
@ -1012,8 +1096,7 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
vif->def_txkey_index,
|
||||
return ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx, key_index,
|
||||
key_type, key_usage, key->key_len,
|
||||
key->seq, key->seq_len, key->key,
|
||||
KEY_OP_INIT_VAL,
|
||||
@ -1024,7 +1107,7 @@ static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
|
||||
u8 key_index, bool pairwise,
|
||||
const u8 *mac_addr)
|
||||
{
|
||||
struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
|
||||
struct ath6kl *ar = ath6kl_priv(ndev);
|
||||
struct ath6kl_vif *vif = netdev_priv(ndev);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);
|
||||
@ -1090,7 +1173,7 @@ static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
|
||||
u8 key_index, bool unicast,
|
||||
bool multicast)
|
||||
{
|
||||
struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
|
||||
struct ath6kl *ar = ath6kl_priv(ndev);
|
||||
struct ath6kl_vif *vif = netdev_priv(ndev);
|
||||
struct ath6kl_key *key = NULL;
|
||||
u8 key_usage;
|
||||
@ -1181,11 +1264,12 @@ static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
|
||||
*/
|
||||
static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
|
||||
enum nl80211_tx_power_setting type,
|
||||
int dbm)
|
||||
int mbm)
|
||||
{
|
||||
struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
|
||||
struct ath6kl_vif *vif;
|
||||
u8 ath6kl_dbm;
|
||||
int dbm = MBM_TO_DBM(mbm);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
|
||||
type, dbm);
|
||||
@ -1288,7 +1372,7 @@ static struct net_device *ath6kl_cfg80211_add_iface(struct wiphy *wiphy,
|
||||
struct net_device *ndev;
|
||||
u8 if_idx, nw_type;
|
||||
|
||||
if (ar->num_vif == MAX_NUM_VIF) {
|
||||
if (ar->num_vif == ar->vif_max) {
|
||||
ath6kl_err("Reached maximum number of supported vif\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
@ -1333,9 +1417,6 @@ static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type);
|
||||
|
||||
if (!ath6kl_cfg80211_ready(vif))
|
||||
return -EIO;
|
||||
|
||||
switch (type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
vif->next_mode = INFRA_NETWORK;
|
||||
@ -1426,7 +1507,7 @@ static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
|
||||
vif->grp_crypto, vif->grp_crypto_len,
|
||||
vif->ssid_len, vif->ssid,
|
||||
vif->req_bssid, vif->ch_hint,
|
||||
ar->connect_ctrl_flags);
|
||||
ar->connect_ctrl_flags, SUBTYPE_NONE);
|
||||
set_bit(CONNECT_PEND, &vif->flags);
|
||||
|
||||
return 0;
|
||||
@ -1453,6 +1534,7 @@ static const u32 cipher_suites[] = {
|
||||
WLAN_CIPHER_SUITE_TKIP,
|
||||
WLAN_CIPHER_SUITE_CCMP,
|
||||
CCKM_KRK_CIPHER_SUITE,
|
||||
WLAN_CIPHER_SUITE_SMS4,
|
||||
};
|
||||
|
||||
static bool is_rate_legacy(s32 rate)
|
||||
@ -1779,7 +1861,7 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
|
||||
|
||||
case ATH6KL_CFG_SUSPEND_DEEPSLEEP:
|
||||
|
||||
ath6kl_cfg80211_stop(ar);
|
||||
ath6kl_cfg80211_stop_all(ar);
|
||||
|
||||
/* save the current power mode before enabling power save */
|
||||
ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
|
||||
@ -1796,7 +1878,7 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
|
||||
|
||||
case ATH6KL_CFG_SUSPEND_CUTPOWER:
|
||||
|
||||
ath6kl_cfg80211_stop(ar);
|
||||
ath6kl_cfg80211_stop_all(ar);
|
||||
|
||||
if (ar->state == ATH6KL_STATE_OFF) {
|
||||
ath6kl_dbg(ATH6KL_DBG_SUSPEND,
|
||||
@ -1816,6 +1898,13 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
|
||||
|
||||
break;
|
||||
|
||||
case ATH6KL_CFG_SUSPEND_SCHED_SCAN:
|
||||
/*
|
||||
* Nothing needed for schedule scan, firmware is already in
|
||||
* wow mode and sleeping most of the time.
|
||||
*/
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -1864,6 +1953,9 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar)
|
||||
}
|
||||
break;
|
||||
|
||||
case ATH6KL_STATE_SCHED_SCAN:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -1987,7 +2079,7 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
|
||||
int ies_len;
|
||||
struct wmi_connect_cmd p;
|
||||
int res;
|
||||
int i;
|
||||
int i, ret;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
|
||||
|
||||
@ -2045,7 +2137,9 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
|
||||
if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
|
||||
return -EOPNOTSUPP; /* TODO */
|
||||
|
||||
vif->dot11_auth_mode = OPEN_AUTH;
|
||||
ret = ath6kl_set_auth_type(vif, info->auth_type);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
memset(&p, 0, sizeof(p));
|
||||
|
||||
@ -2081,6 +2175,9 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
p.prwise_crypto_type |= AES_CRYPT;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_SMS4:
|
||||
p.prwise_crypto_type |= WAPI_CRYPT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (p.prwise_crypto_type == 0) {
|
||||
@ -2100,6 +2197,9 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
p.grp_crypto_type = AES_CRYPT;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_SMS4:
|
||||
p.grp_crypto_type = WAPI_CRYPT;
|
||||
break;
|
||||
default:
|
||||
p.grp_crypto_type = NONE_CRYPT;
|
||||
break;
|
||||
@ -2114,6 +2214,16 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
|
||||
p.dot11_auth_mode = vif->dot11_auth_mode;
|
||||
p.ch = cpu_to_le16(vif->next_chan);
|
||||
|
||||
if (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) {
|
||||
p.nw_subtype = SUBTYPE_P2PGO;
|
||||
} else {
|
||||
/*
|
||||
* Due to firmware limitation, it is not possible to
|
||||
* do P2P mgmt operations in AP mode
|
||||
*/
|
||||
p.nw_subtype = SUBTYPE_NONE;
|
||||
}
|
||||
|
||||
res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p);
|
||||
if (res < 0)
|
||||
return res;
|
||||
@ -2279,9 +2389,23 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
|
||||
}
|
||||
|
||||
*cookie = id;
|
||||
return ath6kl_wmi_send_action_cmd(ar->wmi, vif->fw_vif_idx, id,
|
||||
chan->center_freq, wait,
|
||||
buf, len);
|
||||
|
||||
if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
|
||||
ar->fw_capabilities)) {
|
||||
/*
|
||||
* If capable of doing P2P mgmt operations using
|
||||
* station interface, send additional information like
|
||||
* supported rates to advertise and xmit rates for
|
||||
* probe requests
|
||||
*/
|
||||
return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id,
|
||||
chan->center_freq, wait,
|
||||
buf, len, no_cck);
|
||||
} else {
|
||||
return ath6kl_wmi_send_action_cmd(ar->wmi, vif->fw_vif_idx, id,
|
||||
chan->center_freq, wait,
|
||||
buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
|
||||
@ -2302,6 +2426,90 @@ static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
|
||||
}
|
||||
}
|
||||
|
||||
static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
struct cfg80211_sched_scan_request *request)
|
||||
{
|
||||
struct ath6kl *ar = ath6kl_priv(dev);
|
||||
struct ath6kl_vif *vif = netdev_priv(dev);
|
||||
u16 interval;
|
||||
int ret;
|
||||
u8 i;
|
||||
|
||||
if (ar->state != ATH6KL_STATE_ON)
|
||||
return -EIO;
|
||||
|
||||
if (vif->sme_state != SME_DISCONNECTED)
|
||||
return -EBUSY;
|
||||
|
||||
for (i = 0; i < ar->wiphy->max_sched_scan_ssids; i++) {
|
||||
ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
i, DISABLE_SSID_FLAG,
|
||||
0, NULL);
|
||||
}
|
||||
|
||||
/* fw uses seconds, also make sure that it's >0 */
|
||||
interval = max_t(u16, 1, request->interval / 1000);
|
||||
|
||||
ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
interval, interval,
|
||||
10, 0, 0, 0, 3, 0, 0, 0);
|
||||
|
||||
if (request->n_ssids && request->ssids[0].ssid_len) {
|
||||
for (i = 0; i < request->n_ssids; i++) {
|
||||
ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
i, SPECIFIC_SSID_FLAG,
|
||||
request->ssids[i].ssid_len,
|
||||
request->ssids[i].ssid);
|
||||
}
|
||||
}
|
||||
|
||||
ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
ATH6KL_WOW_MODE_ENABLE,
|
||||
WOW_FILTER_SSID,
|
||||
WOW_HOST_REQ_DELAY);
|
||||
if (ret) {
|
||||
ath6kl_warn("Failed to enable wow with ssid filter: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* this also clears IE in fw if it's not set */
|
||||
ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
WMI_FRAME_PROBE_REQ,
|
||||
request->ie, request->ie_len);
|
||||
if (ret) {
|
||||
ath6kl_warn("Failed to set probe request IE for scheduled scan: %d",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
|
||||
ATH6KL_HOST_MODE_ASLEEP);
|
||||
if (ret) {
|
||||
ath6kl_warn("Failed to enable host sleep mode for sched scan: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ar->state = ATH6KL_STATE_SCHED_SCAN;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath6kl_cfg80211_sscan_stop(struct wiphy *wiphy,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct ath6kl_vif *vif = netdev_priv(dev);
|
||||
bool stopped;
|
||||
|
||||
stopped = __ath6kl_cfg80211_sscan_stop(vif);
|
||||
|
||||
if (!stopped)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ieee80211_txrx_stypes
|
||||
ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
|
||||
[NL80211_IFTYPE_STATION] = {
|
||||
@ -2359,13 +2567,48 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
|
||||
.cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
|
||||
.mgmt_tx = ath6kl_mgmt_tx,
|
||||
.mgmt_frame_register = ath6kl_mgmt_frame_register,
|
||||
.sched_scan_start = ath6kl_cfg80211_sscan_start,
|
||||
.sched_scan_stop = ath6kl_cfg80211_sscan_stop,
|
||||
};
|
||||
|
||||
void ath6kl_cfg80211_stop(struct ath6kl *ar)
|
||||
void ath6kl_cfg80211_stop(struct ath6kl_vif *vif)
|
||||
{
|
||||
ath6kl_cfg80211_sscan_disable(vif);
|
||||
|
||||
switch (vif->sme_state) {
|
||||
case SME_DISCONNECTED:
|
||||
break;
|
||||
case SME_CONNECTING:
|
||||
cfg80211_connect_result(vif->ndev, vif->bssid, NULL, 0,
|
||||
NULL, 0,
|
||||
WLAN_STATUS_UNSPECIFIED_FAILURE,
|
||||
GFP_KERNEL);
|
||||
break;
|
||||
case SME_CONNECTED:
|
||||
cfg80211_disconnected(vif->ndev, 0, NULL, 0, GFP_KERNEL);
|
||||
break;
|
||||
}
|
||||
|
||||
if (test_bit(CONNECTED, &vif->flags) ||
|
||||
test_bit(CONNECT_PEND, &vif->flags))
|
||||
ath6kl_wmi_disconnect_cmd(vif->ar->wmi, vif->fw_vif_idx);
|
||||
|
||||
vif->sme_state = SME_DISCONNECTED;
|
||||
clear_bit(CONNECTED, &vif->flags);
|
||||
clear_bit(CONNECT_PEND, &vif->flags);
|
||||
|
||||
/* disable scanning */
|
||||
if (ath6kl_wmi_scanparams_cmd(vif->ar->wmi, vif->fw_vif_idx, 0xFFFF,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0) != 0)
|
||||
ath6kl_warn("failed to disable scan during stop\n");
|
||||
|
||||
ath6kl_cfg80211_scan_complete_event(vif, true);
|
||||
}
|
||||
|
||||
void ath6kl_cfg80211_stop_all(struct ath6kl *ar)
|
||||
{
|
||||
struct ath6kl_vif *vif;
|
||||
|
||||
/* FIXME: for multi vif */
|
||||
vif = ath6kl_vif_first(ar);
|
||||
if (!vif) {
|
||||
/* save the current power mode before enabling power save */
|
||||
@ -2377,39 +2620,13 @@ void ath6kl_cfg80211_stop(struct ath6kl *ar)
|
||||
return;
|
||||
}
|
||||
|
||||
switch (vif->sme_state) {
|
||||
case SME_CONNECTING:
|
||||
cfg80211_connect_result(vif->ndev, vif->bssid, NULL, 0,
|
||||
NULL, 0,
|
||||
WLAN_STATUS_UNSPECIFIED_FAILURE,
|
||||
GFP_KERNEL);
|
||||
break;
|
||||
case SME_CONNECTED:
|
||||
default:
|
||||
/*
|
||||
* FIXME: oddly enough smeState is in DISCONNECTED during
|
||||
* suspend, why? Need to send disconnected event in that
|
||||
* state.
|
||||
*/
|
||||
cfg80211_disconnected(vif->ndev, 0, NULL, 0, GFP_KERNEL);
|
||||
break;
|
||||
}
|
||||
|
||||
if (test_bit(CONNECTED, &vif->flags) ||
|
||||
test_bit(CONNECT_PEND, &vif->flags))
|
||||
ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
|
||||
|
||||
vif->sme_state = SME_DISCONNECTED;
|
||||
clear_bit(CONNECTED, &vif->flags);
|
||||
clear_bit(CONNECT_PEND, &vif->flags);
|
||||
|
||||
/* disable scanning */
|
||||
if (ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0xFFFF, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0) != 0)
|
||||
printk(KERN_WARNING "ath6kl: failed to disable scan "
|
||||
"during suspend\n");
|
||||
|
||||
ath6kl_cfg80211_scan_complete_event(vif, true);
|
||||
/*
|
||||
* FIXME: we should take ar->list_lock to protect changes in the
|
||||
* vif_list, but that's not trivial to do as ath6kl_cfg80211_stop()
|
||||
* sleeps.
|
||||
*/
|
||||
list_for_each_entry(vif, &ar->vif_list, list)
|
||||
ath6kl_cfg80211_stop(vif);
|
||||
}
|
||||
|
||||
struct ath6kl *ath6kl_core_alloc(struct device *dev)
|
||||
@ -2427,17 +2644,12 @@ struct ath6kl *ath6kl_core_alloc(struct device *dev)
|
||||
}
|
||||
|
||||
ar = wiphy_priv(wiphy);
|
||||
if (!multi_norm_if_support)
|
||||
ar->p2p = !!ath6kl_p2p;
|
||||
ar->p2p = !!ath6kl_p2p;
|
||||
ar->wiphy = wiphy;
|
||||
ar->dev = dev;
|
||||
|
||||
if (multi_norm_if_support)
|
||||
ar->max_norm_iface = 2;
|
||||
else
|
||||
ar->max_norm_iface = 1;
|
||||
ar->vif_max = 1;
|
||||
|
||||
/* FIXME: Remove this once the multivif support is enabled */
|
||||
ar->max_norm_iface = 1;
|
||||
|
||||
spin_lock_init(&ar->lock);
|
||||
@ -2459,9 +2671,6 @@ struct ath6kl *ath6kl_core_alloc(struct device *dev)
|
||||
ar->tx_pwr = 0;
|
||||
|
||||
ar->intra_bss = 1;
|
||||
memset(&ar->sc_params, 0, sizeof(ar->sc_params));
|
||||
ar->sc_params.short_scan_ratio = WMI_SHORTSCANRATIO_DEFAULT;
|
||||
ar->sc_params.scan_ctrl_flags = DEFAULT_SCAN_CTRL_FLAGS;
|
||||
ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD;
|
||||
|
||||
ar->state = ATH6KL_STATE_OFF;
|
||||
@ -2522,6 +2731,8 @@ int ath6kl_register_ieee80211_hw(struct ath6kl *ar)
|
||||
wiphy->wowlan.pattern_min_len = 1;
|
||||
wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE;
|
||||
|
||||
wiphy->max_sched_scan_ssids = 10;
|
||||
|
||||
ret = wiphy_register(wiphy);
|
||||
if (ret < 0) {
|
||||
ath6kl_err("couldn't register wiphy device\n");
|
||||
@ -2541,6 +2752,9 @@ static int ath6kl_init_if_data(struct ath6kl_vif *vif)
|
||||
|
||||
setup_timer(&vif->disconnect_timer, disconnect_timer_handler,
|
||||
(unsigned long) vif->ndev);
|
||||
setup_timer(&vif->sched_scan_timer, ath6kl_wmi_sscan_timer,
|
||||
(unsigned long) vif);
|
||||
|
||||
set_bit(WMM_ENABLED, &vif->flags);
|
||||
spin_lock_init(&vif->if_lock);
|
||||
|
||||
|
@ -20,7 +20,8 @@
|
||||
enum ath6kl_cfg_suspend_mode {
|
||||
ATH6KL_CFG_SUSPEND_DEEPSLEEP,
|
||||
ATH6KL_CFG_SUSPEND_CUTPOWER,
|
||||
ATH6KL_CFG_SUSPEND_WOW
|
||||
ATH6KL_CFG_SUSPEND_WOW,
|
||||
ATH6KL_CFG_SUSPEND_SCHED_SCAN,
|
||||
};
|
||||
|
||||
struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
|
||||
@ -52,6 +53,7 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
|
||||
|
||||
int ath6kl_cfg80211_resume(struct ath6kl *ar);
|
||||
|
||||
void ath6kl_cfg80211_stop(struct ath6kl *ar);
|
||||
void ath6kl_cfg80211_stop(struct ath6kl_vif *vif);
|
||||
void ath6kl_cfg80211_stop_all(struct ath6kl *ar);
|
||||
|
||||
#endif /* ATH6KL_CFG80211_H */
|
||||
|
@ -71,6 +71,7 @@ enum crypto_type {
|
||||
WEP_CRYPT = 0x02,
|
||||
TKIP_CRYPT = 0x04,
|
||||
AES_CRYPT = 0x08,
|
||||
WAPI_CRYPT = 0x10,
|
||||
};
|
||||
|
||||
struct htc_endpoint_credit_dist;
|
||||
|
@ -70,10 +70,20 @@ enum ath6kl_fw_ie_type {
|
||||
ATH6KL_FW_IE_RESERVED_RAM_SIZE = 5,
|
||||
ATH6KL_FW_IE_CAPABILITIES = 6,
|
||||
ATH6KL_FW_IE_PATCH_ADDR = 7,
|
||||
ATH6KL_FW_IE_BOARD_ADDR = 8,
|
||||
ATH6KL_FW_IE_VIF_MAX = 9,
|
||||
};
|
||||
|
||||
enum ath6kl_fw_capability {
|
||||
ATH6KL_FW_CAPABILITY_HOST_P2P = 0,
|
||||
ATH6KL_FW_CAPABILITY_SCHED_SCAN = 1,
|
||||
|
||||
/*
|
||||
* Firmware is capable of supporting P2P mgmt operations on a
|
||||
* station interface. After group formation, the station
|
||||
* interface will become a P2P client/GO interface as the case may be
|
||||
*/
|
||||
ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
|
||||
|
||||
/* this needs to be last */
|
||||
ATH6KL_FW_CAPABILITY_MAX,
|
||||
@ -88,37 +98,47 @@ struct ath6kl_fw_ie {
|
||||
};
|
||||
|
||||
/* AR6003 1.0 definitions */
|
||||
#define AR6003_REV1_VERSION 0x300002ba
|
||||
#define AR6003_HW_1_0_VERSION 0x300002ba
|
||||
|
||||
/* AR6003 2.0 definitions */
|
||||
#define AR6003_REV2_VERSION 0x30000384
|
||||
#define AR6003_REV2_PATCH_DOWNLOAD_ADDRESS 0x57e910
|
||||
#define AR6003_REV2_OTP_FILE "ath6k/AR6003/hw2.0/otp.bin.z77"
|
||||
#define AR6003_REV2_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athwlan.bin.z77"
|
||||
#define AR6003_REV2_TCMD_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athtcmd_ram.bin"
|
||||
#define AR6003_REV2_PATCH_FILE "ath6k/AR6003/hw2.0/data.patch.bin"
|
||||
#define AR6003_REV2_FIRMWARE_2_FILE "ath6k/AR6003/hw2.0/fw-2.bin"
|
||||
#define AR6003_REV2_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.bin"
|
||||
#define AR6003_REV2_DEFAULT_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.SD31.bin"
|
||||
#define AR6003_HW_2_0_VERSION 0x30000384
|
||||
#define AR6003_HW_2_0_PATCH_DOWNLOAD_ADDRESS 0x57e910
|
||||
#define AR6003_HW_2_0_OTP_FILE "ath6k/AR6003/hw2.0/otp.bin.z77"
|
||||
#define AR6003_HW_2_0_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athwlan.bin.z77"
|
||||
#define AR6003_HW_2_0_TCMD_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athtcmd_ram.bin"
|
||||
#define AR6003_HW_2_0_PATCH_FILE "ath6k/AR6003/hw2.0/data.patch.bin"
|
||||
#define AR6003_HW_2_0_FIRMWARE_2_FILE "ath6k/AR6003/hw2.0/fw-2.bin"
|
||||
#define AR6003_HW_2_0_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.bin"
|
||||
#define AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE \
|
||||
"ath6k/AR6003/hw2.0/bdata.SD31.bin"
|
||||
|
||||
/* AR6003 3.0 definitions */
|
||||
#define AR6003_REV3_VERSION 0x30000582
|
||||
#define AR6003_REV3_OTP_FILE "ath6k/AR6003/hw2.1.1/otp.bin"
|
||||
#define AR6003_REV3_FIRMWARE_FILE "ath6k/AR6003/hw2.1.1/athwlan.bin"
|
||||
#define AR6003_REV3_TCMD_FIRMWARE_FILE "ath6k/AR6003/hw2.1.1/athtcmd_ram.bin"
|
||||
#define AR6003_REV3_PATCH_FILE "ath6k/AR6003/hw2.1.1/data.patch.bin"
|
||||
#define AR6003_REV3_FIRMWARE_2_FILE "ath6k/AR6003/hw2.1.1/fw-2.bin"
|
||||
#define AR6003_REV3_BOARD_DATA_FILE "ath6k/AR6003/hw2.1.1/bdata.bin"
|
||||
#define AR6003_REV3_DEFAULT_BOARD_DATA_FILE \
|
||||
"ath6k/AR6003/hw2.1.1/bdata.SD31.bin"
|
||||
#define AR6003_HW_2_1_1_VERSION 0x30000582
|
||||
#define AR6003_HW_2_1_1_OTP_FILE "ath6k/AR6003/hw2.1.1/otp.bin"
|
||||
#define AR6003_HW_2_1_1_FIRMWARE_FILE "ath6k/AR6003/hw2.1.1/athwlan.bin"
|
||||
#define AR6003_HW_2_1_1_TCMD_FIRMWARE_FILE \
|
||||
"ath6k/AR6003/hw2.1.1/athtcmd_ram.bin"
|
||||
#define AR6003_HW_2_1_1_PATCH_FILE "ath6k/AR6003/hw2.1.1/data.patch.bin"
|
||||
#define AR6003_HW_2_1_1_FIRMWARE_2_FILE "ath6k/AR6003/hw2.1.1/fw-2.bin"
|
||||
#define AR6003_HW_2_1_1_BOARD_DATA_FILE "ath6k/AR6003/hw2.1.1/bdata.bin"
|
||||
#define AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE \
|
||||
"ath6k/AR6003/hw2.1.1/bdata.SD31.bin"
|
||||
|
||||
/* AR6004 1.0 definitions */
|
||||
#define AR6004_REV1_VERSION 0x30000623
|
||||
#define AR6004_REV1_FIRMWARE_FILE "ath6k/AR6004/hw6.1/fw.ram.bin"
|
||||
#define AR6004_REV1_FIRMWARE_2_FILE "ath6k/AR6004/hw6.1/fw-2.bin"
|
||||
#define AR6004_REV1_BOARD_DATA_FILE "ath6k/AR6004/hw6.1/bdata.bin"
|
||||
#define AR6004_REV1_DEFAULT_BOARD_DATA_FILE "ath6k/AR6004/hw6.1/bdata.DB132.bin"
|
||||
#define AR6004_REV1_EPPING_FIRMWARE_FILE "ath6k/AR6004/hw6.1/endpointping.bin"
|
||||
#define AR6004_HW_1_0_VERSION 0x30000623
|
||||
#define AR6004_HW_1_0_FIRMWARE_2_FILE "ath6k/AR6004/hw1.0/fw-2.bin"
|
||||
#define AR6004_HW_1_0_FIRMWARE_FILE "ath6k/AR6004/hw1.0/fw.ram.bin"
|
||||
#define AR6004_HW_1_0_BOARD_DATA_FILE "ath6k/AR6004/hw1.0/bdata.bin"
|
||||
#define AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE \
|
||||
"ath6k/AR6004/hw1.0/bdata.DB132.bin"
|
||||
|
||||
/* AR6004 1.1 definitions */
|
||||
#define AR6004_HW_1_1_VERSION 0x30000001
|
||||
#define AR6004_HW_1_1_FIRMWARE_2_FILE "ath6k/AR6004/hw1.1/fw-2.bin"
|
||||
#define AR6004_HW_1_1_FIRMWARE_FILE "ath6k/AR6004/hw1.1/fw.ram.bin"
|
||||
#define AR6004_HW_1_1_BOARD_DATA_FILE "ath6k/AR6004/hw1.1/bdata.bin"
|
||||
#define AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE \
|
||||
"ath6k/AR6004/hw1.1/bdata.DB132.bin"
|
||||
|
||||
/* Per STA data, used in AP mode */
|
||||
#define STA_PS_AWAKE BIT(0)
|
||||
@ -272,6 +292,8 @@ struct ath6kl_bmi {
|
||||
u32 cmd_credits;
|
||||
bool done_sent;
|
||||
u8 *cmd_buf;
|
||||
u32 max_data_size;
|
||||
u32 max_cmd_size;
|
||||
};
|
||||
|
||||
struct target_stats {
|
||||
@ -381,7 +403,16 @@ struct ath6kl_req_key {
|
||||
u8 key_len;
|
||||
};
|
||||
|
||||
#define MAX_NUM_VIF 1
|
||||
enum ath6kl_hif_type {
|
||||
ATH6KL_HIF_TYPE_SDIO,
|
||||
ATH6KL_HIF_TYPE_USB,
|
||||
};
|
||||
|
||||
/*
|
||||
* Driver's maximum limit, note that some firmwares support only one vif
|
||||
* and the runtime (current) limit must be checked from ar->vif_max.
|
||||
*/
|
||||
#define ATH6KL_VIF_MAX 3
|
||||
|
||||
/* vif flags info */
|
||||
enum ath6kl_vif_state {
|
||||
@ -424,7 +455,10 @@ struct ath6kl_vif {
|
||||
struct ath6kl_wep_key wep_key_list[WMI_MAX_KEY_INDEX + 1];
|
||||
struct ath6kl_key keys[WMI_MAX_KEY_INDEX + 1];
|
||||
struct aggr_info *aggr_cntxt;
|
||||
|
||||
struct timer_list disconnect_timer;
|
||||
struct timer_list sched_scan_timer;
|
||||
|
||||
struct cfg80211_scan_request *scan_req;
|
||||
enum sme_state sme_state;
|
||||
int reconnect_flag;
|
||||
@ -442,6 +476,8 @@ struct ath6kl_vif {
|
||||
#define WOW_LIST_ID 0
|
||||
#define WOW_HOST_REQ_DELAY 500 /* ms */
|
||||
|
||||
#define ATH6KL_SCHED_SCAN_RESULT_DELAY 5000 /* ms */
|
||||
|
||||
/* Flag info */
|
||||
enum ath6kl_dev_state {
|
||||
WMI_ENABLED,
|
||||
@ -460,6 +496,7 @@ enum ath6kl_state {
|
||||
ATH6KL_STATE_DEEPSLEEP,
|
||||
ATH6KL_STATE_CUTPOWER,
|
||||
ATH6KL_STATE_WOW,
|
||||
ATH6KL_STATE_SCHED_SCAN,
|
||||
};
|
||||
|
||||
struct ath6kl {
|
||||
@ -474,11 +511,13 @@ struct ath6kl {
|
||||
int tx_pending[ENDPOINT_MAX];
|
||||
int total_tx_data_pend;
|
||||
struct htc_target *htc_target;
|
||||
enum ath6kl_hif_type hif_type;
|
||||
void *hif_priv;
|
||||
struct list_head vif_list;
|
||||
/* Lock to avoid race in vif_list entries among add/del/traverse */
|
||||
spinlock_t list_lock;
|
||||
u8 num_vif;
|
||||
unsigned int vif_max;
|
||||
u8 max_norm_iface;
|
||||
u8 avail_idx_map;
|
||||
spinlock_t lock;
|
||||
@ -517,7 +556,6 @@ struct ath6kl {
|
||||
struct list_head amsdu_rx_buffer_queue;
|
||||
u8 rx_meta_ver;
|
||||
enum wlan_low_pwr_state wlan_pwr_state;
|
||||
struct wmi_scan_params_cmd sc_params;
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
#define AR_MCAST_FILTER_MAC_ADDR_SIZE 4
|
||||
struct {
|
||||
@ -525,12 +563,25 @@ struct ath6kl {
|
||||
size_t rx_report_len;
|
||||
} tm;
|
||||
|
||||
struct {
|
||||
struct ath6kl_hw {
|
||||
u32 id;
|
||||
const char *name;
|
||||
u32 dataset_patch_addr;
|
||||
u32 app_load_addr;
|
||||
u32 app_start_override_addr;
|
||||
u32 board_ext_data_addr;
|
||||
u32 reserved_ram_size;
|
||||
u32 board_addr;
|
||||
u32 refclk_hz;
|
||||
u32 uarttx_pin;
|
||||
|
||||
const char *fw_otp;
|
||||
const char *fw;
|
||||
const char *fw_tcmd;
|
||||
const char *fw_patch;
|
||||
const char *fw_api2;
|
||||
const char *fw_board;
|
||||
const char *fw_default_board;
|
||||
} hw;
|
||||
|
||||
u16 conf_flags;
|
||||
@ -583,7 +634,7 @@ struct ath6kl {
|
||||
#endif /* CONFIG_ATH6KL_DEBUG */
|
||||
};
|
||||
|
||||
static inline void *ath6kl_priv(struct net_device *dev)
|
||||
static inline struct ath6kl *ath6kl_priv(struct net_device *dev)
|
||||
{
|
||||
return ((struct ath6kl_vif *) netdev_priv(dev))->ar;
|
||||
}
|
||||
|
@ -1551,10 +1551,10 @@ static ssize_t ath6kl_listen_int_read(struct file *file,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath6kl *ar = file->private_data;
|
||||
char buf[16];
|
||||
char buf[32];
|
||||
int len;
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%u %u\n", ar->listen_intvl_t,
|
||||
len = scnprintf(buf, sizeof(buf), "%u %u\n", ar->listen_intvl_t,
|
||||
ar->listen_intvl_b);
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
|
@ -41,6 +41,7 @@ enum ATH6K_DEBUG_MASK {
|
||||
ATH6KL_DBG_BOOT = BIT(18), /* driver init and fw boot */
|
||||
ATH6KL_DBG_WMI_DUMP = BIT(19),
|
||||
ATH6KL_DBG_SUSPEND = BIT(20),
|
||||
ATH6KL_DBG_USB = BIT(21),
|
||||
ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */
|
||||
};
|
||||
|
||||
|
@ -91,6 +91,36 @@ static inline int ath6kl_hif_suspend(struct ath6kl *ar,
|
||||
return ar->hif_ops->suspend(ar, wow);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read from the ATH6KL through its diagnostic window. No cooperation from
|
||||
* the Target is required for this.
|
||||
*/
|
||||
static inline int ath6kl_hif_diag_read32(struct ath6kl *ar, u32 address,
|
||||
u32 *value)
|
||||
{
|
||||
return ar->hif_ops->diag_read32(ar, address, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write to the ATH6KL through its diagnostic window. No cooperation from
|
||||
* the Target is required for this.
|
||||
*/
|
||||
static inline int ath6kl_hif_diag_write32(struct ath6kl *ar, u32 address,
|
||||
__le32 value)
|
||||
{
|
||||
return ar->hif_ops->diag_write32(ar, address, value);
|
||||
}
|
||||
|
||||
static inline int ath6kl_hif_bmi_read(struct ath6kl *ar, u8 *buf, u32 len)
|
||||
{
|
||||
return ar->hif_ops->bmi_read(ar, buf, len);
|
||||
}
|
||||
|
||||
static inline int ath6kl_hif_bmi_write(struct ath6kl *ar, u8 *buf, u32 len)
|
||||
{
|
||||
return ar->hif_ops->bmi_write(ar, buf, len);
|
||||
}
|
||||
|
||||
static inline int ath6kl_hif_resume(struct ath6kl *ar)
|
||||
{
|
||||
ath6kl_dbg(ATH6KL_DBG_HIF, "hif resume\n");
|
||||
|
@ -689,6 +689,11 @@ int ath6kl_hif_setup(struct ath6kl_device *dev)
|
||||
ath6kl_dbg(ATH6KL_DBG_HIF, "hif block size %d mbox addr 0x%x\n",
|
||||
dev->htc_cnxt->block_sz, dev->ar->mbox_info.htc_addr);
|
||||
|
||||
/* usb doesn't support enabling interrupts */
|
||||
/* FIXME: remove check once USB support is implemented */
|
||||
if (dev->ar->hif_type == ATH6KL_HIF_TYPE_USB)
|
||||
return 0;
|
||||
|
||||
status = ath6kl_hif_disable_intrs(dev);
|
||||
|
||||
fail_setup:
|
||||
|
@ -35,6 +35,7 @@
|
||||
#define MAX_SCATTER_REQ_TRANSFER_SIZE (32 * 1024)
|
||||
|
||||
#define MANUFACTURER_ID_AR6003_BASE 0x300
|
||||
#define MANUFACTURER_ID_AR6004_BASE 0x400
|
||||
/* SDIO manufacturer ID and Codes */
|
||||
#define MANUFACTURER_ID_ATH6KL_BASE_MASK 0xFF00
|
||||
#define MANUFACTURER_CODE 0x271 /* Atheros */
|
||||
@ -244,6 +245,10 @@ struct ath6kl_hif_ops {
|
||||
void (*cleanup_scatter)(struct ath6kl *ar);
|
||||
int (*suspend)(struct ath6kl *ar, struct cfg80211_wowlan *wow);
|
||||
int (*resume)(struct ath6kl *ar);
|
||||
int (*diag_read32)(struct ath6kl *ar, u32 address, u32 *value);
|
||||
int (*diag_write32)(struct ath6kl *ar, u32 address, __le32 value);
|
||||
int (*bmi_read)(struct ath6kl *ar, u8 *buf, u32 len);
|
||||
int (*bmi_write)(struct ath6kl *ar, u8 *buf, u32 len);
|
||||
int (*power_on)(struct ath6kl *ar);
|
||||
int (*power_off)(struct ath6kl *ar);
|
||||
void (*stop)(struct ath6kl *ar);
|
||||
|
@ -2543,6 +2543,12 @@ int ath6kl_htc_wait_target(struct htc_target *target)
|
||||
struct htc_service_connect_resp resp;
|
||||
int status;
|
||||
|
||||
/* FIXME: remove once USB support is implemented */
|
||||
if (target->dev->ar->hif_type == ATH6KL_HIF_TYPE_USB) {
|
||||
ath6kl_err("HTC doesn't support USB yet. Patience!\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* we should be getting 1 control message that the target is ready */
|
||||
packet = htc_wait_for_ctrl_msg(target);
|
||||
|
||||
@ -2772,7 +2778,9 @@ void ath6kl_htc_cleanup(struct htc_target *target)
|
||||
{
|
||||
struct htc_packet *packet, *tmp_packet;
|
||||
|
||||
ath6kl_hif_cleanup_scatter(target->dev->ar);
|
||||
/* FIXME: remove check once USB support is implemented */
|
||||
if (target->dev->ar->hif_type != ATH6KL_HIF_TYPE_USB)
|
||||
ath6kl_hif_cleanup_scatter(target->dev->ar);
|
||||
|
||||
list_for_each_entry_safe(packet, tmp_packet,
|
||||
&target->free_ctrl_txbuf, list) {
|
||||
|
@ -33,6 +33,80 @@ module_param(debug_mask, uint, 0644);
|
||||
module_param(testmode, uint, 0644);
|
||||
module_param(suspend_cutpower, bool, 0444);
|
||||
|
||||
static const struct ath6kl_hw hw_list[] = {
|
||||
{
|
||||
.id = AR6003_HW_2_0_VERSION,
|
||||
.name = "ar6003 hw 2.0",
|
||||
.dataset_patch_addr = 0x57e884,
|
||||
.app_load_addr = 0x543180,
|
||||
.board_ext_data_addr = 0x57e500,
|
||||
.reserved_ram_size = 6912,
|
||||
.refclk_hz = 26000000,
|
||||
.uarttx_pin = 8,
|
||||
|
||||
/* hw2.0 needs override address hardcoded */
|
||||
.app_start_override_addr = 0x944C00,
|
||||
|
||||
.fw_otp = AR6003_HW_2_0_OTP_FILE,
|
||||
.fw = AR6003_HW_2_0_FIRMWARE_FILE,
|
||||
.fw_tcmd = AR6003_HW_2_0_TCMD_FIRMWARE_FILE,
|
||||
.fw_patch = AR6003_HW_2_0_PATCH_FILE,
|
||||
.fw_api2 = AR6003_HW_2_0_FIRMWARE_2_FILE,
|
||||
.fw_board = AR6003_HW_2_0_BOARD_DATA_FILE,
|
||||
.fw_default_board = AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE,
|
||||
},
|
||||
{
|
||||
.id = AR6003_HW_2_1_1_VERSION,
|
||||
.name = "ar6003 hw 2.1.1",
|
||||
.dataset_patch_addr = 0x57ff74,
|
||||
.app_load_addr = 0x1234,
|
||||
.board_ext_data_addr = 0x542330,
|
||||
.reserved_ram_size = 512,
|
||||
.refclk_hz = 26000000,
|
||||
.uarttx_pin = 8,
|
||||
|
||||
.fw_otp = AR6003_HW_2_1_1_OTP_FILE,
|
||||
.fw = AR6003_HW_2_1_1_FIRMWARE_FILE,
|
||||
.fw_tcmd = AR6003_HW_2_1_1_TCMD_FIRMWARE_FILE,
|
||||
.fw_patch = AR6003_HW_2_1_1_PATCH_FILE,
|
||||
.fw_api2 = AR6003_HW_2_1_1_FIRMWARE_2_FILE,
|
||||
.fw_board = AR6003_HW_2_1_1_BOARD_DATA_FILE,
|
||||
.fw_default_board = AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE,
|
||||
},
|
||||
{
|
||||
.id = AR6004_HW_1_0_VERSION,
|
||||
.name = "ar6004 hw 1.0",
|
||||
.dataset_patch_addr = 0x57e884,
|
||||
.app_load_addr = 0x1234,
|
||||
.board_ext_data_addr = 0x437000,
|
||||
.reserved_ram_size = 19456,
|
||||
.board_addr = 0x433900,
|
||||
.refclk_hz = 26000000,
|
||||
.uarttx_pin = 11,
|
||||
|
||||
.fw = AR6004_HW_1_0_FIRMWARE_FILE,
|
||||
.fw_api2 = AR6004_HW_1_0_FIRMWARE_2_FILE,
|
||||
.fw_board = AR6004_HW_1_0_BOARD_DATA_FILE,
|
||||
.fw_default_board = AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE,
|
||||
},
|
||||
{
|
||||
.id = AR6004_HW_1_1_VERSION,
|
||||
.name = "ar6004 hw 1.1",
|
||||
.dataset_patch_addr = 0x57e884,
|
||||
.app_load_addr = 0x1234,
|
||||
.board_ext_data_addr = 0x437000,
|
||||
.reserved_ram_size = 11264,
|
||||
.board_addr = 0x43d400,
|
||||
.refclk_hz = 40000000,
|
||||
.uarttx_pin = 11,
|
||||
|
||||
.fw = AR6004_HW_1_1_FIRMWARE_FILE,
|
||||
.fw_api2 = AR6004_HW_1_1_FIRMWARE_2_FILE,
|
||||
.fw_board = AR6004_HW_1_1_BOARD_DATA_FILE,
|
||||
.fw_default_board = AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* Include definitions here that can be used to tune the WLAN module
|
||||
* behavior. Different customers can tune the behavior as per their needs,
|
||||
@ -58,7 +132,6 @@ module_param(suspend_cutpower, bool, 0444);
|
||||
*/
|
||||
#define WLAN_CONFIG_DISCONNECT_TIMEOUT 10
|
||||
|
||||
#define CONFIG_AR600x_DEBUG_UART_TX_PIN 8
|
||||
|
||||
#define ATH6KL_DATA_OFFSET 64
|
||||
struct sk_buff *ath6kl_buf_alloc(int size)
|
||||
@ -348,11 +421,7 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx)
|
||||
status = -EIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: Make sure p2p configurations are not applied to
|
||||
* non-p2p capable interfaces when multivif support is enabled.
|
||||
*/
|
||||
if (ar->p2p) {
|
||||
if (ar->p2p && (ar->vif_max == 1 || idx)) {
|
||||
ret = ath6kl_wmi_info_req_cmd(ar->wmi, idx,
|
||||
P2P_FLAG_CAPABILITIES_REQ |
|
||||
P2P_FLAG_MACADDR_REQ |
|
||||
@ -365,11 +434,7 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: Make sure p2p configurations are not applied to
|
||||
* non-p2p capable interfaces when multivif support is enabled.
|
||||
*/
|
||||
if (ar->p2p) {
|
||||
if (ar->p2p && (ar->vif_max == 1 || idx)) {
|
||||
/* Enable Probe Request reporting for P2P */
|
||||
ret = ath6kl_wmi_probe_report_req_cmd(ar->wmi, idx, true);
|
||||
if (ret) {
|
||||
@ -385,7 +450,7 @@ int ath6kl_configure_target(struct ath6kl *ar)
|
||||
{
|
||||
u32 param, ram_reserved_size;
|
||||
u8 fw_iftype, fw_mode = 0, fw_submode = 0;
|
||||
int i;
|
||||
int i, status;
|
||||
|
||||
/*
|
||||
* Note: Even though the firmware interface type is
|
||||
@ -397,7 +462,7 @@ int ath6kl_configure_target(struct ath6kl *ar)
|
||||
*/
|
||||
fw_iftype = HI_OPTION_FW_MODE_BSS_STA;
|
||||
|
||||
for (i = 0; i < MAX_NUM_VIF; i++)
|
||||
for (i = 0; i < ar->vif_max; i++)
|
||||
fw_mode |= fw_iftype << (i * HI_OPTION_FW_MODE_BITS);
|
||||
|
||||
/*
|
||||
@ -411,15 +476,11 @@ int ath6kl_configure_target(struct ath6kl *ar)
|
||||
fw_submode |= HI_OPTION_FW_SUBMODE_NONE <<
|
||||
(i * HI_OPTION_FW_SUBMODE_BITS);
|
||||
|
||||
for (i = ar->max_norm_iface; i < MAX_NUM_VIF; i++)
|
||||
for (i = ar->max_norm_iface; i < ar->vif_max; i++)
|
||||
fw_submode |= HI_OPTION_FW_SUBMODE_P2PDEV <<
|
||||
(i * HI_OPTION_FW_SUBMODE_BITS);
|
||||
|
||||
/*
|
||||
* FIXME: This needs to be removed once the multivif
|
||||
* support is enabled.
|
||||
*/
|
||||
if (ar->p2p)
|
||||
if (ar->p2p && ar->vif_max == 1)
|
||||
fw_submode = HI_OPTION_FW_SUBMODE_P2PDEV;
|
||||
|
||||
param = HTC_PROTOCOL_VERSION;
|
||||
@ -442,7 +503,7 @@ int ath6kl_configure_target(struct ath6kl *ar)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
param |= (MAX_NUM_VIF << HI_OPTION_NUM_DEV_SHIFT);
|
||||
param |= (ar->vif_max << HI_OPTION_NUM_DEV_SHIFT);
|
||||
param |= fw_mode << HI_OPTION_FW_MODE_SHIFT;
|
||||
param |= fw_submode << HI_OPTION_FW_SUBMODE_SHIFT;
|
||||
|
||||
@ -491,6 +552,24 @@ int ath6kl_configure_target(struct ath6kl *ar)
|
||||
/* use default number of control buffers */
|
||||
return -EIO;
|
||||
|
||||
/* Configure GPIO AR600x UART */
|
||||
param = ar->hw.uarttx_pin;
|
||||
status = ath6kl_bmi_write(ar,
|
||||
ath6kl_get_hi_item_addr(ar,
|
||||
HI_ITEM(hi_dbg_uart_txpin)),
|
||||
(u8 *)¶m, 4);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
/* Configure target refclk_hz */
|
||||
param = ar->hw.refclk_hz;
|
||||
status = ath6kl_bmi_write(ar,
|
||||
ath6kl_get_hi_item_addr(ar,
|
||||
HI_ITEM(hi_refclk_hz)),
|
||||
(u8 *)¶m, 4);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -550,11 +629,11 @@ static int ath6kl_get_fw(struct ath6kl *ar, const char *filename,
|
||||
static const char *get_target_ver_dir(const struct ath6kl *ar)
|
||||
{
|
||||
switch (ar->version.target_ver) {
|
||||
case AR6003_REV1_VERSION:
|
||||
case AR6003_HW_1_0_VERSION:
|
||||
return "ath6k/AR6003/hw1.0";
|
||||
case AR6003_REV2_VERSION:
|
||||
case AR6003_HW_2_0_VERSION:
|
||||
return "ath6k/AR6003/hw2.0";
|
||||
case AR6003_REV3_VERSION:
|
||||
case AR6003_HW_2_1_1_VERSION:
|
||||
return "ath6k/AR6003/hw2.1.1";
|
||||
}
|
||||
ath6kl_warn("%s: unsupported target version 0x%x.\n", __func__,
|
||||
@ -612,17 +691,10 @@ static int ath6kl_fetch_board_file(struct ath6kl *ar)
|
||||
if (ar->fw_board != NULL)
|
||||
return 0;
|
||||
|
||||
switch (ar->version.target_ver) {
|
||||
case AR6003_REV2_VERSION:
|
||||
filename = AR6003_REV2_BOARD_DATA_FILE;
|
||||
break;
|
||||
case AR6004_REV1_VERSION:
|
||||
filename = AR6004_REV1_BOARD_DATA_FILE;
|
||||
break;
|
||||
default:
|
||||
filename = AR6003_REV3_BOARD_DATA_FILE;
|
||||
break;
|
||||
}
|
||||
if (WARN_ON(ar->hw.fw_board == NULL))
|
||||
return -EINVAL;
|
||||
|
||||
filename = ar->hw.fw_board;
|
||||
|
||||
ret = ath6kl_get_fw(ar, filename, &ar->fw_board,
|
||||
&ar->fw_board_len);
|
||||
@ -640,17 +712,7 @@ static int ath6kl_fetch_board_file(struct ath6kl *ar)
|
||||
ath6kl_warn("Failed to get board file %s (%d), trying to find default board file.\n",
|
||||
filename, ret);
|
||||
|
||||
switch (ar->version.target_ver) {
|
||||
case AR6003_REV2_VERSION:
|
||||
filename = AR6003_REV2_DEFAULT_BOARD_DATA_FILE;
|
||||
break;
|
||||
case AR6004_REV1_VERSION:
|
||||
filename = AR6004_REV1_DEFAULT_BOARD_DATA_FILE;
|
||||
break;
|
||||
default:
|
||||
filename = AR6003_REV3_DEFAULT_BOARD_DATA_FILE;
|
||||
break;
|
||||
}
|
||||
filename = ar->hw.fw_default_board;
|
||||
|
||||
ret = ath6kl_get_fw(ar, filename, &ar->fw_board,
|
||||
&ar->fw_board_len);
|
||||
@ -674,19 +736,14 @@ static int ath6kl_fetch_otp_file(struct ath6kl *ar)
|
||||
if (ar->fw_otp != NULL)
|
||||
return 0;
|
||||
|
||||
switch (ar->version.target_ver) {
|
||||
case AR6003_REV2_VERSION:
|
||||
filename = AR6003_REV2_OTP_FILE;
|
||||
break;
|
||||
case AR6004_REV1_VERSION:
|
||||
ath6kl_dbg(ATH6KL_DBG_TRC, "AR6004 doesn't need OTP file\n");
|
||||
if (ar->hw.fw_otp == NULL) {
|
||||
ath6kl_dbg(ATH6KL_DBG_BOOT,
|
||||
"no OTP file configured for this hw\n");
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
filename = AR6003_REV3_OTP_FILE;
|
||||
break;
|
||||
}
|
||||
|
||||
filename = ar->hw.fw_otp;
|
||||
|
||||
ret = ath6kl_get_fw(ar, filename, &ar->fw_otp,
|
||||
&ar->fw_otp_len);
|
||||
if (ret) {
|
||||
@ -707,38 +764,22 @@ static int ath6kl_fetch_fw_file(struct ath6kl *ar)
|
||||
return 0;
|
||||
|
||||
if (testmode) {
|
||||
switch (ar->version.target_ver) {
|
||||
case AR6003_REV2_VERSION:
|
||||
filename = AR6003_REV2_TCMD_FIRMWARE_FILE;
|
||||
break;
|
||||
case AR6003_REV3_VERSION:
|
||||
filename = AR6003_REV3_TCMD_FIRMWARE_FILE;
|
||||
break;
|
||||
case AR6004_REV1_VERSION:
|
||||
ath6kl_warn("testmode not supported with ar6004\n");
|
||||
if (ar->hw.fw_tcmd == NULL) {
|
||||
ath6kl_warn("testmode not supported\n");
|
||||
return -EOPNOTSUPP;
|
||||
default:
|
||||
ath6kl_warn("unknown target version: 0x%x\n",
|
||||
ar->version.target_ver);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
filename = ar->hw.fw_tcmd;
|
||||
|
||||
set_bit(TESTMODE, &ar->flag);
|
||||
|
||||
goto get_fw;
|
||||
}
|
||||
|
||||
switch (ar->version.target_ver) {
|
||||
case AR6003_REV2_VERSION:
|
||||
filename = AR6003_REV2_FIRMWARE_FILE;
|
||||
break;
|
||||
case AR6004_REV1_VERSION:
|
||||
filename = AR6004_REV1_FIRMWARE_FILE;
|
||||
break;
|
||||
default:
|
||||
filename = AR6003_REV3_FIRMWARE_FILE;
|
||||
break;
|
||||
}
|
||||
if (WARN_ON(ar->hw.fw == NULL))
|
||||
return -EINVAL;
|
||||
|
||||
filename = ar->hw.fw;
|
||||
|
||||
get_fw:
|
||||
ret = ath6kl_get_fw(ar, filename, &ar->fw, &ar->fw_len);
|
||||
@ -756,27 +797,20 @@ static int ath6kl_fetch_patch_file(struct ath6kl *ar)
|
||||
const char *filename;
|
||||
int ret;
|
||||
|
||||
switch (ar->version.target_ver) {
|
||||
case AR6003_REV2_VERSION:
|
||||
filename = AR6003_REV2_PATCH_FILE;
|
||||
break;
|
||||
case AR6004_REV1_VERSION:
|
||||
/* FIXME: implement for AR6004 */
|
||||
if (ar->fw_patch != NULL)
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
filename = AR6003_REV3_PATCH_FILE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ar->fw_patch == NULL) {
|
||||
ret = ath6kl_get_fw(ar, filename, &ar->fw_patch,
|
||||
&ar->fw_patch_len);
|
||||
if (ret) {
|
||||
ath6kl_err("Failed to get patch file %s: %d\n",
|
||||
filename, ret);
|
||||
return ret;
|
||||
}
|
||||
if (ar->hw.fw_patch == NULL)
|
||||
return 0;
|
||||
|
||||
filename = ar->hw.fw_patch;
|
||||
|
||||
ret = ath6kl_get_fw(ar, filename, &ar->fw_patch,
|
||||
&ar->fw_patch_len);
|
||||
if (ret) {
|
||||
ath6kl_err("Failed to get patch file %s: %d\n",
|
||||
filename, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -811,19 +845,10 @@ static int ath6kl_fetch_fw_api2(struct ath6kl *ar)
|
||||
int ret, ie_id, i, index, bit;
|
||||
__le32 *val;
|
||||
|
||||
switch (ar->version.target_ver) {
|
||||
case AR6003_REV2_VERSION:
|
||||
filename = AR6003_REV2_FIRMWARE_2_FILE;
|
||||
break;
|
||||
case AR6003_REV3_VERSION:
|
||||
filename = AR6003_REV3_FIRMWARE_2_FILE;
|
||||
break;
|
||||
case AR6004_REV1_VERSION:
|
||||
filename = AR6004_REV1_FIRMWARE_2_FILE;
|
||||
break;
|
||||
default:
|
||||
if (ar->hw.fw_api2 == NULL)
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
filename = ar->hw.fw_api2;
|
||||
|
||||
ret = request_firmware(&fw, filename, ar->dev);
|
||||
if (ret)
|
||||
@ -913,12 +938,15 @@ static int ath6kl_fetch_fw_api2(struct ath6kl *ar)
|
||||
ar->hw.reserved_ram_size);
|
||||
break;
|
||||
case ATH6KL_FW_IE_CAPABILITIES:
|
||||
if (ie_len < DIV_ROUND_UP(ATH6KL_FW_CAPABILITY_MAX, 8))
|
||||
break;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_BOOT,
|
||||
"found firmware capabilities ie (%zd B)\n",
|
||||
ie_len);
|
||||
|
||||
for (i = 0; i < ATH6KL_FW_CAPABILITY_MAX; i++) {
|
||||
index = ALIGN(i, 8) / 8;
|
||||
index = i / 8;
|
||||
bit = i % 8;
|
||||
|
||||
if (data[index] & (1 << bit))
|
||||
@ -937,9 +965,34 @@ static int ath6kl_fetch_fw_api2(struct ath6kl *ar)
|
||||
ar->hw.dataset_patch_addr = le32_to_cpup(val);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_BOOT,
|
||||
"found patch address ie 0x%d\n",
|
||||
"found patch address ie 0x%x\n",
|
||||
ar->hw.dataset_patch_addr);
|
||||
break;
|
||||
case ATH6KL_FW_IE_BOARD_ADDR:
|
||||
if (ie_len != sizeof(*val))
|
||||
break;
|
||||
|
||||
val = (__le32 *) data;
|
||||
ar->hw.board_addr = le32_to_cpup(val);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_BOOT,
|
||||
"found board address ie 0x%x\n",
|
||||
ar->hw.board_addr);
|
||||
break;
|
||||
case ATH6KL_FW_IE_VIF_MAX:
|
||||
if (ie_len != sizeof(*val))
|
||||
break;
|
||||
|
||||
val = (__le32 *) data;
|
||||
ar->vif_max = min_t(unsigned int, le32_to_cpup(val),
|
||||
ATH6KL_VIF_MAX);
|
||||
|
||||
if (ar->vif_max > 1 && !ar->p2p)
|
||||
ar->max_norm_iface = 2;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_BOOT,
|
||||
"found vif max ie %d\n", ar->vif_max);
|
||||
break;
|
||||
default:
|
||||
ath6kl_dbg(ATH6KL_DBG_BOOT, "Unknown fw ie: %u\n",
|
||||
le32_to_cpup(&hdr->id));
|
||||
@ -994,8 +1047,8 @@ static int ath6kl_upload_board_file(struct ath6kl *ar)
|
||||
* For AR6004, host determine Target RAM address for
|
||||
* writing board data.
|
||||
*/
|
||||
if (ar->target_type == TARGET_TYPE_AR6004) {
|
||||
board_address = AR6004_REV1_BOARD_DATA_ADDRESS;
|
||||
if (ar->hw.board_addr != 0) {
|
||||
board_address = ar->hw.board_addr;
|
||||
ath6kl_bmi_write(ar,
|
||||
ath6kl_get_hi_item_addr(ar,
|
||||
HI_ITEM(hi_board_data)),
|
||||
@ -1013,7 +1066,8 @@ static int ath6kl_upload_board_file(struct ath6kl *ar)
|
||||
HI_ITEM(hi_board_ext_data)),
|
||||
(u8 *) &board_ext_address, 4);
|
||||
|
||||
if (board_ext_address == 0) {
|
||||
if (ar->target_type == TARGET_TYPE_AR6003 &&
|
||||
board_ext_address == 0) {
|
||||
ath6kl_err("Failed to get board file target address.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -1033,8 +1087,8 @@ static int ath6kl_upload_board_file(struct ath6kl *ar)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ar->fw_board_len == (board_data_size +
|
||||
board_ext_data_size)) {
|
||||
if (board_ext_address &&
|
||||
ar->fw_board_len == (board_data_size + board_ext_data_size)) {
|
||||
|
||||
/* write extended board data */
|
||||
ath6kl_dbg(ATH6KL_DBG_BOOT,
|
||||
@ -1092,8 +1146,8 @@ static int ath6kl_upload_otp(struct ath6kl *ar)
|
||||
bool from_hw = false;
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(ar->fw_otp == NULL))
|
||||
return -ENOENT;
|
||||
if (ar->fw_otp == NULL)
|
||||
return 0;
|
||||
|
||||
address = ar->hw.app_load_addr;
|
||||
|
||||
@ -1142,7 +1196,7 @@ static int ath6kl_upload_firmware(struct ath6kl *ar)
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(ar->fw == NULL))
|
||||
return -ENOENT;
|
||||
return 0;
|
||||
|
||||
address = ar->hw.app_load_addr;
|
||||
|
||||
@ -1172,8 +1226,8 @@ static int ath6kl_upload_patch(struct ath6kl *ar)
|
||||
u32 address, param;
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(ar->fw_patch == NULL))
|
||||
return -ENOENT;
|
||||
if (ar->fw_patch == NULL)
|
||||
return 0;
|
||||
|
||||
address = ar->hw.dataset_patch_addr;
|
||||
|
||||
@ -1258,7 +1312,7 @@ static int ath6kl_init_upload(struct ath6kl *ar)
|
||||
return status;
|
||||
|
||||
/* WAR to avoid SDIO CRC err */
|
||||
if (ar->version.target_ver == AR6003_REV2_VERSION) {
|
||||
if (ar->version.target_ver == AR6003_HW_2_0_VERSION) {
|
||||
ath6kl_err("temporary war to avoid sdio crc error\n");
|
||||
|
||||
param = 0x20;
|
||||
@ -1315,47 +1369,29 @@ static int ath6kl_init_upload(struct ath6kl *ar)
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
/* Configure GPIO AR6003 UART */
|
||||
param = CONFIG_AR600x_DEBUG_UART_TX_PIN;
|
||||
status = ath6kl_bmi_write(ar,
|
||||
ath6kl_get_hi_item_addr(ar,
|
||||
HI_ITEM(hi_dbg_uart_txpin)),
|
||||
(u8 *)¶m, 4);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int ath6kl_init_hw_params(struct ath6kl *ar)
|
||||
{
|
||||
switch (ar->version.target_ver) {
|
||||
case AR6003_REV2_VERSION:
|
||||
ar->hw.dataset_patch_addr = AR6003_REV2_DATASET_PATCH_ADDRESS;
|
||||
ar->hw.app_load_addr = AR6003_REV2_APP_LOAD_ADDRESS;
|
||||
ar->hw.board_ext_data_addr = AR6003_REV2_BOARD_EXT_DATA_ADDRESS;
|
||||
ar->hw.reserved_ram_size = AR6003_REV2_RAM_RESERVE_SIZE;
|
||||
const struct ath6kl_hw *hw;
|
||||
int i;
|
||||
|
||||
/* hw2.0 needs override address hardcoded */
|
||||
ar->hw.app_start_override_addr = 0x944C00;
|
||||
for (i = 0; i < ARRAY_SIZE(hw_list); i++) {
|
||||
hw = &hw_list[i];
|
||||
|
||||
break;
|
||||
case AR6003_REV3_VERSION:
|
||||
ar->hw.dataset_patch_addr = AR6003_REV3_DATASET_PATCH_ADDRESS;
|
||||
ar->hw.app_load_addr = 0x1234;
|
||||
ar->hw.board_ext_data_addr = AR6003_REV3_BOARD_EXT_DATA_ADDRESS;
|
||||
ar->hw.reserved_ram_size = AR6003_REV3_RAM_RESERVE_SIZE;
|
||||
break;
|
||||
case AR6004_REV1_VERSION:
|
||||
ar->hw.dataset_patch_addr = AR6003_REV2_DATASET_PATCH_ADDRESS;
|
||||
ar->hw.app_load_addr = AR6003_REV3_APP_LOAD_ADDRESS;
|
||||
ar->hw.board_ext_data_addr = AR6004_REV1_BOARD_EXT_DATA_ADDRESS;
|
||||
ar->hw.reserved_ram_size = AR6004_REV1_RAM_RESERVE_SIZE;
|
||||
break;
|
||||
default:
|
||||
if (hw->id == ar->version.target_ver)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE(hw_list)) {
|
||||
ath6kl_err("Unsupported hardware version: 0x%x\n",
|
||||
ar->version.target_ver);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ar->hw = *hw;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_BOOT,
|
||||
"target_ver 0x%x target_type 0x%x dataset_patch 0x%x app_load_addr 0x%x\n",
|
||||
ar->version.target_ver, ar->target_type,
|
||||
@ -1364,10 +1400,25 @@ static int ath6kl_init_hw_params(struct ath6kl *ar)
|
||||
"app_start_override_addr 0x%x board_ext_data_addr 0x%x reserved_ram_size 0x%x",
|
||||
ar->hw.app_start_override_addr, ar->hw.board_ext_data_addr,
|
||||
ar->hw.reserved_ram_size);
|
||||
ath6kl_dbg(ATH6KL_DBG_BOOT,
|
||||
"refclk_hz %d uarttx_pin %d",
|
||||
ar->hw.refclk_hz, ar->hw.uarttx_pin);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *ath6kl_init_get_hif_name(enum ath6kl_hif_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case ATH6KL_HIF_TYPE_SDIO:
|
||||
return "sdio";
|
||||
case ATH6KL_HIF_TYPE_USB:
|
||||
return "usb";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ath6kl_init_hw_start(struct ath6kl *ar)
|
||||
{
|
||||
long timeleft;
|
||||
@ -1428,6 +1479,15 @@ int ath6kl_init_hw_start(struct ath6kl *ar)
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_BOOT, "firmware booted\n");
|
||||
|
||||
|
||||
if (test_and_clear_bit(FIRST_BOOT, &ar->flag)) {
|
||||
ath6kl_info("%s %s fw %s%s\n",
|
||||
ar->hw.name,
|
||||
ath6kl_init_get_hif_name(ar->hif_type),
|
||||
ar->wiphy->fw_version,
|
||||
test_bit(TESTMODE, &ar->flag) ? " testmode" : "");
|
||||
}
|
||||
|
||||
if (ar->version.abi_ver != ATH6KL_ABI_VERSION) {
|
||||
ath6kl_err("abi version mismatch: host(0x%x), target(0x%x)\n",
|
||||
ATH6KL_ABI_VERSION, ar->version.abi_ver);
|
||||
@ -1448,7 +1508,7 @@ int ath6kl_init_hw_start(struct ath6kl *ar)
|
||||
if ((ath6kl_set_host_app_area(ar)) != 0)
|
||||
ath6kl_err("unable to set the host app area\n");
|
||||
|
||||
for (i = 0; i < MAX_NUM_VIF; i++) {
|
||||
for (i = 0; i < ar->vif_max; i++) {
|
||||
ret = ath6kl_target_config_wlan_params(ar, i);
|
||||
if (ret)
|
||||
goto err_htc_stop;
|
||||
@ -1558,7 +1618,7 @@ int ath6kl_core_init(struct ath6kl *ar)
|
||||
goto err_node_cleanup;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_NUM_VIF; i++)
|
||||
for (i = 0; i < ar->vif_max; i++)
|
||||
ar->avail_idx_map |= BIT(i);
|
||||
|
||||
rtnl_lock();
|
||||
@ -1603,7 +1663,17 @@ int ath6kl_core_init(struct ath6kl *ar)
|
||||
|
||||
ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM |
|
||||
WIPHY_FLAG_HAVE_AP_SME |
|
||||
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
|
||||
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
|
||||
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
|
||||
|
||||
if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities))
|
||||
ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
|
||||
|
||||
ar->wiphy->probe_resp_offload =
|
||||
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
|
||||
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
|
||||
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P |
|
||||
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U;
|
||||
|
||||
set_bit(FIRST_BOOT, &ar->flag);
|
||||
|
||||
|
@ -175,64 +175,6 @@ void ath6kl_free_cookie(struct ath6kl *ar, struct ath6kl_cookie *cookie)
|
||||
ar->cookie_count++;
|
||||
}
|
||||
|
||||
/* set the window address register (using 4-byte register access ). */
|
||||
static int ath6kl_set_addrwin_reg(struct ath6kl *ar, u32 reg_addr, u32 addr)
|
||||
{
|
||||
int status;
|
||||
s32 i;
|
||||
__le32 addr_val;
|
||||
|
||||
/*
|
||||
* Write bytes 1,2,3 of the register to set the upper address bytes,
|
||||
* the LSB is written last to initiate the access cycle
|
||||
*/
|
||||
|
||||
for (i = 1; i <= 3; i++) {
|
||||
/*
|
||||
* Fill the buffer with the address byte value we want to
|
||||
* hit 4 times. No need to worry about endianness as the
|
||||
* same byte is copied to all four bytes of addr_val at
|
||||
* any time.
|
||||
*/
|
||||
memset((u8 *)&addr_val, ((u8 *)&addr)[i], 4);
|
||||
|
||||
/*
|
||||
* Hit each byte of the register address with a 4-byte
|
||||
* write operation to the same address, this is a harmless
|
||||
* operation.
|
||||
*/
|
||||
status = hif_read_write_sync(ar, reg_addr + i, (u8 *)&addr_val,
|
||||
4, HIF_WR_SYNC_BYTE_FIX);
|
||||
if (status)
|
||||
break;
|
||||
}
|
||||
|
||||
if (status) {
|
||||
ath6kl_err("failed to write initial bytes of 0x%x to window reg: 0x%X\n",
|
||||
addr, reg_addr);
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the address register again, this time write the whole
|
||||
* 4-byte value. The effect here is that the LSB write causes the
|
||||
* cycle to start, the extra 3 byte write to bytes 1,2,3 has no
|
||||
* effect since we are writing the same values again
|
||||
*/
|
||||
addr_val = cpu_to_le32(addr);
|
||||
status = hif_read_write_sync(ar, reg_addr,
|
||||
(u8 *)&(addr_val),
|
||||
4, HIF_WR_SYNC_BYTE_INC);
|
||||
|
||||
if (status) {
|
||||
ath6kl_err("failed to write 0x%x to window reg: 0x%X\n",
|
||||
addr, reg_addr);
|
||||
return status;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read from the hardware through its diagnostic window. No cooperation
|
||||
* from the firmware is required for this.
|
||||
@ -241,14 +183,7 @@ int ath6kl_diag_read32(struct ath6kl *ar, u32 address, u32 *value)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* set window register to start read cycle */
|
||||
ret = ath6kl_set_addrwin_reg(ar, WINDOW_READ_ADDR_ADDRESS, address);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* read the data */
|
||||
ret = hif_read_write_sync(ar, WINDOW_DATA_ADDRESS, (u8 *) value,
|
||||
sizeof(*value), HIF_RD_SYNC_BYTE_INC);
|
||||
ret = ath6kl_hif_diag_read32(ar, address, value);
|
||||
if (ret) {
|
||||
ath6kl_warn("failed to read32 through diagnose window: %d\n",
|
||||
ret);
|
||||
@ -266,18 +201,15 @@ int ath6kl_diag_write32(struct ath6kl *ar, u32 address, __le32 value)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* set write data */
|
||||
ret = hif_read_write_sync(ar, WINDOW_DATA_ADDRESS, (u8 *) &value,
|
||||
sizeof(value), HIF_WR_SYNC_BYTE_INC);
|
||||
ret = ath6kl_hif_diag_write32(ar, address, value);
|
||||
|
||||
if (ret) {
|
||||
ath6kl_err("failed to write 0x%x during diagnose window to 0x%d\n",
|
||||
address, value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* set window register, which starts the write cycle */
|
||||
return ath6kl_set_addrwin_reg(ar, WINDOW_WRITE_ADDR_ADDRESS,
|
||||
address);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath6kl_diag_read(struct ath6kl *ar, u32 address, void *data, u32 length)
|
||||
@ -465,7 +397,9 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel)
|
||||
case NONE_AUTH:
|
||||
if (vif->prwise_crypto == WEP_CRYPT)
|
||||
ath6kl_install_static_wep_keys(vif);
|
||||
break;
|
||||
if (!ik->valid || ik->key_type != WAPI_CRYPT)
|
||||
break;
|
||||
/* for WAPI, we need to set the delayed group key, continue: */
|
||||
case WPA_PSK_AUTH:
|
||||
case WPA2_PSK_AUTH:
|
||||
case (WPA_PSK_AUTH | WPA2_PSK_AUTH):
|
||||
@ -534,6 +468,18 @@ void ath6kl_connect_ap_mode_sta(struct ath6kl_vif *vif, u16 aid, u8 *mac_addr,
|
||||
wpa_ie = pos; /* WPS IE */
|
||||
break; /* overrides WPA/RSN IE */
|
||||
}
|
||||
} else if (pos[0] == 0x44 && wpa_ie == NULL) {
|
||||
/*
|
||||
* Note: WAPI Parameter Set IE re-uses Element ID that
|
||||
* was officially allocated for BSS AC Access Delay. As
|
||||
* such, we need to be a bit more careful on when
|
||||
* parsing the frame. However, BSS AC Access Delay
|
||||
* element is not supposed to be included in
|
||||
* (Re)Association Request frames, so this should not
|
||||
* cause problems.
|
||||
*/
|
||||
wpa_ie = pos; /* WAPI IE */
|
||||
break;
|
||||
}
|
||||
pos += 2 + pos[1];
|
||||
}
|
||||
@ -581,20 +527,6 @@ void ath6kl_disconnect(struct ath6kl_vif *vif)
|
||||
|
||||
/* WMI Event handlers */
|
||||
|
||||
static const char *get_hw_id_string(u32 id)
|
||||
{
|
||||
switch (id) {
|
||||
case AR6003_REV1_VERSION:
|
||||
return "1.0";
|
||||
case AR6003_REV2_VERSION:
|
||||
return "2.0";
|
||||
case AR6003_REV3_VERSION:
|
||||
return "2.1.1";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver)
|
||||
{
|
||||
struct ath6kl *ar = devt;
|
||||
@ -617,13 +549,6 @@ void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver)
|
||||
/* indicate to the waiting thread that the ready event was received */
|
||||
set_bit(WMI_READY, &ar->flag);
|
||||
wake_up(&ar->event_wq);
|
||||
|
||||
if (test_and_clear_bit(FIRST_BOOT, &ar->flag)) {
|
||||
ath6kl_info("hw %s fw %s%s\n",
|
||||
get_hw_id_string(ar->wiphy->hw_version),
|
||||
ar->wiphy->fw_version,
|
||||
test_bit(TESTMODE, &ar->flag) ? " testmode" : "");
|
||||
}
|
||||
}
|
||||
|
||||
void ath6kl_scan_complete_evt(struct ath6kl_vif *vif, int status)
|
||||
@ -1077,21 +1002,11 @@ static int ath6kl_open(struct net_device *dev)
|
||||
|
||||
static int ath6kl_close(struct net_device *dev)
|
||||
{
|
||||
struct ath6kl *ar = ath6kl_priv(dev);
|
||||
struct ath6kl_vif *vif = netdev_priv(dev);
|
||||
|
||||
netif_stop_queue(dev);
|
||||
|
||||
ath6kl_disconnect(vif);
|
||||
|
||||
if (test_bit(WMI_READY, &ar->flag)) {
|
||||
if (ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0xFFFF,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0))
|
||||
return -EIO;
|
||||
|
||||
}
|
||||
|
||||
ath6kl_cfg80211_scan_complete_event(vif, true);
|
||||
ath6kl_cfg80211_stop(vif);
|
||||
|
||||
clear_bit(WLAN_ENABLED, &vif->flags);
|
||||
|
||||
|
@ -40,8 +40,12 @@ struct ath6kl_sdio {
|
||||
struct bus_request bus_req[BUS_REQUEST_MAX_NUM];
|
||||
|
||||
struct ath6kl *ar;
|
||||
|
||||
u8 *dma_buffer;
|
||||
|
||||
/* protects access to dma_buffer */
|
||||
struct mutex dma_buffer_mutex;
|
||||
|
||||
/* scatter request list head */
|
||||
struct list_head scat_req;
|
||||
|
||||
@ -396,6 +400,7 @@ static int ath6kl_sdio_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf,
|
||||
if (buf_needs_bounce(buf)) {
|
||||
if (!ar_sdio->dma_buffer)
|
||||
return -ENOMEM;
|
||||
mutex_lock(&ar_sdio->dma_buffer_mutex);
|
||||
tbuf = ar_sdio->dma_buffer;
|
||||
memcpy(tbuf, buf, len);
|
||||
bounced = true;
|
||||
@ -406,6 +411,9 @@ static int ath6kl_sdio_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf,
|
||||
if ((request & HIF_READ) && bounced)
|
||||
memcpy(buf, tbuf, len);
|
||||
|
||||
if (bounced)
|
||||
mutex_unlock(&ar_sdio->dma_buffer_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -799,7 +807,28 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((flags & MMC_PM_WAKE_SDIO_IRQ) && wow) {
|
||||
if (!(flags & MMC_PM_WAKE_SDIO_IRQ))
|
||||
goto deepsleep;
|
||||
|
||||
/* sdio irq wakes up host */
|
||||
|
||||
if (ar->state == ATH6KL_STATE_SCHED_SCAN) {
|
||||
ret = ath6kl_cfg80211_suspend(ar,
|
||||
ATH6KL_CFG_SUSPEND_SCHED_SCAN,
|
||||
NULL);
|
||||
if (ret) {
|
||||
ath6kl_warn("Schedule scan suspend failed: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ);
|
||||
if (ret)
|
||||
ath6kl_warn("set sdio wake irq flag failed: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (wow) {
|
||||
/*
|
||||
* The host sdio controller is capable of keep power and
|
||||
* sdio irq wake up at this point. It's fine to continue
|
||||
@ -816,6 +845,7 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
|
||||
return ret;
|
||||
}
|
||||
|
||||
deepsleep:
|
||||
return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_DEEPSLEEP, NULL);
|
||||
}
|
||||
|
||||
@ -839,6 +869,8 @@ static int ath6kl_sdio_resume(struct ath6kl *ar)
|
||||
|
||||
case ATH6KL_STATE_WOW:
|
||||
break;
|
||||
case ATH6KL_STATE_SCHED_SCAN:
|
||||
break;
|
||||
}
|
||||
|
||||
ath6kl_cfg80211_resume(ar);
|
||||
@ -846,6 +878,264 @@ static int ath6kl_sdio_resume(struct ath6kl *ar)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* set the window address register (using 4-byte register access ). */
|
||||
static int ath6kl_set_addrwin_reg(struct ath6kl *ar, u32 reg_addr, u32 addr)
|
||||
{
|
||||
int status;
|
||||
u8 addr_val[4];
|
||||
s32 i;
|
||||
|
||||
/*
|
||||
* Write bytes 1,2,3 of the register to set the upper address bytes,
|
||||
* the LSB is written last to initiate the access cycle
|
||||
*/
|
||||
|
||||
for (i = 1; i <= 3; i++) {
|
||||
/*
|
||||
* Fill the buffer with the address byte value we want to
|
||||
* hit 4 times.
|
||||
*/
|
||||
memset(addr_val, ((u8 *)&addr)[i], 4);
|
||||
|
||||
/*
|
||||
* Hit each byte of the register address with a 4-byte
|
||||
* write operation to the same address, this is a harmless
|
||||
* operation.
|
||||
*/
|
||||
status = ath6kl_sdio_read_write_sync(ar, reg_addr + i, addr_val,
|
||||
4, HIF_WR_SYNC_BYTE_FIX);
|
||||
if (status)
|
||||
break;
|
||||
}
|
||||
|
||||
if (status) {
|
||||
ath6kl_err("%s: failed to write initial bytes of 0x%x "
|
||||
"to window reg: 0x%X\n", __func__,
|
||||
addr, reg_addr);
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the address register again, this time write the whole
|
||||
* 4-byte value. The effect here is that the LSB write causes the
|
||||
* cycle to start, the extra 3 byte write to bytes 1,2,3 has no
|
||||
* effect since we are writing the same values again
|
||||
*/
|
||||
status = ath6kl_sdio_read_write_sync(ar, reg_addr, (u8 *)(&addr),
|
||||
4, HIF_WR_SYNC_BYTE_INC);
|
||||
|
||||
if (status) {
|
||||
ath6kl_err("%s: failed to write 0x%x to window reg: 0x%X\n",
|
||||
__func__, addr, reg_addr);
|
||||
return status;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kl_sdio_diag_read32(struct ath6kl *ar, u32 address, u32 *data)
|
||||
{
|
||||
int status;
|
||||
|
||||
/* set window register to start read cycle */
|
||||
status = ath6kl_set_addrwin_reg(ar, WINDOW_READ_ADDR_ADDRESS,
|
||||
address);
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
/* read the data */
|
||||
status = ath6kl_sdio_read_write_sync(ar, WINDOW_DATA_ADDRESS,
|
||||
(u8 *)data, sizeof(u32), HIF_RD_SYNC_BYTE_INC);
|
||||
if (status) {
|
||||
ath6kl_err("%s: failed to read from window data addr\n",
|
||||
__func__);
|
||||
return status;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int ath6kl_sdio_diag_write32(struct ath6kl *ar, u32 address,
|
||||
__le32 data)
|
||||
{
|
||||
int status;
|
||||
u32 val = (__force u32) data;
|
||||
|
||||
/* set write data */
|
||||
status = ath6kl_sdio_read_write_sync(ar, WINDOW_DATA_ADDRESS,
|
||||
(u8 *) &val, sizeof(u32), HIF_WR_SYNC_BYTE_INC);
|
||||
if (status) {
|
||||
ath6kl_err("%s: failed to write 0x%x to window data addr\n",
|
||||
__func__, data);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* set window register, which starts the write cycle */
|
||||
return ath6kl_set_addrwin_reg(ar, WINDOW_WRITE_ADDR_ADDRESS,
|
||||
address);
|
||||
}
|
||||
|
||||
static int ath6kl_sdio_bmi_credits(struct ath6kl *ar)
|
||||
{
|
||||
u32 addr;
|
||||
unsigned long timeout;
|
||||
int ret;
|
||||
|
||||
ar->bmi.cmd_credits = 0;
|
||||
|
||||
/* Read the counter register to get the command credits */
|
||||
addr = COUNT_DEC_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 4;
|
||||
|
||||
timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT);
|
||||
while (time_before(jiffies, timeout) && !ar->bmi.cmd_credits) {
|
||||
|
||||
/*
|
||||
* Hit the credit counter with a 4-byte access, the first byte
|
||||
* read will hit the counter and cause a decrement, while the
|
||||
* remaining 3 bytes has no effect. The rationale behind this
|
||||
* is to make all HIF accesses 4-byte aligned.
|
||||
*/
|
||||
ret = ath6kl_sdio_read_write_sync(ar, addr,
|
||||
(u8 *)&ar->bmi.cmd_credits, 4,
|
||||
HIF_RD_SYNC_BYTE_INC);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to decrement the command credit "
|
||||
"count register: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* The counter is only 8 bits.
|
||||
* Ignore anything in the upper 3 bytes
|
||||
*/
|
||||
ar->bmi.cmd_credits &= 0xFF;
|
||||
}
|
||||
|
||||
if (!ar->bmi.cmd_credits) {
|
||||
ath6kl_err("bmi communication timeout\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kl_bmi_get_rx_lkahd(struct ath6kl *ar)
|
||||
{
|
||||
unsigned long timeout;
|
||||
u32 rx_word = 0;
|
||||
int ret = 0;
|
||||
|
||||
timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT);
|
||||
while ((time_before(jiffies, timeout)) && !rx_word) {
|
||||
ret = ath6kl_sdio_read_write_sync(ar,
|
||||
RX_LOOKAHEAD_VALID_ADDRESS,
|
||||
(u8 *)&rx_word, sizeof(rx_word),
|
||||
HIF_RD_SYNC_BYTE_INC);
|
||||
if (ret) {
|
||||
ath6kl_err("unable to read RX_LOOKAHEAD_VALID\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* all we really want is one bit */
|
||||
rx_word &= (1 << ENDPOINT1);
|
||||
}
|
||||
|
||||
if (!rx_word) {
|
||||
ath6kl_err("bmi_recv_buf FIFO empty\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath6kl_sdio_bmi_write(struct ath6kl *ar, u8 *buf, u32 len)
|
||||
{
|
||||
int ret;
|
||||
u32 addr;
|
||||
|
||||
ret = ath6kl_sdio_bmi_credits(ar);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
addr = ar->mbox_info.htc_addr;
|
||||
|
||||
ret = ath6kl_sdio_read_write_sync(ar, addr, buf, len,
|
||||
HIF_WR_SYNC_BYTE_INC);
|
||||
if (ret)
|
||||
ath6kl_err("unable to send the bmi data to the device\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath6kl_sdio_bmi_read(struct ath6kl *ar, u8 *buf, u32 len)
|
||||
{
|
||||
int ret;
|
||||
u32 addr;
|
||||
|
||||
/*
|
||||
* During normal bootup, small reads may be required.
|
||||
* Rather than issue an HIF Read and then wait as the Target
|
||||
* adds successive bytes to the FIFO, we wait here until
|
||||
* we know that response data is available.
|
||||
*
|
||||
* This allows us to cleanly timeout on an unexpected
|
||||
* Target failure rather than risk problems at the HIF level.
|
||||
* In particular, this avoids SDIO timeouts and possibly garbage
|
||||
* data on some host controllers. And on an interconnect
|
||||
* such as Compact Flash (as well as some SDIO masters) which
|
||||
* does not provide any indication on data timeout, it avoids
|
||||
* a potential hang or garbage response.
|
||||
*
|
||||
* Synchronization is more difficult for reads larger than the
|
||||
* size of the MBOX FIFO (128B), because the Target is unable
|
||||
* to push the 129th byte of data until AFTER the Host posts an
|
||||
* HIF Read and removes some FIFO data. So for large reads the
|
||||
* Host proceeds to post an HIF Read BEFORE all the data is
|
||||
* actually available to read. Fortunately, large BMI reads do
|
||||
* not occur in practice -- they're supported for debug/development.
|
||||
*
|
||||
* So Host/Target BMI synchronization is divided into these cases:
|
||||
* CASE 1: length < 4
|
||||
* Should not happen
|
||||
*
|
||||
* CASE 2: 4 <= length <= 128
|
||||
* Wait for first 4 bytes to be in FIFO
|
||||
* If CONSERVATIVE_BMI_READ is enabled, also wait for
|
||||
* a BMI command credit, which indicates that the ENTIRE
|
||||
* response is available in the the FIFO
|
||||
*
|
||||
* CASE 3: length > 128
|
||||
* Wait for the first 4 bytes to be in FIFO
|
||||
*
|
||||
* For most uses, a small timeout should be sufficient and we will
|
||||
* usually see a response quickly; but there may be some unusual
|
||||
* (debug) cases of BMI_EXECUTE where we want an larger timeout.
|
||||
* For now, we use an unbounded busy loop while waiting for
|
||||
* BMI_EXECUTE.
|
||||
*
|
||||
* If BMI_EXECUTE ever needs to support longer-latency execution,
|
||||
* especially in production, this code needs to be enhanced to sleep
|
||||
* and yield. Also note that BMI_COMMUNICATION_TIMEOUT is currently
|
||||
* a function of Host processor speed.
|
||||
*/
|
||||
if (len >= 4) { /* NB: Currently, always true */
|
||||
ret = ath6kl_bmi_get_rx_lkahd(ar);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
addr = ar->mbox_info.htc_addr;
|
||||
ret = ath6kl_sdio_read_write_sync(ar, addr, buf, len,
|
||||
HIF_RD_SYNC_BYTE_INC);
|
||||
if (ret) {
|
||||
ath6kl_err("Unable to read the bmi data from the device: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath6kl_sdio_stop(struct ath6kl *ar)
|
||||
{
|
||||
struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
|
||||
@ -890,6 +1180,10 @@ static const struct ath6kl_hif_ops ath6kl_sdio_ops = {
|
||||
.cleanup_scatter = ath6kl_sdio_cleanup_scatter,
|
||||
.suspend = ath6kl_sdio_suspend,
|
||||
.resume = ath6kl_sdio_resume,
|
||||
.diag_read32 = ath6kl_sdio_diag_read32,
|
||||
.diag_write32 = ath6kl_sdio_diag_write32,
|
||||
.bmi_read = ath6kl_sdio_bmi_read,
|
||||
.bmi_write = ath6kl_sdio_bmi_write,
|
||||
.power_on = ath6kl_sdio_power_on,
|
||||
.power_off = ath6kl_sdio_power_off,
|
||||
.stop = ath6kl_sdio_stop,
|
||||
@ -958,6 +1252,7 @@ static int ath6kl_sdio_probe(struct sdio_func *func,
|
||||
spin_lock_init(&ar_sdio->lock);
|
||||
spin_lock_init(&ar_sdio->scat_lock);
|
||||
spin_lock_init(&ar_sdio->wr_async_lock);
|
||||
mutex_init(&ar_sdio->dma_buffer_mutex);
|
||||
|
||||
INIT_LIST_HEAD(&ar_sdio->scat_req);
|
||||
INIT_LIST_HEAD(&ar_sdio->bus_req_freeq);
|
||||
@ -976,8 +1271,10 @@ static int ath6kl_sdio_probe(struct sdio_func *func,
|
||||
}
|
||||
|
||||
ar_sdio->ar = ar;
|
||||
ar->hif_type = ATH6KL_HIF_TYPE_SDIO;
|
||||
ar->hif_priv = ar_sdio;
|
||||
ar->hif_ops = &ath6kl_sdio_ops;
|
||||
ar->bmi.max_data_size = 256;
|
||||
|
||||
ath6kl_sdio_set_mbox_info(ar);
|
||||
|
||||
@ -1027,13 +1324,15 @@ static void ath6kl_sdio_remove(struct sdio_func *func)
|
||||
static const struct sdio_device_id ath6kl_sdio_devices[] = {
|
||||
{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x0))},
|
||||
{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x1))},
|
||||
{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x0))},
|
||||
{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x1))},
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(sdio, ath6kl_sdio_devices);
|
||||
|
||||
static struct sdio_driver ath6kl_sdio_driver = {
|
||||
.name = "ath6kl",
|
||||
.name = "ath6kl_sdio",
|
||||
.id_table = ath6kl_sdio_devices,
|
||||
.probe = ath6kl_sdio_probe,
|
||||
.remove = ath6kl_sdio_remove,
|
||||
@ -1063,13 +1362,19 @@ MODULE_AUTHOR("Atheros Communications, Inc.");
|
||||
MODULE_DESCRIPTION("Driver support for Atheros AR600x SDIO devices");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
|
||||
MODULE_FIRMWARE(AR6003_REV2_OTP_FILE);
|
||||
MODULE_FIRMWARE(AR6003_REV2_FIRMWARE_FILE);
|
||||
MODULE_FIRMWARE(AR6003_REV2_PATCH_FILE);
|
||||
MODULE_FIRMWARE(AR6003_REV2_BOARD_DATA_FILE);
|
||||
MODULE_FIRMWARE(AR6003_REV2_DEFAULT_BOARD_DATA_FILE);
|
||||
MODULE_FIRMWARE(AR6003_REV3_OTP_FILE);
|
||||
MODULE_FIRMWARE(AR6003_REV3_FIRMWARE_FILE);
|
||||
MODULE_FIRMWARE(AR6003_REV3_PATCH_FILE);
|
||||
MODULE_FIRMWARE(AR6003_REV3_BOARD_DATA_FILE);
|
||||
MODULE_FIRMWARE(AR6003_REV3_DEFAULT_BOARD_DATA_FILE);
|
||||
MODULE_FIRMWARE(AR6003_HW_2_0_OTP_FILE);
|
||||
MODULE_FIRMWARE(AR6003_HW_2_0_FIRMWARE_FILE);
|
||||
MODULE_FIRMWARE(AR6003_HW_2_0_PATCH_FILE);
|
||||
MODULE_FIRMWARE(AR6003_HW_2_0_BOARD_DATA_FILE);
|
||||
MODULE_FIRMWARE(AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE);
|
||||
MODULE_FIRMWARE(AR6003_HW_2_1_1_OTP_FILE);
|
||||
MODULE_FIRMWARE(AR6003_HW_2_1_1_FIRMWARE_FILE);
|
||||
MODULE_FIRMWARE(AR6003_HW_2_1_1_PATCH_FILE);
|
||||
MODULE_FIRMWARE(AR6003_HW_2_1_1_BOARD_DATA_FILE);
|
||||
MODULE_FIRMWARE(AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE);
|
||||
MODULE_FIRMWARE(AR6004_HW_1_0_FIRMWARE_FILE);
|
||||
MODULE_FIRMWARE(AR6004_HW_1_0_BOARD_DATA_FILE);
|
||||
MODULE_FIRMWARE(AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE);
|
||||
MODULE_FIRMWARE(AR6004_HW_1_1_FIRMWARE_FILE);
|
||||
MODULE_FIRMWARE(AR6004_HW_1_1_BOARD_DATA_FILE);
|
||||
MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE);
|
||||
|
@ -20,7 +20,7 @@
|
||||
#define AR6003_BOARD_DATA_SZ 1024
|
||||
#define AR6003_BOARD_EXT_DATA_SZ 768
|
||||
|
||||
#define AR6004_BOARD_DATA_SZ 7168
|
||||
#define AR6004_BOARD_DATA_SZ 6144
|
||||
#define AR6004_BOARD_EXT_DATA_SZ 0
|
||||
|
||||
#define RESET_CONTROL_ADDRESS 0x00000000
|
||||
@ -334,20 +334,6 @@ struct host_interest {
|
||||
(((target_type) == TARGET_TYPE_AR6003) ? AR6003_VTOP(vaddr) : \
|
||||
(((target_type) == TARGET_TYPE_AR6004) ? AR6004_VTOP(vaddr) : 0))
|
||||
|
||||
#define AR6003_REV2_APP_LOAD_ADDRESS 0x543180
|
||||
#define AR6003_REV2_BOARD_EXT_DATA_ADDRESS 0x57E500
|
||||
#define AR6003_REV2_DATASET_PATCH_ADDRESS 0x57e884
|
||||
#define AR6003_REV2_RAM_RESERVE_SIZE 6912
|
||||
|
||||
#define AR6003_REV3_APP_LOAD_ADDRESS 0x545000
|
||||
#define AR6003_REV3_BOARD_EXT_DATA_ADDRESS 0x542330
|
||||
#define AR6003_REV3_DATASET_PATCH_ADDRESS 0x57FF74
|
||||
#define AR6003_REV3_RAM_RESERVE_SIZE 512
|
||||
|
||||
#define AR6004_REV1_BOARD_DATA_ADDRESS 0x435400
|
||||
#define AR6004_REV1_BOARD_EXT_DATA_ADDRESS 0x437000
|
||||
#define AR6004_REV1_RAM_RESERVE_SIZE 11264
|
||||
|
||||
#define ATH6KL_FWLOG_PAYLOAD_SIZE 1500
|
||||
|
||||
struct ath6kl_dbglog_buf {
|
||||
|
@ -453,11 +453,11 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
|
||||
set_bit(WMI_CTRL_EP_FULL, &ar->flag);
|
||||
spin_unlock_bh(&ar->lock);
|
||||
ath6kl_err("wmi ctrl ep is full\n");
|
||||
goto stop_adhoc_netq;
|
||||
return action;
|
||||
}
|
||||
|
||||
if (packet->info.tx.tag == ATH6KL_CONTROL_PKT_TAG)
|
||||
goto stop_adhoc_netq;
|
||||
return action;
|
||||
|
||||
/*
|
||||
* The last MAX_HI_COOKIE_NUM "batch" of cookies are reserved for
|
||||
@ -465,20 +465,18 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
|
||||
*/
|
||||
if (ar->ac_stream_pri_map[ar->ep2ac_map[endpoint]] <
|
||||
ar->hiac_stream_active_pri &&
|
||||
ar->cookie_count <= MAX_HI_COOKIE_NUM) {
|
||||
ar->cookie_count <= MAX_HI_COOKIE_NUM)
|
||||
/*
|
||||
* Give preference to the highest priority stream by
|
||||
* dropping the packets which overflowed.
|
||||
*/
|
||||
action = HTC_SEND_FULL_DROP;
|
||||
goto stop_adhoc_netq;
|
||||
}
|
||||
|
||||
stop_adhoc_netq:
|
||||
/* FIXME: Locking */
|
||||
spin_lock_bh(&ar->list_lock);
|
||||
list_for_each_entry(vif, &ar->vif_list, list) {
|
||||
if (vif->nw_type == ADHOC_NETWORK) {
|
||||
if (vif->nw_type == ADHOC_NETWORK ||
|
||||
action != HTC_SEND_FULL_DROP) {
|
||||
spin_unlock_bh(&ar->list_lock);
|
||||
|
||||
spin_lock_bh(&vif->if_lock);
|
||||
@ -543,7 +541,7 @@ void ath6kl_tx_complete(void *context, struct list_head *packet_queue)
|
||||
int status;
|
||||
enum htc_endpoint_id eid;
|
||||
bool wake_event = false;
|
||||
bool flushing[MAX_NUM_VIF] = {false};
|
||||
bool flushing[ATH6KL_VIF_MAX] = {false};
|
||||
u8 if_idx;
|
||||
struct ath6kl_vif *vif;
|
||||
|
||||
@ -571,8 +569,6 @@ void ath6kl_tx_complete(void *context, struct list_head *packet_queue)
|
||||
if (!skb || !skb->data)
|
||||
goto fatal;
|
||||
|
||||
packet->buf = skb->data;
|
||||
|
||||
__skb_queue_tail(&skb_queue, skb);
|
||||
|
||||
if (!status && (packet->act_len != skb->len))
|
||||
@ -593,10 +589,10 @@ void ath6kl_tx_complete(void *context, struct list_head *packet_queue)
|
||||
|
||||
if (eid == ar->ctrl_ep) {
|
||||
if_idx = wmi_cmd_hdr_get_if_idx(
|
||||
(struct wmi_cmd_hdr *) skb->data);
|
||||
(struct wmi_cmd_hdr *) packet->buf);
|
||||
} else {
|
||||
if_idx = wmi_data_hdr_get_if_idx(
|
||||
(struct wmi_data_hdr *) skb->data);
|
||||
(struct wmi_data_hdr *) packet->buf);
|
||||
}
|
||||
|
||||
vif = ath6kl_get_vif_by_index(ar, if_idx);
|
||||
|
431
drivers/net/wireless/ath/ath6kl/usb.c
Normal file
431
drivers/net/wireless/ath/ath6kl/usb.c
Normal file
@ -0,0 +1,431 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011 Atheros Communications Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "core.h"
|
||||
|
||||
/* usb device object */
|
||||
struct ath6kl_usb {
|
||||
struct usb_device *udev;
|
||||
struct usb_interface *interface;
|
||||
u8 *diag_cmd_buffer;
|
||||
u8 *diag_resp_buffer;
|
||||
struct ath6kl *ar;
|
||||
};
|
||||
|
||||
/* diagnostic command defnitions */
|
||||
#define ATH6KL_USB_CONTROL_REQ_SEND_BMI_CMD 1
|
||||
#define ATH6KL_USB_CONTROL_REQ_RECV_BMI_RESP 2
|
||||
#define ATH6KL_USB_CONTROL_REQ_DIAG_CMD 3
|
||||
#define ATH6KL_USB_CONTROL_REQ_DIAG_RESP 4
|
||||
|
||||
#define ATH6KL_USB_CTRL_DIAG_CC_READ 0
|
||||
#define ATH6KL_USB_CTRL_DIAG_CC_WRITE 1
|
||||
|
||||
struct ath6kl_usb_ctrl_diag_cmd_write {
|
||||
__le32 cmd;
|
||||
__le32 address;
|
||||
__le32 value;
|
||||
__le32 _pad[1];
|
||||
} __packed;
|
||||
|
||||
struct ath6kl_usb_ctrl_diag_cmd_read {
|
||||
__le32 cmd;
|
||||
__le32 address;
|
||||
} __packed;
|
||||
|
||||
struct ath6kl_usb_ctrl_diag_resp_read {
|
||||
__le32 value;
|
||||
} __packed;
|
||||
|
||||
#define ATH6KL_USB_MAX_DIAG_CMD (sizeof(struct ath6kl_usb_ctrl_diag_cmd_write))
|
||||
#define ATH6KL_USB_MAX_DIAG_RESP (sizeof(struct ath6kl_usb_ctrl_diag_resp_read))
|
||||
|
||||
static void ath6kl_usb_destroy(struct ath6kl_usb *ar_usb)
|
||||
{
|
||||
usb_set_intfdata(ar_usb->interface, NULL);
|
||||
|
||||
kfree(ar_usb->diag_cmd_buffer);
|
||||
kfree(ar_usb->diag_resp_buffer);
|
||||
|
||||
kfree(ar_usb);
|
||||
}
|
||||
|
||||
static struct ath6kl_usb *ath6kl_usb_create(struct usb_interface *interface)
|
||||
{
|
||||
struct ath6kl_usb *ar_usb = NULL;
|
||||
struct usb_device *dev = interface_to_usbdev(interface);
|
||||
int status = 0;
|
||||
|
||||
ar_usb = kzalloc(sizeof(struct ath6kl_usb), GFP_KERNEL);
|
||||
if (ar_usb == NULL)
|
||||
goto fail_ath6kl_usb_create;
|
||||
|
||||
memset(ar_usb, 0, sizeof(struct ath6kl_usb));
|
||||
usb_set_intfdata(interface, ar_usb);
|
||||
ar_usb->udev = dev;
|
||||
ar_usb->interface = interface;
|
||||
|
||||
ar_usb->diag_cmd_buffer = kzalloc(ATH6KL_USB_MAX_DIAG_CMD, GFP_KERNEL);
|
||||
if (ar_usb->diag_cmd_buffer == NULL) {
|
||||
status = -ENOMEM;
|
||||
goto fail_ath6kl_usb_create;
|
||||
}
|
||||
|
||||
ar_usb->diag_resp_buffer = kzalloc(ATH6KL_USB_MAX_DIAG_RESP,
|
||||
GFP_KERNEL);
|
||||
if (ar_usb->diag_resp_buffer == NULL) {
|
||||
status = -ENOMEM;
|
||||
goto fail_ath6kl_usb_create;
|
||||
}
|
||||
|
||||
fail_ath6kl_usb_create:
|
||||
if (status != 0) {
|
||||
ath6kl_usb_destroy(ar_usb);
|
||||
ar_usb = NULL;
|
||||
}
|
||||
return ar_usb;
|
||||
}
|
||||
|
||||
static void ath6kl_usb_device_detached(struct usb_interface *interface)
|
||||
{
|
||||
struct ath6kl_usb *ar_usb;
|
||||
|
||||
ar_usb = usb_get_intfdata(interface);
|
||||
if (ar_usb == NULL)
|
||||
return;
|
||||
|
||||
ath6kl_stop_txrx(ar_usb->ar);
|
||||
|
||||
ath6kl_core_cleanup(ar_usb->ar);
|
||||
|
||||
ath6kl_usb_destroy(ar_usb);
|
||||
}
|
||||
|
||||
static int ath6kl_usb_submit_ctrl_out(struct ath6kl_usb *ar_usb,
|
||||
u8 req, u16 value, u16 index, void *data,
|
||||
u32 size)
|
||||
{
|
||||
u8 *buf = NULL;
|
||||
int ret;
|
||||
|
||||
if (size > 0) {
|
||||
buf = kmalloc(size, GFP_KERNEL);
|
||||
if (buf == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(buf, data, size);
|
||||
}
|
||||
|
||||
/* note: if successful returns number of bytes transfered */
|
||||
ret = usb_control_msg(ar_usb->udev,
|
||||
usb_sndctrlpipe(ar_usb->udev, 0),
|
||||
req,
|
||||
USB_DIR_OUT | USB_TYPE_VENDOR |
|
||||
USB_RECIP_DEVICE, value, index, buf,
|
||||
size, 1000);
|
||||
|
||||
if (ret < 0) {
|
||||
ath6kl_dbg(ATH6KL_DBG_USB, "%s failed,result = %d\n",
|
||||
__func__, ret);
|
||||
}
|
||||
|
||||
kfree(buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kl_usb_submit_ctrl_in(struct ath6kl_usb *ar_usb,
|
||||
u8 req, u16 value, u16 index, void *data,
|
||||
u32 size)
|
||||
{
|
||||
u8 *buf = NULL;
|
||||
int ret;
|
||||
|
||||
if (size > 0) {
|
||||
buf = kmalloc(size, GFP_KERNEL);
|
||||
if (buf == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* note: if successful returns number of bytes transfered */
|
||||
ret = usb_control_msg(ar_usb->udev,
|
||||
usb_rcvctrlpipe(ar_usb->udev, 0),
|
||||
req,
|
||||
USB_DIR_IN | USB_TYPE_VENDOR |
|
||||
USB_RECIP_DEVICE, value, index, buf,
|
||||
size, 2 * HZ);
|
||||
|
||||
if (ret < 0) {
|
||||
ath6kl_dbg(ATH6KL_DBG_USB, "%s failed,result = %d\n",
|
||||
__func__, ret);
|
||||
}
|
||||
|
||||
memcpy((u8 *) data, buf, size);
|
||||
|
||||
kfree(buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kl_usb_ctrl_msg_exchange(struct ath6kl_usb *ar_usb,
|
||||
u8 req_val, u8 *req_buf, u32 req_len,
|
||||
u8 resp_val, u8 *resp_buf, u32 *resp_len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* send command */
|
||||
ret = ath6kl_usb_submit_ctrl_out(ar_usb, req_val, 0, 0,
|
||||
req_buf, req_len);
|
||||
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
if (resp_buf == NULL) {
|
||||
/* no expected response */
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* get response */
|
||||
ret = ath6kl_usb_submit_ctrl_in(ar_usb, resp_val, 0, 0,
|
||||
resp_buf, *resp_len);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath6kl_usb_diag_read32(struct ath6kl *ar, u32 address, u32 *data)
|
||||
{
|
||||
struct ath6kl_usb *ar_usb = ar->hif_priv;
|
||||
struct ath6kl_usb_ctrl_diag_resp_read *resp;
|
||||
struct ath6kl_usb_ctrl_diag_cmd_read *cmd;
|
||||
u32 resp_len;
|
||||
int ret;
|
||||
|
||||
cmd = (struct ath6kl_usb_ctrl_diag_cmd_read *) ar_usb->diag_cmd_buffer;
|
||||
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
cmd->cmd = ATH6KL_USB_CTRL_DIAG_CC_READ;
|
||||
cmd->address = cpu_to_le32(address);
|
||||
resp_len = sizeof(*resp);
|
||||
|
||||
ret = ath6kl_usb_ctrl_msg_exchange(ar_usb,
|
||||
ATH6KL_USB_CONTROL_REQ_DIAG_CMD,
|
||||
(u8 *) cmd,
|
||||
sizeof(struct ath6kl_usb_ctrl_diag_cmd_write),
|
||||
ATH6KL_USB_CONTROL_REQ_DIAG_RESP,
|
||||
ar_usb->diag_resp_buffer, &resp_len);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
resp = (struct ath6kl_usb_ctrl_diag_resp_read *)
|
||||
ar_usb->diag_resp_buffer;
|
||||
|
||||
*data = le32_to_cpu(resp->value);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath6kl_usb_diag_write32(struct ath6kl *ar, u32 address, __le32 data)
|
||||
{
|
||||
struct ath6kl_usb *ar_usb = ar->hif_priv;
|
||||
struct ath6kl_usb_ctrl_diag_cmd_write *cmd;
|
||||
|
||||
cmd = (struct ath6kl_usb_ctrl_diag_cmd_write *) ar_usb->diag_cmd_buffer;
|
||||
|
||||
memset(cmd, 0, sizeof(struct ath6kl_usb_ctrl_diag_cmd_write));
|
||||
cmd->cmd = cpu_to_le32(ATH6KL_USB_CTRL_DIAG_CC_WRITE);
|
||||
cmd->address = cpu_to_le32(address);
|
||||
cmd->value = data;
|
||||
|
||||
return ath6kl_usb_ctrl_msg_exchange(ar_usb,
|
||||
ATH6KL_USB_CONTROL_REQ_DIAG_CMD,
|
||||
(u8 *) cmd,
|
||||
sizeof(*cmd),
|
||||
0, NULL, NULL);
|
||||
|
||||
}
|
||||
|
||||
static int ath6kl_usb_bmi_read(struct ath6kl *ar, u8 *buf, u32 len)
|
||||
{
|
||||
struct ath6kl_usb *ar_usb = ar->hif_priv;
|
||||
int ret;
|
||||
|
||||
/* get response */
|
||||
ret = ath6kl_usb_submit_ctrl_in(ar_usb,
|
||||
ATH6KL_USB_CONTROL_REQ_RECV_BMI_RESP,
|
||||
0, 0, buf, len);
|
||||
if (ret != 0) {
|
||||
ath6kl_err("Unable to read the bmi data from the device: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kl_usb_bmi_write(struct ath6kl *ar, u8 *buf, u32 len)
|
||||
{
|
||||
struct ath6kl_usb *ar_usb = ar->hif_priv;
|
||||
int ret;
|
||||
|
||||
/* send command */
|
||||
ret = ath6kl_usb_submit_ctrl_out(ar_usb,
|
||||
ATH6KL_USB_CONTROL_REQ_SEND_BMI_CMD,
|
||||
0, 0, buf, len);
|
||||
if (ret != 0) {
|
||||
ath6kl_err("unable to send the bmi data to the device: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kl_usb_power_on(struct ath6kl *ar)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath6kl_usb_power_off(struct ath6kl *ar)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ath6kl_hif_ops ath6kl_usb_ops = {
|
||||
.diag_read32 = ath6kl_usb_diag_read32,
|
||||
.diag_write32 = ath6kl_usb_diag_write32,
|
||||
.bmi_read = ath6kl_usb_bmi_read,
|
||||
.bmi_write = ath6kl_usb_bmi_write,
|
||||
.power_on = ath6kl_usb_power_on,
|
||||
.power_off = ath6kl_usb_power_off,
|
||||
};
|
||||
|
||||
/* ath6kl usb driver registered functions */
|
||||
static int ath6kl_usb_probe(struct usb_interface *interface,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_device *dev = interface_to_usbdev(interface);
|
||||
struct ath6kl *ar;
|
||||
struct ath6kl_usb *ar_usb = NULL;
|
||||
int vendor_id, product_id;
|
||||
int ret = 0;
|
||||
|
||||
usb_get_dev(dev);
|
||||
|
||||
vendor_id = le16_to_cpu(dev->descriptor.idVendor);
|
||||
product_id = le16_to_cpu(dev->descriptor.idProduct);
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_USB, "vendor_id = %04x\n", vendor_id);
|
||||
ath6kl_dbg(ATH6KL_DBG_USB, "product_id = %04x\n", product_id);
|
||||
|
||||
if (interface->cur_altsetting)
|
||||
ath6kl_dbg(ATH6KL_DBG_USB, "USB Interface %d\n",
|
||||
interface->cur_altsetting->desc.bInterfaceNumber);
|
||||
|
||||
|
||||
if (dev->speed == USB_SPEED_HIGH)
|
||||
ath6kl_dbg(ATH6KL_DBG_USB, "USB 2.0 Host\n");
|
||||
else
|
||||
ath6kl_dbg(ATH6KL_DBG_USB, "USB 1.1 Host\n");
|
||||
|
||||
ar_usb = ath6kl_usb_create(interface);
|
||||
|
||||
if (ar_usb == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto err_usb_put;
|
||||
}
|
||||
|
||||
ar = ath6kl_core_alloc(&ar_usb->udev->dev);
|
||||
if (ar == NULL) {
|
||||
ath6kl_err("Failed to alloc ath6kl core\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_usb_destroy;
|
||||
}
|
||||
|
||||
ar->hif_priv = ar_usb;
|
||||
ar->hif_type = ATH6KL_HIF_TYPE_USB;
|
||||
ar->hif_ops = &ath6kl_usb_ops;
|
||||
ar->mbox_info.block_size = 16;
|
||||
ar->bmi.max_data_size = 252;
|
||||
|
||||
ar_usb->ar = ar;
|
||||
|
||||
ret = ath6kl_core_init(ar);
|
||||
if (ret) {
|
||||
ath6kl_err("Failed to init ath6kl core: %d\n", ret);
|
||||
goto err_core_free;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
err_core_free:
|
||||
ath6kl_core_free(ar);
|
||||
err_usb_destroy:
|
||||
ath6kl_usb_destroy(ar_usb);
|
||||
err_usb_put:
|
||||
usb_put_dev(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ath6kl_usb_remove(struct usb_interface *interface)
|
||||
{
|
||||
usb_put_dev(interface_to_usbdev(interface));
|
||||
ath6kl_usb_device_detached(interface);
|
||||
}
|
||||
|
||||
/* table of devices that work with this driver */
|
||||
static struct usb_device_id ath6kl_usb_ids[] = {
|
||||
{USB_DEVICE(0x0cf3, 0x9374)},
|
||||
{ /* Terminating entry */ },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(usb, ath6kl_usb_ids);
|
||||
|
||||
static struct usb_driver ath6kl_usb_driver = {
|
||||
.name = "ath6kl_usb",
|
||||
.probe = ath6kl_usb_probe,
|
||||
.disconnect = ath6kl_usb_remove,
|
||||
.id_table = ath6kl_usb_ids,
|
||||
};
|
||||
|
||||
static int ath6kl_usb_init(void)
|
||||
{
|
||||
usb_register(&ath6kl_usb_driver);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath6kl_usb_exit(void)
|
||||
{
|
||||
usb_deregister(&ath6kl_usb_driver);
|
||||
}
|
||||
|
||||
module_init(ath6kl_usb_init);
|
||||
module_exit(ath6kl_usb_exit);
|
||||
|
||||
MODULE_AUTHOR("Atheros Communications, Inc.");
|
||||
MODULE_DESCRIPTION("Driver support for Atheros AR600x USB devices");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
MODULE_FIRMWARE(AR6004_HW_1_0_FIRMWARE_FILE);
|
||||
MODULE_FIRMWARE(AR6004_HW_1_0_BOARD_DATA_FILE);
|
||||
MODULE_FIRMWARE(AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE);
|
||||
MODULE_FIRMWARE(AR6004_HW_1_1_FIRMWARE_FILE);
|
||||
MODULE_FIRMWARE(AR6004_HW_1_1_BOARD_DATA_FILE);
|
||||
MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE);
|
@ -85,7 +85,7 @@ struct ath6kl_vif *ath6kl_get_vif_by_index(struct ath6kl *ar, u8 if_idx)
|
||||
{
|
||||
struct ath6kl_vif *vif, *found = NULL;
|
||||
|
||||
if (WARN_ON(if_idx > (MAX_NUM_VIF - 1)))
|
||||
if (WARN_ON(if_idx > (ar->vif_max - 1)))
|
||||
return NULL;
|
||||
|
||||
/* FIXME: Locking */
|
||||
@ -187,7 +187,7 @@ int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb,
|
||||
struct wmi_data_hdr *data_hdr;
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(skb == NULL || (if_idx > MAX_NUM_VIF - 1)))
|
||||
if (WARN_ON(skb == NULL || (if_idx > wmi->parent_dev->vif_max - 1)))
|
||||
return -EINVAL;
|
||||
|
||||
if (tx_meta_info) {
|
||||
@ -977,6 +977,13 @@ static int ath6kl_wmi_tkip_micerr_event_rx(struct wmi *wmi, u8 *datap, int len,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ath6kl_wmi_sscan_timer(unsigned long ptr)
|
||||
{
|
||||
struct ath6kl_vif *vif = (struct ath6kl_vif *) ptr;
|
||||
|
||||
cfg80211_sched_scan_results(vif->ar->wiphy);
|
||||
}
|
||||
|
||||
static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len,
|
||||
struct ath6kl_vif *vif)
|
||||
{
|
||||
@ -1066,6 +1073,21 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len,
|
||||
return -ENOMEM;
|
||||
cfg80211_put_bss(bss);
|
||||
|
||||
/*
|
||||
* Firmware doesn't return any event when scheduled scan has
|
||||
* finished, so we need to use a timer to find out when there are
|
||||
* no more results.
|
||||
*
|
||||
* The timer is started from the first bss info received, otherwise
|
||||
* the timer would not ever fire if the scan interval is short
|
||||
* enough.
|
||||
*/
|
||||
if (ar->state == ATH6KL_STATE_SCHED_SCAN &&
|
||||
!timer_pending(&vif->sched_scan_timer)) {
|
||||
mod_timer(&vif->sched_scan_timer, jiffies +
|
||||
msecs_to_jiffies(ATH6KL_SCHED_SCAN_RESULT_DELAY));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1620,7 +1642,7 @@ int ath6kl_wmi_cmd_send(struct wmi *wmi, u8 if_idx, struct sk_buff *skb,
|
||||
int ret;
|
||||
u16 info1;
|
||||
|
||||
if (WARN_ON(skb == NULL || (if_idx > (MAX_NUM_VIF - 1))))
|
||||
if (WARN_ON(skb == NULL || (if_idx > (wmi->parent_dev->vif_max - 1))))
|
||||
return -EINVAL;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_WMI, "wmi tx id %d len %d flag %d\n",
|
||||
@ -1682,7 +1704,8 @@ int ath6kl_wmi_connect_cmd(struct wmi *wmi, u8 if_idx,
|
||||
u8 pairwise_crypto_len,
|
||||
enum crypto_type group_crypto,
|
||||
u8 group_crypto_len, int ssid_len, u8 *ssid,
|
||||
u8 *bssid, u16 channel, u32 ctrl_flags)
|
||||
u8 *bssid, u16 channel, u32 ctrl_flags,
|
||||
u8 nw_subtype)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct wmi_connect_cmd *cc;
|
||||
@ -1722,6 +1745,7 @@ int ath6kl_wmi_connect_cmd(struct wmi *wmi, u8 if_idx,
|
||||
cc->grp_crypto_len = group_crypto_len;
|
||||
cc->ch = cpu_to_le16(channel);
|
||||
cc->ctrl_flags = cpu_to_le32(ctrl_flags);
|
||||
cc->nw_subtype = nw_subtype;
|
||||
|
||||
if (bssid != NULL)
|
||||
memcpy(cc->bssid, bssid, ETH_ALEN);
|
||||
@ -1774,6 +1798,72 @@ int ath6kl_wmi_disconnect_cmd(struct wmi *wmi, u8 if_idx)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
|
||||
enum wmi_scan_type scan_type,
|
||||
u32 force_fgscan, u32 is_legacy,
|
||||
u32 home_dwell_time, u32 force_scan_interval,
|
||||
s8 num_chan, u16 *ch_list, u32 no_cck, u32 *rates)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct wmi_begin_scan_cmd *sc;
|
||||
s8 size;
|
||||
int i, band, ret;
|
||||
struct ath6kl *ar = wmi->parent_dev;
|
||||
int num_rates;
|
||||
|
||||
size = sizeof(struct wmi_begin_scan_cmd);
|
||||
|
||||
if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN))
|
||||
return -EINVAL;
|
||||
|
||||
if (num_chan > WMI_MAX_CHANNELS)
|
||||
return -EINVAL;
|
||||
|
||||
if (num_chan)
|
||||
size += sizeof(u16) * (num_chan - 1);
|
||||
|
||||
skb = ath6kl_wmi_get_new_buf(size);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
sc = (struct wmi_begin_scan_cmd *) skb->data;
|
||||
sc->scan_type = scan_type;
|
||||
sc->force_fg_scan = cpu_to_le32(force_fgscan);
|
||||
sc->is_legacy = cpu_to_le32(is_legacy);
|
||||
sc->home_dwell_time = cpu_to_le32(home_dwell_time);
|
||||
sc->force_scan_intvl = cpu_to_le32(force_scan_interval);
|
||||
sc->no_cck = cpu_to_le32(no_cck);
|
||||
sc->num_ch = num_chan;
|
||||
|
||||
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
|
||||
struct ieee80211_supported_band *sband =
|
||||
ar->wiphy->bands[band];
|
||||
u32 ratemask = rates[band];
|
||||
u8 *supp_rates = sc->supp_rates[band].rates;
|
||||
num_rates = 0;
|
||||
|
||||
for (i = 0; i < sband->n_bitrates; i++) {
|
||||
if ((BIT(i) & ratemask) == 0)
|
||||
continue; /* skip rate */
|
||||
supp_rates[num_rates++] =
|
||||
(u8) (sband->bitrates[i].bitrate / 5);
|
||||
}
|
||||
sc->supp_rates[band].nrates = num_rates;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_chan; i++)
|
||||
sc->ch_list[i] = cpu_to_le16(ch_list[i]);
|
||||
|
||||
ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_BEGIN_SCAN_CMDID,
|
||||
NO_SYNC_WMIFLAG);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ath6kl_wmi_start_scan_cmd is to be deprecated. Use
|
||||
* ath6kl_wmi_begin_scan_cmd instead. The new function supports P2P
|
||||
* mgmt operations using station interface.
|
||||
*/
|
||||
int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx,
|
||||
enum wmi_scan_type scan_type,
|
||||
u32 force_fgscan, u32 is_legacy,
|
||||
@ -2940,7 +3030,10 @@ int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type,
|
||||
p = (struct wmi_set_appie_cmd *) skb->data;
|
||||
p->mgmt_frm_type = mgmt_frm_type;
|
||||
p->ie_len = ie_len;
|
||||
memcpy(p->ie_info, ie, ie_len);
|
||||
|
||||
if (ie != NULL && ie_len > 0)
|
||||
memcpy(p->ie_info, ie, ie_len);
|
||||
|
||||
return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_APPIE_CMDID,
|
||||
NO_SYNC_WMIFLAG);
|
||||
}
|
||||
@ -2981,6 +3074,10 @@ int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx, u32 freq, u32 dur)
|
||||
NO_SYNC_WMIFLAG);
|
||||
}
|
||||
|
||||
/* ath6kl_wmi_send_action_cmd is to be deprecated. Use
|
||||
* ath6kl_wmi_send_mgmt_cmd instead. The new function supports P2P
|
||||
* mgmt operations using station interface.
|
||||
*/
|
||||
int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq,
|
||||
u32 wait, const u8 *data, u16 data_len)
|
||||
{
|
||||
@ -3018,14 +3115,57 @@ int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq,
|
||||
NO_SYNC_WMIFLAG);
|
||||
}
|
||||
|
||||
int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq,
|
||||
u32 wait, const u8 *data, u16 data_len,
|
||||
u32 no_cck)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct wmi_send_mgmt_cmd *p;
|
||||
u8 *buf;
|
||||
|
||||
if (wait)
|
||||
return -EINVAL; /* Offload for wait not supported */
|
||||
|
||||
buf = kmalloc(data_len, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
skb = ath6kl_wmi_get_new_buf(sizeof(*p) + data_len);
|
||||
if (!skb) {
|
||||
kfree(buf);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
kfree(wmi->last_mgmt_tx_frame);
|
||||
memcpy(buf, data, data_len);
|
||||
wmi->last_mgmt_tx_frame = buf;
|
||||
wmi->last_mgmt_tx_frame_len = data_len;
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_WMI, "send_action_cmd: id=%u freq=%u wait=%u "
|
||||
"len=%u\n", id, freq, wait, data_len);
|
||||
p = (struct wmi_send_mgmt_cmd *) skb->data;
|
||||
p->id = cpu_to_le32(id);
|
||||
p->freq = cpu_to_le32(freq);
|
||||
p->wait = cpu_to_le32(wait);
|
||||
p->no_cck = cpu_to_le32(no_cck);
|
||||
p->len = cpu_to_le16(data_len);
|
||||
memcpy(p->data, data, data_len);
|
||||
return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SEND_MGMT_CMDID,
|
||||
NO_SYNC_WMIFLAG);
|
||||
}
|
||||
|
||||
int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u8 if_idx, u32 freq,
|
||||
const u8 *dst, const u8 *data,
|
||||
u16 data_len)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct wmi_p2p_probe_response_cmd *p;
|
||||
size_t cmd_len = sizeof(*p) + data_len;
|
||||
|
||||
skb = ath6kl_wmi_get_new_buf(sizeof(*p) + data_len);
|
||||
if (data_len == 0)
|
||||
cmd_len++; /* work around target minimum length requirement */
|
||||
|
||||
skb = ath6kl_wmi_get_new_buf(cmd_len);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -329,6 +329,10 @@ enum wmi_cmd_id {
|
||||
WMI_SYNCHRONIZE_CMDID,
|
||||
WMI_CREATE_PSTREAM_CMDID,
|
||||
WMI_DELETE_PSTREAM_CMDID,
|
||||
/* WMI_START_SCAN_CMDID is to be deprecated. Use
|
||||
* WMI_BEGIN_SCAN_CMDID instead. The new cmd supports P2P mgmt
|
||||
* operations using station interface.
|
||||
*/
|
||||
WMI_START_SCAN_CMDID,
|
||||
WMI_SET_SCAN_PARAMS_CMDID,
|
||||
WMI_SET_BSS_FILTER_CMDID,
|
||||
@ -542,12 +546,61 @@ enum wmi_cmd_id {
|
||||
WMI_GTK_OFFLOAD_OP_CMDID,
|
||||
WMI_REMAIN_ON_CHNL_CMDID,
|
||||
WMI_CANCEL_REMAIN_ON_CHNL_CMDID,
|
||||
/* WMI_SEND_ACTION_CMDID is to be deprecated. Use
|
||||
* WMI_SEND_MGMT_CMDID instead. The new cmd supports P2P mgmt
|
||||
* operations using station interface.
|
||||
*/
|
||||
WMI_SEND_ACTION_CMDID,
|
||||
WMI_PROBE_REQ_REPORT_CMDID,
|
||||
WMI_DISABLE_11B_RATES_CMDID,
|
||||
WMI_SEND_PROBE_RESPONSE_CMDID,
|
||||
WMI_GET_P2P_INFO_CMDID,
|
||||
WMI_AP_JOIN_BSS_CMDID,
|
||||
|
||||
WMI_SMPS_ENABLE_CMDID,
|
||||
WMI_SMPS_CONFIG_CMDID,
|
||||
WMI_SET_RATECTRL_PARM_CMDID,
|
||||
/* LPL specific commands*/
|
||||
WMI_LPL_FORCE_ENABLE_CMDID,
|
||||
WMI_LPL_SET_POLICY_CMDID,
|
||||
WMI_LPL_GET_POLICY_CMDID,
|
||||
WMI_LPL_GET_HWSTATE_CMDID,
|
||||
WMI_LPL_SET_PARAMS_CMDID,
|
||||
WMI_LPL_GET_PARAMS_CMDID,
|
||||
|
||||
WMI_SET_BUNDLE_PARAM_CMDID,
|
||||
|
||||
/*GreenTx specific commands*/
|
||||
|
||||
WMI_GREENTX_PARAMS_CMDID,
|
||||
|
||||
WMI_RTT_MEASREQ_CMDID,
|
||||
WMI_RTT_CAPREQ_CMDID,
|
||||
WMI_RTT_STATUSREQ_CMDID,
|
||||
|
||||
/* WPS Commands */
|
||||
WMI_WPS_START_CMDID,
|
||||
WMI_GET_WPS_STATUS_CMDID,
|
||||
|
||||
/* More P2P commands */
|
||||
WMI_SET_NOA_CMDID,
|
||||
WMI_GET_NOA_CMDID,
|
||||
WMI_SET_OPPPS_CMDID,
|
||||
WMI_GET_OPPPS_CMDID,
|
||||
WMI_ADD_PORT_CMDID,
|
||||
WMI_DEL_PORT_CMDID,
|
||||
|
||||
/* 802.11w cmd */
|
||||
WMI_SET_RSN_CAP_CMDID,
|
||||
WMI_GET_RSN_CAP_CMDID,
|
||||
WMI_SET_IGTK_CMDID,
|
||||
|
||||
WMI_RX_FILTER_COALESCE_FILTER_OP_CMDID,
|
||||
WMI_RX_FILTER_SET_FRAME_TEST_LIST_CMDID,
|
||||
|
||||
WMI_SEND_MGMT_CMDID,
|
||||
WMI_BEGIN_SCAN_CMDID,
|
||||
|
||||
};
|
||||
|
||||
enum wmi_mgmt_frame_type {
|
||||
@ -567,6 +620,14 @@ enum network_type {
|
||||
AP_NETWORK = 0x10,
|
||||
};
|
||||
|
||||
enum network_subtype {
|
||||
SUBTYPE_NONE,
|
||||
SUBTYPE_BT,
|
||||
SUBTYPE_P2PDEV,
|
||||
SUBTYPE_P2PCLIENT,
|
||||
SUBTYPE_P2PGO,
|
||||
};
|
||||
|
||||
enum dot11_auth_mode {
|
||||
OPEN_AUTH = 0x01,
|
||||
SHARED_AUTH = 0x02,
|
||||
@ -639,6 +700,7 @@ struct wmi_connect_cmd {
|
||||
__le16 ch;
|
||||
u8 bssid[ETH_ALEN];
|
||||
__le32 ctrl_flags;
|
||||
u8 nw_subtype;
|
||||
} __packed;
|
||||
|
||||
/* WMI_RECONNECT_CMDID */
|
||||
@ -726,6 +788,43 @@ enum wmi_scan_type {
|
||||
WMI_SHORT_SCAN = 1,
|
||||
};
|
||||
|
||||
struct wmi_supp_rates {
|
||||
u8 nrates;
|
||||
u8 rates[ATH6KL_RATE_MAXSIZE];
|
||||
};
|
||||
|
||||
struct wmi_begin_scan_cmd {
|
||||
__le32 force_fg_scan;
|
||||
|
||||
/* for legacy cisco AP compatibility */
|
||||
__le32 is_legacy;
|
||||
|
||||
/* max duration in the home channel(msec) */
|
||||
__le32 home_dwell_time;
|
||||
|
||||
/* time interval between scans (msec) */
|
||||
__le32 force_scan_intvl;
|
||||
|
||||
/* no CCK rates */
|
||||
__le32 no_cck;
|
||||
|
||||
/* enum wmi_scan_type */
|
||||
u8 scan_type;
|
||||
|
||||
/* Supported rates to advertise in the probe request frames */
|
||||
struct wmi_supp_rates supp_rates[IEEE80211_NUM_BANDS];
|
||||
|
||||
/* how many channels follow */
|
||||
u8 num_ch;
|
||||
|
||||
/* channels in Mhz */
|
||||
__le16 ch_list[1];
|
||||
} __packed;
|
||||
|
||||
/* wmi_start_scan_cmd is to be deprecated. Use
|
||||
* wmi_begin_scan_cmd instead. The new structure supports P2P mgmt
|
||||
* operations using station interface.
|
||||
*/
|
||||
struct wmi_start_scan_cmd {
|
||||
__le32 force_fg_scan;
|
||||
|
||||
@ -748,9 +847,6 @@ struct wmi_start_scan_cmd {
|
||||
__le16 ch_list[1];
|
||||
} __packed;
|
||||
|
||||
/* WMI_SET_SCAN_PARAMS_CMDID */
|
||||
#define WMI_SHORTSCANRATIO_DEFAULT 3
|
||||
|
||||
/*
|
||||
* Warning: scan control flag value of 0xFF is used to disable
|
||||
* all flags in WMI_SCAN_PARAMS_CMD. Do not add any more
|
||||
@ -783,13 +879,6 @@ enum wmi_scan_ctrl_flags_bits {
|
||||
ENABLE_SCAN_ABORT_EVENT = 0x40
|
||||
};
|
||||
|
||||
#define DEFAULT_SCAN_CTRL_FLAGS \
|
||||
(CONNECT_SCAN_CTRL_FLAGS | \
|
||||
SCAN_CONNECTED_CTRL_FLAGS | \
|
||||
ACTIVE_SCAN_CTRL_FLAGS | \
|
||||
ROAM_SCAN_CTRL_FLAGS | \
|
||||
ENABLE_AUTO_CTRL_FLAGS)
|
||||
|
||||
struct wmi_scan_params_cmd {
|
||||
/* sec */
|
||||
__le16 fg_start_period;
|
||||
@ -1818,7 +1907,7 @@ struct wmi_set_ip_cmd {
|
||||
} __packed;
|
||||
|
||||
enum ath6kl_wow_filters {
|
||||
WOW_FILTER_SSID = BIT(0),
|
||||
WOW_FILTER_SSID = BIT(1),
|
||||
WOW_FILTER_OPTION_MAGIC_PACKET = BIT(2),
|
||||
WOW_FILTER_OPTION_EAP_REQ = BIT(3),
|
||||
WOW_FILTER_OPTION_PATTERNS = BIT(4),
|
||||
@ -1963,7 +2052,7 @@ struct wmi_tx_complete_event {
|
||||
* !!! Warning !!!
|
||||
* -Changing the following values needs compilation of both driver and firmware
|
||||
*/
|
||||
#define AP_MAX_NUM_STA 8
|
||||
#define AP_MAX_NUM_STA 10
|
||||
|
||||
/* Spl. AID used to set DTIM flag in the beacons */
|
||||
#define MCAST_AID 0xFF
|
||||
@ -2046,6 +2135,10 @@ struct wmi_remain_on_chnl_cmd {
|
||||
__le32 duration;
|
||||
} __packed;
|
||||
|
||||
/* wmi_send_action_cmd is to be deprecated. Use
|
||||
* wmi_send_mgmt_cmd instead. The new structure supports P2P mgmt
|
||||
* operations using station interface.
|
||||
*/
|
||||
struct wmi_send_action_cmd {
|
||||
__le32 id;
|
||||
__le32 freq;
|
||||
@ -2054,6 +2147,15 @@ struct wmi_send_action_cmd {
|
||||
u8 data[0];
|
||||
} __packed;
|
||||
|
||||
struct wmi_send_mgmt_cmd {
|
||||
__le32 id;
|
||||
__le32 freq;
|
||||
__le32 wait;
|
||||
__le32 no_cck;
|
||||
__le16 len;
|
||||
u8 data[0];
|
||||
} __packed;
|
||||
|
||||
struct wmi_tx_status_event {
|
||||
__le32 id;
|
||||
u8 ack_status;
|
||||
@ -2242,7 +2344,8 @@ int ath6kl_wmi_connect_cmd(struct wmi *wmi, u8 if_idx,
|
||||
u8 pairwise_crypto_len,
|
||||
enum crypto_type group_crypto,
|
||||
u8 group_crypto_len, int ssid_len, u8 *ssid,
|
||||
u8 *bssid, u16 channel, u32 ctrl_flags);
|
||||
u8 *bssid, u16 channel, u32 ctrl_flags,
|
||||
u8 nw_subtype);
|
||||
|
||||
int ath6kl_wmi_reconnect_cmd(struct wmi *wmi, u8 if_idx, u8 *bssid,
|
||||
u16 channel);
|
||||
@ -2252,6 +2355,14 @@ int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx,
|
||||
u32 force_fgscan, u32 is_legacy,
|
||||
u32 home_dwell_time, u32 force_scan_interval,
|
||||
s8 num_chan, u16 *ch_list);
|
||||
|
||||
int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
|
||||
enum wmi_scan_type scan_type,
|
||||
u32 force_fgscan, u32 is_legacy,
|
||||
u32 home_dwell_time, u32 force_scan_interval,
|
||||
s8 num_chan, u16 *ch_list, u32 no_cck,
|
||||
u32 *rates);
|
||||
|
||||
int ath6kl_wmi_scanparams_cmd(struct wmi *wmi, u8 if_idx, u16 fg_start_sec,
|
||||
u16 fg_end_sec, u16 bg_sec,
|
||||
u16 minact_chdw_msec, u16 maxact_chdw_msec,
|
||||
@ -2346,6 +2457,10 @@ int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx, u32 freq,
|
||||
int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq,
|
||||
u32 wait, const u8 *data, u16 data_len);
|
||||
|
||||
int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq,
|
||||
u32 wait, const u8 *data, u16 data_len,
|
||||
u32 no_cck);
|
||||
|
||||
int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u8 if_idx, u32 freq,
|
||||
const u8 *dst, const u8 *data,
|
||||
u16 data_len);
|
||||
@ -2359,6 +2474,8 @@ int ath6kl_wmi_cancel_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx);
|
||||
int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type,
|
||||
const u8 *ie, u8 ie_len);
|
||||
|
||||
void ath6kl_wmi_sscan_timer(unsigned long ptr);
|
||||
|
||||
struct ath6kl_vif *ath6kl_get_vif_by_index(struct ath6kl *ar, u8 if_idx);
|
||||
void *ath6kl_wmi_init(struct ath6kl *devt);
|
||||
void ath6kl_wmi_shutdown(struct wmi *wmi);
|
||||
|
Loading…
Reference in New Issue
Block a user