linuxOS_AP06/kernel/drivers/bluetooth/swt/skw_common.c
2025-07-02 10:30:25 +08:00

415 lines
9.4 KiB
C

/*
*
* Seekwave Bluetooth driver
*
* Copyright (C) 2023 Seekwave Tech Ltd.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <linux/time.h>
#include <linux/err.h>
#include <linux/proc_fs.h>
#include <linux/skbuff.h>
#include <linux/kernel.h>
#include "skw_common.h"
#include "skw_btsnoop.h"
#if ((BT_HCI_LOG_EN == 1) || (BT_CP_LOG_EN == 1))
#define FILE_RW_ENABLE
#endif
#ifndef BD_ADDR_FILE_PATH
//#define BD_ADDR_FILE_PATH SEEKWAVE_BT_LOG_PATH
#else
#endif
#define BD_ADDR_FILE_PATH "/devinfo/skwbt"
static unsigned char bdaddr_lap[4] = {0x12, 0x24, 0x56};
static char bdaddr_valid = 0;
static unsigned int randseed;
#ifdef FILE_RW_ENABLE
mm_segment_t skwbt_get_fs(void)
{
mm_segment_t oldfs;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)
oldfs = force_uaccess_begin();
#else
oldfs = get_fs();
set_fs(KERNEL_DS);
#endif
return oldfs;
}
void skwbt_set_fs(mm_segment_t fs)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)
force_uaccess_end(fs);
#else
set_fs(fs);
#endif
}
#endif
ssize_t skw_file_write(struct file *fp, const void *buf, size_t len)
{
#ifdef FILE_RW_ENABLE
ssize_t res_len = 0;
loff_t pos = fp->f_pos;
mm_segment_t fs = skwbt_get_fs();
res_len = skw_write(fp, buf, len, &pos);
fp->f_pos = pos;
skwbt_set_fs(fs);
return res_len;
#else
return 0;
#endif
}
EXPORT_SYMBOL_GPL(skw_file_write);
ssize_t skw_file_read(struct file *fp, void *buf, size_t len)
{
#ifdef FILE_RW_ENABLE
ssize_t res_len = 0;
loff_t pos = fp->f_pos;
mm_segment_t fs = skwbt_get_fs();
res_len = skw_read(fp, buf, len, &pos);
fp->f_pos = pos;
skwbt_set_fs(fs);
return res_len;
#else
return 0;
#endif
}
EXPORT_SYMBOL_GPL(skw_file_read);
/*
file copy
return 1:success
*/
char skw_file_copy(char *scr_file, char *des_file)
{
#ifdef FILE_RW_ENABLE
struct file *src_fp = filp_open(scr_file, O_RDONLY, 0644);
struct file *des_fp = filp_open(des_file, O_RDWR | O_CREAT, 0644);
char *pld_buf;
int len;
if(IS_ERR(src_fp) || (IS_ERR(des_fp)))
{
return -1;
}
pld_buf = (char *)kzalloc(1025, GFP_KERNEL);
while(1)
{
len = skw_file_read(src_fp, pld_buf, 1024);
if(len <= 0)
{
break;
}
skw_file_write(des_fp, pld_buf, len);
}
kfree(pld_buf);
filp_close(src_fp, NULL);
filp_close(des_fp, NULL);
#endif
return 1;
}
EXPORT_SYMBOL_GPL(skw_file_copy);
unsigned int skw_rand(void)
{
unsigned int r;// = randseed = randseed * 1103515245 + 12345;
do
{
r = randseed = randseed * 1103515245 + 12345;
r = (r << 16) | ((r >> 16) & 0xFFFF);
} while(r == 0);
return r;
}
void skw_srand(void)
{
randseed = (unsigned int) ktime_get_ns();
skw_rand();
skw_rand();
skw_rand();
}
void skw_bd_addr_gen_init(void)
{
#ifdef BD_ADDR_FILE_PATH
#ifdef FILE_RW_ENABLE
struct file *fp = NULL;
char file_path[256] = {0};
if(bdaddr_valid)
{
return ;
}
skw_srand();
snprintf(file_path, 256, "%s/skwbdaddr", BD_ADDR_FILE_PATH);
SKWBT_INFO("skwbdaddr init path:%s\n", file_path);
fp = filp_open(file_path, O_RDWR, 0666);
if((fp == NULL) || IS_ERR(fp))
{
fp = filp_open(file_path, O_RDWR | O_CREAT | O_TRUNC, 0666);
if((fp == NULL) || IS_ERR(fp))
{
SKWBT_INFO("skwbdaddr open err:%ld\n", PTR_ERR(fp));
}
else
{
bdaddr_lap[0] = (unsigned char)(skw_rand() & 0xFF);
bdaddr_lap[1] = (unsigned char)(skw_rand() & 0xFF);
bdaddr_lap[2] = (unsigned char)(skw_rand() & 0xFF);
SKWBT_INFO("skwbd addr:%x\n", *((u32 *)bdaddr_lap));
if(skw_file_write(fp, bdaddr_lap, 3) != 3)
{
SKWBT_INFO("skwbd addr write err:%ld\n", PTR_ERR(fp));
}
bdaddr_valid = 1;
filp_close(fp, NULL);
}
}
else
{
if(skw_file_read(fp, bdaddr_lap, 3) > 0)
{
bdaddr_valid = 1;
}
filp_close(fp, NULL);
}
#endif
#endif
}
EXPORT_SYMBOL_GPL(skw_bd_addr_gen_init);
char skw_get_bd_addr(unsigned char *buffer)
{
if(bdaddr_valid > 0)
{
buffer[0] = bdaddr_lap[0];
buffer[1] = bdaddr_lap[1];
buffer[2] = bdaddr_lap[2];
return 1;
}
return 0;
}
EXPORT_SYMBOL_GPL(skw_get_bd_addr);
char *skw_strchr(char *str, const char ch)
{
char *ptr = str;
while((ptr != NULL) && ((*ptr) != '\r') && ((*ptr) != '\n') && ((*ptr) != 0))
{
if((*ptr) == ch)
{
return ptr;
}
ptr ++;
}
return NULL;
}
int skw_strlen(char *str)
{
char *ptr = str;
int str_len = 0;
while((ptr != NULL) && ((*ptr) != '\r') && ((*ptr) != '\n') && ((*ptr) != 0))
{
ptr ++;
str_len ++;
}
return str_len;
}
EXPORT_SYMBOL_GPL(skw_strlen);
unsigned char skw_char2hex(char ch)
{
unsigned char num = 0;
if(ch >= '0' && ch <= '9')
{
num = ch - 48;//0:48
}
else if(ch >= 'a' && ch <= 'f')
{
num = ch + 10 - 97;//a:97
}
else if(ch >= 'A' && ch <= 'F')
{
num = ch + 10 - 65;//A:65
}
return num;
}
EXPORT_SYMBOL_GPL(skw_char2hex);
/*
data_str = "xxxx;...."
*/
char *skwbt_config_get_uint8(char *data_str, uint8_t *value)
{
char *split0 = skw_strchr(data_str, ';');
uint8_t len = 0;
char buffer[8] = {0};
if((split0 == NULL) || (split0 == data_str))
{
return NULL;
}
len = split0 - data_str;
if(len > 4)//invalid
{
SKWBT_INFO("%s, invalid str , %s", __func__, data_str);
return NULL;
}
memcpy(buffer, data_str, len);
*value = (int)simple_strtol(buffer, NULL, 10);
return split0 + 1;//skip ;
}
void skw_parse_wakeup_adv_conf(char *data_str, Wakeup_ADV_Info_St *wakeup_adv_info)
{
//WakeupADVData=GPIO_No(decimal);Level(decimal);addr offset(decimal);ADVData(Hex);Mask(Hex)
int str_len = strlen(data_str);
char *base_ptr = data_str;
char *split0, *split1;
uint8_t adv_grp_nums = 0, adv_len = 0, mask_len;
uint8_t gpio_no = 0, level = 0, addr_offset;
uint8_t i = 0, j = 0, k;
Wakeup_ADV_Grp_St *adv_grp;
int total_len = 0;
wakeup_adv_info->data_len = 0;
if(str_len > 512)
{
SKWBT_INFO("%s, invalid config str, %s", __func__, data_str);
return ;
}
if((base_ptr = skwbt_config_get_uint8(base_ptr, &gpio_no)) == NULL)
{
return ;
}
if((base_ptr = skwbt_config_get_uint8(base_ptr, &level)) == NULL)
{
return ;
}
for(k = 0; k < BLE_ADV_WAKEUP_GRP_NUMS; k++)
{
//addr offset(decimal);ADVData(Hex);Mask(Hex)
if((base_ptr = skwbt_config_get_uint8(base_ptr, &addr_offset)) == NULL)
{
break;
}
if((addr_offset == 1) || (addr_offset > 26))
{
SKWBT_INFO("%s, invalid addr_offset , %s", __func__, data_str);
return ;
}
adv_grp = &wakeup_adv_info->adv_group[k];
split0 = strchr(base_ptr, ';');
if(split0 == NULL)
{
SKWBT_INFO("%s, invalid config , %s", __func__, data_str);
return ;
}
split1 = strchr(split0 + 1, ';');
adv_len = split0 - base_ptr;
adv_grp->addr_offset = addr_offset;
adv_grp->grp_len = adv_len + 2;//add addr_offset & self length
split0 ++;//skip ;
if(split1 == NULL)
{
mask_len = data_str + str_len - split0;
}
else
{
mask_len = split1 - split0;
}
if(mask_len != adv_len)
{
SKWBT_INFO("%s, mask_len != adv_len , %s", __func__, data_str);
return ;
}
SKWBT_INFO("grp len:%d, adv_len:%d", adv_grp->grp_len, adv_len);
for(i = 0, j = 0; i < adv_len; j ++, i += 2)
{
adv_grp->data[j] = (skw_char2hex(base_ptr[i]) << 4) | skw_char2hex(base_ptr[i + 1]);
adv_grp->mask[j] = (skw_char2hex(split0[i]) << 4) | skw_char2hex(split0[i + 1]);
}
total_len += adv_grp->grp_len;
adv_grp_nums ++;
if(split1 == NULL)
{
break;
}
base_ptr = split1 + 1;
}
wakeup_adv_info->data_len = total_len;//not contain gpio, level, grp_nums, gpio_no
wakeup_adv_info->grp_nums = adv_grp_nums;
wakeup_adv_info->gpio_no = gpio_no;
wakeup_adv_info->level = level;
SKWBT_INFO("ADV str len:%d, gpio:%d, level:%d, adv_grp_nums:%d, total_len:%d, Data:%s", str_len, gpio_no, level, adv_grp_nums, total_len, data_str);
}
EXPORT_SYMBOL_GPL(skw_parse_wakeup_adv_conf);