1889 lines
50 KiB
C
1889 lines
50 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 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
|
|
*/
|
|
|
|
#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;
|
|
#if (LINUX_VERSION_CODE > KERNEL_VERSION(5, 10, 60))
|
|
struct kernel_siginfo info;
|
|
#else
|
|
struct siginfo info;
|
|
#endif
|
|
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");
|
|
}
|
|
|
|
}
|
|
|
|
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));
|
|
|
|
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(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(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){
|
|
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,®_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,®_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)®mask;
|
|
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;
|
|
}
|