luckfox-pico-sdk/sysdrv/drv_ko/wifi/atbm/hal_apollo/internal_cmd.c
luckfox-eng29 8f34c2760d project:build.sh: Added fastboot support; custom modifications to U-Boot and kernel implemented using patches.
project:cfg:BoardConfig_IPC: Added fastboot BoardConfig file and firmware post-scripts, distinguishing between
the BoardConfigs for Luckfox Pico Pro and Luckfox Pico Max. project:app: Added fastboot_client and rk_smart_door
for quick boot applications; updated rkipc app to adapt to the latest media library. media:samples: Added more
usage examples. media:rockit: Fixed bugs; removed support for retrieving data frames from VPSS. media:isp:
Updated rkaiq library and related tools to support connection to RKISP_Tuner. sysdrv:Makefile: Added support for
compiling drv_ko on Luckfox Pico Ultra W using Ubuntu; added support for custom root filesystem.
sysdrv:tools:board: Updated Buildroot optional mirror sources, updated some software versions, and stored device
tree files and configuration files that undergo multiple modifications for U-Boot and kernel separately.
sysdrv:source:mcu: Used RISC-V MCU SDK with RT-Thread system, mainly for initializing camera AE during quick
boot. sysdrv:source:uboot: Added support for fastboot; added high baud rate DDR bin for serial firmware upgrades.
sysdrv:source:kernel: Upgraded to version 5.10.160; increased NPU frequency for RV1106G3; added support for
fastboot.

Signed-off-by: luckfox-eng29 <eng29@luckfox.com>
2024-10-14 09:47:04 +08:00

2612 lines
69 KiB
C

#include <linux/module.h>
#include <linux/kobject.h>
#include <linux/kthread.h>
#include <linux/dcache.h>
#include <linux/netdevice.h>
#include <linux/rtnetlink.h>
#include "apollo.h"
#include "bh.h"
#include "hwio.h"
#include "wsm.h"
#include "sbus.h"
#include "debug.h"
#include "apollo_plat.h"
#include "sta.h"
#include "ap.h"
#include "scan.h"
#include "internal_cmd.h"
#include "svn_version.h"
static struct atbm_gpio_config atbm_gpio_table[]=
{
{
.gpio = 4,
.flags = 0,
.fun_ctrl = {.base_addr = 0x1740000C,.start_bit = 0,.width = 4,.val = 0,},
.pup_ctrl = {.base_addr = 0x1740000C,.start_bit = 11,.width = 1,.val = 0,},
.pdu_ctrl = {.base_addr = 0x1740000C,.start_bit = 12,.width = 1,.val = 0,},
.dir_ctrl = {.base_addr = 0x16800028,.start_bit = 4,.width = 1,.val = 0,},
.out_val = {.base_addr = 0x16800024,.start_bit = 4,.width = 1,.val = 0,},
.out_val = {.base_addr = 0x16800020,.start_bit = 4,.width = 1,.val = 0,},
},
{
.gpio = 20,
.flags = 0,
.fun_ctrl = {.base_addr = 0x1740002C,.start_bit = 0,.width = 4,.val = 0,},
.pup_ctrl = {.base_addr = 0x1740002C,.start_bit = 11,.width = 1,.val = 0,},
.pdu_ctrl = {.base_addr = 0x1740002C,.start_bit = 12,.width = 1,.val = 0,},
.dir_ctrl = {.base_addr = 0x16800028,.start_bit = 20,.width = 1,.val = 0,},
.out_val = {.base_addr = 0x16800024,.start_bit = 20,.width = 1,.val = 0,},
.in_val = {.base_addr = 0x16800020,.start_bit = 20,.width = 1,.val = 0,},
},
{
.gpio = 21,
.flags = 0,
.fun_ctrl = {.base_addr = 0x1740002C,.start_bit = 16,.width = 4,.val = 0,},
.pup_ctrl = {.base_addr = 0x1740002C,.start_bit = 27,.width = 1,.val = 0,},
.pdu_ctrl = {.base_addr = 0x1740002C,.start_bit = 28,.width = 1,.val = 0,},
.dir_ctrl = {.base_addr = 0x16800028,.start_bit = 21,.width = 1,.val = 0,},
.out_val = {.base_addr = 0x16800024,.start_bit = 21,.width = 1,.val = 0,},
.in_val = {.base_addr = 0x16800020,.start_bit = 21,.width = 1,.val = 0,},
},
{
.gpio = 22,
.flags = 0,
.fun_ctrl = {.base_addr = 0x17400030,.start_bit = 0,.width = 4,.val = 0,},
.pup_ctrl = {.base_addr = 0x17400030,.start_bit = 11,.width = 1,.val = 0,},
.pdu_ctrl = {.base_addr = 0x17400030,.start_bit = 12,.width = 1,.val = 0,},
.dir_ctrl = {.base_addr = 0x16800028,.start_bit = 22,.width = 1,.val = 0,},
.out_val = {.base_addr = 0x16800024,.start_bit = 22,.width = 1,.val = 0,},
.in_val = {.base_addr = 0x16800020,.start_bit = 22,.width = 1,.val = 0,},
},
{
.gpio = 23,
.flags = 0,
.fun_ctrl = {.base_addr = 0x17400030,.start_bit = 16,.width = 4,.val = 0,},
.pup_ctrl = {.base_addr = 0x17400030,.start_bit = 27,.width = 1,.val = 0,},
.pdu_ctrl = {.base_addr = 0x17400030,.start_bit = 28,.width = 1,.val = 0,},
.dir_ctrl = {.base_addr = 0x16800028,.start_bit = 23,.width = 1,.val = 0,},
.out_val = {.base_addr = 0x16800024,.start_bit = 23,.width = 1,.val = 0,},
.in_val = {.base_addr = 0x16800020,.start_bit = 23,.width = 1,.val = 0,},
},
};
#define DCXO_TRIM_REG 0x1610100c //bit 5:0
#define ATBM_WSM_ADAPTIVE "set_adaptive"ATBM_SPACE_STR
#define ATBM_WSM_TXPWR_DCXO "set_txpwr_and_dcxo"ATBM_SPACE_STR
#define ATBM_WSM_TXPWR "set_txpower"ATBM_SPACE_STR
#define ATBM_WSM_SET_FREQ "set_freq"ATBM_SPACE_STR"%d"ATBM_SPACE_STR"%d"
#define ATBM_WSM_FIX_RATE "lmac_rate"ATBM_SPACE_STR"%d"
#define ATBM_WSM_TOP_RATE "lmac_max_rate"ATBM_SPACE_STR"%d"
#define ATBM_WSM_MIN_RATE "lmac_min_rate"ATBM_SPACE_STR"%d"
#define ATBM_WSM_SET_RATE_POWER "set_spec_rate_txpower_mode"ATBM_SPACE_STR"%d"ATBM_SPACE_STR"%d"
#ifdef CONFIG_ATBM_MONITOR_SPECIAL_MAC
#define ATBM_WSM_MONITOR_MAC "set_sta_monitor"ATBM_SPACE_STR"%d"ATBM_SPACE_STR"%d"ATBM_SPACE_STR"%x,%x,%x,%x,%x,%x"
#endif
#define ATBM_WSM_CMD_LEN 1680
const char *chip_6038 = "6038";
const char *chip_6032 = "6032";
const char *chip_6032i = "6032i";
const char *chip_101B = "101B";
unsigned char char2Hex(const char chart)
{
unsigned char ret = 0;
if((chart>='0')&&(chart<='9')){
ret = chart-'0';
}else if((chart>='a')&&(chart<='f')){
ret = chart - 'a'+0x0a;
}else if((chart>='A')&&(chart<='F')){
ret = chart - 'A'+0x0a;
}
return ret;
}
/*
Func: str2mac
Param:
str->string format of MAC address
i.e. 00:11:22:33:44:55
Return:
error -1
OK 0
*/
int str2mac(char *dst_mac, char *src_str)
{
int i;
if(dst_mac == NULL || src_str == NULL)
return -1;
for(i=0; i<6; i++){
dst_mac[i] = (char2Hex(src_str[i*3]) << 4) + (char2Hex(src_str[i*3 + 1]));
atbm_printk_wext("str2mac: %x\n", dst_mac[i]);
}
return 0;
}
/*
add by yuzhihuang
20220224 xiongmai_question
*/
#if 0
#include <linux/sched.h>
#include <asm/siginfo.h>
#include <linux/pid_namespace.h>
#include <linux/pid.h>
void send_signal(int sig_num,int user_pid)
{
struct task_struct *current_task = NULL;
struct siginfo info;
int ret;
printk("%s,%d.sending signal %d to owner %d\n",__func__, __LINE__, sig_num, user_pid);
memset(&info, 0, sizeof(struct siginfo));
info.si_signo = sig_num;
info.si_code = 0;
info.si_int = 1234;
if (current_task == NULL){
rcu_read_lock();
current_task = pid_task(find_vpid(user_pid), PIDTYPE_PID);
rcu_read_unlock();
}
ret = send_sig_info(sig_num, &info, current_task);
if (ret < 0) {
printk("error sending signal\n");
}
}
#endif
int DCXOCodeWrite(struct atbm_common *hw_priv,u8 data)
{
#ifndef SPI_BUS
u32 uiRegData;
atbm_direct_read_reg_32(hw_priv, DCXO_TRIM_REG, &uiRegData);
//hw_priv->sbus_ops->sbus_read_sync(hw_priv->sbus_priv,DCXO_TRIM_REG,&uiRegData,4);
uiRegData &= ~0x40003F;
uiRegData |= (((data&0x40)<<16)|(data&0x3f));
atbm_direct_write_reg_32(hw_priv, DCXO_TRIM_REG, uiRegData);
//hw_priv->sbus_ops->sbus_write_sync(hw_priv->sbus_priv,DCXO_TRIM_REG,&uiRegData,4);
#endif
return 0;
}
u8 DCXOCodeRead(struct atbm_common *hw_priv)
{
#ifndef SPI_BUS
u32 uiRegData;
u8 dcxo;
u8 dcxo_hi,dcxo_low;
atbm_direct_read_reg_32(hw_priv, DCXO_TRIM_REG, &uiRegData);
//hw_priv->sbus_ops->sbus_read_sync(hw_priv->sbus_priv,DCXO_TRIM_REG,&uiRegData,4);//
dcxo_hi = (uiRegData>>22)&0x01;
dcxo_low = uiRegData&0x3f;
dcxo = (dcxo_hi << 6) + (dcxo_low&0x3f);
return dcxo;
#else
return 0;
#endif
}
extern int atbm_direct_read_reg_32(struct atbm_common *hw_priv, u32 addr, u32 *val);
extern int atbm_direct_write_reg_32(struct atbm_common *hw_priv, u32 addr, u32 val);
extern struct etf_test_config etf_config;
//get chip crystal type
u32 GetChipCrystalType(struct atbm_common *hw_priv)
{
#ifndef SPI_BUS
u32 pin_reg;
u32 pin_reg17400000;
atbm_direct_read_reg_32(hw_priv, 0x17400000, &pin_reg17400000);
atbm_direct_write_reg_32(hw_priv, 0x17400000, pin_reg17400000 | BIT(8));
atbm_direct_read_reg_32(hw_priv, 0x17400000, &pin_reg17400000);
if (pin_reg17400000 & BIT(17))
{
etf_config.chip_crystal_type = 1;
}
atbm_direct_read_reg_32(hw_priv, 0x16101010, &pin_reg);
if (pin_reg & BIT(5))
{
etf_config.chip_crystal_type |= BIT(1);
}
if (pin_reg & BIT(27))
{
etf_config.chip_crystal_type |= BIT(2);
}
atbm_direct_write_reg_32(hw_priv, 0x17400000, pin_reg17400000);
atbm_printk_always("crystal:%d\n",etf_config.chip_crystal_type);
return pin_reg17400000;
#else
return 0;
#endif
}
int ieee80211_set_channel(struct wiphy *wiphy,
struct net_device *netdev,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type);
static void atbm_internal_cmd_scan_dump(struct ieee80211_internal_scan_request *scan_req)
{
int i;
if(scan_req->n_ssids){
for(i = 0;i<scan_req->n_ssids;i++){
atbm_printk_debug("%s: ssid[%s][%d]\n",__func__,scan_req->ssids[i].ssid,scan_req->ssids[i].ssid_len);
}
}
if(scan_req->n_channels){
for(i = 0;i<scan_req->n_channels;i++){
atbm_printk_debug("%s: channel[%d]\n",__func__,scan_req->channels[i]);
}
}
if(scan_req->n_macs){
for(i = 0;i<scan_req->n_macs;i++){
atbm_printk_debug("%s: mac[%pM]\n",__func__,scan_req->macs[i].mac);
}
}
atbm_printk_debug("%s: ie_len[%d]\n",__func__,scan_req->ie_len);
}
bool atbm_internal_cmd_scan_build(struct ieee80211_local *local,struct ieee80211_internal_scan_request *req,
u8* channels,int n_channels,struct cfg80211_ssid *ssids,int n_ssids,
struct ieee80211_internal_mac *macs,int n_macs)
{
u8* local_scan_ie;
u8* scan_ie;
int ie_len;
/*
*use default internal handle
*/
req->result_handle = NULL;
req->priv = NULL;
req->channels = channels;
req->n_channels = n_channels;
req->ssids = ssids;
req->n_ssids = n_ssids;
req->macs = macs;
req->n_macs = n_macs;
req->no_cck = true;
rcu_read_lock();
local_scan_ie = rcu_dereference(local->internal_scan_ie);
ie_len = local->internal_scan_ie_len;
if(local_scan_ie && ie_len){
scan_ie = atbm_kzalloc(ie_len,GFP_ATOMIC);
if(scan_ie == NULL){
rcu_read_unlock();
return false;
}
memcpy(scan_ie,local_scan_ie,ie_len);
req->ies = scan_ie;
req->ie_len = ie_len;
}else {
req->ies = NULL;
req->ie_len = 0;
}
rcu_read_unlock();
return true;
}
bool atbm_internal_cmd_scan_triger(struct ieee80211_sub_if_data *sdata,struct ieee80211_internal_scan_request *req)
{
struct cfg80211_scan_request *scan_req = NULL;
struct ieee80211_local *local = sdata->local;
u8 n_channels = 0;
int i;
struct wiphy *wiphy = local->hw.wiphy;
u8 index;
void *pos;
void *pos_end;
long status = 20*HZ;
ASSERT_RTNL();
ieee80211_scan_cancel(local);
atbm_flush_workqueue(local->workqueue);
mutex_lock(&local->mtx);
if(!ieee80211_sdata_running(sdata)){
atbm_printk_scan("%s:%d\n",__func__,__LINE__);
goto err;
}
if (local->scan_req)
{
atbm_printk_scan("%s:%d\n",__func__,__LINE__);
goto err;
}
#ifdef CONFIG_ATBM_SUPPORT_P2P
if (!list_empty(&local->roc_list))
{
goto err;
}
#endif
if (!list_empty(&local->work_list)) {
atbm_printk_scan("%s(%s):work_list is not empty,pend scan\n",__func__,sdata->name);
goto err;
}
if(atbm_ieee80211_suspend(sdata->local)==true){
atbm_printk_err("ieee80211_scan drop:suspend\n");
goto err;
}
if(req->n_channels == 0){
for (i = 0; i < IEEE80211_NUM_BANDS; i++)
if (wiphy->bands[i])
n_channels += wiphy->bands[i]->n_channels;
}else {
n_channels = req->n_channels;
}
scan_req = atbm_kzalloc(sizeof(*scan_req)
+ sizeof(*scan_req->ssids) * req->n_ssids
+ sizeof(*scan_req->channels) * n_channels
+ req->ie_len + req->n_channels + sizeof(struct ieee80211_internal_mac)*req->n_macs, GFP_KERNEL);
if(scan_req == NULL){
atbm_printk_scan("%s:atbm_kzalloc scan_req err\n",__func__);
goto err;
}
pos = (void *)&scan_req->channels[n_channels];
pos_end = (void*)((u8*)pos+sizeof(*scan_req->ssids) * req->n_ssids+
req->ie_len + req->n_channels + sizeof(struct ieee80211_internal_mac)*req->n_macs);
/*
*set channel
*/
if(req->n_channels){
int freq;
for (i = 0;i<req->n_channels;i++){
if(req->channels[i] <= 14){
freq = 2412+(req->channels[i] - 1)*5;
if(req->channels[i] == 14)
freq = 2484;
}else {
freq = 5000 + (5*req->channels[i]);
}
atbm_printk_debug("%s:channel(%d),freq(%d)\n",__func__,req->channels[i],freq);
scan_req->channels[i] = ieee80211_get_channel(wiphy,freq);
if(scan_req->channels[i] == NULL){
goto err;
}
}
}else {
enum ieee80211_band band;
i = 0;
/* all channels */
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
int j;
if (!wiphy->bands[band])
continue;
for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
scan_req->channels[i] = &wiphy->bands[band]->channels[j];
i++;
}
}
}
scan_req->n_channels = n_channels;
/*
*set ssid
*/
if( req->n_ssids){
scan_req->ssids = (void *)pos;
for(i=0;i<req->n_ssids;i++){
atbm_printk_debug("%s:scan ssid(%s)(%d)\n",__func__,req->ssids[i].ssid,req->ssids[i].ssid_len);
scan_req->ssids[i].ssid_len = req->ssids[i].ssid_len;
memcpy(scan_req->ssids[i].ssid,req->ssids[i].ssid,req->ssids[i].ssid_len);
}
pos = scan_req->ssids+req->n_ssids;
}
scan_req->n_ssids = req->n_ssids;
/*
*set macs
*/
local->internal_scan.req.n_macs = req->n_macs;
if(req->n_macs){
local->internal_scan.req.macs = pos;
memcpy(local->internal_scan.req.macs, req->macs,sizeof(struct ieee80211_internal_mac)*req->n_macs);
pos = local->internal_scan.req.macs + req->n_macs;
}
/*
*set ie
*/
if (req->ie_len) {
scan_req->ie = (void *)pos;
memcpy((void*)scan_req->ie,req->ies,req->ie_len);
scan_req->ie_len = req->ie_len;
pos = (u8*)scan_req->ie+req->ie_len;
}
/*
*set channel
*/
if(req->channels){
local->internal_scan.req.channels = pos;
memcpy(local->internal_scan.req.channels,req->channels,req->n_channels);
pos = local->internal_scan.req.channels+req->n_channels;
}
WARN_ON(pos != pos_end);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
for (i = 0; i < IEEE80211_NUM_BANDS; i++)
if (wiphy->bands[i])
scan_req->rates[i] =
(1 << wiphy->bands[i]->n_bitrates) - 1;
scan_req->no_cck = req->no_cck;
#endif
scan_req->wiphy = wiphy;
local->internal_scan.req.n_channels = req->n_channels;
local->internal_scan.req.ies = (u8*)scan_req->ie;
local->internal_scan.req.ie_len = scan_req->ie_len;
local->internal_scan.req.ssids = scan_req->ssids;
local->internal_scan.req.n_ssids = scan_req->n_ssids;
memcpy(local->internal_scan.req.bssid,req->bssid,6);
local->internal_scan.req.req_flags = req->req_flags;
rcu_assign_pointer(local->internal_scan.req.result_handle,req->result_handle);
rcu_assign_pointer(local->internal_scan.req.priv,req->priv);
atbm_common_hash_list_init(local->internal_scan.mac_hash_list,IEEE80211_INTERNAL_SCAN_HASHENTRIES);
for(index = 0;index<local->internal_scan.req.n_macs;index++){
int hash_index = atbm_hash_index(local->internal_scan.req.macs[index].mac,6,IEEE80211_INTERNAL_SCAN_HASHBITS);
struct hlist_head *hlist = &local->internal_scan.mac_hash_list[hash_index];
hlist_add_head(&local->internal_scan.req.macs[index].hnode,hlist);
}
atbm_internal_cmd_scan_dump(&local->internal_scan.req);
if(ieee80211_internal_scan_triger(sdata,scan_req) == false){
atbm_printk_scan("%s scan triger err\n",__func__);
for(index = 0;index<local->internal_scan.req.n_macs;index++){
hlist_del(&local->internal_scan.req.macs[index].hnode);
}
rcu_assign_pointer(local->internal_scan.req.result_handle,NULL);
rcu_assign_pointer(local->internal_scan.req.priv,NULL);
memset(&local->internal_scan.req,0,sizeof(struct ieee80211_internal_scan_sta));
goto err;
}
if(local->scan_req_wrap.flags & IEEE80211_SCAN_REQ_SPILT){
status = 60*HZ;
}
mutex_unlock(&local->mtx);
status = wait_event_timeout(local->internal_scan_wq,atomic_read(&local->internal_scan_status) != IEEE80211_INTERNAL_SCAN_STATUS__WAIT,status);
if(status == 0){
return false;
}
atbm_printk_debug("%s: status(%ld)\n",__func__,status);
if(atomic_read(&local->internal_scan_status) == IEEE80211_INTERNAL_SCAN_STATUS__ABORT)
return false;
return true;
err:
if(scan_req)
atbm_kfree(scan_req);
mutex_unlock(&local->mtx);
return false;
}
bool atbm_internal_cmd_stainfo(struct ieee80211_local *local,struct ieee80211_internal_sta_req *sta_req)
{
struct ieee80211_internal_sta_info stainfo;
struct sta_info *sta;
u8 index = 0;
struct hlist_head *hhead;
struct hlist_node *node;
struct ieee80211_internal_mac *mac_node;
unsigned int hash_index = 0;
bool (__rcu *sta_handle)(struct ieee80211_internal_sta_info *stainfo,void *priv);
struct hlist_head atbm_sta_mac_hlist[ATBM_COMMON_HASHENTRIES];
memset(&stainfo,0,sizeof(struct ieee80211_internal_sta_info));
WARN_ON(sta_req->sta_handle == NULL);
//BUG_ON((sta_req->n_macs != 0)&&(sta_req->macs == NULL));
if((sta_req->n_macs != 0)&&(sta_req->macs == NULL)){
atbm_printk_err("%s %d ,ERROR !!! (sta_req->n_macs != 0)&&(sta_req->macs == NULL)\n",__func__,__LINE__);
return false;
}
atbm_common_hash_list_init(atbm_sta_mac_hlist,ATBM_COMMON_HASHENTRIES);
for(index = 0;index<sta_req->n_macs;index++){
hash_index = atbm_hash_index(sta_req->macs[index].mac,
6,ATBM_COMMON_HASHBITS);
hhead = &atbm_sta_mac_hlist[hash_index];
hlist_add_head(&sta_req->macs[index].hnode,&atbm_sta_mac_hlist[hash_index]);
}
mutex_lock(&local->sta_mtx);
sta_handle = rcu_dereference(sta_req->sta_handle);
list_for_each_entry_rcu(sta, &local->sta_list, list) {
struct ieee80211_channel_state *chan_state = ieee80211_get_channel_state(local, sta->sdata);
if(sta->sdata->vif.type != sta_req->type){
continue;
}
if(sta->uploaded == false){
continue;
}
if(sta->dead == true){
continue;
}
if(sta_req->n_macs){
u8 sta_needed = false;
hash_index = atbm_hash_index(sta->sta.addr,6,ATBM_COMMON_HASHBITS);
hhead = &atbm_sta_mac_hlist[hash_index];
hlist_for_each(node,hhead){
mac_node = hlist_entry(node,struct ieee80211_internal_mac,hnode);
if (memcmp(mac_node->mac,sta->sta.addr,6) == 0){
sta_needed = true;
break;
}
}
if(sta_needed == false){
continue;
}
}
stainfo.sdata = sta->sdata;
if(sta_req->req_flag&IEEE80211_INTERNAL_STA_FLAGS_CHANNEL){
stainfo.channel = channel_hw_value(chan_state->oper_channel);
stainfo.channel_type = !!(test_sta_flag(sta,WLAN_STA_40M_CH)&&!test_sta_flag(sta,WLAN_STA_40M_CH_SEND_20M));
}
if(sta_req->req_flag&IEEE80211_INTERNAL_STA_FLAGS_SIGNAL){
stainfo.signal = sta->last_signal2;
stainfo.avg_signal = (s8) -atbm_ewma_read(&sta->avg_signal2);
}
if(sta_req->req_flag&IEEE80211_INTERNAL_STA_FLAGS_TXRXBYTE){
stainfo.rx_bytes = sta->rx_bytes;
stainfo.tx_bytes = sta->tx_bytes;
}
if(sta_req->req_flag&IEEE80211_INTERNAL_STA_FLAGS_TOPRATE){
struct atbm_common *hw_priv = (struct atbm_common *)local->hw.priv;
struct atbm_vif *priv = (struct atbm_vif *)sta->sdata->vif.drv_priv;
if(sta->sdata->vif.type == NL80211_IFTYPE_STATION){
wsm_read_mib(hw_priv, WSM_MIB_ID_GET_RATE, &stainfo.top_rate, sizeof(unsigned int), priv->if_id);
}else if(sta->sdata->vif.type == NL80211_IFTYPE_AP){
struct atbm_sta_priv *sta_priv = (struct atbm_sta_priv *)&sta->sta.drv_priv;
u8 sta_id = (u8)sta_priv->link_id;
if(sta_id != 0){
wsm_write_mib(hw_priv, WSM_MIB_ID_GET_RATE, &sta_id, 1,priv->if_id);
wsm_read_mib(hw_priv, WSM_MIB_ID_GET_RATE, &stainfo.top_rate, sizeof(unsigned int), priv->if_id);
}
}
stainfo.top_rate = stainfo.top_rate/2;
}
if(sta_req->req_flag&IEEE80211_INTERNAL_STA_FLAGS_SSID){
rcu_read_lock();
stainfo.ssid_len = 0;
memset(stainfo.ssid,0,IEEE80211_MAX_SSID_LEN);
if(sta->sdata->vif.type == NL80211_IFTYPE_STATION){
struct cfg80211_bss *cbss = sta->sdata->u.mgd.associated;
if(cbss){
const char *ssid = NULL;
ssid = ieee80211_bss_get_ie(cbss, ATBM_WLAN_EID_SSID);
if(ssid){
memcpy(stainfo.ssid, &ssid[2], ssid[1]);
stainfo.ssid_len = ssid[1];
}
}
}else if(sta->sdata->vif.type == NL80211_IFTYPE_AP){
struct ieee80211_bss_conf *bss_conf = &sta->sdata->vif.bss_conf;
stainfo.ssid_len = bss_conf->ssid_len;
if(stainfo.ssid_len)
memcpy(stainfo.ssid,bss_conf->ssid,stainfo.ssid_len);
}else {
WARN_ON(1);
}
rcu_read_unlock();
}
memcpy(stainfo.mac,sta->sta.addr,6);
stainfo.filled = sta_req->req_flag;
if(sta_handle)
sta_handle(&stainfo,sta_req->priv);
memset(&stainfo,0,sizeof(struct ieee80211_internal_sta_info));
}
mutex_unlock(&local->sta_mtx);
return true;
}
bool atbm_internal_cmd_monitor_req(struct ieee80211_sub_if_data *sdata,struct ieee80211_internal_monitor_req *monitor_req)
{
struct ieee80211_local *local = sdata->local;
struct atbm_vif *priv = (struct atbm_vif *)sdata->vif.drv_priv;
bool res = false;
unsigned int freq;
struct ieee80211_sub_if_data *other_sdata;
struct ieee80211_channel *chan;
enum nl80211_iftype old_type = sdata->vif.type;
if(!ieee80211_sdata_running(sdata)){
return false;
}
if(priv->join_status != ATBM_APOLLO_JOIN_STATUS_PASSIVE){
return false;
}
list_for_each_entry(other_sdata, &local->interfaces, list){
if(!ieee80211_sdata_running(other_sdata)){
continue;
}
priv = (struct atbm_vif *)other_sdata->vif.drv_priv;
if(priv->join_status != ATBM_APOLLO_JOIN_STATUS_PASSIVE){
return false;
}
}
if(ieee8011_channel_valid(&local->hw,monitor_req->ch) == false){
return false;
}
switch(monitor_req->chtype){
case NL80211_CHAN_NO_HT:
case NL80211_CHAN_HT20:
case NL80211_CHAN_HT40MINUS:
case NL80211_CHAN_HT40PLUS:
break;
default:
atbm_printk_err("error, %d\n", monitor_req->chtype);
return false;
}
if(monitor_req->ch <= 14){
freq = 2412+(monitor_req->ch - 1)*5;
}else {
freq = 5000 + (5*monitor_req->ch);
}
chan = ieee80211_get_channel(local->hw.wiphy, freq);
if(chan == NULL){
return false;
}
local->internal_monitor.req.ch = monitor_req->ch;
local->internal_monitor.req.chtype = monitor_req->chtype;
rcu_assign_pointer(local->internal_monitor.req.monitor_rx,monitor_req->monitor_rx);
rcu_assign_pointer(local->internal_monitor.req.priv,monitor_req->priv);
atbm_printk_debug("%s:[%s] channel %d\n",__func__,sdata->name,local->internal_monitor.req.ch);
if(ieee80211_if_change_type(sdata, NL80211_IFTYPE_MONITOR)){
res = false;
goto err;
}
if(ieee80211_set_channel(local->hw.wiphy,sdata->dev,chan,monitor_req->chtype)){
goto err;
}
return true;
err:
ieee80211_if_change_type(sdata,old_type);
rcu_assign_pointer(local->internal_monitor.req.monitor_rx,NULL);
rcu_assign_pointer(local->internal_monitor.req.priv,NULL);
local->internal_monitor.req.ch = 0;
return res;
}
bool atbm_internal_cmd_stop_monitor(struct ieee80211_sub_if_data *sdata)
{
if(!ieee80211_sdata_running(sdata)){
return false;
}
if(sdata->vif.type != NL80211_IFTYPE_MONITOR){
return false;
}
ieee80211_if_change_type(sdata,NL80211_IFTYPE_STATION);
rcu_assign_pointer(sdata->local->internal_monitor.req.monitor_rx,NULL);
rcu_assign_pointer(sdata->local->internal_monitor.req.priv,NULL);
synchronize_rcu();
sdata->local->internal_monitor.req.ch = 0;
sdata->local->internal_monitor.req.chtype = 0;
return true;
}
bool atbm_internal_cmd_req_iftype(struct ieee80211_sub_if_data *sdata,struct ieee80211_internal_iftype_req *req)
{
enum nl80211_iftype new_iftype;
enum nl80211_iftype old_iftype = sdata->vif.type;
struct ieee80211_local *local = sdata->local;
bool change_channel = true;
bool change_iftype = true;
ASSERT_RTNL();
atbm_printk_debug("%s:type(%d),channel(%d)\n",__func__,req->if_type,req->channel);
if (sdata->vif.type == NL80211_IFTYPE_STATION && sdata->u.mgd.associated){
goto params_err;
}
if (sdata->vif.type == NL80211_IFTYPE_AP && sdata->u.ap.beacon){
goto params_err;
}
switch(req->if_type){
case IEEE80211_INTERNAL_IFTYPE_REQ__MANAGED:
new_iftype = NL80211_IFTYPE_STATION;
if(new_iftype == sdata->vif.type){
change_iftype = false;
}
change_channel = false;
break;
case IEEE80211_INTERNAL_IFTYPE_REQ__MONITOR:
new_iftype = NL80211_IFTYPE_MONITOR;
if(new_iftype == sdata->vif.type){
change_iftype = false;
}
break;
default:
goto params_err;
}
if(change_iftype == true){
if(ieee80211_if_change_type(sdata, new_iftype)){
goto params_err;
}
}
if(change_channel == true) {
struct ieee80211_channel *chan = ieee8011_chnum_to_channel(&sdata->local->hw,req->channel);
if(chan == NULL){
goto interface_err;
}
if(ieee80211_set_channel(local->hw.wiphy,sdata->dev,chan,NL80211_CHAN_HT20)){
goto interface_err;
}
}
return true;
interface_err:
ieee80211_if_change_type(sdata,old_iftype);
params_err:
return false;
}
bool atbm_internal_wsm_adaptive(struct atbm_common *hw_priv,struct ieee80211_internal_wsm_adaptive *adaptive)
{
char* cmd = NULL;
int len;
bool res = true;
cmd = atbm_kzalloc(ATBM_WSM_CMD_LEN,GFP_KERNEL);
if(cmd == NULL){
res = false;
goto err;
}
len = snprintf(cmd,ATBM_WSM_CMD_LEN,ATBM_WSM_ADAPTIVE"%d",adaptive->enable);
if(len<=0){
res = false;
goto err;
}
if(len+1>ATBM_WSM_CMD_LEN){
res = false;
goto err;
}
atbm_printk_debug("%s:wsm [%s][%d]\n",__func__,cmd,len);
if( wsm_write_mib(hw_priv, WSM_MIB_ID_FW_CMD, cmd, len+1,0) < 0){
res = false;
}
err:
if(cmd)
atbm_kfree(cmd);
return res;
}
bool atbm_internal_wsm_txpwr_dcxo(struct atbm_common *hw_priv,struct ieee80211_internal_wsm_txpwr_dcxo *txpwr_dcxo)
{
int len;
char* cmd = NULL;
bool res = true;
if(txpwr_dcxo->txpwr_L > 32 || txpwr_dcxo->txpwr_L < -32){
atbm_printk_err("error, txpwr_L %d\n", txpwr_dcxo->txpwr_L);
res = false;
goto err;
}
if(txpwr_dcxo->txpwr_M > 32 || txpwr_dcxo->txpwr_M < -32){
atbm_printk_err("error, txpwr_M %d\n", txpwr_dcxo->txpwr_M);
res = false;
goto err;
}
if(txpwr_dcxo->txpwr_H > 32 || txpwr_dcxo->txpwr_H < -32){
atbm_printk_err("error, txpwr_H %d\n", txpwr_dcxo->txpwr_H);
res = false;
goto err;
}
if(txpwr_dcxo->dcxo > 127 || txpwr_dcxo->dcxo < 0){
atbm_printk_err("error, dcxo %d\n", txpwr_dcxo->dcxo);
res = false;
goto err;
}
cmd = atbm_kzalloc(ATBM_WSM_CMD_LEN,GFP_KERNEL);
if(cmd == NULL){
res = false;
goto err;
}
len = snprintf(cmd, ATBM_WSM_CMD_LEN,"set_txpwr_and_dcxo,%d,%d,%d,%d ",
txpwr_dcxo->txpwr_L,txpwr_dcxo->txpwr_M, txpwr_dcxo->txpwr_H, txpwr_dcxo->dcxo);
if(len<=0){
res = false;
goto err;
}
if(len+1>ATBM_WSM_CMD_LEN){
res = false;
goto err;
}
atbm_printk_debug("%s:wsm [%s][%d]\n",__func__,cmd,len);
if(wsm_write_mib(hw_priv, WSM_MIB_ID_FW_CMD, cmd, len+1, 0) < 0){
res = false;
}
err:
if(cmd)
atbm_kfree(cmd);
return res;
}
bool atbm_internal_wsm_txpwr(struct atbm_common *hw_priv,struct ieee80211_internal_wsm_txpwr *txpwr)
{
int len;
char* cmd = NULL;
bool res = true;
/*
*0,3,15,63
*/
if(txpwr->txpwr_indx != 0 &&
txpwr->txpwr_indx != 3 &&
txpwr->txpwr_indx != 15 &&
txpwr->txpwr_indx != 63){
atbm_printk_err("error, txpwr_indx %d\n", txpwr->txpwr_indx);
res = false;
goto err;
}
cmd = atbm_kzalloc(ATBM_WSM_CMD_LEN,GFP_KERNEL);
if(cmd == NULL){
res = false;
goto err;
}
len = snprintf(cmd, ATBM_WSM_CMD_LEN, ATBM_WSM_TXPWR"%d",txpwr->txpwr_indx);
if(len<=0){
res = false;
goto err;
}
if(len+1>ATBM_WSM_CMD_LEN){
res = false;
goto err;
}
atbm_printk_debug("%s:wsm [%s][%d]\n",__func__,cmd,len);
if(wsm_write_mib(hw_priv, WSM_MIB_ID_FW_CMD, cmd, len+1, 0) < 0){
res = false;
}
err:
if(cmd)
atbm_kfree(cmd);
return res;
}
bool atbm_internal_wsm_set_rate(struct atbm_common *hw_priv,struct ieee80211_internal_rate_req *req)
{
int len;
char* cmd = NULL;
bool res = true;
cmd = atbm_kzalloc(ATBM_WSM_CMD_LEN,GFP_KERNEL);
if(cmd == NULL){
res = false;
goto err;
}
if(req->flags & IEEE80211_INTERNAL_RATE_FLAGS_CLEAR_TX_RATE){
len = snprintf(cmd, ATBM_WSM_CMD_LEN, ATBM_WSM_FIX_RATE,0);
if(len<=0){
res = false;
goto err;
}
if(wsm_write_mib(hw_priv, WSM_MIB_ID_FW_CMD, cmd, len+1, 0) < 0){
res = false;
goto err;
}
memset(cmd,0,ATBM_WSM_CMD_LEN);
}
if(req->flags & IEEE80211_INTERNAL_RATE_FLAGS_CLEAE_TOP_RATE){
len = snprintf(cmd, ATBM_WSM_CMD_LEN, ATBM_WSM_TOP_RATE,0);
if(len<=0){
res = false;
goto err;
}
if(wsm_write_mib(hw_priv, WSM_MIB_ID_FW_CMD, cmd, len+1, 0) < 0){
res = false;
goto err;
}
memset(cmd,0,ATBM_WSM_CMD_LEN);
}
if(req->flags & IEEE80211_INTERNAL_RATE_FLAGS_CLEAR_MIN_RATE){
len = snprintf(cmd, ATBM_WSM_CMD_LEN, ATBM_WSM_MIN_RATE,0);
if(len<=0){
res = false;
goto err;
}
if(wsm_write_mib(hw_priv, WSM_MIB_ID_FW_CMD, cmd, len+1, 0) < 0){
res = false;
goto err;
}
memset(cmd,0,ATBM_WSM_CMD_LEN);
}
if(req->flags & IEEE80211_INTERNAL_RATE_FLAGS_SET_TX_RATE){
len = snprintf(cmd, ATBM_WSM_CMD_LEN, ATBM_WSM_FIX_RATE,req->rate);
if(len<=0){
res = false;
goto err;
}
if(wsm_write_mib(hw_priv, WSM_MIB_ID_FW_CMD, cmd, len+1, 0) < 0){
res = false;
goto err;
}
memset(cmd,0,ATBM_WSM_CMD_LEN);
}
if(req->flags & IEEE80211_INTERNAL_RATE_FLAGS_SET_TOP_RATE){
len = snprintf(cmd, ATBM_WSM_CMD_LEN, ATBM_WSM_TOP_RATE,req->rate);
if(len<=0){
res = false;
goto err;
}
if(wsm_write_mib(hw_priv, WSM_MIB_ID_FW_CMD, cmd, len+1, 0) < 0){
res = false;
goto err;
}
memset(cmd,0,ATBM_WSM_CMD_LEN);
}
if(req->flags & IEEE80211_INTERNAL_RATE_FLAGS_SET_MIN_RATE){
len = snprintf(cmd, ATBM_WSM_CMD_LEN, ATBM_WSM_MIN_RATE,req->rate);
if(len<=0){
res = false;
goto err;
}
if(wsm_write_mib(hw_priv, WSM_MIB_ID_FW_CMD, cmd, len+1, 0) < 0){
res = false;
goto err;
}
memset(cmd,0,ATBM_WSM_CMD_LEN);
}
err:
if(cmd)
atbm_kfree(cmd);
return res;
}
bool atbm_internal_wsm_set_rate_power(struct atbm_common *hw_priv,
struct ieee80211_internal_rate_power_req *req)
{
#define MIN_RATE_INDEX (0)
#define MAX_RATE_INDEX (10)
#define MIN_POWER (-16)
#define MAX_POWER (16)
bool ret = true;
char* cmd = NULL;
int len = 0;
if((req->rate_index < MIN_RATE_INDEX) ||(req->rate_index > MAX_RATE_INDEX)){
ret = false;
goto exit;
}
if((req->power < MIN_POWER) ||(req->power > MAX_POWER)){
ret = false;
goto exit;
}
cmd = atbm_kzalloc(ATBM_WSM_CMD_LEN,GFP_KERNEL);
if(cmd == NULL){
ret = false;
goto exit;
}
len = snprintf(cmd, ATBM_WSM_CMD_LEN, ATBM_WSM_SET_RATE_POWER,req->rate_index,req->power);
if(len <= 0){
ret = false;
goto exit;
}
if(wsm_write_mib(hw_priv, WSM_MIB_ID_FW_CMD, cmd, len+1, 0) < 0){
ret = false;
goto exit;
}
exit:
if(cmd)
atbm_kfree(cmd);
return ret;
#undef MIN_RATE_INDEX
#undef MAX_RATE_INDEX
#undef MIN_POWER
#undef MAX_POWER
}
static char spec_oui_buf[256];
static char *spec_oui = "NULL";
module_param(spec_oui,charp,0644);
MODULE_PARM_DESC(spec_oui,"special oui");
void atbm_set_special_oui(struct atbm_common *hw_priv, char *pdata, int len)
{
memset(spec_oui_buf, 0, 256);
memcpy(spec_oui_buf, pdata, len);
spec_oui = spec_oui_buf;
}
static int wifi_tx_pw = 0;
static char wifi_txpw_buf[64]={0};
static char *wifi_txpw = "NULL";
module_param(wifi_txpw,charp,0644);
MODULE_PARM_DESC(wifi_txpw,"wifi tx power");
int atbm_get_tx_power(void)
{
return wifi_tx_pw;
}
void atbm_set_tx_power(struct atbm_common *hw_priv, int txpw)
{
char *p20, *p40, *pHT;
wifi_tx_pw = txpw;
if(wifi_tx_pw & BIT(0))
p20 = "20M-High ";
else
p20 = "20M-Normal ";
if(wifi_tx_pw & BIT(1))
p40 = "40M-High ";
else
p40 = "40M-Normal ";
if((hw_priv->channel_type == NL80211_CHAN_HT20)||(hw_priv->channel_type == NL80211_CHAN_NO_HT))
pHT = "20M-Mode";
else
pHT = "40M-Mode";
memset(wifi_txpw_buf, 0, sizeof(wifi_txpw_buf));
sprintf(wifi_txpw_buf, "%s, %s, %s", p20, p40, pHT);
wifi_txpw = wifi_txpw_buf;
return;
}
#define ATBM_SPECIAL_FREQ_MAX_LEN 128
static char wifi_freq_buf[ATBM_SPECIAL_FREQ_MAX_LEN]={0};
static char *wifi_freq = "NULL";
module_param(wifi_freq,charp,0644);
MODULE_PARM_DESC(wifi_freq,"wifi freq");
void atbm_set_freq(struct ieee80211_local *local)
{
struct hlist_head *hlist;
struct hlist_node *node;
struct hlist_node *node_temp;
struct ieee80211_special_freq *freq_node;
int hash_index = 0;
int n_freqs = 0;
int len = 0;
int total_len = 0;
char *freq_show = wifi_freq_buf;
memset(freq_show,0,ATBM_SPECIAL_FREQ_MAX_LEN);
for(hash_index = 0;hash_index<ATBM_COMMON_HASHENTRIES;hash_index++){
hlist = &local->special_freq_list[hash_index];
hlist_for_each_safe(node,node_temp,hlist){
freq_node = hlist_entry(node,struct ieee80211_special_freq,hnode);
n_freqs ++ ;
len = scnprintf(freq_show+total_len,ATBM_SPECIAL_FREQ_MAX_LEN-total_len,"ch:%d, freq:%d \n",
channel_hw_value(freq_node->channel),freq_node->freq);
total_len += len;
}
}
if(n_freqs == 0){
wifi_freq = "NULL";
}else {
wifi_freq = wifi_freq_buf;
}
#if 0
int i;
memset(wifi_freq_buf, 0, sizeof(wifi_freq_buf));
for(i=0; i<CHANNEL_NUM; i++){
if(pdata[i].flag == 1){
sprintf(wifi_freq_buf+strlen(wifi_freq_buf), "ch:%d, freq:%d \n", i+1, pdata[i].special_freq);
}
}
wifi_freq = wifi_freq_buf;
return;
#endif
}
bool atbm_internal_freq_set(struct ieee80211_hw *hw,struct ieee80211_internal_set_freq_req *req)
{
struct ieee80211_local *local = hw_to_local(hw);
struct atbm_common *hw_priv = (struct atbm_common *)hw->priv;
struct ieee80211_channel *channel;
char* cmd = NULL;
int len;
bool res = true;
struct ieee80211_special_freq special_req;
ASSERT_RTNL();
channel = ieee8011_chnum_to_channel(hw,req->channel_num);
if(channel == NULL){
res = false;
goto out;
}
if(req->set == false){
req->freq = channel_center_freq(channel);
}
if((req->freq < 2300) || (req->freq>2600)){
res = false;
goto out;
}
mutex_lock(&local->mtx);
__ieee80211_recalc_idle(local);
mutex_unlock(&local->mtx);
if((local->hw.conf.flags & IEEE80211_CONF_IDLE) == 0){
res = false;
goto out;
}
cmd = atbm_kzalloc(ATBM_WSM_CMD_LEN,GFP_KERNEL);
if(cmd == NULL){
res = false;
goto out;
}
len = snprintf(cmd, ATBM_WSM_CMD_LEN, ATBM_WSM_SET_FREQ,req->channel_num,(int)req->freq);
if(len <= 0){
res = false;
goto out;
}
if(len+1>ATBM_WSM_CMD_LEN){
res = false;
goto out;
}
special_req.channel = channel;
special_req.freq = req->freq;
if(channel_center_freq(channel) != req->freq){
if(ieee80211_special_freq_update(local,&special_req) == false){
res = false;
goto out;
}
}else {
ieee80211_special_freq_clear(local,&special_req);
}
if(wsm_write_mib(hw_priv, WSM_MIB_ID_FW_CMD, cmd, len+1, 0) < 0){
ieee80211_special_freq_clear(local,&special_req);
res = false;
goto out;
}
out:
if(cmd)
atbm_kfree(cmd);
return res;
}
bool atbm_internal_channel_auto_select(struct ieee80211_sub_if_data *sdata,
struct ieee80211_internal_channel_auto_select_req *req)
{
struct ieee80211_internal_scan_request scan_req;
scan_req.req_flags = IEEE80211_INTERNAL_SCAN_FLAGS__CCA;
/*
*all off supported channel will be scanned
*/
scan_req.channels = NULL;
scan_req.n_channels = 0;
scan_req.macs = NULL;
scan_req.n_macs = 0;
scan_req.ies = NULL;
scan_req.ie_len = 0;
scan_req.no_cck = false;
scan_req.priv = NULL;
scan_req.result_handle = NULL;
scan_req.ssids = NULL;
scan_req.n_ssids = 0;
return atbm_internal_cmd_scan_triger(sdata,&scan_req);
}
static bool atbm_internal_channel_auto_select_results_handle(struct ieee80211_hw *hw,struct atbm_internal_scan_results_req *req,struct ieee80211_internal_scan_sta *sta_info)
{
struct ieee80211_internal_channel_auto_select_results *cca_results = (struct ieee80211_internal_channel_auto_select_results *)req->priv;
s8 signal = (s8)sta_info->signal;
u8 cur_channel = sta_info->channel;
u8 index = 0;
struct ieee80211_channel *channel;
if(ieee8011_channel_valid(hw,cur_channel) == false){
return false;
}
if(sta_info->cca == false){
return false;
}
req->n_stas ++;
cca_results->n_aps[cur_channel-1]++;
if(cca_results->version == 1)
cca_results->weight[cur_channel-1] += ieee80211_rssi_weight(signal);
else
cca_results->weight[cur_channel-1]++;
channel = ieee8011_chnum_to_channel(hw,cur_channel);
if(channel_in_special(channel) == true){
return true;
}
/*
*2.4G channel
*/
atbm_printk_debug("ssid[%s],channel[%d],signal(%d)\n",sta_info->ssid,cur_channel,signal);
/*
*channel 1-13
*weight[x] += val[x] + val[x-1] + val[x-2] + val[x-3] + val[x+1] + val[x+2] + val[x+3]
*/
if(cur_channel<=13){
u8 low;
u8 high;
low = cur_channel>=4?cur_channel-3:1;
high = cur_channel<= 10 ? cur_channel+3:13;
for(index=cur_channel+1;index<=high;index++){
channel = ieee8011_chnum_to_channel(hw,index);
/*
*skip special freq
*/
if(channel_in_special(channel) == true){
atbm_printk_debug("%s:skip special freq(%d)\n",__func__,channel_hw_value(channel));
continue;
}
if(cca_results->version == 1)
cca_results->weight[index-1] += ieee80211_rssi_weight(signal - 2*(index-cur_channel));
else
cca_results->weight[index-1] ++;
}
for(index=cur_channel-1;index>=low;index--){
channel = ieee8011_chnum_to_channel(hw,index);
/*
*skip special freq
*/
if(channel_in_special(channel) == true){
atbm_printk_debug("%s:skip special freq(%d)\n",__func__,channel_hw_value(channel));
continue;
}
if(cca_results->version == 1)
cca_results->weight[index-1] += ieee80211_rssi_weight(signal - 2*(cur_channel-index));
else
cca_results->weight[index-1] ++;
}
}
/*
*channel 14
*/
else if(cur_channel == 14){
}
/*
*5G channel
*/
else {
}
for(index = 0;index<IEEE80211_ATBM_MAX_SCAN_CHANNEL_INDEX;index++){
atbm_printk_debug("weight[%d]=[%d]\n",index,cca_results->weight[index]);
}
return true;
}
bool atbm_internal_channel_auto_select_results(struct ieee80211_sub_if_data *sdata,
struct ieee80211_internal_channel_auto_select_results *results)
{
#define ATBM_BUSY_RATIO_MIN 100
struct atbm_internal_scan_results_req results_req;
struct ieee80211_local *local = sdata->local;
u8 *busy_ratio;
u8 i;
u32 min_ap_num = (u32)(-1);
u8 min_busy_ratio = 128;
u8 min_ap_num_ration = 128;
u8 channel = 0;
int band;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0))
u32 ignore_flags = IEEE80211_CHAN_DISABLED;
#endif
struct ieee80211_supported_band *sband;
u8 ignor_channel_mask[IEEE80211_ATBM_MAX_SCAN_CHANNEL_INDEX];
u8 channel_mask[IEEE80211_ATBM_MAX_SCAN_CHANNEL_INDEX];
results_req.n_stas = 0;
results_req.flush = true;
results_req.priv = results;
results_req.result_handle = atbm_internal_channel_auto_select_results_handle;
busy_ratio = ieee80211_scan_cca_val_get(&local->hw);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0))
ignore_flags |= IEEE80211_CHAN_NO_OFDM;
#endif
if(ieee80211_scan_internal_req_results(local,&results_req) == false){
goto err;
}
for(i = 0;i<14;i++){
atbm_printk_debug("busy_ratio[%d]=[%d]\n",i,busy_ratio[i]);
}
memset(ignor_channel_mask,0,IEEE80211_ATBM_MAX_SCAN_CHANNEL_INDEX);
memset(channel_mask,1,IEEE80211_ATBM_MAX_SCAN_CHANNEL_INDEX);
for(i= 0;i<results->ignore_n_channels;i++){
//BUG_ON(results->ignore_channels == NULL);
if(results->ignore_channels == NULL){
atbm_printk_err("%s %d ,ERROR !!! results->ignore_channels is NULL\n",__func__,__LINE__);
goto err;
}
if(ieee8011_channel_valid(&local->hw,results->ignore_channels[i]) == false){
goto err;
}
ignor_channel_mask[results->ignore_channels[i]-1] = 1;
atbm_printk_debug("%s channel %d ignored\n",__func__,results->ignore_channels[i]);
}
if(results->n_channels){
memset(channel_mask,0,IEEE80211_ATBM_MAX_SCAN_CHANNEL_INDEX);
for(i = 0;i<results->n_channels;i++){
//BUG_ON(results->channels == NULL);
if(results->channels == NULL){
atbm_printk_err("%s %d ,ERROR !!! results->channels is NULL\n",__func__,__LINE__);
goto err;
}
if(ieee8011_channel_valid(&local->hw,results->channels[i]) == false){
goto err;
}
channel_mask[results->channels[i]-1] = 1;
}
}
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
sband = local->hw.wiphy->bands[band];
if (!sband)
continue;
/*
*2.4G channel and 5G
*/
for(i = 0;i<sband->n_channels;i++){
/*
*0 means that the channel do not process cca
*/
if(busy_ratio[channel_hw_value(&sband->channels[i])-1] == 0){
continue;
}
if(ignor_channel_mask[channel_hw_value(&sband->channels[i])-1] == 1){
continue;
}
if(channel_mask[channel_hw_value(&sband->channels[i])-1] == 0){
continue;
}
/*
*special freq must be skiped
*/
if(channel_in_special(&sband->channels[i])){
atbm_printk_debug("%s:skip special freq(%d)\n",__func__,channel_hw_value(&sband->channels[i]));
continue;
}
/*
*some disabled channel must be skiped
*/
/**
if(ignore_flags&sband->channels[i].flags){
atbm_printk_debug("%s: channel[%d] not support ofdm\n",__func__,channel_hw_value(&sband->channels[i]));
continue;
}
*/
// atbm_printk_err("\n");
// atbm_printk_err("channel[%d] min_ap_num [%d] min_ap_num_ration[%d] min_busy_ratio[%d] \n",channel,min_ap_num,min_ap_num_ration,min_busy_ratio);
// atbm_printk_err("i = %d , busy_ratio[%d] = %d \n",i,channel_hw_value(&sband->channels[i])-1,busy_ratio[channel_hw_value(&sband->channels[i])-1]);
if(busy_ratio[channel_hw_value(&sband->channels[i])-1]<ATBM_BUSY_RATIO_MIN){
if(results->weight[channel_hw_value(&sband->channels[i])-1]<=min_ap_num){
if(results->weight[channel_hw_value(&sband->channels[i])-1]==min_ap_num){
if(busy_ratio[channel_hw_value(&sband->channels[i])-1]<=min_ap_num_ration){
min_ap_num = results->weight[channel_hw_value(&sband->channels[i])-1];
channel = channel_hw_value(&sband->channels[i]);
min_ap_num_ration = busy_ratio[channel_hw_value(&sband->channels[i])-1];
}
}else {
min_ap_num = results->weight[channel_hw_value(&sband->channels[i])-1];
channel = channel_hw_value(&sband->channels[i]);
min_ap_num_ration = busy_ratio[channel_hw_value(&sband->channels[i])-1];
}
}
}else if(min_ap_num == (u32)(-1)){
if(busy_ratio[channel_hw_value(&sband->channels[i])-1]<min_busy_ratio){
min_busy_ratio = busy_ratio[channel_hw_value(&sband->channels[i])-1];
channel = channel_hw_value(&sband->channels[i]);
}
}
}
}
if(channel == 0){
//WARN_ON(channel == 0);
atbm_printk_err("auto select fail! \n");
goto err;
}
atbm_printk_debug("auto_select channel %d\n",channel);
memcpy(results->busy_ratio,busy_ratio,IEEE80211_ATBM_MAX_SCAN_CHANNEL_INDEX);
results->susgest_channel = channel;
ieee80211_scan_cca_val_put(&local->hw);
return true;
err:
ieee80211_scan_cca_val_put(&local->hw);
return false;
}
#ifdef CONFIG_ATBM_MONITOR_SPECIAL_MAC
bool atbm_internal_mac_monitor(struct ieee80211_hw *hw,struct ieee80211_internal_mac_monitor *monitor)
{
struct atbm_common *hw_priv = (struct atbm_common *)hw->priv;
char* cmd = NULL;
int len = 0;
bool ret = true;
cmd = atbm_kzalloc(ATBM_WSM_CMD_LEN,GFP_KERNEL);
if(cmd == NULL){
ret = false;
goto exit;
}
if(monitor->flags & (IEEE80211_INTERNAL_MAC_MONITOR_START | IEEE80211_INTERNAL_MAC_MONITOR_STOP)){
atbm_printk_err("mac_monitor:enable(%d),mac[%pM]\n",__func__,
!!(monitor->flags&IEEE80211_INTERNAL_MAC_MONITOR_START),
monitor->mac);
len = scnprintf(cmd, ATBM_WSM_CMD_LEN, ATBM_WSM_MONITOR_MAC,monitor->index,
!!(monitor->flags&IEEE80211_INTERNAL_MAC_MONITOR_START),
monitor->mac[0],monitor->mac[1],
monitor->mac[2],monitor->mac[3],
monitor->mac[4],monitor->mac[5]);
if(len<=0){
ret = false;
goto exit;
}
if(wsm_write_mib(hw_priv, WSM_MIB_ID_FW_CMD, cmd, len+1, 0) < 0){
ret = false;
goto exit;
}
}
if(monitor->flags & IEEE80211_INTERNAL_MAC_MONITOR_RESULTS){
int i = 0;
if(wsm_read_mib(hw_priv,WSM_MIB_ID_GET_MONITOR_MAC_STATUS,cmd,ATBM_WSM_CMD_LEN,0) != 0){
ret = false;
goto exit;
}
for (i = 0;i<IEEE80211_INTERNAL_MAC_MONITOR_RESULTS;i++){
monitor->reults[i].found = *cmd++;
monitor->reults[i].rssi = *cmd++;
monitor->reults[i].forcestop = *cmd++;
monitor->reults[i].used = *cmd++;
monitor->reults[i].index = *cmd++;
monitor->reults[i].enabled = *cmd++;
memcpy(monitor->reults[i].mac,cmd,6); cmd += 6;
monitor->reults[i].delta_time = __le32_to_cpu(*((u32*)cmd)); cmd += 4;
if(monitor->reults[i].used == 0){
monitor->reults[i].used = 1;
break;
}
}
}
exit:
if(cmd)
atbm_kfree(cmd);
return ret;
}
#endif
bool atbm_internal_request_chip_cap(struct ieee80211_hw *hw,struct ieee80211_internal_req_chip *req)
{
struct atbm_common *hw_priv = (struct atbm_common *)hw->priv;
if(req->flags & IEEE80211_INTERNAL_REQ_CHIP_FLAGS__CHIP_VER){
if(hw_priv->wsm_caps.firmwareCap &CAPABILITIES_EFUSE8){
req->chip_version = chip_6038;
}else if(hw_priv->wsm_caps.firmwareCap &CAPABILITIES_EFUSEI){
req->chip_version = chip_6032i;
}else if(hw_priv->wsm_caps.firmwareCap &CAPABILITIES_EFUSEB){
req->chip_version = chip_101B;
}else {
req->chip_version = chip_6032i;
}
}
/*other code */
return true;
}
#ifdef CONFIG_ATBM_SUPPORT_AP_CONFIG
bool atbm_internal_update_ap_conf(struct ieee80211_sub_if_data *sdata,
struct ieee80211_internal_ap_conf *conf_req,bool clear)
{
if(!ieee80211_sdata_running(sdata)){
atbm_printk_scan("%s:%d\n",__func__,__LINE__);
goto err;
}
if(conf_req&&conf_req->channel){
if(ieee8011_channel_valid(&sdata->local->hw,(int)conf_req->channel) == false){
atbm_printk_err("atbm_internal_update_ap_conf,ieee8011_channel_valid \n");
goto err;
}
}
return ieee80211_update_ap_config(sdata,conf_req,clear);
err:
return false;
}
#endif
int atbm_internal_addr_read_bit(struct atbm_common *hw_priv,u32 addr,u8 endBit,
u8 startBit,u32 *data )
{
u32 reg_val=0;
u32 regmask=0;
int ret = 0;
ret=atbm_direct_read_reg_32(hw_priv,addr,&reg_val);
if(ret<0){
goto rw_end;
}
regmask = ~((1<<startBit) -1);
regmask &= ((1<<endBit) -1)|(1<<endBit);
reg_val &= regmask;
reg_val >>= startBit;
*data = reg_val;
rw_end:
return ret;
}
int atbm_internal_addr_write_bit(struct atbm_common *hw_priv,u32 addr,u8 endBit,
u8 startBit,u32 data)
{
u32 reg_val=0;
u32 regmask=0;
int ret = 0;
ret = atbm_direct_read_reg_32(hw_priv,addr,&reg_val);
if(ret<0){
atbm_printk_err("%s:read err\n",__func__);
goto rw_end;
}
atbm_printk_err("%s:ret(%d)\n",__func__,ret);
regmask = ~((1<<startBit) -1);
regmask &= ((1<<endBit) -1)|(1<<endBit);
reg_val &= ~regmask;
reg_val |= (data <<startBit)&regmask;
ret = atbm_direct_write_reg_32(hw_priv,addr,reg_val);
if(ret<0)
{
atbm_printk_err("%s:write err\n",__func__);
goto rw_end;
}
if(ret)
ret = 0;
rw_end:
atbm_printk_err("%s:ret(%d)\n",__func__,ret);
return ret;
}
static int atbm_internal_gpio_set(struct atbm_common *hw_priv,struct atbm_ctr_addr *gpio_addr)
{
unsigned int status = -1;
if(atbm_bh_is_term(hw_priv)){
atbm_printk_err("%s:atbm term\n",__func__);
goto exit;
}
status = atbm_internal_addr_write_bit(hw_priv,gpio_addr->base_addr,
gpio_addr->start_bit+gpio_addr->width,gpio_addr->start_bit,gpio_addr->val);
exit:
return status;
}
static int atbm_internal_gpio_get(struct atbm_common *hw_priv,struct atbm_ctr_addr *gpio_addr)
{
unsigned int status = -1;
if(atbm_bh_is_term(hw_priv)){
atbm_printk_err("%s:atbm term\n",__func__);
goto exit;
}
status = atbm_internal_addr_read_bit(hw_priv,gpio_addr->base_addr,
gpio_addr->start_bit+gpio_addr->width-1,gpio_addr->start_bit,&gpio_addr->val);
exit:
return status;
}
static struct atbm_gpio_config *atbm_internal_gpio_reqest(struct atbm_common *hw_priv,int gpio)
{
int i = 0;
struct atbm_gpio_config *gpio_dev = NULL;
for(i = 0;i < ARRAY_SIZE(atbm_gpio_table);i++){
gpio_dev = &atbm_gpio_table[i];
if(gpio_dev->gpio == gpio){
return gpio_dev;
}
}
return NULL;
}
bool atbm_internal_gpio_config(struct atbm_common *hw_priv,int gpio,bool dir ,bool pu,bool default_val)
{
struct atbm_gpio_config *gpio_dev = NULL;
bool ret = true;
int status = -1;
gpio_dev = atbm_internal_gpio_reqest(hw_priv,gpio);
if(gpio_dev == NULL){
atbm_printk_err("%s:gpio (%d) is err\n",__func__,gpio);
ret = false;
goto exit;
}
gpio_dev->fun_ctrl.val = 3;
gpio_dev->dir_ctrl.val = dir == true ? 1:0;
gpio_dev->pup_ctrl.val = pu == true ? 1:0;
gpio_dev->pdu_ctrl.val = pu == false ? 1:0;
status = atbm_internal_gpio_set(hw_priv,&gpio_dev->fun_ctrl);
if(status){
atbm_printk_err("%s:gpio function(%d)(%d) is err\n",__func__,gpio,status);
ret = false;
goto exit;
}
status = atbm_internal_gpio_set(hw_priv,&gpio_dev->dir_ctrl);
if(status){
atbm_printk_err("%s:gpio dir(%d) is err\n",__func__,gpio);
ret = false;
goto exit;
}
status = atbm_internal_gpio_set(hw_priv,&gpio_dev->pup_ctrl);
if(status){
atbm_printk_err("%s:gpio pup(%d) is err\n",__func__,gpio);
ret = false;
goto exit;
}
status = atbm_internal_gpio_set(hw_priv,&gpio_dev->pup_ctrl);
if(status){
atbm_printk_err("%s:gpio pdu(%d) is err\n",__func__,gpio);
ret = false;
goto exit;
}
if(dir == true){
gpio_dev->out_val.val = default_val == true ? 1:0;
status = atbm_internal_gpio_set(hw_priv,&gpio_dev->out_val);
if(status){
atbm_printk_err("%s:gpio out(%d) is err\n",__func__,gpio);
ret = false;
goto exit;
}
}
gpio_dev->flags = ATBM_GPIO_CONFIG__FUNCTION_CONFIGD;
if(dir == true)
gpio_dev->flags |= ATBM_GPIO_CONFIG__OUTPUT;
else
gpio_dev->flags |= ATBM_GPIO_CONFIG__INPUT;
if(pu)
gpio_dev->flags |= ATBM_GPIO_CONFIG__PUP;
else
gpio_dev->flags |= ATBM_GPIO_CONFIG__PUD;
exit:
return ret;
}
bool atbm_internal_gpio_output(struct atbm_common *hw_priv,int gpio,bool set)
{
struct atbm_gpio_config *gpio_dev = NULL;
bool ret =true;
gpio_dev = atbm_internal_gpio_reqest(hw_priv,gpio);
if(gpio_dev == NULL){
atbm_printk_err("%s:gpio (%d) is err\n",__func__,gpio);
ret = false;
goto exit;
}
if(!(gpio_dev->flags & ATBM_GPIO_CONFIG__FUNCTION_CONFIGD)){
atbm_printk_err("%s:gpio (%d) is not configed\n",__func__,gpio);
ret = false;
goto exit;
}
if(!(gpio_dev->flags & ATBM_GPIO_CONFIG__OUTPUT)){
atbm_printk_err("%s:gpio (%d) is not output mode\n",__func__,gpio);
ret = false;
goto exit;
}
gpio_dev->out_val.val = set == true ? 1:0;
if(atbm_internal_gpio_set(hw_priv,&gpio_dev->out_val)){
atbm_printk_err("%s:gpio out(%d) is err\n",__func__,gpio);
ret = false;
goto exit;
}
exit:
return ret;
}
bool atbm_internal_gpio_input(struct atbm_common *hw_priv,int gpio,bool *set)
{
struct atbm_gpio_config *gpio_dev = NULL;
bool ret =true;
gpio_dev = atbm_internal_gpio_reqest(hw_priv,gpio);
if(gpio_dev == NULL){
atbm_printk_err("%s:gpio (%d) is err\n",__func__,gpio);
ret = false;
goto exit;
}
if(!(gpio_dev->flags & ATBM_GPIO_CONFIG__FUNCTION_CONFIGD)){
atbm_printk_err("%s:gpio (%d) is not configed\n",__func__,gpio);
ret = false;
goto exit;
}
if(!(gpio_dev->flags & ATBM_GPIO_CONFIG__INPUT)){
atbm_printk_err("%s:gpio (%d) is not input mode\n",__func__,gpio);
ret = false;
goto exit;
}
if(atbm_internal_gpio_get(hw_priv,&gpio_dev->in_val)){
atbm_printk_err("%s:gpio out(%d) is err\n",__func__,gpio);
ret = false;
goto exit;
}
*set = gpio_dev->in_val.val ? true:false;
exit:
return ret;
}
/*
WSM_EDCA_SET(&priv->edca, queue, params->aifs,
params->cw_min, params->cw_max, params->txop, 0xc8,
params->uapsd);
*/
bool atbm_internal_edca_update(struct ieee80211_sub_if_data *sdata,int queue,int aifs,int cw_win,int cw_max,int txop)
{
bool ret = false;
struct atbm_vif *priv = (struct atbm_vif *)sdata->vif.drv_priv;
if(!ieee80211_sdata_running(sdata)){
atbm_printk_scan("%s:%d\n",__func__,__LINE__);
goto exit;
}
if(atomic_read(&priv->enabled) == 0){
atbm_printk_err("%s:disabled\n",__func__);
goto exit;
}
WSM_EDCA_SET(&priv->edca, queue, aifs,
cw_win, cw_max, txop, 0xc8,
priv->edca.params[queue].uapsdEnable);
ret = wsm_set_edca_params(priv->hw_priv, &priv->edca, priv->if_id);
if (ret) {
atbm_printk_err("%s:wsm_set_edca_params\n",__func__);
goto exit;
}
ret = true;
exit:
return ret;
}
struct atbm_vendor_cfg_ie private_ie;
int atbm_internal_recv_6441_vendor_ie(struct atbm_vendor_cfg_ie *recv_ie)
{
// if(recv_ie){
// if(memcmp(recv_ie,&private_ie,sizeof(struct atbm_vendor_cfg_ie))){
memcpy(&private_ie,recv_ie,sizeof(struct atbm_vendor_cfg_ie));
return 0;
// }
// }
// return -1;
}
struct atbm_vendor_cfg_ie * atbm_internal_get_6441_vendor_ie(void)
{
struct atbm_vendor_cfg_ie ie;
memset(&ie,0,sizeof(struct atbm_vendor_cfg_ie));
if(memcmp(&ie,&private_ie,sizeof(struct atbm_vendor_cfg_ie)) == 0)
return NULL;
return &private_ie;
}
#include "country_code.h"
#if CONFIG_CFG80211_INTERNAL_REGDB
int atbm_set_country_code_to_cfg80211(struct ieee80211_local *local,char *country)
{
int i = 0,found = 0;
if(!local || !country){
atbm_printk_err("%s %d : %s,%s\n",__func__,__LINE__,local==NULL?"local is NULL":" ",country?" ":"country is NULL");
return -1;
}
//country_code = atbm_country_code;
for(i = 0;memcmp(atbm_country_code[i],"00",2)!=0;i++){
if(memcmp(country,atbm_country_code[i],2) == 0){
found = 1;
break;
}
}
if(found == 0){
atbm_printk_err("unknow country code (%c%c) \n",country[0],country[1]);
return -1;
}
if(regulatory_hint(local->hw.wiphy,country) != 0){
atbm_printk_err("not set country code to cfg80211\n");
return -1;
}
memcpy(local->country_code,country,2);
return 0;
}
#endif
u32 MyRand(void)
{
u32 random_num = 0;
u32 randseed = 0;
#if (LINUX_VERSION_CODE > KERNEL_VERSION(5, 0, 0))
randseed = ktime_get_seconds();
#else
struct timex txc;
do_gettimeofday(&(txc.time));
//randseed = jiffies;
randseed = txc.time.tv_sec;
#endif
random_num = randseed * 1103515245 + 12345;
return ((random_num/65536)%32768);
}
int MacStringToHex(char *mac, u8 *umac)
{
int i = 0, j = 0;
unsigned char d = 0;
char ch = 0,buffer[12] = {0};
if(mac)
memcpy(buffer, mac, strlen(mac));
for (i=0;i<12;i++)
{
ch = buffer[i];
if (ch >= '0' && ch <= '9')
{
d = (d<<4) | (ch - '0');
}
else if (ch >= 'a' && ch <= 'f')
{
d = (d<<4) | (ch - 'a' + 10);
}
else if (ch >= 'A' && ch <= 'F')
{
d = (d<<4) | (ch - 'A' + 10);
}
if((i%2 == 1)){
umac[j++] = d;
d = 0;
}
}
return 0;
}
extern u8 ETF_bStartTx;
extern u8 ETF_bStartRx;
extern u8 ucWriteEfuseFlag;
extern int atbm_test_rx_cnt;
extern int txevm_total;
extern u32 chipversion;
extern struct rxstatus_signed gRxs_s;
char ch_and_type[20];
extern int wsm_start_tx(struct atbm_common *hw_priv, struct ieee80211_vif *vif);
extern int wsm_stop_tx(struct atbm_common *hw_priv);
extern int wsm_start_tx_v2(struct atbm_common *hw_priv, struct ieee80211_vif *vif );
#define CHIP_VERSION_REG 0x0acc017c //chip version reg address
#define DCXO_CODE_MINI 0//24//0
#define DCXO_CODE_MAX 127//38//63
extern u8 CodeStart;
extern u8 CodeEnd;
extern struct etf_test_config etf_config;
//config etf test arguments by config_param.txt
void etf_PT_test_config(char *param)
{
int Freq = 0;
int txEvm = 0;
int rxEvm = 0;
int rxEvmthreshold = 0;
int txEvmthreshold = 0;
int Txpwrmax = 0;
int Txpwrmin = 0;
int Rxpwrmax = 0;
int Rxpwrmin = 0;
int rssifilter = 0;
int cableloss = 0;
int default_dcxo = 0;
int noFreqCali = 0;
char mac[12] = {0};
int dcxo_max_min = 0;
memset(&etf_config, 0, sizeof(struct etf_test_config));
if(strlen(param) != 0)
{
atbm_printk_always("<USE CONFIG FILE>\n");
atbm_printk_always("param:%s\n", param);
sscanf(param, "cfg:%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%s",
&Freq, &txEvm, &rxEvm, &txEvmthreshold,&rxEvmthreshold,&Txpwrmax,
&Txpwrmin, &Rxpwrmax, &Rxpwrmin, &rssifilter, &cableloss, &default_dcxo,&noFreqCali, &dcxo_max_min, mac);
etf_config.freq_ppm = Freq;
etf_config.txevm = (txEvm?txEvm:65536); //txevm filter
etf_config.rxevm = (rxEvm?rxEvm:65536); //rxevm filter
etf_config.txevmthreshold = txEvmthreshold;
etf_config.rxevmthreshold = rxEvmthreshold;
etf_config.txpwrmax = Txpwrmax;
etf_config.txpwrmin = Txpwrmin;
etf_config.rxpwrmax = Rxpwrmax;
etf_config.rxpwrmin = Rxpwrmin;
etf_config.rssifilter = rssifilter;
etf_config.cableloss = (cableloss?cableloss:30)*4;
etf_config.default_dcxo = default_dcxo;
etf_config.noFfreqCaliFalg = noFreqCali;
dcxo_max_min &= 0xffff;
etf_config.dcxo_code_min = dcxo_max_min & 0xff;
etf_config.dcxo_code_max = (dcxo_max_min >> 8) & 0xff;
if(etf_config.dcxo_code_min < DCXO_CODE_MAX)
CodeStart = etf_config.dcxo_code_min;
else
CodeStart = DCXO_CODE_MINI;
if((etf_config.dcxo_code_max > DCXO_CODE_MINI) && (etf_config.dcxo_code_max <= DCXO_CODE_MAX))
CodeEnd = etf_config.dcxo_code_max;
else
CodeEnd = DCXO_CODE_MAX;
if(strlen(mac) == 12){
etf_config.writemacflag = 1;
MacStringToHex(mac, etf_config.writemac);
}
}
else
{
etf_config.freq_ppm = 7000;
etf_config.rxevm = (rxEvm?rxEvm:65536);
etf_config.rssifilter = -100;
etf_config.txevm = (txEvm?txEvm:65536);
etf_config.txevmthreshold = 400;
etf_config.rxevmthreshold = 400;
etf_config.cableloss = 30*4;
CodeStart = DCXO_CODE_MINI;
CodeEnd = DCXO_CODE_MAX;
}
etf_config.featureid = MyRand();
atbm_printk_always("featureid:%d\n", etf_config.featureid);
atbm_printk_always("Freq:%d,txEvm:%d,rxEvm:%d,txevmthreshold:%d,rxevmthreshold:%d,Txpwrmax:%d,Txpwrmin:%d,Rxpwrmax:%d,Rxpwrmin:%d,rssifilter:%d,cableloss:%d,default_dcxo:%d,noFreqCali:%d",
etf_config.freq_ppm,etf_config.txevm,etf_config.rxevm,etf_config.txevmthreshold,etf_config.rxevmthreshold,
etf_config.txpwrmax,etf_config.txpwrmin,etf_config.rxpwrmax,
etf_config.rxpwrmin,etf_config.rssifilter,etf_config.cableloss,etf_config.default_dcxo,
etf_config.noFfreqCaliFalg);
atbm_printk_always("dcxomin:%d,dcxomax:%d", etf_config.dcxo_code_min, etf_config.dcxo_code_max);
if(strlen(mac) == 12){
atbm_printk_always("WRITE MAC:%02X%02X%02X%02X%02X%02X\n",
etf_config.writemac[0],etf_config.writemac[1],etf_config.writemac[2],
etf_config.writemac[3],etf_config.writemac[4],etf_config.writemac[5]);
}
atbm_printk_always("\n");
}
//get chip version funciton
u32 GetChipVersion(struct atbm_common *hw_priv)
{
#ifndef SPI_BUS
u32 uiRegData;
atbm_direct_read_reg_32(hw_priv, CHIP_VERSION_REG, &uiRegData);
//hw_priv->sbus_ops->sbus_read_sync(hw_priv->sbus_priv,CHIP_VERSION_REG,&uiRegData,4);
return uiRegData;
#else
return 0;
#endif
}
int atbm_internal_start_tx(struct atbm_common *hw_priv,start_tx_param_t *tx_param)
{
int i = 0,flag = 0;
u32 rate;
int etf_v2 = 0;
u8 ucDbgPrintOpenFlag = 1;
struct atbm_vif *vif;
//char threshold_param[100] = {0};
int channel;
int band_value;
int is_40M;
int len;
int greedfiled;
memset(&gRxs_s, 0, sizeof(struct rxstatus_signed));
chipversion = GetChipVersion(hw_priv);
atbm_printk_wext("chipversion:0x%x\n", chipversion);
if(ETF_bStartTx || ETF_bStartRx){
if(ETF_bStartTx){
atbm_internal_stop_tx(hw_priv);
msleep(500);
}else{
atbm_printk_err("Error! already start_tx, please stop_rx first!\n");
return 0;
}
}
channel = tx_param->channel;
band_value = tx_param->rate;
is_40M = tx_param->is_40M;
len = tx_param->pktlen;
greedfiled = tx_param->greedfiled;
//check rate
switch(band_value){
case 10: rate = WSM_TRANSMIT_RATE_1;
break;
case 20: rate = WSM_TRANSMIT_RATE_2;
break;
case 55: rate = WSM_TRANSMIT_RATE_5;
break;
case 110: rate = WSM_TRANSMIT_RATE_11;
break;
case 60: rate = WSM_TRANSMIT_RATE_6;
break;
case 90: rate = WSM_TRANSMIT_RATE_9;
break;
case 120: rate = WSM_TRANSMIT_RATE_12;
break;
case 180: rate = WSM_TRANSMIT_RATE_18;
break;
case 240: rate = WSM_TRANSMIT_RATE_24;
break;
case 360: rate = WSM_TRANSMIT_RATE_36;
break;
case 480: rate = WSM_TRANSMIT_RATE_48;
break;
case 540: rate = WSM_TRANSMIT_RATE_54;
break;
case 65: rate = WSM_TRANSMIT_RATE_HT_6;
break;
case 130: rate = WSM_TRANSMIT_RATE_HT_13;
break;
case 195: rate = WSM_TRANSMIT_RATE_HT_19;
break;
case 260: rate = WSM_TRANSMIT_RATE_HT_26;
break;
case 390: rate = WSM_TRANSMIT_RATE_HT_39;
break;
case 520: rate = WSM_TRANSMIT_RATE_HT_52;
break;
case 585: rate = WSM_TRANSMIT_RATE_HT_58;
break;
case 650: rate = WSM_TRANSMIT_RATE_HT_65;
break;
default:
atbm_printk_err("invalid rate!\n");
return -EINVAL;
}
if((is_40M == 1 )&& (rate < WSM_TRANSMIT_RATE_HT_6)){
atbm_printk_err("invalid 40M rate\n");
return -EINVAL;
}
if((is_40M == 1 )&& ((channel < 3)||(channel > 11))){
atbm_printk_err("invalid 40M rate,channel value range:3~11\n");
return -EINVAL;
}
if((is_40M == 1 )&&(hw_priv->chip_version == ARES_6012B) ){
atbm_printk_err("invalid 40M rate,current chip is not support HT40!!\n");
return -EINVAL;
}
if(len == 99999){
ucWriteEfuseFlag = 1;
etf_v2 = 1;
len = hw_priv->etf_len = 1000;
}else if(len == 99998)
{
ucWriteEfuseFlag = 0;
etf_v2 = 1;
len = hw_priv->etf_len = 1000;
}
//Prevent USB from being unplugged suddenly in product testing
//11b 100% duty cycle
if((rate <= WSM_TRANSMIT_RATE_11)&&(len == 0))
{
len = 1000;
if(is_40M == 1){
is_40M = NL80211_CHAN_HT40PLUS;//
channel -= 2;
}
hw_priv->etf_channel = channel;
hw_priv->etf_channel_type = is_40M;
hw_priv->etf_rate = rate;
hw_priv->etf_len = len;
hw_priv->etf_greedfiled = greedfiled;
atbm_for_each_vif(hw_priv,vif,i){
if((vif != NULL)){
atbm_printk_wext("*******\n");
down(&hw_priv->scan.lock);
WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_DBG_PRINT_TO_HOST,
&ucDbgPrintOpenFlag, sizeof(ucDbgPrintOpenFlag), vif->if_id));
mutex_lock(&hw_priv->conf_mutex);
ETF_bStartTx = 1;
mutex_unlock(&hw_priv->conf_mutex);
if(wsm_start_tx(hw_priv, vif->vif) != 0){
up(&hw_priv->scan.lock);
atbm_printk_err("%s:%d,wsm_start_tx error\n", __func__, __LINE__);
goto _exit;
}
msleep(1000);
wsm_oper_unlock(hw_priv);
wsm_stop_tx(hw_priv);
wsm_stop_scan(hw_priv,i);
if(atbm_hw_cancel_delayed_work(&hw_priv->scan.timeout,true))
atbm_scan_timeout(&hw_priv->scan.timeout.work);
//up(&hw_priv->scan.lock);
msleep(1000);
hw_priv->etf_rate = 5;
if(wsm_start_tx(hw_priv, vif->vif) != 0){
up(&hw_priv->scan.lock);
atbm_printk_err("%s:%d,wsm_start_tx error\n", __func__, __LINE__);
goto _exit;
}
}
break;
}
}
else{
//check len
if(len < 200 || len > 1024){
atbm_printk_err("len:%d\n", len);
atbm_printk_err("invalid len!\n");
return -EINVAL;
}
if(is_40M == 1){
is_40M = NL80211_CHAN_HT40PLUS;//
channel -= 2;
}
atbm_printk_wext("NL80211_CHAN_HT40PLUS:%d\n", NL80211_CHAN_HT40PLUS);
//printk("%d, %d, %d, %d\n", channel, rate, len, is_40M);
hw_priv->etf_channel = channel;
hw_priv->etf_channel_type = is_40M;
hw_priv->etf_rate = rate;
hw_priv->etf_len = len;
hw_priv->etf_greedfiled = greedfiled;
atbm_for_each_vif(hw_priv,vif,i){
if((vif != NULL)){
atbm_printk_wext("*******\n");
down(&hw_priv->scan.lock);
if(!etf_v2)
{
WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_DBG_PRINT_TO_HOST,
&ucDbgPrintOpenFlag, sizeof(ucDbgPrintOpenFlag), vif->if_id));
}
mutex_lock(&hw_priv->conf_mutex);
if(etf_v2){
atbm_test_rx_cnt = 0;
txevm_total = 0;
if(etf_v2)
{
hw_priv->bStartTx = 1;
hw_priv->bStartTxWantCancel = 1;
hw_priv->etf_test_v2 =1;
}
if(tx_param->threshold_param)
etf_PT_test_config(tx_param->threshold_param);
else
atbm_printk_err("ERROR !!!!!!! tx_param->threshold_param is NULL!!!!");
if(chipversion == 0x49)
GetChipCrystalType(hw_priv);
if(wsm_start_tx_v2(hw_priv, vif->vif) != 0)
{
up(&hw_priv->scan.lock);
atbm_printk_err("%s:%d,wsm_start_tx_v2 error\n", __func__, __LINE__);
}
}
else
{
ETF_bStartTx = 1;
if(wsm_start_tx(hw_priv, vif->vif) != 0)
{
up(&hw_priv->scan.lock);
atbm_printk_err("%s:%d,wsm_start_tx error\n", __func__, __LINE__);
}
}
mutex_unlock(&hw_priv->conf_mutex);
break;
}
}
}
_exit:
return 0;
}
int atbm_internal_stop_tx(struct atbm_common *hw_priv)
{
int i = 0;
struct atbm_vif *vif;
msleep(500);
if(0 == ETF_bStartTx){
atbm_printk_err("please start start_rx first,then stop_rx\n");
return -EINVAL;
}
mutex_lock(&hw_priv->conf_mutex);
ETF_bStartTx = 0;
mutex_unlock(&hw_priv->conf_mutex);
//./iwpriv wlan0 fwdbg 0
atbm_for_each_vif(hw_priv,vif,i){
if((vif != NULL)){
// wsm_oper_unlock(hw_priv);
wsm_stop_tx(hw_priv);
wsm_stop_scan(hw_priv,i);
if(atbm_hw_cancel_delayed_work(&hw_priv->scan.timeout,true))
atbm_scan_timeout(&hw_priv->scan.timeout.work);
if (unlikely(down_trylock(&hw_priv->scan.lock))){
}
up(&hw_priv->scan.lock);
break;
}
}
//printk("%s %d\n", __FUNCTION__, __LINE__)
return 0;
}
int atbm_internal_start_rx(struct atbm_common *hw_priv,int channel,int is_40M)
{
int i = 0;
char cmd[20] = "monitor 1 ";
u8 ucDbgPrintOpenFlag = 1;
struct atbm_vif *vif;
if(ETF_bStartTx || ETF_bStartRx){
if(ETF_bStartRx){
atbm_printk_err("start rx : %s ,stop now and change chan[%d],is_40M[%d]\n",ch_and_type,channel,is_40M);
atbm_internal_stop_rx(hw_priv,NULL);
msleep(500);
}else{
atbm_printk_err("Error! already ETF_bStartRx, please stop_tx first!\n");
return 0;
}
}
if((is_40M == 1 )&& ((channel == 1)||(channel > 11))){
atbm_printk_err("invalid 40M rate\n");
return -EINVAL;
}
if((is_40M == 1 )&&(hw_priv->chip_version == ARES_6012B) ){
atbm_printk_err("invalid 40M rate,current chip is not support HT40!!\n");
return -EINVAL;
}
atbm_for_each_vif(hw_priv,vif,i){
if (vif != NULL)
{
WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_DBG_PRINT_TO_HOST,
&ucDbgPrintOpenFlag, sizeof(ucDbgPrintOpenFlag), vif->if_id));
break;
}
}
sprintf(cmd,"monitor 1 %d %d",channel,is_40M);
memset(ch_and_type, 0, 20);
//memcpy(ch_and_type, extra, wrqu->data.length);
sprintf(ch_and_type,"%d %d",channel,is_40M);
// memcpy(cmd+10, extra, wrqu->data.length);
atbm_printk_err("CMD:%s\n", cmd);
i = 0;
atbm_for_each_vif(hw_priv,vif,i){
if (vif != NULL)
{
ETF_bStartRx = 1;
WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_FW_CMD,
cmd, strlen(cmd)+1, vif->if_id));
break;
}
}
return 0;
}
int atbm_internal_stop_rx(struct atbm_common *hw_priv,fixed_freq_rx_data *rx_data)
{
int i = 0;
int ret = 0;
char cmd[20] = "monitor 0 ";
u8 ucDbgPrintOpenFlag = 0;
u32 rx_status[3] = {0,0,0};
u8 *status = NULL;
int len = 0;
struct atbm_vif *vif;
if((0 == ETF_bStartRx) || (NULL == ch_and_type)){
atbm_printk_err("please start start_rx first,then stop_rx\n");
return -EINVAL;
}
ETF_bStartRx = 0;
ret = wsm_read_shmem(hw_priv,(u32)RX_STATUS_ADDR,rx_status,sizeof(rx_status));
if(ret != 0){
ret = -EINVAL;
goto exit;
}
if(rx_data){
if(rx_data->status_data == NULL){
status = atbm_kzalloc(512,GFP_KERNEL);
}else
status = rx_data->status_data;
}else{
status = atbm_kzalloc(512,GFP_KERNEL);
}
if(status == NULL){
ret = -ENOMEM;
goto exit;
}
memset(status,0,512);
len = scnprintf(status,512,"rxSuccess:%d, FcsErr:%d, PlcpErr:%d\n",
rx_status[0]-rx_status[1],rx_status[1],rx_status[2]);
if(rx_data){
memcpy(rx_data->status_data,status,512);
rx_data->len = len;
}
memcpy(cmd+10, ch_and_type, strlen(ch_and_type));
//printk("cmd %s\n", cmd);
atbm_printk_always("%s:%s\n",__func__,status);
i = 0;
atbm_for_each_vif(hw_priv,vif,i){
if (vif != NULL)
{
WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_FW_CMD,
cmd, 13, vif->if_id));
break;
}
}
atbm_for_each_vif(hw_priv,vif,i){
if (vif != NULL)
{
WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_DBG_PRINT_TO_HOST,
&ucDbgPrintOpenFlag, sizeof(ucDbgPrintOpenFlag), vif->if_id));
break;
}
}
ret = 0;
exit:
if(rx_data == NULL && status){
atbm_printk_err("%s : release status! \n",__func__);
atbm_kfree(status);
}
return ret;
}