Compare commits

..

2 Commits

Author SHA1 Message Date
test0r 82ba594a44 bes2600: default STANDARD_FACTORY_EFUSE_FLAG off for PineTab2 factory.txt format
The shipped factory calibration file bes2600_factory.txt on PineTab2
(danctnix linux-firmware 0.3.5_2023.0209) contains 30 calibration
fields: head (3), iq/xtal (3), 2.4G power 11n (5), 5G power 11n (15),
bt (4). The file terminates with '%%\n' directly after edr_power.

When STANDARD_FACTORY_EFUSE_FLAG is defined at compile time the driver
assembles STANDARD_FACTORY with an extra select_efuse_flag section
appended and expects 31 sscanf matches (FACTORY_MEMBER_NUM=31):

    __STANDARD_FACTORY + \"##select_efuse_flag\\nselect_efuse:%hx\\n\"
                      + \"%%%%\\n\"

The PineTab2 factory.txt has no select_efuse_flag section, so sscanf
stops after field 30 and factory_parse() returns -1 with:

    bes2600_factory.txt parse fail
    read and check bes2600/bes2600_factory.txt error
    factory cali data get failed.

This was latent until the preceding patch (use request_firmware() for
factory.txt read) fixed the path bug that masked the parse failure.

Default STANDARD_FACTORY_EFUSE_FLAG to n. The flag remains overridable
at build time (make STANDARD_FACTORY_EFUSE_FLAG=y ...) for chips /
firmware packages that do ship the select_efuse_flag section.

Also: the wsm_save_factory_txt_to_mcu() prototype in wsm.h was
inconsistently wrapped in a conditional that keyed on
STANDARD_FACTORY_EFUSE_FLAG, but the function definition in wsm.c and
the call site in sta.c are ungated. With the flag now defaulting to
n, the gcc -Werror=missing-prototypes flag breaks the build. Drop the
conditional wrapper around the prototype — the function exists and is
used regardless of the factory-parse flag.

Tested-on: PineTab2 (BES2600WM + RK3566) running linux-pinetab2
6.19.10-danctnix1-1. With the flag defaulted off, factory_parse()
succeeds on the shipped factory.txt, factory_cali_data is populated,
and dmesg no longer shows the parse-fail / read-and-check-error /
factory-cali-data-get-failed sequence.

Signed-off-by: Markus Fritsche <fritsche.markus@gmail.com>
2026-04-22 12:26:22 +02:00
test0r 1a5d54a321 bes2600: use request_firmware() for factory.txt read
The BES2600 factory calibration file (bes2600_factory.txt) was being read
via filp_open() + kernel_read() from a hard-coded absolute path baked in
at compile time via the FACTORY_PATH Makefile macro
(default: /lib/firmware/bes2600_factory.txt).

This had several problems:

1. Path mismatch - linux-firmware-style packaging (and danctnix 0.2-5
   device-pine64-pinetab2) ships the file at
   /lib/firmware/bes2600/bes2600_factory.txt, not /lib/firmware/. The
   driver logged '(NULL device *): read and check
   /lib/firmware/bes2600_factory.txt error' on every boot on PineTab2
   running linux-pinetab2 6.19.10-danctnix1-1.

2. Direct filesystem access via filp_open() / kernel_read() from a driver
   is an anti-pattern that upstream rejects: drivers should use
   request_firmware() to get binary data from userspace-managed firmware
   directories. request_firmware() natively searches the firmware_class
   path list (typically /lib/firmware + derivatives), associates the load
   with a uevent, and respects the firmware-loading infrastructure.

3. The (NULL device *) prefix in error messages indicated the absence of
   proper device-context logging. While this patch does not yet thread
   struct device through, the upstream path uses request_firmware() which
   works with dev=NULL and is the building block for a follow-up patch
   that adds per-chip device context.

Repoint the FACTORY_PATH default to the firmware-class name
(bes2600/bes2600_factory.txt) - request_firmware() prepends
/lib/firmware/ from the configured search paths. The macro remains
overridable at build time for non-standard deployments.

Rewrite factory_section_read_file() to:
  * Call request_firmware(&fw, path, NULL).
  * Size-check fw->size against FACTORY_MAX_SIZE.
  * memcpy the data into the caller's buffer.
  * Always call release_firmware() on exit.

The file write path (factory_section_write_file + kernel_write) is left
unchanged in this patch; it is the subject of a follow-up patch that
removes kernel_write and moves any remaining userspace-visible factory
configuration to a standard kernel-userspace boundary (debugfs or
nl80211 testmode).

No caller signature changes. No Makefile flag drops. Bisectable.

Tested-on: PineTab2 (BES2600WM + RK3566) running linux-pinetab2
6.19.10-danctnix1-1, deployed via /lib/modules/<ver>/extra/. Verified
post-reboot: original 'read and check /lib/firmware/bes2600_factory.txt
error' is gone; request_firmware reads the file successfully (a separate
factory_parse() bug, previously masked by the read failure, is now
exposed and tracked separately).

Signed-off-by: Markus Fritsche <fritsche.markus@gmail.com>
2026-04-22 10:09:44 +02:00
11 changed files with 801 additions and 121 deletions
+13 -1
View File
@@ -2,7 +2,7 @@ KERN_DIR = /lib/modules/$(KERNELRELEASE)/build
# feature option # feature option
BES2600 ?= m BES2600 ?= m
CONFIG_BES2600_TESTMODE ?= y CONFIG_BES2600_TESTMODE ?= n
CONFIG_BES2600_ENABLE_DEVEL_LOGS ?= n CONFIG_BES2600_ENABLE_DEVEL_LOGS ?= n
@@ -28,6 +28,7 @@ CONFIG_BES2600_WIFI_BOOT_ON ?= y
CONFIG_BES2600_BT_BOOT_ON ?= n CONFIG_BES2600_BT_BOOT_ON ?= n
BES2600_GPIO_WAKEUP_AP ?= n BES2600_GPIO_WAKEUP_AP ?= n
BES2600_WRITE_DPD_TO_FILE ?= n
BES2600_TX_MORE_RETRY ?= n BES2600_TX_MORE_RETRY ?= n
# bes evb # bes evb
@@ -92,6 +93,12 @@ ccflags-y += -DBES_UNIFIED_PM
ccflags-y += -DBES_SDIO_OPTIMIZED_LEN ccflags-y += -DBES_SDIO_OPTIMIZED_LEN
ccflags-y += -DBES2600_HOST_TIMESTAMP_DEBUG ccflags-y += -DBES2600_HOST_TIMESTAMP_DEBUG
ifeq ($(BES2600_WRITE_DPD_TO_FILE),y)
BES2600_DPD_PATH ?= /data/cfg/bes2600_dpd.bin
BES2600_DEFAULT_DPD_PATH ?= /lib/firmware/bes2600_dpd.bin
BES2600_DPD_GOLDEN_PATH ?= /data/cfg/bes2600_dpd_golden.bin
endif
ifeq ($(BES2600_DUMP_FW_DPD_LOG),y) ifeq ($(BES2600_DUMP_FW_DPD_LOG),y)
BES2600_DPD_LOG_PATH ?= /data/applog/bes2600_dpd_log.log BES2600_DPD_LOG_PATH ?= /data/applog/bes2600_dpd_log.log
endif endif
@@ -128,6 +135,9 @@ ccflags-y += $(call boolen_flag,BSS_LOSS_CHECK,y)
ccflags-y += $(call string_flag,BES2600_LOAD_FW_TOOL_PATH) ccflags-y += $(call string_flag,BES2600_LOAD_FW_TOOL_PATH)
ccflags-y += $(call string_flag,BES2600_LOAD_FW_TOOL_DEVICE) ccflags-y += $(call string_flag,BES2600_LOAD_FW_TOOL_DEVICE)
ccflags-y += $(call string_flag,BES2600_DRV_VERSION) ccflags-y += $(call string_flag,BES2600_DRV_VERSION)
ccflags-y += $(call string_flag,BES2600_DPD_PATH)
ccflags-y += $(call string_flag,BES2600_DEFAULT_DPD_PATH)
ccflags-y += $(call string_flag,BES2600_DPD_GOLDEN_PATH)
ccflags-y += $(call boolen_flag,BES2600_INDEPENDENT_EVB,y) ccflags-y += $(call boolen_flag,BES2600_INDEPENDENT_EVB,y)
ccflags-y += $(call boolen_flag,BES2600_INTEGRATED_MODULE_V1,y) ccflags-y += $(call boolen_flag,BES2600_INTEGRATED_MODULE_V1,y)
@@ -149,6 +159,8 @@ ccflags-y += $(call boolen_flag,FACTORY_SAVE_MULTI_PATH,y)
ccflags-y += $(call boolen_flag,FACTORY_CRC_CHECK,y) ccflags-y += $(call boolen_flag,FACTORY_CRC_CHECK,y)
ccflags-y += $(call boolen_flag,BES2600_GPIO_WAKEUP_AP,y) ccflags-y += $(call boolen_flag,BES2600_GPIO_WAKEUP_AP,y)
ccflags-y += $(call boolen_flag,BES2600_WRITE_DPD_TO_FILE,y)
ccflags-y += $(call boolen_flag,BES2600_DUMP_FW_DPD_LOG,y) ccflags-y += $(call boolen_flag,BES2600_DUMP_FW_DPD_LOG,y)
ccflags-y += $(call string_flag,BES2600_DPD_LOG_PATH) ccflags-y += $(call string_flag,BES2600_DPD_LOG_PATH)
+47 -30
View File
@@ -31,18 +31,6 @@
static DEFINE_MUTEX(factory_lock); static DEFINE_MUTEX(factory_lock);
/*
* struct device * for request_firmware() context. Set once at SDIO
* probe via bes2600_factory_set_dev(). NULL is tolerated (falls back
* to the udev-less firmware-class path) but loses per-device logging.
*/
static struct device *bes2600_factory_dev;
void bes2600_factory_set_dev(struct device *dev)
{
bes2600_factory_dev = dev;
}
/* /*
* It is only used for temporary storage. * It is only used for temporary storage.
* Every time get the factory, it will read from the * Every time get the factory, it will read from the
@@ -160,7 +148,7 @@ static int factory_section_read_file(char *path, void *buffer)
bes_devel("requesting firmware-class %s\n", path); bes_devel("requesting firmware-class %s\n", path);
ret = request_firmware(&fw, path, bes2600_factory_dev); ret = request_firmware(&fw, path, NULL);
if (ret) { if (ret) {
bes_devel("BES2600: request_firmware(%s) failed: %d\n", path, ret); bes_devel("BES2600: request_firmware(%s) failed: %d\n", path, ret);
return -1; return -1;
@@ -179,6 +167,34 @@ static int factory_section_read_file(char *path, void *buffer)
return ret; return ret;
} }
/**
* factory_section_write_file - Write data of specified length to file
* @path: path of the file
* @buffer: storage of write data
* @size: length of data to write
*
* Return: length on success, negative error code otherwise.
*/
static int factory_section_write_file(char *path, void *buffer, int size)
{
int ret = 0;
struct file *fp;
bes_devel("writing %s \n", path);
fp = filp_open(path, O_TRUNC | O_CREAT | O_RDWR, S_IRUSR);
if (IS_ERR(fp)) {
bes_devel("BES2600 : can't open %s\n",path);
return -1;
}
ret = kernel_write(fp, buffer, size, &fp->f_pos);
filp_close(fp,NULL);
return ret;
}
static inline int factory_parse(uint8_t *source_buf, struct factory_t *factory) static inline int factory_parse(uint8_t *source_buf, struct factory_t *factory)
{ {
int ret = 0; int ret = 0;
@@ -870,22 +886,9 @@ static inline int factory_build(uint8_t *dest_buf, struct factory_t *factory)
#endif #endif
} }
/*
* Rebuild the serialised calibration blob in file_buffer from the live
* in-memory factory_save_p. Previously this function also persisted the
* blob back to FACTORY_PATH via filp_open(O_CREAT) + kernel_write(); that
* is not acceptable in mainline, so the persistence step has been removed.
*
* The in-memory factory_save_p remains authoritative for the duration of
* the session; on the next probe the firmware-class file is read back
* read-only via request_firmware(). If cross-reboot persistence of runtime
* calibration updates becomes a requirement, the expected route is a
* userspace-facing dump interface (debugfs read-only blob, or nl80211
* vendor command) that lets userspace read the serialised form and store
* it under its own privileges.
*/
static int bes2600_wifi_cali_table_save(u8 *file_buffer, struct factory_t *factory_save_p) static int bes2600_wifi_cali_table_save(u8 *file_buffer, struct factory_t *factory_save_p)
{ {
int ret = 0;
int w_size; int w_size;
u32 crc_len = sizeof(factory_data_t); u32 crc_len = sizeof(factory_data_t);
#ifndef STANDARD_FACTORY_EFUSE_FLAG #ifndef STANDARD_FACTORY_EFUSE_FLAG
@@ -894,11 +897,13 @@ static int bes2600_wifi_cali_table_save(u8 *file_buffer, struct factory_t *facto
bes_devel("enter %s\n", __func__); bes_devel("enter %s\n", __func__);
if (!file_buffer) if (!file_buffer) {
return -ENOMEM; return -ENOMEM;
}
if (!factory_save_p) if (!factory_save_p) {
return -ENOENT; return -ENOENT;
}
/* All initialized to space */ /* All initialized to space */
memset(file_buffer, 32, FACTORY_MAX_SIZE); memset(file_buffer, 32, FACTORY_MAX_SIZE);
@@ -910,10 +915,22 @@ static int bes2600_wifi_cali_table_save(u8 *file_buffer, struct factory_t *facto
w_size = factory_build(file_buffer, factory_save_p); w_size = factory_build(file_buffer, factory_save_p);
if (w_size < 0 || w_size > FACTORY_MAX_SIZE) { if (w_size < 0 || w_size > FACTORY_MAX_SIZE) {
bes_err("%s: build failed! w_size = %d.", __func__, w_size); bes_err("%s: build failed! ret = %d.", __func__, ret);
return -ETXTBSY; return -ETXTBSY;
} }
#ifdef FACTORY_SAVE_MULTI_PATH
/* avoid trailing characters '\0' */
file_buffer[w_size] = 32;
ret = factory_section_write_file(FACTORY_PATH, file_buffer, FACTORY_MAX_SIZE);
#else
ret = factory_section_write_file(FACTORY_PATH, file_buffer, w_size);
#endif
if(ret < 0) {
bes_err("%s: write failed! ret = %d.", __func__, ret);
return ret;
}
return 0; return 0;
} }
-3
View File
@@ -199,9 +199,6 @@ enum factory_cali_status {
/* just calibrate 11n, other protocols are automatically mapped */ /* just calibrate 11n, other protocols are automatically mapped */
#define WIFI_RF_11N_MODE 0x15 #define WIFI_RF_11N_MODE 0x15
/* set the struct device * used for request_firmware() context */
void bes2600_factory_set_dev(struct device *dev);
/* read wifi & bt factory cali value*/ /* read wifi & bt factory cali value*/
u8* bes2600_get_factory_cali_data(u8 *file_buffer, u32 *data_len, char *path); u8* bes2600_get_factory_cali_data(u8 *file_buffer, u32 *data_len, char *path);
void factory_little_endian_cvrt(u8 *data); void factory_little_endian_cvrt(u8 *data);
+1 -42
View File
@@ -30,7 +30,6 @@
#include "bes2600.h" #include "bes2600.h"
#include "sbus.h" #include "sbus.h"
#include "bes2600_plat.h" #include "bes2600_plat.h"
#include "bes2600_factory.h"
#include "hwio.h" #include "hwio.h"
#include "bes_chardev.h" #include "bes_chardev.h"
#include "bes_log.h" #include "bes_log.h"
@@ -95,7 +94,6 @@ struct sbus_priv {
struct work_struct tx_work; struct work_struct tx_work;
struct scatterlist tx_sg[BES_SDIO_TX_MULTIPLE_NUM + 1]; struct scatterlist tx_sg[BES_SDIO_TX_MULTIPLE_NUM + 1];
struct scatterlist tx_sg_nosignal[BES_SDIO_TX_MULTIPLE_NUM_NOSIGNAL + 1]; struct scatterlist tx_sg_nosignal[BES_SDIO_TX_MULTIPLE_NUM_NOSIGNAL + 1];
u8 *tx_bounce;
u32 tx_data_cnt; u32 tx_data_cnt;
u32 tx_xfer_cnt; u32 tx_xfer_cnt;
u32 tx_proc_cnt; u32 tx_proc_cnt;
@@ -1137,26 +1135,7 @@ static void sdio_tx_work(struct work_struct *work)
} }
} }
/* sg_set_buf(&sg[scatters], tx_buffer->buf, align);
* The transfer length is rounded up to the SDIO block
* size, but tx_buffer->buf is only tx_buffer->len bytes
* long (it usually aliases into an skb linear head).
* Copy into a driver-owned bounce buffer and zero-pad
* to the aligned size; otherwise DMA reads past the
* skb and leaks adjacent kernel memory on the wire --
* observed as KFENCE OOB reads from
* bes_sdio_memcpy_to_io_helper via dma_map_sg.
*/
if (WARN_ON_ONCE(total_len + align > MAX_SDIO_TRANSFER_LEN))
goto flush_previous;
memcpy(self->tx_bounce + total_len,
tx_buffer->buf, tx_buffer->len);
if (align > tx_buffer->len)
memset(self->tx_bounce + total_len +
tx_buffer->len, 0,
align - tx_buffer->len);
sg_set_buf(&sg[scatters],
self->tx_bounce + total_len, align);
total_len += align; total_len += align;
++scatters; ++scatters;
/*del_node:*/ /*del_node:*/
@@ -1855,9 +1834,6 @@ static int bes2600_sdio_probe(struct sdio_func *func,
if (ret) if (ret)
goto err; goto err;
/* wire struct device into factory.c for request_firmware() context */
bes2600_factory_set_dev(dev);
self->pdata = bes2600_get_platform_data(); self->pdata = bes2600_get_platform_data();
self->func = func; self->func = func;
self->dev = &func->dev; self->dev = &func->dev;
@@ -1877,17 +1853,6 @@ static int bes2600_sdio_probe(struct sdio_func *func,
if (!self->single_gathered_buffer) if (!self->single_gathered_buffer)
return -ENOMEM; return -ENOMEM;
#endif #endif
#ifdef BES_SDIO_TX_MULTIPLE_ENABLE
self->tx_bounce = (u8 *)__get_dma_pages(GFP_KERNEL,
get_order(MAX_SDIO_TRANSFER_LEN));
if (!self->tx_bounce) {
#ifndef SDIO_HOST_ADMA_SUPPORT
free_pages((unsigned long)self->single_gathered_buffer,
get_order(MAX_SDIO_TRANSFER_LEN));
#endif
return -ENOMEM;
}
#endif
#ifdef BES_SDIO_RXTX_TOGGLE #ifdef BES_SDIO_RXTX_TOGGLE
self->fw_started = false; self->fw_started = false;
#endif #endif
@@ -2016,12 +1981,6 @@ static void bes2600_sdio_remove(struct sdio_func *func)
if (self->single_gathered_buffer) { if (self->single_gathered_buffer) {
free_pages((unsigned long)self->single_gathered_buffer, get_order(MAX_SDIO_TRANSFER_LEN)); free_pages((unsigned long)self->single_gathered_buffer, get_order(MAX_SDIO_TRANSFER_LEN));
} }
#endif
#ifdef BES_SDIO_TX_MULTIPLE_ENABLE
if (self->tx_bounce) {
free_pages((unsigned long)self->tx_bounce,
get_order(MAX_SDIO_TRANSFER_LEN));
}
#endif #endif
kfree(self); kfree(self);
} }
+662
View File
@@ -43,6 +43,12 @@ enum bus_probe_state {
}; };
struct bes_cdev { struct bes_cdev {
struct cdev cdev;
dev_t dev_id;
int major;
int minor;
struct class *class;
struct device *device;
atomic_t num_proc; atomic_t num_proc;
wait_queue_head_t open_wq; wait_queue_head_t open_wq;
spinlock_t status_lock; spinlock_t status_lock;
@@ -63,6 +69,9 @@ struct bes_cdev {
struct delayed_work probe_timeout_work; struct delayed_work probe_timeout_work;
enum bus_probe_state bus_probe; enum bus_probe_state bus_probe;
struct work_struct wifi_force_close_work; struct work_struct wifi_force_close_work;
#ifdef BES2600_WRITE_DPD_TO_FILE
int no_dpd;
#endif
enum pend_read_op read_flag; enum pend_read_op read_flag;
enum wakeup_event wakeup_by_event; /* used to filter unwanted event wakeup reason report */ enum wakeup_event wakeup_by_event; /* used to filter unwanted event wakeup reason report */
u16 wakeup_state; /* for userspace check wakeup reason */ u16 wakeup_state; /* for userspace check wakeup reason */
@@ -82,6 +91,9 @@ struct bes2600_op_map {
static struct bes_cdev bes2600_cdev; static struct bes_cdev bes2600_cdev;
module_param_named(fw_type, bes2600_cdev.fw_type, int, 0644); module_param_named(fw_type, bes2600_cdev.fw_type, int, 0644);
#ifdef BES2600_WRITE_DPD_TO_FILE
module_param_named(no_dpd, bes2600_cdev.no_dpd, int, 0644);
#endif
extern int bes2600_register_net_dev(struct sbus_priv *bus_priv); extern int bes2600_register_net_dev(struct sbus_priv *bus_priv);
extern int bes2600_unregister_net_dev(struct sbus_priv *bus_priv); extern int bes2600_unregister_net_dev(struct sbus_priv *bus_priv);
@@ -237,18 +249,351 @@ int bes2600_switch_bt(bool on)
return ret; return ret;
} }
static int bes2600_get_cmd_and_ifname(const char *str, char **result)
{
int cmd_len = 0;
int ifname_len = 0;
char *sp = NULL;
char *tmp_ptr = NULL;
char *cmd_ptr = NULL;
/* check if input arguments is valid */
if (!str || strncmp(str, "ifname:", 7) != 0)
return -1;
sp = strchr(str, ' ');
if (strncmp(sp + 1, "cmd:", 4) != 0)
return -1;
/* extract interface name */
ifname_len = sp - str - 7;
tmp_ptr = kmalloc(ifname_len + 1, GFP_KERNEL);
if (!tmp_ptr) {
return -2;
}
strncpy(tmp_ptr, str+7, ifname_len);
tmp_ptr[ifname_len] = '\0';
result[0] = tmp_ptr;
/* get command length */
cmd_ptr = strstr(str, "cmd:");
cmd_ptr += 4;
sp = strchr(cmd_ptr, ' ');
if (!sp) { /* the command don't have any parameter */
cmd_len = strlen(cmd_ptr);
if (cmd_ptr[cmd_len - 1] == '\n')
--cmd_len;
} else { /* the command have one or more parameter */
cmd_len = sp - cmd_ptr;
}
/* copy command to out buffer */
tmp_ptr = kmalloc( cmd_len + 1, GFP_KERNEL);
if (!tmp_ptr) {
kfree(result[0]);
result[0] = NULL;
return -3;
}
strncpy(tmp_ptr, cmd_ptr, cmd_len);
tmp_ptr[cmd_len] = '\0';
result[1] = tmp_ptr;
return 0;
}
static void bes2600_recyle_cmd_and_ifname_mem(char **info)
{
if (info[0]) {
kfree(info[0]);
info[0] = NULL;
}
if (info[1]) {
kfree(info[1]);
info[1] = NULL;
}
}
static int bes2600_op_default_handler(const char *str)
{
char *info[2] = {0};
if (bes2600_get_cmd_and_ifname(str, info) == 0) {
bes_devel("cmd(%s) on %s not handled\n", info[1], info[0]);
} else {
bes_err("%s get command fail, the origin string is %s\n", __func__, str);
}
bes2600_recyle_cmd_and_ifname_mem(info);
return 0;
}
static int bes2600_op_wifi_bt_on_off(const char *str)
{
char *info[2] = {0};
int ret = 0;
enum wait_state wait_state;
enum bus_probe_state probe_state;
unsigned long status = 0;
spin_lock(&bes2600_cdev.status_lock);
probe_state = bes2600_cdev.bus_probe;
wait_state = bes2600_cdev.wait_state;
spin_unlock(&bes2600_cdev.status_lock);
/* only work for wifi signal mode */
if (bes2600_cdev.fw_type != BES2600_FW_TYPE_WIFI_SIGNAL)
return -EFAULT;
/* wait bus probe operation end */
if (probe_state == BES2600_BUS_PROBE_START) {
bes_devel("wait bus probe operation end\n");
status = wait_event_timeout(bes2600_cdev.probe_done_wq,
(bes2600_cdev.bus_probe > BES2600_BUS_PROBE_START),
HZ);
WARN_ON(status <= 0);
}
/* must wait previous operation end in critical section */
if (wait_state != BES2600_BOOT_WAIT_NONE) {
bes_devel("wait previous operation end\n");
status = wait_event_timeout(bes2600_cdev.probe_done_wq,
(bes2600_cdev.wait_state == BES2600_BOOT_WAIT_NONE),
HZ * 8);
WARN_ON(status <= 0);
}
/* if dpd calibration is doing, modify wifi and bt state directly */
spin_lock(&bes2600_cdev.status_lock);
if (bes2600_cdev.bus_probe == BES2600_BUS_PROBE_OK && !bes2600_cdev.dpd_calied) {
if (bes2600_get_cmd_and_ifname(str, info) == 0) {
if (strncmp(info[1], "WIFI_ON", 7) == 0) {
bes2600_cdev.wifi_opened = true;
} else if (strncmp(info[1], "WIFI_OFF", 8) == 0) {
bes2600_cdev.wifi_opened = false;
} else if (strncmp(info[1], "BT_ON", 5) == 0) {
bes2600_cdev.bt_opened = true;
bes2600_cdev.bton_pending = true;
} else if (strncmp(info[1], "BT_OFF", 6) == 0) {
bes2600_cdev.bt_opened = false;
bes2600_cdev.bton_pending = false;
}
}
bes2600_recyle_cmd_and_ifname_mem(info);
spin_unlock(&bes2600_cdev.status_lock);
/* wait probe done event */
status = wait_event_timeout(bes2600_cdev.probe_done_wq,
bes2600_bootup_end(), HZ * 8);
WARN_ON(status <= 0);
return (status <= 0 || bes2600_chrdev_is_bus_error()) ? -EFAULT : 0;
}
spin_unlock(&bes2600_cdev.status_lock);
/* process wifi/bt on/off operation */
if (bes2600_get_cmd_and_ifname(str, info) == 0) {
if (strncmp(info[1], "WIFI_ON", 7) == 0) {
ret = bes2600_switch_wifi(1);
} else if (strncmp(info[1], "WIFI_OFF", 8) == 0) {
ret = bes2600_switch_wifi(0);
} else if (strncmp(info[1], "BT_ON", 5) == 0) {
ret = bes2600_switch_bt(1);
} else if (strncmp(info[1], "BT_OFF", 6) == 0) {
ret = bes2600_switch_bt(0);
}
}
if (!ret && bes2600_chrdev_check_system_close())
ret = bes2600_chrdev_do_system_close(bes2600_cdev.sbus_ops,
bes2600_cdev.sbus_priv);
bes2600_recyle_cmd_and_ifname_mem(info);
return ret ;
}
static int bes2600_op_change_fw_type(const char *str)
{
int ret = 0;
int temp = 0;
long status = 0;
char *cmd_ptr = NULL;
char fw_type[5] = {0};
bool sys_closed = bes2600_chrdev_check_system_close();
bes_devel("%s is called, arg:%s\n", __func__, str);
if (!bes2600_cdev.sbus_ops->power_switch && !bes2600_cdev.sbus_ops->reboot)
return -EPERM;
/* check if user input is valid */
cmd_ptr = strstr(str, "CHANGE_FW_TYPE ");
if (strlen(str) < 16 || !cmd_ptr) {
bes_err("the format of \"%s\" is error\n", str);
return -EINVAL;
}
/* convert fw_type from string to int */
strncpy(fw_type, cmd_ptr + 14, 4);
fw_type[0] = '+';
ret = kstrtoint(fw_type, 10, &temp);
if (ret < 0) {
bes_err("%s parse error\n", __func__);
return -EINVAL;
}
/* no need to realod firmware if new fw_type is equal to the old */
if (temp == bes2600_cdev.fw_type ) {
bes_devel("fw type is equal\n");
return 0;
}
/* close wifi net device */
if (bes2600_cdev.sbus_priv
&& bes2600_is_net_dev_created(bes2600_cdev.sbus_priv)) {
bes2600_unregister_net_dev(bes2600_cdev.sbus_priv);
}
/* update firmware type */
bes2600_cdev.fw_type = temp;
bes2600_chrdev_update_signal_mode();
if (!sys_closed) {
/* close device to call disconnect function */
if (bes2600_cdev.sbus_ops->power_switch)
bes2600_cdev.sbus_ops->power_switch(bes2600_cdev.sbus_priv, 0);
else if (bes2600_cdev.sbus_ops->reboot)
bes2600_cdev.sbus_ops->reboot(bes2600_cdev.sbus_priv);
}
if (bes2600_cdev.sbus_ops->reboot)
bes2600_chrdev_start_bus_probe();
/* wait disconnect event */
status = wait_event_timeout(bes2600_cdev.probe_done_wq, (bes2600_cdev.sbus_priv == NULL), HZ * 10);
WARN_ON(status <= 0);
if (bes2600_cdev.dpd_calied
&& bes2600_chrdev_check_system_close()) {
bes_devel("no need to reload firmware\n");
return 0;
}
bes_devel("reload firmware...\n");
/* power on device to call probe function */
if (bes2600_cdev.sbus_ops->power_switch)
bes2600_cdev.sbus_ops->power_switch(NULL, 1);
/* wait probe done event */
status = wait_event_timeout(bes2600_cdev.probe_done_wq,
bes2600_bootup_end(), HZ * 10);
WARN_ON(status <= 0);
ret = (status <= 0 || bes2600_chrdev_is_bus_error()) ? -1 : 0;
return ret;
}
static int bes2600_op_bt_wakeup(const char *str)
{
int ret = 0;
unsigned long status = 0;
spin_lock(&bes2600_cdev.status_lock);
if (!bes2600_cdev.bt_opened) {
spin_unlock(&bes2600_cdev.status_lock);
return -EFAULT;
}
spin_unlock(&bes2600_cdev.status_lock);
/* wait probe done event */
status = wait_event_timeout(bes2600_cdev.probe_done_wq,
bes2600_bootup_end(), HZ * 8);
if (status <= 0 || bes2600_chrdev_is_bus_error())
return -EFAULT;
bes_devel("bes2600 wakeup bt.\n");
ret = bes2600_chrdev_switch_subsys(GPIO_WAKE_FLAG_BT_LP_ON, SUBSYSTEM_BT_LP, true);
return ret;
}
static int bes2600_op_bt_sleep(const char *str)
{
int ret = 0;
unsigned long status = 0;
spin_lock(&bes2600_cdev.status_lock);
if (!bes2600_cdev.bt_opened) {
spin_unlock(&bes2600_cdev.status_lock);
return -EFAULT;
}
spin_unlock(&bes2600_cdev.status_lock);
/* wait probe done event */
status = wait_event_timeout(bes2600_cdev.probe_done_wq,
bes2600_bootup_end(), HZ * 8);
if (status <= 0 || bes2600_chrdev_is_bus_error())
return -EFAULT;
bes_devel("bes2600 allow bt sleep.\n");
ret = bes2600_chrdev_switch_subsys(GPIO_WAKE_FLAG_BT_LP_OFF, SUBSYSTEM_BT_LP, false);
return ret;
}
static int bes2600_op_set_wakeup_read_flag(const char *str)
{
bes_devel("%s is called, arg:%s\n", __func__, str);
spin_lock(&bes2600_cdev.status_lock);
bes2600_cdev.read_flag = BES_CDEV_READ_WAKEUP_STATE;
spin_unlock(&bes2600_cdev.status_lock);
return 0;
}
#ifdef FW_DOWNLOAD_UART_DAEMON #ifdef FW_DOWNLOAD_UART_DAEMON
int bes2600_load_uevent(char *env[])
{
return kobject_uevent_env(&bes2600_cdev.device->kobj, KOBJ_CHANGE, env);
}
#endif #endif
static struct bes2600_op_map bes2600_op_map_tab[] ={
/*op op_len handler */
{"P2P_SET_NOA", 11, bes2600_op_default_handler},
{"P2P_SET_PS", 10, bes2600_op_default_handler},
{"SET_AP_WPS_P2P_IE", 17, bes2600_op_default_handler},
{"LINKSPEED", 9, bes2600_op_default_handler},
{"RSSI", 4, bes2600_op_default_handler},
{"GETBAND", 7, bes2600_op_default_handler},
{"WLS_BATCHING", 12, bes2600_op_default_handler},
{"MACADDR", 7, bes2600_op_default_handler},
{"RXFILTER-START", 14, bes2600_op_default_handler},
{"RXFILTER-STOP", 13, bes2600_op_default_handler},
{"RXFILTER-ADD", 12, bes2600_op_default_handler},
{"RXFILTER-REMOVE", 15, bes2600_op_default_handler},
{"BTCOEXMODE", 10, bes2600_op_default_handler},
{"BTCOEXSCAN-START", 16, bes2600_op_default_handler},
{"BTCOEXSCAN-STOP", 15, bes2600_op_default_handler},
{"SETSUSPENDMODE", 14, bes2600_op_default_handler},
{"COUNTRY", 7, bes2600_op_default_handler},
{"WIFI_ON", 7, bes2600_op_wifi_bt_on_off},
{"WIFI_OFF", 8, bes2600_op_wifi_bt_on_off},
{"BT_ON", 5, bes2600_op_wifi_bt_on_off},
{"BT_OFF", 6, bes2600_op_wifi_bt_on_off},
{"CHANGE_FW_TYPE", 14, bes2600_op_change_fw_type},
{"BT_WAKEUP", 9, bes2600_op_bt_wakeup},
{"BT_SLEEP", 8, bes2600_op_bt_sleep},
{"WAKEUP_STATE", 12, bes2600_op_set_wakeup_read_flag},
};
static int bes2600_chrdev_check_system_close_internal(void) static int bes2600_chrdev_check_system_close_internal(void)
{ {
@@ -258,13 +603,255 @@ static int bes2600_chrdev_check_system_close_internal(void)
&& (bes2600_cdev.wifi_opened == false); && (bes2600_cdev.wifi_opened == false);
} }
static int bes2600_chrdev_open(struct inode *inode, struct file *filp)
{
if (atomic_read(&bes2600_cdev.num_proc) > 0) {
wait_event_timeout(bes2600_cdev.open_wq,
(atomic_read(&bes2600_cdev.num_proc) == 0),
MAX_SCHEDULE_TIMEOUT);
}
bes_devel("bes2600 char device is opened\n");
atomic_inc(&bes2600_cdev.num_proc);
return 0;
}
static ssize_t bes2600_chrdev_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
char buf[64] = {0};
unsigned int len;
long status = 0;
switch (bes2600_cdev.read_flag) {
case BES_CDEV_READ_WAKEUP_STATE:
if (bes2600_chrdev_wakeup_by_event_get() > WAKEUP_EVENT_NONE) {
status = wait_event_timeout(bes2600_cdev.wakeup_reason_wq,
bes2600_chrdev_wakeup_by_event_get() == WAKEUP_EVENT_NONE, HZ * 2);
WARN_ON(status <= 0);
}
len = sprintf(buf, "wakeup_reason: %u, src_port: %u\n",
bes2600_cdev.wakeup_state, bes2600_cdev.src_port);
break;
default:
len = sprintf(buf, "dpd_calied:%d wifi_opened:%d bt_opened:%d fw_type:%d\n",
bes2600_cdev.dpd_calied,
bes2600_cdev.wifi_opened,
bes2600_cdev.bt_opened,
bes2600_cdev.fw_type);
break;
}
len = sizeof(buf);
/* reset read flag */
spin_lock(&bes2600_cdev.status_lock);
bes2600_cdev.read_flag = BES_CDEV_READ_NUM_MAX;
spin_unlock(&bes2600_cdev.status_lock);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static ssize_t bes2600_chrdev_write(struct file *file,
const char __user *user_buf, size_t count, loff_t *ppos)
{
int i = 0;
int cmd_num = ARRAY_SIZE(bes2600_op_map_tab);
int cmd_len = 0;
int ret = 0;
char *info[2] = {0};
char *buf = NULL;
/* copy content from user space to kernel */
/* message format:"ifname:wlanx cmd:xxx arg1 arg2 ..." */
buf = kmalloc(count + 1, GFP_KERNEL);
if (copy_from_user(buf, user_buf, count))
return -EFAULT;
/* add terminal character */
buf[count] = '\0';
/* extract comand and interface */
if (bes2600_get_cmd_and_ifname(buf, info) != 0) {
bes_err("%s get command fail, the origin string is %s\n", __func__, buf);
kfree(buf);
return -EINVAL;
}
/* match operation item and execure its handler */
cmd_len = strlen(info[1]);
for (i = 0; i < cmd_num; i++) {
if (cmd_len < bes2600_op_map_tab[i].op_len)
continue;
if (strncasecmp(info[1], bes2600_op_map_tab[i].op, bes2600_op_map_tab[i].op_len) == 0) {
ret = bes2600_op_map_tab[i].handler(buf);
break;
}
}
/* operation item mismatch */
if (i == cmd_num) {
bes_err("cmd(%s) mismatch\n", info[1]);
}
bes2600_recyle_cmd_and_ifname_mem(info);
kfree(buf);
return (ret == 0) ? count : ret;
}
static int bes2600_chrdev_release (struct inode *inode, struct file *file)
{
if (atomic_dec_and_test(&bes2600_cdev.num_proc)) {
wake_up(&bes2600_cdev.open_wq);
}
bes_devel("bes2600 char device is closed\n");
return 0;
}
static struct file_operations bes2600_chardev_fops =
{
.owner = THIS_MODULE,
.open = bes2600_chrdev_open,
.read = bes2600_chrdev_read,
.write = bes2600_chrdev_write,
.release = bes2600_chrdev_release,
};
#ifdef BES2600_WRITE_DPD_TO_FILE
static int bes2600_chrdev_write_dpd_data_to_file(const char *path, void *buffer, int size)
{
int ret = 0;
struct file *fp;
if (buffer == NULL || size == 0)
return 0;
fp = filp_open(path, O_TRUNC | O_CREAT | O_RDWR, S_IRUSR);
if (IS_ERR(fp)) {
bes_err("BES2600 : can't open %s\n",path);
return -1;
}
ret = kernel_write(fp, buffer, size, &fp->f_pos);
if (ret < 0)
bes_err("write dpd to file failed\n");
filp_close(fp,NULL);
bes_devel("write dpd to %s\n", path);
return ret;
}
static bool bes2600_chrdev_dpd_is_vaild(u8 *dpd_data)
{
u32 cal_crc = 0;
u32 dpd_crc = le32_to_cpup((__le32 *)(dpd_data));
u32 dpd_ver = le32_to_cpup((__le32 *)(dpd_data + DPD_VERSION_OFFSET));
/* check version */
if (dpd_ver < DPD_CUR_VERSION)
return false;
cal_crc ^= 0xffffffffL;
cal_crc = crc32_le(cal_crc, dpd_data + 4, DPD_BIN_SIZE - 4);
cal_crc ^= 0xffffffffL;
/* check if the dpd data is valid */
if (cal_crc != dpd_crc) {
bes_err(
"bes2600 dpd data from file check failed, calc_crc:0x%08x dpd_crc: 0x%08x\n",
cal_crc, dpd_crc);
return false;
}
return true;
}
static int bes2600_chrdev_read_and_check_dpd_data(const char *file, u8 **data, u32 *len)
{
int ret = 0;
u8* read_data = NULL;
struct file *fp;
/* open file */
fp = filp_open(file, O_RDONLY, 0);//S_IRUSR
if (IS_ERR(fp)) {
bes_devel("BES2600 : can't open %s\n",file);
return -1;
}
#ifdef BES2600_WRITE_DPD_TO_FILE
if (fp->f_inode->i_size != DPD_BIN_FILE_SIZE) {
bes_err(
"bes2600 dpd data file size check failed, read_size: %lld file_size: %d\n",
fp->f_inode->i_size, DPD_BIN_FILE_SIZE);
filp_close(fp, NULL);
return -1;
}
#endif
/* allocate memory for storing reading data */
read_data = kmalloc(fp->f_inode->i_size, GFP_KERNEL);
if (read_data == NULL) {
bes_devel("%s alloc mem fail\n", __func__);
goto err1;
}
/* read data from file */
ret = kernel_read(fp, read_data, fp->f_inode->i_size, &fp->f_pos);
if (ret < DPD_BIN_SIZE) {
bes_err("%s read fail, ret=%d\n", __func__, ret);
goto err2;
}
/* check dpd version and crc */
if (!bes2600_chrdev_dpd_is_vaild(read_data))
goto err2;
/* close file */
filp_close(fp, NULL);
/* copy data to external */
*data = read_data;
*len = DPD_BIN_SIZE;;
/* output debug information */
bes_devel("read dpd data from %s\n", file);
return 0;
err2:
kfree(read_data);
err1:
filp_close(fp, NULL);
*data = NULL;
*len = 0;
return -1;
}
#endif
const u8* bes2600_chrdev_get_dpd_data(u32 *len) const u8* bes2600_chrdev_get_dpd_data(u32 *len)
{ {
#ifdef BES2600_WRITE_DPD_TO_FILE
if (!bes2600_cdev.dpd_calied && bes2600_cdev.no_dpd) {
/* read dpd data from file that stores factory dpd calibration data */
if ((bes2600_chrdev_read_and_check_dpd_data(BES2600_DPD_GOLDEN_PATH,
&bes2600_cdev.dpd_data, &bes2600_cdev.dpd_len) < 0) &&
(bes2600_chrdev_read_and_check_dpd_data(BES2600_DEFAULT_DPD_PATH,
&bes2600_cdev.dpd_data, &bes2600_cdev.dpd_len) < 0)) {
bes_err("%s read dpd data fail\n", __func__);
return NULL;
} else {
bes2600_cdev.dpd_calied = true;
}
}
#endif
if (!bes2600_cdev.dpd_calied) if (!bes2600_cdev.dpd_calied)
return NULL; return NULL;
if (len) if (len)
@@ -325,6 +912,14 @@ int bes2600_chrdev_update_dpd_data(void)
} }
spin_unlock(&bes2600_cdev.status_lock); spin_unlock(&bes2600_cdev.status_lock);
#ifdef BES2600_WRITE_DPD_TO_FILE
/* write dpd data to file */
memset(bes2600_cdev.dpd_data + DPD_BIN_SIZE, 0, DPD_BIN_FILE_SIZE - DPD_BIN_SIZE);
bes2600_chrdev_write_dpd_data_to_file(BES2600_DPD_PATH,
bes2600_cdev.dpd_data, DPD_BIN_FILE_SIZE);
#endif
return 0; return 0;
} }
@@ -529,6 +1124,12 @@ void bes2600_chrdev_update_signal_mode(void)
static void bes2600_chrdev_wifi_force_close_work(struct work_struct *work) static void bes2600_chrdev_wifi_force_close_work(struct work_struct *work)
{ {
char wifi_state[15];
char bt_state[15];
char fw_type[15];
char *env[] = { wifi_state, bt_state, fw_type, NULL };
int ret;
if (bes2600_chrdev_is_wifi_opened()) { if (bes2600_chrdev_is_wifi_opened()) {
bes_devel("system exeception, force wifi down\n"); bes_devel("system exeception, force wifi down\n");
@@ -545,6 +1146,14 @@ static void bes2600_chrdev_wifi_force_close_work(struct work_struct *work)
bes2600_chrdev_do_system_close(bes2600_cdev.sbus_ops, bes2600_chrdev_do_system_close(bes2600_cdev.sbus_ops,
bes2600_cdev.sbus_priv); bes2600_cdev.sbus_priv);
} }
/* notify userspace */
snprintf(wifi_state, sizeof(wifi_state), "WIFI_OPENED=%d", bes2600_cdev.wifi_opened);
snprintf(bt_state, sizeof(bt_state), "BT_OPENED=%d", bes2600_cdev.bt_opened);
snprintf(fw_type, sizeof(fw_type), "FW_TYPE=%d", bes2600_cdev.fw_type);
ret = kobject_uevent_env(&bes2600_cdev.device->kobj, KOBJ_CHANGE, env);
if (!ret)
bes_err("bes2600 notify userspace failed\n");
} }
} }
@@ -638,6 +1247,46 @@ int bes2600_chrdev_wakeup_by_event_get(void)
int bes2600_chrdev_init(struct sbus_ops *ops) int bes2600_chrdev_init(struct sbus_ops *ops)
{ {
int ret = 0;
/* allocate devide id */
ret = alloc_chrdev_region(&bes2600_cdev.dev_id, 0, 1, "bes2600_chrdev");
if (ret < 0){
bes_err("bes2600 alloc device id fail\n");
ret = -EFAULT;
goto fail;
}
/* extract major and minor device id */
bes2600_cdev.major = MAJOR(bes2600_cdev.dev_id);
bes2600_cdev.minor = MINOR(bes2600_cdev.dev_id);
/* add char device and bind operation function */
bes2600_cdev.cdev.owner = THIS_MODULE;
cdev_init(&bes2600_cdev.cdev, &bes2600_chardev_fops);
ret = cdev_add(&bes2600_cdev.cdev, bes2600_cdev.dev_id, 1);
if (ret < 0){
bes_err("bes2600 char device add fail\n");
ret = -EFAULT;
goto fail1;
}
/* create class for creating device node */
bes2600_cdev.class = class_create("bes2600_chrdev");
if (IS_ERR(bes2600_cdev.class)){
bes_err("bes2600 char device add fail\n");
ret = -EFAULT;
goto fail2;
}
/* get char device pointer */
bes2600_cdev.device = device_create(bes2600_cdev.class, NULL, bes2600_cdev.dev_id, NULL, "bes2600");
if (IS_ERR(bes2600_cdev.device)){
bes_err("bes2600 char device create fail\n");
ret = -EFAULT;
goto fail3;
}
/* initialise global variable */ /* initialise global variable */
atomic_set(&bes2600_cdev.num_proc, 0); atomic_set(&bes2600_cdev.num_proc, 0);
init_waitqueue_head(&bes2600_cdev.open_wq); init_waitqueue_head(&bes2600_cdev.open_wq);
@@ -669,6 +1318,15 @@ int bes2600_chrdev_init(struct sbus_ops *ops)
bes_devel("%s done\n", __func__); bes_devel("%s done\n", __func__);
return 0; return 0;
fail3:
class_destroy(bes2600_cdev.class);
fail2:
cdev_del(&bes2600_cdev.cdev);
fail1:
unregister_chrdev_region(bes2600_cdev.dev_id, 1);
fail:
return ret;
} }
void bes2600_chrdev_free(void) void bes2600_chrdev_free(void)
@@ -678,5 +1336,9 @@ void bes2600_chrdev_free(void)
bes2600_free_dpd_log_buffer(); bes2600_free_dpd_log_buffer();
#endif #endif
bes2600_chrdev_free_dpd_data(); bes2600_chrdev_free_dpd_data();
cdev_del(&bes2600_cdev.cdev);
unregister_chrdev_region(bes2600_cdev.dev_id, 1);
device_destroy(bes2600_cdev.class, bes2600_cdev.dev_id);
class_destroy(bes2600_cdev.class);
bes_devel("%s done\n", __func__); bes_devel("%s done\n", __func__);
} }
+34
View File
@@ -125,6 +125,8 @@ int bes_host_slave_sync(struct bes2600_common *hw_priv)
} }
*/ */
//#define DATA_DUMP_OBSERVE
static int bes_firmware_download_write_reg(struct platform_fw_t *fw_data, u32 addr, u32 val) static int bes_firmware_download_write_reg(struct platform_fw_t *fw_data, u32 addr, u32 val)
{ {
u8 frame_num = 0; u8 frame_num = 0;
@@ -466,6 +468,14 @@ static int bes_firmware_download(struct platform_fw_t *fw_data, const char *fw_n
const struct firmware *fw_bin; const struct firmware *fw_bin;
#ifdef DATA_DUMP_OBSERVE
char *observe;
size_t observe_len;
loff_t observe_off = 0;
mm_segment_t old_fs;
struct file *observe_file = NULL;
#endif
struct fw_msg_hdr_t header; struct fw_msg_hdr_t header;
struct fw_info_t fw_info; struct fw_info_t fw_info;
struct download_fw_t download_addr; struct download_fw_t download_addr;
@@ -573,6 +583,14 @@ retry:
} }
download_addr.addr = fw_info.addr; download_addr.addr = fw_info.addr;
#ifdef DATA_DUMP_OBSERVE
observe_file = filp_open("/lib/firmware/bes2002_fw_write.bin", O_CREAT | O_RDWR, 0);
if (IS_ERR(observe_file)) {
bes_err("create data_dump file err:%ld\n", IS_ERR(observe_file));
observe_file = NULL;
}
#endif
while (code_length) { while (code_length) {
#if 1 #if 1
@@ -622,6 +640,17 @@ retry:
//mdelay(5000); //mdelay(5000);
bes_devel("tx_download_firmware_data:%x %d\n", download_addr.addr, length); bes_devel("tx_download_firmware_data:%x %d\n", download_addr.addr, length);
#ifdef DATA_DUMP_OBSERVE
if (observe_file) {
observe = (char *)(long_buf + sizeof(struct fw_msg_hdr_t) + sizeof(struct download_fw_t));
observe_len = length - sizeof(struct fw_msg_hdr_t) - sizeof(struct download_fw_t);
old_fs = get_fs();
set_fs(KERNEL_DS);
vfs_write(observe_file, observe, observe_len, &observe_off);
set_fs(old_fs);
}
#endif
ret = bes2600_data_write(long_buf, length > 512 ? length : 512); ret = bes2600_data_write(long_buf, length > 512 ? length : 512);
if (ret) { if (ret) {
bes_err("tx download fw data err:%d\n", ret); bes_err("tx download fw data err:%d\n", ret);
@@ -803,6 +832,11 @@ retry:
err2: err2:
kfree(long_buf); kfree(long_buf);
#ifdef DATA_DUMP_OBSERVE
if (observe_file) {
filp_close(observe_file, NULL);
}
#endif
err1: err1:
kfree(short_buf); kfree(short_buf);
release_firmware(fw_bin); release_firmware(fw_bin);
-23
View File
@@ -8,26 +8,3 @@ extern struct device *global_dev;
#define bes_info(fmt, ...) dev_info(global_dev, fmt, ##__VA_ARGS__) #define bes_info(fmt, ...) dev_info(global_dev, fmt, ##__VA_ARGS__)
#define bes_warn(fmt, ...) dev_warn(global_dev, fmt, ##__VA_ARGS__) #define bes_warn(fmt, ...) dev_warn(global_dev, fmt, ##__VA_ARGS__)
#define bes_err(fmt, ...) dev_err(global_dev, fmt, ##__VA_ARGS__) #define bes_err(fmt, ...) dev_err(global_dev, fmt, ##__VA_ARGS__)
/*
* Legacy debug-subsystem-tagged log macros. The per-subsystem filtering
* was never implemented in-tree; these shims let code paths gated by
* CONFIG_BES2600_TESTMODE / CONFIG_BES2600_ITP / BES2600_DETECTION_LOGIC
* build when their conditions are enabled. The first argument is
* currently unused; pick one of the BES2600_DBG_* constants below for
* documentation.
*/
#define BES2600_DBG_SBUS 0
#define BES2600_DBG_DOWNLOAD 0
#define BES2600_DBG_ITP 0
#define BES2600_DBG_TEST_MODE 0
#define bes2600_info(_dbg, fmt, ...) bes_info(fmt, ##__VA_ARGS__)
#define bes2600_err(_dbg, fmt, ...) bes_err(fmt, ##__VA_ARGS__)
#define bes2600_warn(_dbg, fmt, ...) bes_warn(fmt, ##__VA_ARGS__)
#define bes2600_dbg(_dbg, fmt, ...) bes_devel(fmt, ##__VA_ARGS__)
#define bes2600_err_with_cond(_cond, _dbg, fmt, ...) \
do { \
if (_cond) \
bes_err(fmt, ##__VA_ARGS__); \
} while (0)
+4 -18
View File
@@ -472,7 +472,6 @@ static int bes2600_pwr_enter_lp_mode(struct bes2600_common *hw_priv)
int i = 0; int i = 0;
struct bes2600_vif *priv; struct bes2600_vif *priv;
int ret = 0; int ret = 0;
int timeouts = 0;
char ip_str[20]; char ip_str[20];
unsigned long status = 0; unsigned long status = 0;
@@ -529,35 +528,22 @@ static int bes2600_pwr_enter_lp_mode(struct bes2600_common *hw_priv)
if (ret) { if (ret) {
atomic_set(&hw_priv->bes_power.pm_set_in_process, 0); atomic_set(&hw_priv->bes_power.pm_set_in_process, 0);
bes_err("%s, set operation mode fail\n", __func__); bes_err("%s, set operation mode fail\n", __func__);
timeouts++;
continue;
} }
/* wait power save mode changed indication */ /* wait power save mode changed indication */
status = wait_for_completion_timeout(&hw_priv->bes_power.pm_enter_cmpl, 5 * HZ); status = wait_for_completion_timeout(&hw_priv->bes_power.pm_enter_cmpl, 5 * HZ);
atomic_set(&hw_priv->bes_power.pm_set_in_process, 0); atomic_set(&hw_priv->bes_power.pm_set_in_process, 0);
reinit_completion(&hw_priv->bes_power.pm_enter_cmpl); reinit_completion(&hw_priv->bes_power.pm_enter_cmpl);
if (!status) { if (!status)
bes_devel("%s, wait pm ind timeout\n", __func__); bes_err("%s, wait pm ind timeout\n", __func__);
timeouts++;
}
} else { } else {
bes_devel("skip enter lp mode\n"); bes_devel("skip enter lp mode\n");
} }
} }
} }
/* /* set device low power configuration */
* Enter the device-end of the LP transition only if every per-VIF bes2600_pwr_device_enter_lp_mode(hw_priv);
* mac80211 handshake reached firmware-ACKed completion. Doing the
* device-LP setup while any VIF is still pending leaves the driver
* in an inconsistent state that cascades into SDIO TX errors on
* the BES2600.
*/
if (timeouts == 0)
bes2600_pwr_device_enter_lp_mode(hw_priv);
else
ret = -ETIMEDOUT;
return ret; return ret;
} }
+35
View File
@@ -790,6 +790,41 @@ void bes2600_core_release(struct bes2600_common *self)
return; return;
} }
#if (GET_MAC_ADDR_METHOD == 2) || (GET_MAC_ADDR_METHOD == 3) /* To use macaddr and ps mode of customers */
int access_file(char *path, char *buffer, int size, int isRead)
{
int ret=0;
struct file *fp;
mm_segment_t old_fs = get_fs();
if(isRead)
fp = filp_open(path,O_RDONLY,S_IRUSR);
else
fp = filp_open(path,O_CREAT|O_WRONLY,S_IRUSR);
if (IS_ERR(fp)) {
bes_err("BES2600 : can't open %s\n", path);
return -1;
}
if (isRead) {
fp->f_pos = 0;
set_fs(KERNEL_DS);
ret = vfs_read(fp,buffer,size,&fp->f_pos);
set_fs(old_fs);
} else {
fp->f_pos = 0;
set_fs(KERNEL_DS);
ret = vfs_write(fp,buffer,size,&fp->f_pos);
set_fs(old_fs);
}
filp_close(fp,NULL);
bes_info("BES2600 : access_file return code(%d)\n", ret);
return ret;
}
#endif
int bes2600_wifi_start(struct bes2600_common *hw_priv) int bes2600_wifi_start(struct bes2600_common *hw_priv)
{ {
int ret = 0, if_id; int ret = 0, if_id;
+3 -3
View File
@@ -3633,7 +3633,7 @@ static int bes2600_set_power_save(struct ieee80211_hw *hw,
* *
* Returns: 0 on success or non zero value on failure * Returns: 0 on success or non zero value on failure
*/ */
static int bes2600_start_stop_tsm(struct ieee80211_hw *hw, void *data) int bes2600_start_stop_tsm(struct ieee80211_hw *hw, void *data)
{ {
struct bes_msg_start_stop_tsm *start_stop_tsm = struct bes_msg_start_stop_tsm *start_stop_tsm =
(struct bes_msg_start_stop_tsm *) data; (struct bes_msg_start_stop_tsm *) data;
@@ -3663,7 +3663,7 @@ static int bes2600_start_stop_tsm(struct ieee80211_hw *hw, void *data)
* *
* Returns: TSM parameters collected * Returns: TSM parameters collected
*/ */
static int bes2600_get_tsm_params(struct ieee80211_hw *hw) int bes2600_get_tsm_params(struct ieee80211_hw *hw)
{ {
struct bes2600_common *hw_priv = hw->priv; struct bes2600_common *hw_priv = hw->priv;
struct bes_tsm_stats tsm_stats; struct bes_tsm_stats tsm_stats;
@@ -3703,7 +3703,7 @@ static int bes2600_get_tsm_params(struct ieee80211_hw *hw)
* *
* Returns: Returns the last measured roam delay * Returns: Returns the last measured roam delay
*/ */
static int bes2600_get_roam_delay(struct ieee80211_hw *hw) int bes2600_get_roam_delay(struct ieee80211_hw *hw)
{ {
struct bes2600_common *hw_priv = hw->priv; struct bes2600_common *hw_priv = hw->priv;
u16 roam_delay = hw_priv->tsm_info.roam_delay / 1000; u16 roam_delay = hw_priv->tsm_info.roam_delay / 1000;
+2 -1
View File
@@ -18,7 +18,8 @@ License: LGPL-2.1
License for more details. License for more details.
. .
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this library; if not, see <https://www.gnu.org/licenses/>. along with this library; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
. .
On Debian systems, the full text of the GNU Lesser General Public License On Debian systems, the full text of the GNU Lesser General Public License
version 2.1 can be found in the file "/usr/share/common-licenses/LGPL-2.1". version 2.1 can be found in the file "/usr/share/common-licenses/LGPL-2.1".