mirror of
https://github.com/torvalds/linux.git
synced 2024-12-02 09:01:34 +00:00
Merge branch 'for-linville' of git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx
This commit is contained in:
commit
9e49a9d3d6
@ -93,8 +93,7 @@ static void wl1251_spi_wake(struct wl1251 *wl)
|
||||
memset(&t, 0, sizeof(t));
|
||||
spi_message_init(&m);
|
||||
|
||||
/*
|
||||
* Set WSPI_INIT_COMMAND
|
||||
/* Set WSPI_INIT_COMMAND
|
||||
* the data is being send from the MSB to LSB
|
||||
*/
|
||||
cmd[2] = 0xff;
|
||||
@ -262,7 +261,8 @@ static int wl1251_spi_probe(struct spi_device *spi)
|
||||
wl->if_ops = &wl1251_spi_ops;
|
||||
|
||||
/* 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;
|
||||
|
||||
ret = spi_setup(spi);
|
||||
@ -329,29 +329,7 @@ static struct spi_driver wl1251_spi_driver = {
|
||||
.remove = wl1251_spi_remove,
|
||||
};
|
||||
|
||||
static int __init wl1251_spi_init(void)
|
||||
{
|
||||
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_spi_driver(wl1251_spi_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>");
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/etherdevice.h>
|
||||
|
||||
#include "../wlcore/wlcore.h"
|
||||
#include "../wlcore/debug.h"
|
||||
@ -594,8 +595,8 @@ static const struct wlcore_partition_set wl18xx_ptable[PART_TABLE_LEN] = {
|
||||
.mem3 = { .start = 0x00000000, .size = 0x00000000 },
|
||||
},
|
||||
[PART_PHY_INIT] = {
|
||||
.mem = { .start = 0x80926000,
|
||||
.size = sizeof(struct wl18xx_mac_and_phy_params) },
|
||||
.mem = { .start = WL18XX_PHY_INIT_MEM_ADDR,
|
||||
.size = WL18XX_PHY_INIT_MEM_SIZE },
|
||||
.reg = { .start = 0x00000000, .size = 0x00000000 },
|
||||
.mem2 = { .start = 0x00000000, .size = 0x00000000 },
|
||||
.mem3 = { .start = 0x00000000, .size = 0x00000000 },
|
||||
@ -799,6 +800,9 @@ static int wl18xx_pre_upload(struct wl1271 *wl)
|
||||
u32 tmp;
|
||||
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]);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
@ -815,6 +819,35 @@ static int wl18xx_pre_upload(struct wl1271 *wl)
|
||||
wl1271_debug(DEBUG_BOOT, "chip id 0x%x", 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:
|
||||
return ret;
|
||||
@ -1286,6 +1319,16 @@ static int wl18xx_get_mac(struct wl1271 *wl)
|
||||
((mac1 & 0xff000000) >> 24);
|
||||
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]);
|
||||
|
||||
out:
|
||||
|
@ -38,6 +38,9 @@
|
||||
#define WL18XX_REG_BOOT_PART_SIZE 0x00014578
|
||||
|
||||
#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_REG_CONFIG_BASE (WL18XX_REGISTERS_BASE + 0x02000)
|
||||
@ -217,4 +220,16 @@ static const char * const rdl_names[] = {
|
||||
[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__ */
|
||||
|
@ -1,5 +1,5 @@
|
||||
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_sdio-objs = sdio.o
|
||||
|
@ -1,10 +1,9 @@
|
||||
|
||||
/*
|
||||
* This file is part of wl1271
|
||||
* This file is part of wlcore
|
||||
*
|
||||
* Copyright (C) 2008-2010 Nokia Corporation
|
||||
*
|
||||
* Contact: Luciano Coelho <luciano.coelho@nokia.com>
|
||||
* Copyright (C) 2011-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
|
||||
@ -24,34 +23,23 @@
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/crc32.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/wl12xx.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "wlcore.h"
|
||||
#include "debug.h"
|
||||
#include "wl12xx_80211.h"
|
||||
#include "io.h"
|
||||
#include "event.h"
|
||||
#include "tx.h"
|
||||
#include "rx.h"
|
||||
#include "ps.h"
|
||||
#include "init.h"
|
||||
#include "debugfs.h"
|
||||
#include "cmd.h"
|
||||
#include "boot.h"
|
||||
#include "testmode.h"
|
||||
#include "scan.h"
|
||||
#include "hw_ops.h"
|
||||
|
||||
#define WL1271_BOOT_RETRIES 3
|
||||
#include "sysfs.h"
|
||||
|
||||
#define WL1271_BOOT_RETRIES 3
|
||||
|
||||
@ -65,8 +53,7 @@ static void __wl1271_op_remove_interface(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 int wl12xx_set_authorized(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
static int wl12xx_set_authorized(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -983,7 +970,7 @@ static int wlcore_fw_wakeup(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) +
|
||||
wl->fw_status_priv_len, GFP_KERNEL);
|
||||
if (!wl->fw_status_1)
|
||||
@ -993,7 +980,7 @@ static int wl1271_setup(struct wl1271 *wl)
|
||||
(((u8 *) wl->fw_status_1) +
|
||||
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) {
|
||||
kfree(wl->fw_status_1);
|
||||
return -ENOMEM;
|
||||
@ -1668,8 +1655,7 @@ static int wl1271_configure_suspend(struct wl1271 *wl,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wl1271_configure_resume(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif)
|
||||
static void wl1271_configure_resume(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
int ret = 0;
|
||||
bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
|
||||
@ -2603,6 +2589,7 @@ unlock:
|
||||
cancel_work_sync(&wlvif->rx_streaming_enable_work);
|
||||
cancel_work_sync(&wlvif->rx_streaming_disable_work);
|
||||
cancel_delayed_work_sync(&wlvif->connection_loss_work);
|
||||
cancel_delayed_work_sync(&wlvif->channel_switch_work);
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
}
|
||||
@ -3210,14 +3197,6 @@ static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
if (ret < 0)
|
||||
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;
|
||||
@ -3374,6 +3353,46 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
|
||||
}
|
||||
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)
|
||||
{
|
||||
int ret;
|
||||
@ -3782,8 +3801,7 @@ static int wlcore_set_beacon_template(struct wl1271 *wl,
|
||||
struct ieee80211_hdr *hdr;
|
||||
u32 min_rate;
|
||||
int ret;
|
||||
int ieoffset = offsetof(struct ieee80211_mgmt,
|
||||
u.beacon.variable);
|
||||
int ieoffset = offsetof(struct ieee80211_mgmt, u.beacon.variable);
|
||||
struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
|
||||
u16 tmpl_id;
|
||||
|
||||
@ -4230,8 +4248,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
|
||||
}
|
||||
|
||||
/* Handle new association with HT. Do this after join. */
|
||||
if (sta_exists &&
|
||||
(changed & BSS_CHANGED_HT)) {
|
||||
if (sta_exists) {
|
||||
bool enabled =
|
||||
bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT;
|
||||
|
||||
@ -5368,6 +5385,7 @@ static const struct ieee80211_ops wl1271_ops = {
|
||||
.ampdu_action = wl1271_op_ampdu_action,
|
||||
.tx_frames_pending = wl1271_tx_frames_pending,
|
||||
.set_bitrate_mask = wl12xx_set_bitrate_mask,
|
||||
.set_default_unicast_key = wl1271_op_set_default_key_idx,
|
||||
.channel_switch = wl12xx_op_channel_switch,
|
||||
.flush = wlcore_op_flush,
|
||||
.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)
|
||||
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)
|
||||
{
|
||||
int i;
|
||||
@ -5827,8 +5700,6 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define WL1271_DEFAULT_CHANNEL 0
|
||||
|
||||
struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size,
|
||||
u32 mbox_size)
|
||||
{
|
||||
@ -5881,7 +5752,7 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size,
|
||||
goto err_hw;
|
||||
}
|
||||
|
||||
wl->channel = WL1271_DEFAULT_CHANNEL;
|
||||
wl->channel = 0;
|
||||
wl->rx_counter = 0;
|
||||
wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
|
||||
wl->band = IEEE80211_BAND_2GHZ;
|
||||
@ -5988,11 +5859,8 @@ int wlcore_free_hw(struct wl1271 *wl)
|
||||
wake_up_interruptible_all(&wl->fwlog_waitq);
|
||||
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->mbox);
|
||||
free_page((unsigned long)wl->fwlog);
|
||||
@ -6104,36 +5972,13 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context)
|
||||
if (ret)
|
||||
goto out_irq;
|
||||
|
||||
/* 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");
|
||||
ret = wlcore_sysfs_init(wl);
|
||||
if (ret)
|
||||
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;
|
||||
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:
|
||||
wl1271_unregister_hw(wl);
|
||||
|
||||
|
@ -110,7 +110,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl)
|
||||
DECLARE_COMPLETION_ONSTACK(compl);
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
u32 start_time = jiffies;
|
||||
unsigned long start_time = jiffies;
|
||||
bool pending = false;
|
||||
|
||||
/*
|
||||
|
@ -434,19 +434,7 @@ static struct spi_driver wl1271_spi_driver = {
|
||||
.remove = wl1271_remove,
|
||||
};
|
||||
|
||||
static int __init wl1271_init(void)
|
||||
{
|
||||
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_spi_driver(wl1271_spi_driver);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
|
||||
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
|
||||
|
216
drivers/net/wireless/ti/wlcore/sysfs.c
Normal file
216
drivers/net/wireless/ti/wlcore/sysfs.c
Normal file
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
28
drivers/net/wireless/ti/wlcore/sysfs.h
Normal file
28
drivers/net/wireless/ti/wlcore/sysfs.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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,
|
||||
is_wep = (cipher == WLAN_CIPHER_SUITE_WEP40) ||
|
||||
(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);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
Loading…
Reference in New Issue
Block a user