Commit 9e49a9d3 authored by John W. Linville's avatar John W. Linville
parents 0b21eb9a 789e90e5
...@@ -93,8 +93,7 @@ static void wl1251_spi_wake(struct wl1251 *wl) ...@@ -93,8 +93,7 @@ static void wl1251_spi_wake(struct wl1251 *wl)
memset(&t, 0, sizeof(t)); memset(&t, 0, sizeof(t));
spi_message_init(&m); spi_message_init(&m);
/* /* Set WSPI_INIT_COMMAND
* Set WSPI_INIT_COMMAND
* the data is being send from the MSB to LSB * the data is being send from the MSB to LSB
*/ */
cmd[2] = 0xff; cmd[2] = 0xff;
...@@ -262,7 +261,8 @@ static int wl1251_spi_probe(struct spi_device *spi) ...@@ -262,7 +261,8 @@ static int wl1251_spi_probe(struct spi_device *spi)
wl->if_ops = &wl1251_spi_ops; wl->if_ops = &wl1251_spi_ops;
/* This is the only SPI value that we need to set here, the rest /* This is the only SPI value that we need to set here, the rest
* comes from the board-peripherals file */ * comes from the board-peripherals file
*/
spi->bits_per_word = 32; spi->bits_per_word = 32;
ret = spi_setup(spi); ret = spi_setup(spi);
...@@ -329,29 +329,7 @@ static struct spi_driver wl1251_spi_driver = { ...@@ -329,29 +329,7 @@ static struct spi_driver wl1251_spi_driver = {
.remove = wl1251_spi_remove, .remove = wl1251_spi_remove,
}; };
static int __init wl1251_spi_init(void) module_spi_driver(wl1251_spi_driver);
{
int ret;
ret = spi_register_driver(&wl1251_spi_driver);
if (ret < 0) {
wl1251_error("failed to register spi driver: %d", ret);
goto out;
}
out:
return ret;
}
static void __exit wl1251_spi_exit(void)
{
spi_unregister_driver(&wl1251_spi_driver);
wl1251_notice("unloaded");
}
module_init(wl1251_spi_init);
module_exit(wl1251_spi_exit);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>"); MODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>");
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/etherdevice.h>
#include "../wlcore/wlcore.h" #include "../wlcore/wlcore.h"
#include "../wlcore/debug.h" #include "../wlcore/debug.h"
...@@ -594,8 +595,8 @@ static const struct wlcore_partition_set wl18xx_ptable[PART_TABLE_LEN] = { ...@@ -594,8 +595,8 @@ static const struct wlcore_partition_set wl18xx_ptable[PART_TABLE_LEN] = {
.mem3 = { .start = 0x00000000, .size = 0x00000000 }, .mem3 = { .start = 0x00000000, .size = 0x00000000 },
}, },
[PART_PHY_INIT] = { [PART_PHY_INIT] = {
.mem = { .start = 0x80926000, .mem = { .start = WL18XX_PHY_INIT_MEM_ADDR,
.size = sizeof(struct wl18xx_mac_and_phy_params) }, .size = WL18XX_PHY_INIT_MEM_SIZE },
.reg = { .start = 0x00000000, .size = 0x00000000 }, .reg = { .start = 0x00000000, .size = 0x00000000 },
.mem2 = { .start = 0x00000000, .size = 0x00000000 }, .mem2 = { .start = 0x00000000, .size = 0x00000000 },
.mem3 = { .start = 0x00000000, .size = 0x00000000 }, .mem3 = { .start = 0x00000000, .size = 0x00000000 },
...@@ -799,6 +800,9 @@ static int wl18xx_pre_upload(struct wl1271 *wl) ...@@ -799,6 +800,9 @@ static int wl18xx_pre_upload(struct wl1271 *wl)
u32 tmp; u32 tmp;
int ret; int ret;
BUILD_BUG_ON(sizeof(struct wl18xx_mac_and_phy_params) >
WL18XX_PHY_INIT_MEM_SIZE);
ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]); ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
if (ret < 0) if (ret < 0)
goto out; goto out;
...@@ -815,6 +819,35 @@ static int wl18xx_pre_upload(struct wl1271 *wl) ...@@ -815,6 +819,35 @@ static int wl18xx_pre_upload(struct wl1271 *wl)
wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp); wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp);
ret = wlcore_read32(wl, WL18XX_SCR_PAD2, &tmp); ret = wlcore_read32(wl, WL18XX_SCR_PAD2, &tmp);
if (ret < 0)
goto out;
/*
* Workaround for FDSP code RAM corruption (needed for PG2.1
* and newer; for older chips it's a NOP). Change FDSP clock
* settings so that it's muxed to the ATGP clock instead of
* its own clock.
*/
ret = wlcore_set_partition(wl, &wl->ptable[PART_PHY_INIT]);
if (ret < 0)
goto out;
/* disable FDSP clock */
ret = wlcore_write32(wl, WL18XX_PHY_FPGA_SPARE_1,
MEM_FDSP_CLK_120_DISABLE);
if (ret < 0)
goto out;
/* set ATPG clock toward FDSP Code RAM rather than its own clock */
ret = wlcore_write32(wl, WL18XX_PHY_FPGA_SPARE_1,
MEM_FDSP_CODERAM_FUNC_CLK_SEL);
if (ret < 0)
goto out;
/* re-enable FDSP clock */
ret = wlcore_write32(wl, WL18XX_PHY_FPGA_SPARE_1,
MEM_FDSP_CLK_120_ENABLE);
out: out:
return ret; return ret;
...@@ -1286,6 +1319,16 @@ static int wl18xx_get_mac(struct wl1271 *wl) ...@@ -1286,6 +1319,16 @@ static int wl18xx_get_mac(struct wl1271 *wl)
((mac1 & 0xff000000) >> 24); ((mac1 & 0xff000000) >> 24);
wl->fuse_nic_addr = (mac1 & 0xffffff); wl->fuse_nic_addr = (mac1 & 0xffffff);
if (!wl->fuse_oui_addr && !wl->fuse_nic_addr) {
u8 mac[ETH_ALEN];
eth_random_addr(mac);
wl->fuse_oui_addr = (mac[0] << 16) + (mac[1] << 8) + mac[2];
wl->fuse_nic_addr = (mac[3] << 16) + (mac[4] << 8) + mac[5];
wl1271_warning("MAC address from fuse not available, using random locally administered addresses.");
}
ret = wlcore_set_partition(wl, &wl->ptable[PART_DOWN]); ret = wlcore_set_partition(wl, &wl->ptable[PART_DOWN]);
out: out:
......
...@@ -38,6 +38,9 @@ ...@@ -38,6 +38,9 @@
#define WL18XX_REG_BOOT_PART_SIZE 0x00014578 #define WL18XX_REG_BOOT_PART_SIZE 0x00014578
#define WL18XX_PHY_INIT_MEM_ADDR 0x80926000 #define WL18XX_PHY_INIT_MEM_ADDR 0x80926000
#define WL18XX_PHY_END_MEM_ADDR 0x8093CA44
#define WL18XX_PHY_INIT_MEM_SIZE \
(WL18XX_PHY_END_MEM_ADDR - WL18XX_PHY_INIT_MEM_ADDR)
#define WL18XX_SDIO_WSPI_BASE (WL18XX_REGISTERS_BASE) #define WL18XX_SDIO_WSPI_BASE (WL18XX_REGISTERS_BASE)
#define WL18XX_REG_CONFIG_BASE (WL18XX_REGISTERS_BASE + 0x02000) #define WL18XX_REG_CONFIG_BASE (WL18XX_REGISTERS_BASE + 0x02000)
...@@ -217,4 +220,16 @@ static const char * const rdl_names[] = { ...@@ -217,4 +220,16 @@ static const char * const rdl_names[] = {
[RDL_4_SP] = "1897 MIMO", [RDL_4_SP] = "1897 MIMO",
}; };
/* FPGA_SPARE_1 register - used to change the PHY ATPG clock at boot time */
#define WL18XX_PHY_FPGA_SPARE_1 0x8093CA40
/* command to disable FDSP clock */
#define MEM_FDSP_CLK_120_DISABLE 0x80000000
/* command to set ATPG clock toward FDSP Code RAM rather than its own clock */
#define MEM_FDSP_CODERAM_FUNC_CLK_SEL 0xC0000000
/* command to re-enable FDSP clock */
#define MEM_FDSP_CLK_120_ENABLE 0x40000000
#endif /* __REG_H__ */ #endif /* __REG_H__ */
wlcore-objs = main.o cmd.o io.o event.o tx.o rx.o ps.o acx.o \ wlcore-objs = main.o cmd.o io.o event.o tx.o rx.o ps.o acx.o \
boot.o init.o debugfs.o scan.o boot.o init.o debugfs.o scan.o sysfs.o
wlcore_spi-objs = spi.o wlcore_spi-objs = spi.o
wlcore_sdio-objs = sdio.o wlcore_sdio-objs = sdio.o
......
/* /*
* This file is part of wl1271 * This file is part of wlcore
* *
* Copyright (C) 2008-2010 Nokia Corporation * Copyright (C) 2008-2010 Nokia Corporation
* * Copyright (C) 2011-2013 Texas Instruments Inc.
* Contact: Luciano Coelho <luciano.coelho@nokia.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
...@@ -24,34 +23,23 @@ ...@@ -24,34 +23,23 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/delay.h>
#include <linux/spi/spi.h>
#include <linux/crc32.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/wl12xx.h> #include <linux/wl12xx.h>
#include <linux/sched.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include "wlcore.h" #include "wlcore.h"
#include "debug.h" #include "debug.h"
#include "wl12xx_80211.h" #include "wl12xx_80211.h"
#include "io.h" #include "io.h"
#include "event.h"
#include "tx.h" #include "tx.h"
#include "rx.h"
#include "ps.h" #include "ps.h"
#include "init.h" #include "init.h"
#include "debugfs.h" #include "debugfs.h"
#include "cmd.h"
#include "boot.h"
#include "testmode.h" #include "testmode.h"
#include "scan.h" #include "scan.h"
#include "hw_ops.h" #include "hw_ops.h"
#include "sysfs.h"
#define WL1271_BOOT_RETRIES 3
#define WL1271_BOOT_RETRIES 3 #define WL1271_BOOT_RETRIES 3
...@@ -65,8 +53,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, ...@@ -65,8 +53,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
static void wlcore_op_stop_locked(struct wl1271 *wl); static void wlcore_op_stop_locked(struct wl1271 *wl);
static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif); static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif);
static int wl12xx_set_authorized(struct wl1271 *wl, static int wl12xx_set_authorized(struct wl1271 *wl, struct wl12xx_vif *wlvif)
struct wl12xx_vif *wlvif)
{ {
int ret; int ret;
...@@ -983,7 +970,7 @@ static int wlcore_fw_wakeup(struct wl1271 *wl) ...@@ -983,7 +970,7 @@ static int wlcore_fw_wakeup(struct wl1271 *wl)
static int wl1271_setup(struct wl1271 *wl) static int wl1271_setup(struct wl1271 *wl)
{ {
wl->fw_status_1 = kmalloc(WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) + wl->fw_status_1 = kzalloc(WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) +
sizeof(*wl->fw_status_2) + sizeof(*wl->fw_status_2) +
wl->fw_status_priv_len, GFP_KERNEL); wl->fw_status_priv_len, GFP_KERNEL);
if (!wl->fw_status_1) if (!wl->fw_status_1)
...@@ -993,7 +980,7 @@ static int wl1271_setup(struct wl1271 *wl) ...@@ -993,7 +980,7 @@ static int wl1271_setup(struct wl1271 *wl)
(((u8 *) wl->fw_status_1) + (((u8 *) wl->fw_status_1) +
WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc)); WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc));
wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL); wl->tx_res_if = kzalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
if (!wl->tx_res_if) { if (!wl->tx_res_if) {
kfree(wl->fw_status_1); kfree(wl->fw_status_1);
return -ENOMEM; return -ENOMEM;
...@@ -1668,8 +1655,7 @@ static int wl1271_configure_suspend(struct wl1271 *wl, ...@@ -1668,8 +1655,7 @@ static int wl1271_configure_suspend(struct wl1271 *wl,
return 0; return 0;
} }
static void wl1271_configure_resume(struct wl1271 *wl, static void wl1271_configure_resume(struct wl1271 *wl, struct wl12xx_vif *wlvif)
struct wl12xx_vif *wlvif)
{ {
int ret = 0; int ret = 0;
bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS; bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
...@@ -2603,6 +2589,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, ...@@ -2603,6 +2589,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
cancel_work_sync(&wlvif->rx_streaming_enable_work); cancel_work_sync(&wlvif->rx_streaming_enable_work);
cancel_work_sync(&wlvif->rx_streaming_disable_work); cancel_work_sync(&wlvif->rx_streaming_disable_work);
cancel_delayed_work_sync(&wlvif->connection_loss_work); cancel_delayed_work_sync(&wlvif->connection_loss_work);
cancel_delayed_work_sync(&wlvif->channel_switch_work);
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
} }
...@@ -3210,14 +3197,6 @@ static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -3210,14 +3197,6 @@ static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
if (ret < 0) if (ret < 0)
return ret; return ret;
/* the default WEP key needs to be configured at least once */
if (key_type == KEY_WEP) {
ret = wl12xx_cmd_set_default_wep_key(wl,
wlvif->default_key,
wlvif->sta.hlid);
if (ret < 0)
return ret;
}
} }
return 0; return 0;
...@@ -3374,6 +3353,46 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, ...@@ -3374,6 +3353,46 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
} }
EXPORT_SYMBOL_GPL(wlcore_set_key); EXPORT_SYMBOL_GPL(wlcore_set_key);
static void wl1271_op_set_default_key_idx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
int key_idx)
{
struct wl1271 *wl = hw->priv;
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
int ret;
wl1271_debug(DEBUG_MAC80211, "mac80211 set default key idx %d",
key_idx);
mutex_lock(&wl->mutex);
if (unlikely(wl->state != WLCORE_STATE_ON)) {
ret = -EAGAIN;
goto out_unlock;
}
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out_unlock;
wlvif->default_key = key_idx;
/* the default WEP key needs to be configured at least once */
if (wlvif->encryption_type == KEY_WEP) {
ret = wl12xx_cmd_set_default_wep_key(wl,
key_idx,
wlvif->sta.hlid);
if (ret < 0)
goto out_sleep;
}
out_sleep:
wl1271_ps_elp_sleep(wl);
out_unlock:
mutex_unlock(&wl->mutex);
}
void wlcore_regdomain_config(struct wl1271 *wl) void wlcore_regdomain_config(struct wl1271 *wl)
{ {
int ret; int ret;
...@@ -3782,8 +3801,7 @@ static int wlcore_set_beacon_template(struct wl1271 *wl, ...@@ -3782,8 +3801,7 @@ static int wlcore_set_beacon_template(struct wl1271 *wl,
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
u32 min_rate; u32 min_rate;
int ret; int ret;
int ieoffset = offsetof(struct ieee80211_mgmt, int ieoffset = offsetof(struct ieee80211_mgmt, u.beacon.variable);
u.beacon.variable);
struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif); struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
u16 tmpl_id; u16 tmpl_id;
...@@ -4230,8 +4248,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, ...@@ -4230,8 +4248,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
} }
/* Handle new association with HT. Do this after join. */ /* Handle new association with HT. Do this after join. */
if (sta_exists && if (sta_exists) {
(changed & BSS_CHANGED_HT)) {
bool enabled = bool enabled =
bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT; bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT;
...@@ -5368,6 +5385,7 @@ static const struct ieee80211_ops wl1271_ops = { ...@@ -5368,6 +5385,7 @@ static const struct ieee80211_ops wl1271_ops = {
.ampdu_action = wl1271_op_ampdu_action, .ampdu_action = wl1271_op_ampdu_action,
.tx_frames_pending = wl1271_tx_frames_pending, .tx_frames_pending = wl1271_tx_frames_pending,
.set_bitrate_mask = wl12xx_set_bitrate_mask, .set_bitrate_mask = wl12xx_set_bitrate_mask,
.set_default_unicast_key = wl1271_op_set_default_key_idx,
.channel_switch = wl12xx_op_channel_switch, .channel_switch = wl12xx_op_channel_switch,
.flush = wlcore_op_flush, .flush = wlcore_op_flush,
.remain_on_channel = wlcore_op_remain_on_channel, .remain_on_channel = wlcore_op_remain_on_channel,
...@@ -5403,151 +5421,6 @@ u8 wlcore_rate_to_idx(struct wl1271 *wl, u8 rate, enum ieee80211_band band) ...@@ -5403,151 +5421,6 @@ u8 wlcore_rate_to_idx(struct wl1271 *wl, u8 rate, enum ieee80211_band band)
return idx; return idx;
} }
static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct wl1271 *wl = dev_get_drvdata(dev);
ssize_t len;
len = PAGE_SIZE;
mutex_lock(&wl->mutex);
len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
wl->sg_enabled);
mutex_unlock(&wl->mutex);
return len;
}
static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct wl1271 *wl = dev_get_drvdata(dev);
unsigned long res;
int ret;
ret = kstrtoul(buf, 10, &res);
if (ret < 0) {
wl1271_warning("incorrect value written to bt_coex_mode");
return count;
}
mutex_lock(&wl->mutex);
res = !!res;
if (res == wl->sg_enabled)
goto out;
wl->sg_enabled = res;
if (unlikely(wl->state != WLCORE_STATE_ON))
goto out;
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out;
wl1271_acx_sg_enable(wl, wl->sg_enabled);
wl1271_ps_elp_sleep(wl);
out:
mutex_unlock(&wl->mutex);
return count;
}
static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
wl1271_sysfs_show_bt_coex_state,
wl1271_sysfs_store_bt_coex_state);
static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct wl1271 *wl = dev_get_drvdata(dev);
ssize_t len;
len = PAGE_SIZE;
mutex_lock(&wl->mutex);
if (wl->hw_pg_ver >= 0)
len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
else
len = snprintf(buf, len, "n/a\n");
mutex_unlock(&wl->mutex);
return len;
}
static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
wl1271_sysfs_show_hw_pg_ver, NULL);
static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buffer, loff_t pos, size_t count)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct wl1271 *wl = dev_get_drvdata(dev);
ssize_t len;
int ret;
ret = mutex_lock_interruptible(&wl->mutex);
if (ret < 0)
return -ERESTARTSYS;
/* Let only one thread read the log at a time, blocking others */
while (wl->fwlog_size == 0) {
DEFINE_WAIT(wait);
prepare_to_wait_exclusive(&wl->fwlog_waitq,
&wait,
TASK_INTERRUPTIBLE);
if (wl->fwlog_size != 0) {
finish_wait(&wl->fwlog_waitq, &wait);
break;
}
mutex_unlock(&wl->mutex);
schedule();
finish_wait(&wl->fwlog_waitq, &wait);
if (signal_pending(current))
return -ERESTARTSYS;
ret = mutex_lock_interruptible(&wl->mutex);
if (ret < 0)
return -ERESTARTSYS;
}
/* Check if the fwlog is still valid */
if (wl->fwlog_size < 0) {
mutex_unlock(&wl->mutex);
return 0;
}
/* Seeking is not supported - old logs are not kept. Disregard pos. */
len = min(count, (size_t)wl->fwlog_size);
wl->fwlog_size -= len;
memcpy(buffer, wl->fwlog, len);
/* Make room for new messages */
memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
mutex_unlock(&wl->mutex);
return len;
}
static struct bin_attribute fwlog_attr = {
.attr = {.name = "fwlog", .mode = S_IRUSR},
.read = wl1271_sysfs_read_fwlog,
};
static void wl12xx_derive_mac_addresses(struct wl1271 *wl, u32 oui, u32 nic) static void wl12xx_derive_mac_addresses(struct wl1271 *wl, u32 oui, u32 nic)
{ {
int i; int i;
...@@ -5827,8 +5700,6 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) ...@@ -5827,8 +5700,6 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
return 0; return 0;
} }
#define WL1271_DEFAULT_CHANNEL 0
struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size, struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size,
u32 mbox_size) u32 mbox_size)
{ {
...@@ -5881,7 +5752,7 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size, ...@@ -5881,7 +5752,7 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size,
goto err_hw; goto err_hw;
} }
wl->channel = WL1271_DEFAULT_CHANNEL; wl->channel = 0;
wl->rx_counter = 0; wl->rx_counter = 0;
wl->power_level = WL1271_DEFAULT_POWER_LEVEL; wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
wl->band = IEEE80211_BAND_2GHZ; wl->band = IEEE80211_BAND_2GHZ;
...@@ -5988,11 +5859,8 @@ int wlcore_free_hw(struct wl1271 *wl) ...@@ -5988,11 +5859,8 @@ int wlcore_free_hw(struct wl1271 *wl)
wake_up_interruptible_all(&wl->fwlog_waitq); wake_up_interruptible_all(&wl->fwlog_waitq);
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
device_remove_bin_file(wl->dev, &fwlog_attr); wlcore_sysfs_free(wl);
device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
device_remove_file(wl->dev, &dev_attr_bt_coex_state);
kfree(wl->buffer_32); kfree(wl->buffer_32);
kfree(wl->mbox); kfree(wl->mbox);
free_page((unsigned long)wl->fwlog); free_page((unsigned long)wl->fwlog);
...@@ -6104,36 +5972,13 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context) ...@@ -6104,36 +5972,13 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context)
if (ret) if (ret)
goto out_irq; goto out_irq;
/* Create sysfs file to control bt coex state */ ret = wlcore_sysfs_init(wl);
ret = device_create_file(wl->dev, &dev_attr_bt_coex_state); if (ret)
if (ret < 0) {
wl1271_error("failed to create sysfs file bt_coex_state");
goto out_unreg; goto out_unreg;
}
/* Create sysfs file to get HW PG version */
ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
if (ret < 0) {
wl1271_error("failed to create sysfs file hw_pg_ver");
goto out_bt_coex_state;
}
/* Create sysfs file for the FW log */
ret = device_create_bin_file(wl->dev, &fwlog_attr);
if (ret < 0) {
wl1271_error("failed to create sysfs file fwlog");
goto out_hw_pg_ver;
}
wl->initialized = true; wl->initialized = true;
goto out; goto out;
out_hw_pg_ver:
device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
out_bt_coex_state:
device_remove_file(wl->dev, &dev_attr_bt_coex_state);
out_unreg: out_unreg:
wl1271_unregister_hw(wl); wl1271_unregister_hw(wl);
......
...@@ -110,7 +110,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl) ...@@ -110,7 +110,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl)
DECLARE_COMPLETION_ONSTACK(compl); DECLARE_COMPLETION_ONSTACK(compl);
unsigned long flags; unsigned long flags;
int ret; int ret;
u32 start_time = jiffies; unsigned long start_time = jiffies;
bool pending = false; bool pending = false;
/* /*
......
...@@ -434,19 +434,7 @@ static struct spi_driver wl1271_spi_driver = { ...@@ -434,19 +434,7 @@ static struct spi_driver wl1271_spi_driver = {
.remove = wl1271_remove, .remove = wl1271_remove,
}; };
static int __init wl1271_init(void) module_spi_driver(wl1271_spi_driver);
{
return spi_register_driver(&wl1271_spi_driver);
}
static void __exit wl1271_exit(void)
{
spi_unregister_driver(&wl1271_spi_driver);
}
module_init(wl1271_init);
module_exit(wl1271_exit);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
......
/*
* This file is part of wlcore
*
* Copyright (C) 2013 Texas Instruments Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include "wlcore.h"
#include "debug.h"
#include "ps.h"
#include "sysfs.h"
static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct wl1271 *wl = dev_get_drvdata(dev);
ssize_t len;
len = PAGE_SIZE;
mutex_lock(&wl->mutex);
len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
wl->sg_enabled);
mutex_unlock(&wl->mutex);
return len;
}
static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct wl1271 *wl = dev_get_drvdata(dev);
unsigned long res;
int ret;
ret = kstrtoul(buf, 10, &res);
if (ret < 0) {
wl1271_warning("incorrect value written to bt_coex_mode");
return count;
}
mutex_lock(&wl->mutex);
res = !!res;
if (res == wl->sg_enabled)
goto out;
wl->sg_enabled = res;
if (unlikely(wl->state != WLCORE_STATE_ON))
goto out;
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out;
wl1271_acx_sg_enable(wl, wl->sg_enabled);
wl1271_ps_elp_sleep(wl);
out:
mutex_unlock(&wl->mutex);
return count;
}
static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
wl1271_sysfs_show_bt_coex_state,
wl1271_sysfs_store_bt_coex_state);
static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct wl1271 *wl = dev_get_drvdata(dev);
ssize_t len;
len = PAGE_SIZE;
mutex_lock(&wl->mutex);
if (wl->hw_pg_ver >= 0)
len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
else
len = snprintf(buf, len, "n/a\n");
mutex_unlock(&wl->mutex);
return len;
}
static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
wl1271_sysfs_show_hw_pg_ver, NULL);
static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buffer, loff_t pos, size_t count)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct wl1271 *wl = dev_get_drvdata(dev);
ssize_t len;
int ret;
ret = mutex_lock_interruptible(&wl->mutex);
if (ret < 0)
return -ERESTARTSYS;
/* Let only one thread read the log at a time, blocking others */
while (wl->fwlog_size == 0) {
DEFINE_WAIT(wait);
prepare_to_wait_exclusive(&wl->fwlog_waitq,
&wait,
TASK_INTERRUPTIBLE);
if (wl->fwlog_size != 0) {
finish_wait(&wl->fwlog_waitq, &wait);
break;
}
mutex_unlock(&wl->mutex);
schedule();
finish_wait(&wl->fwlog_waitq, &wait);
if (signal_pending(current))
return -ERESTARTSYS;
ret = mutex_lock_interruptible(&wl->mutex);
if (ret < 0)
return -ERESTARTSYS;
}
/* Check if the fwlog is still valid */
if (wl->fwlog_size < 0) {
mutex_unlock(&wl->mutex);
return 0;
}
/* Seeking is not supported - old logs are not kept. Disregard pos. */
len = min(count, (size_t)wl->fwlog_size);
wl->fwlog_size -= len;
memcpy(buffer, wl->fwlog, len);
/* Make room for new messages */
memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
mutex_unlock(&wl->mutex);
return len;
}
static struct bin_attribute fwlog_attr = {
.attr = {.name = "fwlog", .mode = S_IRUSR},
.read = wl1271_sysfs_read_fwlog,
};
int wlcore_sysfs_init(struct wl1271 *wl)
{
int ret;
/* Create sysfs file to control bt coex state */
ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
if (ret < 0) {
wl1271_error("failed to create sysfs file bt_coex_state");
goto out;
}
/* Create sysfs file to get HW PG version */
ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
if (ret < 0) {
wl1271_error("failed to create sysfs file hw_pg_ver");
goto out_bt_coex_state;
}
/* Create sysfs file for the FW log */
ret = device_create_bin_file(wl->dev, &fwlog_attr);
if (ret < 0) {
wl1271_error("failed to create sysfs file fwlog");
goto out_hw_pg_ver;
}
goto out;
out_hw_pg_ver:
device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
out_bt_coex_state:
device_remove_file(wl->dev, &dev_attr_bt_coex_state);
out:
return ret;
}
void wlcore_sysfs_free(struct wl1271 *wl)
{
device_remove_bin_file(wl->dev, &fwlog_attr);
device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
device_remove_file(wl->dev, &dev_attr_bt_coex_state);
}
/*
* This file is part of wlcore
*
* Copyright (C) 2013 Texas Instruments Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#ifndef __SYSFS_H__
#define __SYSFS_H__
int wlcore_sysfs_init(struct wl1271 *wl);
void wlcore_sysfs_free(struct wl1271 *wl);
#endif
...@@ -386,7 +386,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -386,7 +386,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
is_wep = (cipher == WLAN_CIPHER_SUITE_WEP40) || is_wep = (cipher == WLAN_CIPHER_SUITE_WEP40) ||
(cipher == WLAN_CIPHER_SUITE_WEP104); (cipher == WLAN_CIPHER_SUITE_WEP104);
if (unlikely(is_wep && wlvif->default_key != idx)) { if (WARN_ON(is_wep && wlvif->default_key != idx)) {
ret = wl1271_set_default_wep_key(wl, wlvif, idx); ret = wl1271_set_default_wep_key(wl, wlvif, idx);
if (ret < 0) if (ret < 0)
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment