Files
2026-08-24 10:03:24 +08:00

256 lines
7.8 KiB
C
Executable File

/* Copyright Statement:
*
* This software/firmware and related documentation ("MediaTek Software") are
* protected under relevant copyright laws. The information contained herein is
* confidential and proprietary to MediaTek Inc. and/or its licensors. Without
* the prior written permission of MediaTek inc. and/or its licensors, any
* reproduction, modification, use or disclosure of MediaTek Software, and
* information contained herein, in whole or in part, shall be strictly
* prohibited.
*
* MediaTek Inc. (C) 2014. All rights reserved.
*
* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
* ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
* WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
* NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
* RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
* INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
* TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
* RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
* OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
* SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
* RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
* ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
* RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
* MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
* CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
*
* The following software/firmware and/or related documentation ("MediaTek
* Software") have been modified by MediaTek Inc. All revisions are subject to
* any receiver's applicable license agreements with MediaTek Inc.
*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <pthread.h>
#include <time.h>
#include <stdint.h>
#include "bt_hci_bdroid.h"
#include "bt_vendor_lib.h"
#include "bt_mtk.h"
#ifndef MTK_LINUX
#include <cutils/properties.h>
#endif
/**************************************************************************
* G L O B A L D E F I N E *
***************************************************************************/
#define BT_IDME_MAC_FILE_NAME "/proc/idme/bt_mac_addr"
/**************************************************************************
* G L O B A L V A R I A B L E S *
***************************************************************************/
BT_INIT_VAR_T btinit[1];
BT_INIT_CB_T btinit_ctrl;
static uint16_t wOpCode;
static HCI_CMD_STATUS_T cmd_status;
extern bt_vendor_callbacks_t *bt_vnd_cbacks;
static BOOL fgGetEFUSE = FALSE;
static UCHAR ucDefaultAddr[6];
static UCHAR ucZeroAddr[6];
VOID thread_exit(INT32 signo)
{
pthread_t tid = pthread_self();
LOG_DBG("Thread %lu is forced to exit...\n", tid);
if (pthread_mutex_unlock(&btinit_ctrl.mutex) != 0) {
LOG_ERROR("pthread_mutex_unlock error\n");
}
pthread_mutexattr_destroy(&btinit_ctrl.attr);
pthread_mutex_destroy(&btinit_ctrl.mutex);
pthread_cond_destroy(&btinit_ctrl.cond);
pthread_exit(0);
}
static VOID HCI_Command_Complete(VOID *p_evt)
{
HC_BT_HDR *p_buf = (HC_BT_HDR *)p_evt;
uint8_t *p;
uint8_t event, status;
uint16_t opcode;
BOOL success;
LOG_DBG("HCI_Command_Complete\n");
p = (uint8_t *)(p_buf + 1);
event = *p;
p += 3;
STREAM_TO_UINT16(opcode, p);
status = *p;
if ((event == 0x0E) && /* Command Complete Event */
(opcode == wOpCode) && /* OpCode correct */
(status == 0)) /* Success */
{
success = TRUE;
} else {
success = FALSE;
}
if (bt_vnd_cbacks) {
bt_vnd_cbacks->dealloc(p_buf);
}
pthread_mutex_lock(&btinit_ctrl.mutex);
cmd_status = success ? CMD_SUCCESS : CMD_FAIL;
/* Wake up command tx thread */
pthread_cond_signal(&btinit_ctrl.cond);
pthread_mutex_unlock(&btinit_ctrl.mutex);
return;
}
static void idme_get_bt_mac_addr(unsigned char *pucBDAddr)
{
int bt_idme_file_fd = -1;
int i;
char bt_mac_addrs[12] = {0};
char buf[3] = {0};
int size = 0;
LOG_DBG("Get BT addr\n");
bt_idme_file_fd = open(BT_IDME_MAC_FILE_NAME, O_RDONLY);
if (bt_idme_file_fd < 0) {
LOG_ERROR("Open BT addr fails\n");
return;
}
size = read(bt_idme_file_fd, bt_mac_addrs, sizeof(bt_mac_addrs));
if (size < 0 || size != 12) {
LOG_ERROR("Read BT addr fails, size:%d\n", size);
close(bt_idme_file_fd);
return;
}
for (i = 0; i < 12; i += 2) {
buf[0] = bt_mac_addrs[i];
buf[1] = bt_mac_addrs[i + 1];
pucBDAddr[i >> 1] = (unsigned char)strtoul(buf, NULL, 16);
LOG_DBG("i = %d, addr = %02x", i >> 1, pucBDAddr[i >> 1]);
}
close(bt_idme_file_fd);
LOG_DBG("Get BT addr PASS\n");
}
static bool HCI_Set_Local_BD_Addr(HC_BT_HDR *p_cmd)
{
int i;
bool ret = false;
uint8_t *p;
unsigned char BD_address[6] = {0};
wOpCode = HCI_SET_BD_ADDRESS_OP_CODE;
idme_get_bt_mac_addr(BD_address); /* Get address from idme */
p_cmd->len = 9;
p = (uint8_t *)(p_cmd + 1);
UINT16_TO_STREAM(p, wOpCode);
*p++ = 6;
for (i = 5; i >= 0; i--) {
*p++ = BD_address[i];
}
/* Send command */
if (bt_vnd_cbacks) {
ret = bt_vnd_cbacks->xmit_cb(wOpCode, p_cmd, HCI_Command_Complete);
}
return ret;
}
VOID *GORM_FW_Init_Thread(VOID *ptr)
{
INT32 i = 0;
HC_BT_HDR *p_buf = NULL;
bt_vendor_op_result_t ret = BT_VND_OP_RESULT_FAIL;
LOG_DBG("FW init thread starts\n");
pthread_mutexattr_init(&btinit_ctrl.attr);
pthread_mutexattr_settype(&btinit_ctrl.attr, PTHREAD_MUTEX_ERRORCHECK);
pthread_mutex_init(&btinit_ctrl.mutex, &btinit_ctrl.attr);
pthread_cond_init(&btinit_ctrl.cond, NULL);
p_buf = NULL;
if (bt_vnd_cbacks) {
p_buf = (HC_BT_HDR *)bt_vnd_cbacks->alloc(BT_HC_HDR_SIZE + \
HCI_CMD_MAX_SIZE);
}
else {
LOG_ERROR("No libbt-hci callbacks!\n");
}
if (p_buf) {
p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
p_buf->offset = 0;
p_buf->layer_specific = 0;
cmd_status = CMD_PENDING;
if (HCI_Set_Local_BD_Addr(p_buf) == FALSE) {
LOG_ERROR("Send command %d fails\n", i);
if (bt_vnd_cbacks) {
bt_vnd_cbacks->dealloc(p_buf);
}
goto exit;
}
}
else {
LOG_ERROR("Alloc command %d buffer fails\n", i);
goto exit;
}
/* Wait for event returned */
pthread_mutex_lock(&btinit_ctrl.mutex);
while (cmd_status == CMD_PENDING) {
pthread_cond_wait(&btinit_ctrl.cond, &btinit_ctrl.mutex);
}
if (cmd_status == CMD_FAIL) {
LOG_ERROR("The event of command %d error\n", i);
pthread_mutex_unlock(&btinit_ctrl.mutex);
goto exit;
}
else {
LOG_DBG("The event of command %d success\n", i);
pthread_mutex_unlock(&btinit_ctrl.mutex);
}
ret = BT_VND_OP_RESULT_SUCCESS;
exit:
pthread_mutexattr_destroy(&btinit_ctrl.attr);
pthread_mutex_destroy(&btinit_ctrl.mutex);
pthread_cond_destroy(&btinit_ctrl.cond);
if (bt_vnd_cbacks) {
bt_vnd_cbacks->fwcfg_cb(ret);
}
btinit_ctrl.worker_thread_running = FALSE;
return NULL;
}