kernel-brax3-ubuntu-touch/drivers/misc/mediatek/btif/common/mtk_btif_exp.c
erascape f319b992b1 kernel-5.15: Initial import brax3 UT kernel
* halium configs enabled

Signed-off-by: erascape <erascape@proton.me>
2025-09-23 15:17:10 +00:00

868 lines
23 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifdef DFT_TAG
#undef DFT_TAG
#endif
#define DFT_TAG "MTK-BTIF-EXP"
/*#include "mtk_btif_exp.h"*/
#include "mtk_btif.h"
/*---------------------------------Function----------------------------------*/
struct _mtk_btif_ *btif_exp_srh_id(unsigned long u_id)
{
int index = 0;
struct _mtk_btif_ *p_btif = NULL;
struct list_head *p_list = NULL;
struct list_head *tmp = NULL;
struct _mtk_btif_user_ *p_user = NULL;
for (index = 0; (index < BTIF_PORT_NR) && (p_btif == NULL); index++) {
p_list = &(g_btif[index].user_list);
list_for_each(tmp, p_list) {
p_user = container_of(tmp,
struct _mtk_btif_user_,
entry);
if (u_id == p_user->u_id) {
p_btif = p_user->p_btif;
BTIF_DBG_FUNC
("BTIF's user id(%lu), p_btif(0x%p)\n",
p_user->u_id, p_btif);
break;
}
}
}
if (p_btif == NULL) {
BTIF_INFO_FUNC
("no btif structure found for BTIF's user id(0x%lx)\n",
u_id);
}
return p_btif;
}
/*-----Normal Mode API declearation-------*/
/*****************************************************************************
* FUNCTION
* mtk_wcn_btif_open
* DESCRIPTION
* open BTIF interface, will do BTIF module HW and SW initialization
* PARAMETERS
* p_owner [IN] pointer to owner who call this API,
* currently there are 2 owner ("stp" or "btif_tester")
* may use this module
* for "stp", BTIF will call rx callback function to route rx data to STP
* for "stp_tester", BTIF will save rx data and wait for native process
* to access
* p_id [IN] BTIF's user id will be put to this address
* RETURNS
* int 0 = BTIF module initialization fail;
* negative = BTIF module initialization success
* if open success, value p_id will be the only identifier
* for user to access BTIF's other operations
* including read/write/dpidle_ctrl/rx_cb_retister
* this user id is only an identifier used for owner identification
*****************************************************************************/
int mtk_wcn_btif_open(char *p_owner, unsigned long *p_id)
{
int i_ret = -1;
unsigned int index = 0;
struct _mtk_btif_user_ *p_new_user = NULL;
struct _mtk_btif_ *p_btif = &g_btif[index];
struct list_head *p_user_list = &(p_btif->user_list);
BTIF_DBG_FUNC("++");
BTIF_DBG_FUNC("p_btif(0x%p)\n", p_btif);
if (mutex_lock_killable(&(p_btif->ops_mtx))) {
BTIF_ERR_FUNC("mutex_lock_killable return failed\n");
return E_BTIF_INTR;
}
if ((p_owner == NULL) || (p_id == NULL)) {
if (p_id)
*p_id = 0;
BTIF_ERR_FUNC("parameter invalid, p_owner(0x%p), p_id(0x%p)\n",
p_owner, p_id);
BTIF_MUTEX_UNLOCK(&(p_btif->ops_mtx));
return E_BTIF_INVAL_PARAM;
}
/*check if btif is already opened or not, if yes, just return fail*/
if (!list_empty(p_user_list)) {
struct list_head *pos = NULL;
struct _mtk_btif_user_ *p_user = NULL;
BTIF_ERR_FUNC("BTIF's user list is not empty\n");
list_for_each(pos, p_user_list) {
p_user = container_of(pos,
struct _mtk_btif_user_,
entry);
BTIF_INFO_FUNC("BTIF's user id(0x%lx), name(%s)\n",
p_user->u_id, p_user->u_name);
}
/*leave p_id alone*/
BTIF_MUTEX_UNLOCK(&(p_btif->ops_mtx));
return E_BTIF_ALREADY_OPEN;
}
p_new_user = vmalloc(sizeof(struct _mtk_btif_user_));
if (p_new_user != NULL) {
INIT_LIST_HEAD(&(p_new_user->entry));
p_new_user->enable = false;
p_new_user->p_btif = p_btif;
p_new_user->u_id = (unsigned long)p_new_user;
strncpy(p_new_user->u_name, p_owner,
sizeof(p_new_user->u_name) - 1);
p_new_user->u_name[sizeof(p_new_user->u_name) - 1] = '\0';
BTIF_DBG_FUNC("owner name:%s, recorded name:%s\n",
p_owner, p_new_user->u_name);
i_ret = btif_open(p_btif);
if (i_ret) {
BTIF_ERR_FUNC("btif_open failed, i_ret(%d)\n", i_ret);
*p_id = 0;
/*free btif new user's structure*/
vfree(p_new_user);
p_new_user = NULL;
} else {
BTIF_INFO_FUNC("btif_open succeed\n");
*p_id = p_new_user->u_id;
/*mark enable flag to true*/
p_new_user->enable = true;
/*add to uer lsit*/
list_add_tail(&(p_new_user->entry), p_user_list);
}
} else {
*p_id = 0;
i_ret = -ENOMEM;
BTIF_ERR_FUNC("alloc memory struct _mtk_btif_user_ failed\n");
}
BTIF_MUTEX_UNLOCK(&(p_btif->ops_mtx));
BTIF_DBG_FUNC("--");
return i_ret;
}
EXPORT_SYMBOL(mtk_wcn_btif_open);
/*****************************************************************************
* FUNCTION
* mtk_wcn_btif_close
* DESCRIPTION
* close BTIF interface, will do BTIF module HW and SW de-initialization
* once this API is called, p_btif should never be used by BTIF's user again
* PARAMETERS
* u_id [IN] BTIF's user id
* RETURNS
* int 0 = succeed;
* others = fail,
* for detailed information, please see ENUM_BTIF_OP_ERROR_CODE
*****************************************************************************/
int mtk_wcn_btif_close(unsigned long u_id)
{
int i_ret = -1;
struct _mtk_btif_ *p_btif = NULL;
struct list_head *pos = NULL;
struct list_head *p_user_list = NULL;
BTIF_DBG_FUNC("++");
p_btif = btif_exp_srh_id(u_id);
if (p_btif == NULL)
return E_BTIF_INVAL_PARAM;
if (mutex_lock_killable(&(p_btif->ops_mtx))) {
BTIF_ERR_FUNC("mutex_lock_killable return failed\n");
return E_BTIF_INTR;
}
p_user_list = &(p_btif->user_list);
list_for_each(pos, p_user_list) {
struct _mtk_btif_user_ *p_user =
container_of(pos, struct _mtk_btif_user_, entry);
if (p_user->u_id == u_id) {
BTIF_INFO_FUNC
("user who's id is 0x%lx deleted from user list\n",
u_id);
list_del(pos);
vfree(p_user);
i_ret = btif_close(p_btif);
if (i_ret)
BTIF_WARN_FUNC("BTIF close failed");
break;
}
}
BTIF_MUTEX_UNLOCK(&(p_btif->ops_mtx));
BTIF_DBG_FUNC("--");
return 0;
}
EXPORT_SYMBOL(mtk_wcn_btif_close);
/*****************************************************************************
* FUNCTION
* mtk_wcn_btif_write
* DESCRIPTION
* send data throuth BTIF module
* there's no internal buffer to cache STP data in BTIF driver,
* if in DMA mode
* btif driver will check if there's enough space in vFIFO for data to send
* in DMA mode
* if yes, put data to vFIFO and return corresponding data length to caller
* if no, corresponding error code will be returned to called
* PARAMETERS
* p_btif [IN] pointer returned by mtk_wcn_btif_open
* p_buf [IN] pointer to target data to send
* len [IN] data length (less than 2014 bytes per STP package)
*
* if in non-DMA mode, BTIF driver will try to write to THR of BTIF controller
* if btif driver detected that no space is available in Tx FIFO,
* will return E_BTIF_NO_SPACE, mostly something is wrong with BTIF or
* consys when this return value is returned
* RETURNS
* int positive: data length send through BTIF;
* negative: please see ENUM_BTIF_OP_ERROR_CODE
* E_BTIF_AGAIN (0) will be returned to caller
* if btif does not have enough vFIFO to send data,
* when caller get 0, he should wait for a moment
* (5~10ms maybe) and try a few times (maybe 10~20)
* if still get E_BTIF_AGAIN,
* should call BTIF's debug API and dump BTIF driver
* and BTIF/DMA register information to kernel log for debug
* E_BTIF_BAD_POINTER will be returned to caller
* if btif is not opened successfully before call this API
* E_BTIF_INVAL_PARAM will be returned if parameter is not valid
*****************************************************************************/
int mtk_wcn_btif_write(unsigned long u_id,
const unsigned char *p_buf, unsigned int len)
{
int i_ret = -1;
struct _mtk_btif_ *p_btif = NULL;
BTIF_DBG_FUNC("++");
p_btif = btif_exp_srh_id(u_id);
if (p_btif == NULL)
return E_BTIF_INVAL_PARAM;
if (p_buf == NULL) {
BTIF_ERR_FUNC("invalid p_buf (0x%p)\n", p_buf);
return E_BTIF_INVAL_PARAM;
}
if ((len == 0) || (len > BTIF_MAX_LEN_PER_PKT)) {
BTIF_ERR_FUNC("invalid buffer length(%d)\n", len);
return E_BTIF_INVAL_PARAM;
}
i_ret = btif_send_data(p_btif, p_buf, len);
BTIF_DBG_FUNC("--, i_ret:%d\n", i_ret);
return i_ret;
}
EXPORT_SYMBOL(mtk_wcn_btif_write);
/*****************************************************************************
* FUNCTION
* mtk_wcn_btif_read
* DESCRIPTION
* read data from BTIF module
* PARAMETERS
* p_btif [IN] pointer returned by mtk_wcn_btif_open
* p_buf [IN/OUT] pointer to buffer where rx data will be put
* max_len [IN] max buffer length
* RETURNS
* int positive: data length read from BTIF;
* negative: please see ENUM_BTIF_OP_ERROR_CODE
*****************************************************************************/
int mtk_wcn_btif_read(unsigned long u_id,
unsigned char *p_buf, unsigned int max_len)
{
return 0;
}
/*****************************************************************************
* FUNCTION
* mtk_wcn_btif_dpidle_ctrl
* DESCRIPTION
* control if BTIF module allow system enter deepidle state or not
* PARAMETERS
* p_btif [IN] pointer returned by mtk_wcn_btif_open
* en_flag [IN] one of enum _ENUM_BTIF_DPIDLE_
* RETURNS
* int always return 0
*****************************************************************************/
int mtk_wcn_btif_dpidle_ctrl(unsigned long u_id,
enum _ENUM_BTIF_DPIDLE_ en_flag)
{
int i_ret = -1;
struct _mtk_btif_ *p_btif = NULL;
p_btif = btif_exp_srh_id(u_id);
if (p_btif == NULL)
return E_BTIF_INVAL_PARAM;
if (en_flag == BTIF_DPIDLE_DISABLE)
i_ret = btif_exit_dpidle(p_btif);
else
i_ret = btif_enter_dpidle(p_btif);
return i_ret;
}
EXPORT_SYMBOL(mtk_wcn_btif_dpidle_ctrl);
/*****************************************************************************
* FUNCTION
* mtk_wcn_btif_rx_cb_register
* DESCRIPTION
* register rx callback function to BTIF module by btif user
* PARAMETERS
* p_btif [IN] pointer returned by mtk_wcn_btif_open
* rx_cb [IN] pointer to stp rx handler callback function,
* should be comply with MTK_WCN_BTIF_RX_CB
* RETURNS
* int 0 = succeed;
* others = fail, for detailed information,
* please see ENUM_BTIF_OP_ERROR_CODE
*****************************************************************************/
int mtk_wcn_btif_rx_cb_register(unsigned long u_id, MTK_WCN_BTIF_RX_CB rx_cb)
{
int i_ret = -1;
struct _mtk_btif_ *p_btif = NULL;
p_btif = btif_exp_srh_id(u_id);
if (p_btif == NULL)
return E_BTIF_INVAL_PARAM;
i_ret = btif_rx_cb_reg(p_btif, rx_cb);
return i_ret;
}
EXPORT_SYMBOL(mtk_wcn_btif_rx_cb_register);
/*****************************************************************************
* FUNCTION
* mtk_wcn_btif_wakeup_consys
* DESCRIPTION
* once sleep command is sent to con sys,
* should call this API before send wakeup command
* to make con sys aware host want to send data to consys
* PARAMETERS
* p_btif [IN] pointer returned by mtk_wcn_btif_open
* RETURNS
* int 0 = succeed; others = fail, for detailed information,
* please see ENUM_BTIF_OP_ERROR_CODE
*****************************************************************************/
int mtk_wcn_btif_wakeup_consys(unsigned long u_id)
{
int i_ret = -1;
struct _mtk_btif_ *p_btif = NULL;
p_btif = btif_exp_srh_id(u_id);
if (p_btif == NULL)
return E_BTIF_INVAL_PARAM;
/*i_ret = hal_btif_raise_wak_sig(p_btif->p_btif_info);*/
i_ret = btif_raise_wak_signal(p_btif);
return i_ret;
}
EXPORT_SYMBOL(mtk_wcn_btif_wakeup_consys);
/***************End of Normal Mode API declearation**********/
/***************Debug Purpose API declearation**********/
/*****************************************************************************
* FUNCTION
* mtk_wcn_btif_loopback_ctrl
* DESCRIPTION
* enable/disable BTIF internal loopback function,
* when this function is enabled data send to btif
* will be received by btif itself
* only for debug purpose, should never use this function in normal mode
* PARAMETERS
* p_btif [IN] pointer returned by mtk_wcn_btif_open
* enable [IN] loopback mode control flag, enable or disable,
* shou be one of enum _ENUM_BTIF_LPBK_MODE_
* RETURNS
* int 0 = succeed;
* others = fail, for detailed information, please see ENUM_BTIF_OP_ERROR_CODE
*****************************************************************************/
int mtk_wcn_btif_loopback_ctrl(unsigned long u_id,
enum _ENUM_BTIF_LPBK_MODE_ enable)
{
int i_ret = -1;
struct _mtk_btif_ *p_btif = NULL;
p_btif = btif_exp_srh_id(u_id);
if (p_btif == NULL)
return E_BTIF_INVAL_PARAM;
i_ret =
btif_lpbk_ctrl(p_btif, enable == BTIF_LPBK_ENABLE ? true : false);
return i_ret;
}
EXPORT_SYMBOL(mtk_wcn_btif_loopback_ctrl);
/*****************************************************************************
* FUNCTION
* mtk_wcn_btif_logger_ctrl
* DESCRIPTION
* control BTIF logger function's behavior
* PARAMETERS
* p_btif [IN] pointer returned by mtk_wcn_btif_open
* flag [IN] should be one of enum _ENUM_BTIF_DBG_ID_
* BTIF_DISABLE_LOGGER - disable btif logger
* BTIF_ENABLE_LOGGER - enable btif logger
* BTIF_DUMP_LOG - dump log logged by btif
* BTIF_CLR_LOG - clear btif log buffer
* BTIF_DUMP_BTIF_REG - dump btif controller's register
* BTIF_DUMP_DMA_REG - dump DMA controller's register
* RETURNS
* int 0 = succeed; others = fail, for detailed information,
* please see ENUM_BTIF_OP_ERROR_CODE
*****************************************************************************/
int mtk_wcn_btif_dbg_ctrl(unsigned long u_id, enum _ENUM_BTIF_DBG_ID_ flag)
{
int i_ret = -1;
struct _mtk_btif_ *p_btif = NULL;
p_btif = btif_exp_srh_id(u_id);
if (p_btif == NULL)
return E_BTIF_INVAL_PARAM;
i_ret = 0;
switch (flag) {
case BTIF_DISABLE_LOGGER:{
BTIF_INFO_FUNC
("disable btif log function for both Tx and Rx\n");
btif_log_buf_disable(&p_btif->tx_log);
btif_log_buf_disable(&p_btif->rx_log);
}
break;
case BTIF_ENABLE_LOGGER:{
BTIF_INFO_FUNC
("enable btif log function for both Tx and Rx\n");
btif_log_buf_enable(&p_btif->tx_log);
btif_log_buf_enable(&p_btif->rx_log);
}
break;
case BTIF_DUMP_LOG:{
BTIF_INFO_FUNC("dump btif log for both Tx and Rx\n");
btif_log_buf_dmp_out(&p_btif->tx_log);
btif_log_buf_dmp_out(&p_btif->rx_log);
}
break;
case BTIF_CLR_LOG:{
BTIF_INFO_FUNC("clear btif log for both Tx and Rx\n");
btif_log_buf_reset(&p_btif->tx_log);
btif_log_buf_reset(&p_btif->rx_log);
}
break;
case BTIF_DUMP_BTIF_REG:
btif_dump_reg(p_btif, REG_ALL);
break;
case BTIF_DUMP_BTIF_IRQ:
btif_dump_reg(p_btif, REG_IRQ);
break;
case BTIF_ENABLE_RT_LOG:
BTIF_INFO_FUNC
("enable btif real time log for both Tx and Rx\n");
btif_log_output_enable(&p_btif->tx_log);
btif_log_output_enable(&p_btif->rx_log);
break;
case BTIF_DISABLE_RT_LOG:
BTIF_INFO_FUNC
("disable btif real time log for both Tx and Rx\n");
btif_log_output_disable(&p_btif->tx_log);
btif_log_output_disable(&p_btif->rx_log);
break;
case BTIF_DUMP_DMA_VFIFO:
btif_dump_dma_vfifo(p_btif);
break;
default:
BTIF_INFO_FUNC("not supported flag:%d\n", flag);
i_ret = -2;
break;
}
return i_ret;
}
EXPORT_SYMBOL(mtk_wcn_btif_dbg_ctrl);
bool mtk_wcn_btif_parser_wmt_evt(unsigned long u_id,
const char *sub_str, unsigned int str_len)
{
bool b_ret = false;
struct _mtk_btif_ *p_btif = NULL;
p_btif = btif_exp_srh_id(u_id);
if (p_btif == NULL)
return E_BTIF_INVAL_PARAM;
b_ret = btif_parser_wmt_evt(p_btif, sub_str, str_len);
BTIF_INFO_FUNC("parser wmt evt %s\n", b_ret ? "ok" : "fail");
return b_ret;
}
EXPORT_SYMBOL(mtk_wcn_btif_parser_wmt_evt);
/**********End of Debug Purpose API declearation**********/
int btif_open_no_id(void)
{
int i_ret = 0;
struct _mtk_btif_ *p_btif = &g_btif[0];
i_ret = btif_open(p_btif);
if (i_ret)
BTIF_ERR_FUNC("btif_open failed, i_ret(%d)\n", i_ret);
else
BTIF_INFO_FUNC("btif_open succeed\n");
return i_ret;
}
int btif_close_no_id(void)
{
int i_ret = 0;
struct _mtk_btif_ *p_btif = &g_btif[0];
i_ret = btif_close(p_btif);
if (i_ret)
BTIF_ERR_FUNC("btif_close failed, i_ret(%d)\n", i_ret);
else
BTIF_INFO_FUNC("btif_close succeed\n");
return i_ret;
}
int btif_write_no_id(const unsigned char *p_buf, unsigned int len)
{
int i_ret = -1;
struct _mtk_btif_ *p_btif = &g_btif[0];
BTIF_DBG_FUNC("++");
if (p_buf == NULL) {
BTIF_ERR_FUNC("invalid p_buf (0x%p)\n", p_buf);
return E_BTIF_INVAL_PARAM;
}
if ((len == 0) || (len > BTIF_MAX_LEN_PER_PKT)) {
BTIF_ERR_FUNC("invalid buffer length(%d)\n", len);
return E_BTIF_INVAL_PARAM;
}
i_ret = btif_send_data(p_btif, p_buf, len);
BTIF_DBG_FUNC("--, i_ret:%d\n", i_ret);
return i_ret;
}
int btif_dpidle_ctrl_no_id(enum _ENUM_BTIF_DPIDLE_ en_flag)
{
int i_ret = -1;
struct _mtk_btif_ *p_btif = &g_btif[0];
if (en_flag == BTIF_DPIDLE_DISABLE)
i_ret = btif_exit_dpidle(p_btif);
else
i_ret = btif_enter_dpidle(p_btif);
return i_ret;
}
int btif_wakeup_consys_no_id(void)
{
int i_ret = -1;
struct _mtk_btif_ *p_btif = &g_btif[0];
/*i_ret = hal_btif_raise_wak_sig(p_btif->p_btif_info);*/
i_ret = btif_raise_wak_signal(p_btif);
return i_ret;
}
int btif_loopback_ctrl_no_id(enum _ENUM_BTIF_LPBK_MODE_ enable)
{
int i_ret = -1;
struct _mtk_btif_ *p_btif = &g_btif[0];
i_ret =
btif_lpbk_ctrl(p_btif, enable == BTIF_LPBK_ENABLE ? true : false);
return i_ret;
}
int btif_dbg_ctrl_no_id(enum _ENUM_BTIF_DBG_ID_ flag)
{
int i_ret = -1;
struct _mtk_btif_ *p_btif = &g_btif[0];
i_ret = 0;
switch (flag) {
case BTIF_DISABLE_LOGGER:{
BTIF_INFO_FUNC
("disable btif log function for both Tx and Rx\n");
btif_log_buf_disable(&p_btif->tx_log);
btif_log_buf_disable(&p_btif->rx_log);
}
break;
case BTIF_ENABLE_LOGGER:{
BTIF_INFO_FUNC
("enable btif log function for both Tx and Rx\n");
btif_log_buf_enable(&p_btif->tx_log);
btif_log_buf_enable(&p_btif->rx_log);
}
break;
case BTIF_DUMP_LOG:{
BTIF_INFO_FUNC("dump btif log for both Tx and Rx\n");
btif_log_buf_dmp_out(&p_btif->tx_log);
btif_log_buf_dmp_out(&p_btif->rx_log);
}
break;
case BTIF_CLR_LOG:{
BTIF_INFO_FUNC("clear btif log for both Tx and Rx\n");
btif_log_buf_reset(&p_btif->tx_log);
btif_log_buf_reset(&p_btif->rx_log);
}
break;
case BTIF_DUMP_BTIF_REG:
btif_dump_reg(p_btif, REG_ALL);
break;
case BTIF_DUMP_BTIF_IRQ:
btif_dump_reg(p_btif, REG_IRQ);
break;
case BTIF_ENABLE_RT_LOG:
BTIF_INFO_FUNC
("enable btif real time log for both Tx and Rx\n");
btif_log_output_enable(&p_btif->tx_log);
btif_log_output_enable(&p_btif->rx_log);
break;
case BTIF_DISABLE_RT_LOG:
BTIF_INFO_FUNC
("disable btif real time log for both Tx and Rx\n");
btif_log_output_disable(&p_btif->tx_log);
btif_log_output_disable(&p_btif->rx_log);
break;
default:
BTIF_INFO_FUNC("not supported flag:%d\n", flag);
i_ret = -2;
break;
}
return i_ret;
}
int mtk_btif_exp_open_test(void)
{
int i_ret = 0;
i_ret = btif_open_no_id();
if (i_ret < 0) {
BTIF_INFO_FUNC("mtk_wcn_btif_open failed\n");
return -1;
}
BTIF_INFO_FUNC("mtk_wcn_btif_open succeed\n");
return i_ret;
}
int mtk_btif_exp_close_test(void)
{
int i_ret = 0;
i_ret = btif_close_no_id();
if (i_ret < 0) {
BTIF_INFO_FUNC("mtk_wcn_btif_close failed\n");
return -1;
}
BTIF_INFO_FUNC("mtk_wcn_btif_close succeed\n");
return i_ret;
}
int mtk_btif_exp_write_test(void)
{
return mtk_btif_exp_write_stress_test(100, 10);
}
int mtk_btif_exp_write_stress_test(unsigned int length, unsigned int max_loop)
{
#define BUF_LEN 1024
int i_ret = 0;
int idx = 0;
int buf_len = length > BUF_LEN ? BUF_LEN : length;
int loop = max_loop > 1000000 ? 1000000 : max_loop;
unsigned char *buffer;
buffer = kmalloc(BUF_LEN, GFP_KERNEL);
if (!buffer) {
BTIF_ERR_FUNC("btif tester kmalloc failed\n");
return -1;
}
for (idx = 0; idx < buf_len; idx++)
/* btif_stress_test_buf[idx] = BUF_LEN -idx; */
*(buffer + idx) = idx % 255;
i_ret = btif_loopback_ctrl_no_id(BTIF_LPBK_ENABLE);
BTIF_INFO_FUNC("mtk_wcn_btif_loopback_ctrl returned %d\n", i_ret);
while (loop--) {
i_ret = btif_write_no_id(buffer, buf_len);
BTIF_INFO_FUNC("mtk_wcn_btif_write left loop:%d, i_ret:%d\n",
loop, i_ret);
if (i_ret != buf_len) {
BTIF_INFO_FUNC("target len %d, sent len: %d\n",
buf_len, i_ret);
break;
}
buf_len--;
if (buf_len <= 0)
buf_len = length > BUF_LEN ? BUF_LEN : length;
}
kfree(buffer);
return i_ret;
}
int mtk_btif_exp_suspend_test(void)
{
int i_ret = 0;
struct _mtk_btif_ *p_btif = &g_btif[0];
i_ret = _btif_suspend(p_btif);
return i_ret;
}
int mtk_btif_exp_restore_noirq_test(void)
{
int i_ret = 0;
struct _mtk_btif_ *p_btif = &g_btif[0];
i_ret = _btif_restore_noirq(p_btif);
return i_ret;
}
int mtk_btif_exp_clock_ctrl(int en)
{
int i_ret = 0;
struct _mtk_btif_ *p_btif = &g_btif[0];
i_ret = btif_clock_ctrl(p_btif, en);
return i_ret;
}
int mtk_btif_exp_resume_test(void)
{
int i_ret = 0;
struct _mtk_btif_ *p_btif = &g_btif[0];
i_ret = _btif_resume(p_btif);
return i_ret;
}
int mtk_btif_exp_enter_dpidle_test(void)
{
return btif_dpidle_ctrl_no_id(BTIF_DPIDLE_ENABLE);
}
int mtk_btif_exp_exit_dpidle_test(void)
{
return btif_dpidle_ctrl_no_id(BTIF_DPIDLE_DISABLE);
}
int mtk_btif_exp_log_debug_test(int flag)
{
int i_ret = 0;
i_ret = btif_dbg_ctrl_no_id(flag);
return i_ret;
}
void mtk_btif_read_cpu_sw_rst_debug_exp(void)
{
mtk_btif_read_cpu_sw_rst_debug();
}
int mtk_btif_exp_rx_has_pending_data(unsigned long u_id)
{
struct _mtk_btif_ *p_btif = NULL;
int has_pending_data = 0;
p_btif = btif_exp_srh_id(u_id);
if (p_btif == NULL) {
BTIF_ERR_FUNC("parameter invalid\n");
return E_BTIF_INVAL_PARAM;
}
/* Lock the data path to ensure that the current data path is
* not processing data. If fail to get lock, it means rx data
* path is busy and we assume there has pending data to avoid
* thread is blocked here.
*/
if (btif_rx_data_path_lock(p_btif))
return 1;
has_pending_data = btif_rx_buf_has_pending_data(p_btif);
if (has_pending_data == 0)
has_pending_data = btif_rx_dma_has_pending_data(p_btif);
btif_rx_data_path_unlock(p_btif);
return has_pending_data;
}
EXPORT_SYMBOL(mtk_btif_exp_rx_has_pending_data);
int mtk_btif_exp_tx_has_pending_data(unsigned long u_id)
{
struct _mtk_btif_ *p_btif = NULL;
p_btif = btif_exp_srh_id(u_id);
if (p_btif == NULL) {
BTIF_ERR_FUNC("E_BTIF_INVAL_PARAM\n");
return E_BTIF_INVAL_PARAM;
}
return btif_tx_dma_has_pending_data(p_btif);
}
EXPORT_SYMBOL(mtk_btif_exp_tx_has_pending_data);
int mtk_btif_is_tx_complete(unsigned long u_id)
{
struct _mtk_btif_ *p_btif = NULL;
p_btif = btif_exp_srh_id(u_id);
if (p_btif == NULL) {
BTIF_ERR_FUNC("E_BTIF_INVAL_PARAM\n");
return E_BTIF_INVAL_PARAM;
}
return btif_is_tx_complete(p_btif);
}
EXPORT_SYMBOL(mtk_btif_is_tx_complete);
struct task_struct *mtk_btif_exp_rx_thread_get(unsigned long u_id)
{
struct _mtk_btif_ *p_btif = NULL;
p_btif = btif_exp_srh_id(u_id);
if (p_btif == NULL) {
BTIF_ERR_FUNC("E_BTIF_INVAL_PARAM\n");
return NULL;
}
return btif_rx_thread_get(p_btif);
}
EXPORT_SYMBOL(mtk_btif_exp_rx_thread_get);
/************End of Function**********/