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

1873 lines
44 KiB
C

/*
*
* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
* Not a Contribution.
*
* Copyright 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you
* may not use this file except in compliance with the License. You may
* obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
*/
/******************************************************************************
*
* Filename: hciattach_aml.c
*
* Description: Contains controller-specific functions, like
* firmware patch download
* low power mode operations
*
******************************************************************************/
#define LOG_TAG "bt_vendor"
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <time.h>
#include <errno.h>
#include <fcntl.h>
#include <dirent.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <bluetooth/bluetooth.h>
#include "hciattach_aml.h"
#include "hciattach.h"
#ifdef __cplusplus
}
#endif
/******************************************************************************
** Macro Definition
******************************************************************************/
#define pr_info(fmt, args...) fprintf(stdout,"[%s] " fmt "\n", __func__, ##args)
#define pr_err(fmt, args...) fprintf(stdout,"[%s]--[ERROR] [%d] " fmt "\n", __func__, __LINE__, ##args)
/*mac addr len */
#define MAC_LEN 6
#define MAC_DELAY 600
uint8_t vendor_local_addr[MAC_LEN];
#define SAVE_MAC "/etc/bluetooth/aml/bt_mac"
/*fwICCM is 0 to download*/
#define fwICCM 0
/*fwDCCM is 1 to download*/
#define fwDCCM 1
#define CHECK_FW 0
#define HCI_EVT_CMD_CMPL_LOCAL_NAME_STRING 6
#define UINT8_TO_STREAM(p, u8) { *(p)++ = (uint8_t)(u8); }
#define UINT16_TO_STREAM(p, u16) { *(p)++ = (uint8_t)(u16); *(p)++ = (uint8_t)((u16) >> 8); }
#define UINT32_TO_STREAM(p, u32) { *(p)++ = (uint8_t)(u32); *(p)++ = (uint8_t)((u32) >> 8); *(p)++ = (uint8_t)((u32) >> 16); *(p)++ = (uint8_t)((u32) >> 24); }
#define ICCM_RAM_BASE (0x000000)
#define DCCM_RAM_BASE (0xd00000)
#define RW_OPERATION_SIZE (248)
#define TCI_READ_REG 0xfef0
#define TCI_WRITE_REG 0xfef1
#define TCI_UPDATE_UART_BAUDRATE 0xfef2
#define TCI_DOWNLOAD_BT_FW 0xfef3
#define HCI_VSC_WRITE_BD_ADDR 0xFC1A
#define ICCM_DCCM_MAX (32 * 1024 * 1024)
/*AML FW DEFINE FILE PATH*/
/*Current module*/
static int AML_MODULE = W1_UART;
#define USB_POWER_UP _IO('m', 1)
#define USB_POWER_DOWN _IO('m', 2)
#define SDIO_POWER_UP _IO('m', 3)
#define SDIO_POWER_DOWN _IO('m', 4)
#define SDIO_GET_DEV_TYPE _IO('m', 5)
#define GET_AML_WIFI_MODULE _IO('m', 7)
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
/******************************************************************************
** Variables
******************************************************************************/
#if 0
unsigned int fwICCM_len = 0,
unsigned int fwICCM_offset = 0;
unsigned int fwDCCM_len = 0,
unsigned int fwDCCM_offset = 0;
#endif
static vnd_userial_cb_t vnd_userial;
static int antenna_number = 2;
static int load_efuse = 0;
/******************************************************************************
** Extern variables
******************************************************************************/
//extern unsigned char vnd_local_bd_addr[6];
static const vnd_module_t aml_module[] ={
{W1_UART, 256, "W1_UART", "aml_w1", AML_W1_BT_FW_UART_FILE },
{W1U_UART, 256, "W1U_UART", "aml_w1u_s", AML_W1U_BT_FW_UART_FILE},
{W2_UART, 256, "W2_UART", "aml_w2_s", AML_W2_BT_FW_UART_FILE },
{W2L_UART, 384, "W2L_UART", "aml_w2l_s", AML_W2L_BT_FW_UART_FILE},
};
static const vnd_chip_t aml_chip[] ={
{W1_UART, "0x8888"},
{W1U_UART, "0x0540"},
{W2_UART, "0x0640"},
{W2_UART, "0x0642"}, // pice module
{W2L_UART, "0x0800"},
{W2L_UART, "0x0840"},
};
typedef int (*callback)(int);
static int do_write(int fd, unsigned char *buf, int len)
{
int ret = 0;
int write_offset = 0;
int write_len = len;
do {
ret = write(fd, buf + write_offset, write_len);
if (ret < 0) {
pr_info("write fail ret:%d,err:%s", ret, strerror(errno));
return ret;
} else if (ret == 0) {
pr_info("write fail with ret:0,err:%s", strerror(errno));
return ret;
} else {
if (ret < write_len) {
pr_info("write pending,do write ret:%d,err:%s", ret, strerror(errno));
write_len = write_len - ret;
write_offset = ret;
} else {
pr_info("write success");
break;
}
}
} while (1);
return len;
}
static int aml_hci_send_cmd(int fd, unsigned char *cmd, int cmd_size, unsigned char *rsp,
unsigned int rsp_size)
{
int ret = -1;
ret = do_write(fd, cmd, cmd_size);
if (ret != cmd_size) {
pr_info("send fail,ret:%d", ret);
goto exit;
}
memset(rsp, 0, rsp_size);
/* Wait for command complete event */
ret = read_hci_event(fd, rsp, rsp_size);
if (ret < 0) {
pr_info("read fail,ret:%d", ret);
goto exit;
}
exit:
return ret;
}
static int aml_set_wake_manf_data(int fd)
{
int ret = 0;
unsigned char rsp[HCI_MAX_EVENT_SIZE] = {'0'};
unsigned char APCF_config_manf_data[] =
{0x01, 0x22, 0xFC, 0x05, 0x19, 0xff, 0x01, 0x0a, 0xb};
if (AML_MODULE != W1_UART) {
pr_info("set wake APCF_config_manf_data");
ret = aml_hci_send_cmd(fd, (unsigned char *)APCF_config_manf_data,
sizeof(APCF_config_manf_data),(unsigned char *)rsp, HCI_MAX_EVENT_SIZE);
}
return ret;
}
static int aml_woble_configure(int fd)
{
unsigned char rsp[HCI_MAX_EVENT_SIZE] = {'0'};
unsigned char reset_cmd[] = {0x01, 0x03, 0x0C, 0x00};
unsigned char read_BD_ADDR[] = {0x01, 0x09, 0x10, 0x00};
unsigned char APCF_config_manf_data[] =
{0x01, 0x22, 0xFC, 0x05, 0x19, 0xff, 0x01, 0x0a, 0xb};
unsigned char APCF_enable[] = {0x01, 0x57, 0xFD, 0x02, 0x00, 0x01};
unsigned char le_set_evt_mask[] =
{0x01, 0x01, 0x20, 0x08, 0x7F, 0x1A, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00};
unsigned char le_scan_param_setting[] =
{0x01, 0x0b, 0x20, 0x07, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00};
unsigned char le_scan_enable[] = {0x01, 0x0c, 0x20, 0x02, 0x01, 0x00};
unsigned char host_sleep_VSC[] = {0x01, 0x21, 0xfc, 0x01, 0x01};
if (AML_MODULE == W1_UART) {
pr_info("W1_UART set aml_woble_cfg");
aml_hci_send_cmd(fd, (unsigned char *)reset_cmd, sizeof(reset_cmd),
(unsigned char *)rsp, HCI_MAX_EVENT_SIZE);
aml_hci_send_cmd(fd, (unsigned char *)host_sleep_VSC, sizeof(host_sleep_VSC),
(unsigned char *)rsp, HCI_MAX_EVENT_SIZE);
aml_hci_send_cmd(fd, (unsigned char *)APCF_config_manf_data,
sizeof(APCF_config_manf_data),(unsigned char *)rsp, HCI_MAX_EVENT_SIZE);
aml_hci_send_cmd(fd, (unsigned char *)le_set_evt_mask,
sizeof(le_set_evt_mask), (unsigned char *)rsp, HCI_MAX_EVENT_SIZE);
aml_hci_send_cmd(fd, (unsigned char *)le_scan_param_setting,
sizeof(le_scan_param_setting), (unsigned char *)rsp, HCI_MAX_EVENT_SIZE);
aml_hci_send_cmd(fd, (unsigned char *)le_scan_enable,
sizeof(le_scan_enable), (unsigned char *)rsp, HCI_MAX_EVENT_SIZE);
} else {
pr_info("other amlbt set aml_woble_cfg");
aml_hci_send_cmd(fd, (unsigned char *)reset_cmd, sizeof(reset_cmd),
(unsigned char *)rsp, HCI_MAX_EVENT_SIZE);
}
return 0;
}
static int antenna_number_act(const char * p_name, char * p_value)
{
antenna_number = strtol(p_value, NULL, 10);
if (antenna_number == 0) {
pr_info("antenna_number use default value 2");
antenna_number = 2;
}
pr_info("%s = %d", p_name, antenna_number);
}
static int load_efuse_act(const char * p_name, char* p_value)
{
load_efuse = strtol(p_value, NULL, 10);
pr_info("%s = %d", p_name, load_efuse);
}
static const d_entry_t entry_table[] = {
{"antenna_number", antenna_number_act},
{"load_efuse", load_efuse_act},
{NULL, NULL}
};
/*****************************************************************************
** Functions
*****************************************************************************/
/*******************************************************************************
**
** Function aml_userial_to_tcio_baud
**
** Description helper function converts USERIAL baud rates into TCIO
** conforming baud rates
**
** Returns TRUE/FALSE
**
*******************************************************************************/
static unsigned char aml_userial_to_tcio_baud(unsigned char cfg_baud, unsigned int *baud)
{
if (cfg_baud == USERIAL_BAUD_115200)
*baud = B115200;
else if (cfg_baud == USERIAL_BAUD_4M)
*baud = B4000000;
else if (cfg_baud == USERIAL_BAUD_3M)
*baud = B3000000;
else if (cfg_baud == USERIAL_BAUD_2M)
*baud = B2000000;
else if (cfg_baud == USERIAL_BAUD_1M)
*baud = B1000000;
else if (cfg_baud == USERIAL_BAUD_921600)
*baud = B921600;
else if (cfg_baud == USERIAL_BAUD_460800)
*baud = B460800;
else if (cfg_baud == USERIAL_BAUD_230400)
*baud = B230400;
else if (cfg_baud == USERIAL_BAUD_57600)
*baud = B57600;
else if (cfg_baud == USERIAL_BAUD_19200)
*baud = B19200;
else if (cfg_baud == USERIAL_BAUD_9600)
*baud = B9600;
else if (cfg_baud == USERIAL_BAUD_1200)
*baud = B1200;
else if (cfg_baud == USERIAL_BAUD_600)
*baud = B600;
else
{
pr_err("userial vendor open: unsupported baud idx %i", cfg_baud);
*baud = B115200;
return FALSE;
}
return TRUE;
}
static int get_config(const char* file)
{
FILE * config_fd;
char line[MAX_LINE_LEN +1] = {0};
char *p_name = NULL;
char *p_value = NULL;
d_entry_t * temp_table = NULL;
config_fd = fopen(file, "r");
if (config_fd == NULL) {
pr_err("open file:%s fail", file);
return 0;
}
while (fgets(line, MAX_LINE_LEN +1, config_fd) != NULL) {
if (line[0] == '#') {
continue;
}
p_name = strtok(line, DELIM);
if (p_name == NULL) {
continue;
}
p_value = strtok(NULL, DELIM);
temp_table = (d_entry_t*)entry_table;
while (temp_table->entry_name != NULL) {
if (!strcmp(temp_table->entry_name, p_name)) {
temp_table->p_action(temp_table->entry_name, p_value);
break;
}
temp_table ++;
}
}
fclose(config_fd);
return 1;
}
/******************************************************************************
** delay function
******************************************************************************/
static void ms_delay(uint32_t timeout)
{
struct timespec delay;
int err;
if (timeout == 0)
return;
delay.tv_sec = timeout / 1000;
delay.tv_nsec = 1000 * 1000 * (timeout % 1000);
/* [u]sleep can't be used because it uses SIGALRM */
do {
err = nanosleep(&delay, &delay);
} while (err < 0 && errno == EINTR);
}
/******************************************************************************
** save file
******************************************************************************/
static uint8_t * aml_getprop_read(const char* str)
{
int fd, n;
char buf[18];
memset(buf, '\0', sizeof(buf));
fd = open(str, O_RDONLY|O_CREAT, 0666);
if (fd < 0)
{
perror("open SAVE_MAC read");
goto error;
}
n = read(fd, buf, sizeof(buf)-1);
if (n < sizeof(buf)-1)
{
pr_info("n < sizeof(buf)");
close(fd);
goto error;
}
buf[sizeof(buf)-1] ='\0';
close(fd);
if (strnlen(buf, 17) != 17)
{
pr_info("don't matching bt mac");
goto error;
}
sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
&vendor_local_addr[0], &vendor_local_addr[1], &vendor_local_addr[2],\
&vendor_local_addr[3], &vendor_local_addr[4], &vendor_local_addr[5]);
return vendor_local_addr;
error:
return NULL;
}
static int aml_setprop_write(const char *str, int size)
{
int err = -1;
int fd;
fd = open(SAVE_MAC, O_WRONLY|O_CREAT, 0666);
if (fd < 0)
{
perror("open SAVE_MAC write");
goto error;
}
err = write(fd, str, size);
if (err != size)
{
pr_err("write fail");
}
close(fd);
error:
return err;
}
static int get_fw_version(char *str)
{
int fd;
int ret;
char * fw_version = NULL;
str = str + 7; //skip 7byte
ret = asprintf(&fw_version, "fw_version: date = %02x.%02x, number = 0x%02x%02x\n", *(str+1),*str,*(str+3),*(str+2));
if (ret <= 0)
{
goto error;
}
fd = open(FW_VER_FILE, O_WRONLY|O_CREAT|O_TRUNC, 0666);
if (fd < 0)
{
pr_err("open fw_file fail");
free(fw_version);
goto error;
}
write(fd, fw_version, strlen(fw_version));
free(fw_version);
close(fd);
error:
return 0;
}
/******************************************************************************
** set bdaddr
******************************************************************************/
static int aml_set_bdaddr(int fd)
{
int size;
int err = -1;
unsigned char cmd[HCI_MAX_CMD_SIZE];
unsigned char rsp[HCI_MAX_EVENT_SIZE];
char *cmd_hdr = NULL;
char buf[18];
uint8_t *tempbuf;
uint8_t local_addr[MAC_LEN];
if ((tempbuf = aml_getprop_read(NUIFYKEY_MAC)) != NULL)
{
memcpy(local_addr, tempbuf, MAC_LEN);
goto set_mac;
}
else if ((tempbuf = aml_getprop_read(SAVE_MAC)) != NULL)
{
memcpy(local_addr, tempbuf, MAC_LEN);
goto set_mac;
}
memset(buf, '\0', sizeof(buf));
srand(time(NULL));
memset(local_addr, '\0', MAC_LEN);
local_addr[0] = 0x22;
local_addr[1] = 0x22;
local_addr[2] = (uint8_t)rand();
local_addr[3] = (uint8_t)rand();
local_addr[4] = (uint8_t)rand();
local_addr[5] = (uint8_t)rand();
sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x",local_addr[0],\
local_addr[1], local_addr[2], local_addr[3], local_addr[4], local_addr[5]);
err = aml_setprop_write(buf, sizeof(buf));
if (err < 0)
{
pr_info("aml_getprop_write fail");
}
set_mac:
pr_info("set bdaddr: %02x:%02x:%02x:%02x:%02x:%02x", local_addr[0],\
local_addr[1], local_addr[2], local_addr[3], local_addr[4], local_addr[5]);
memset(cmd, 0x0, HCI_MAX_CMD_SIZE);
memset(rsp, 0x0, HCI_MAX_EVENT_SIZE);
cmd_hdr = (void *) (cmd + 1);
cmd[0] = HCI_COMMAND_PKT;
UINT16_TO_STREAM(cmd_hdr, HCI_VSC_WRITE_BD_ADDR);
*cmd_hdr++ = MAC_LEN;
*cmd_hdr++ = local_addr[5];
*cmd_hdr++ = local_addr[4];
*cmd_hdr++ = local_addr[3];
*cmd_hdr++ = local_addr[2];
*cmd_hdr++ = local_addr[1];
*cmd_hdr++ = local_addr[0];
size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + MAC_LEN);
err = write(fd, cmd, size);
if (err != size) {
pr_err("Send failed with ret value: %d", err);
goto error;
}
/* Wait for command complete event */
err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE);
if ( err < 0) {
pr_err("Failed to set patch info on Controllern");
goto error;
}
if (rsp[4] != cmd[1] || rsp[5] != cmd[2] || rsp[6] != 0X00) {
pr_err("Failed to set_bdaddr, command failure");
return -1;
}
get_fw_version(rsp);
pr_info("success");
error:
return err;
}
/*******************************************************************************
**
** Function hw_config_set_rf_params
**
** Description Config rf parameters to controller
**
** Returns
**
**
*******************************************************************************/
static int hw_config_set_rf_params(int fd)
{
int retval = FALSE;
int err = -1;
int size;
unsigned char cmd[HCI_MAX_CMD_SIZE];
unsigned char rsp[HCI_MAX_EVENT_SIZE];
char *cmd_hdr = NULL;
uint8_t antenna_num = 0;
int fd_a2dp_cfg = 0;
char buffer[255] = { 0 };
char c = '=';
uint32_t reg_data = 0;
uint8_t a2dp_sink_enable = 0;
antenna_num = antenna_number;
pr_info("Setting parameters to controller: antenna number=%d.", antenna_num);
//////////////////////////////////////////////////////////////////
fd_a2dp_cfg = open(AML_A2DP_CFG_FILE, O_RDONLY);
if (fd_a2dp_cfg < 0)
{
pr_info("In %s, Open failed:%s", __FUNCTION__, strerror(errno));
return FALSE;
}
size = read(fd_a2dp_cfg, buffer, sizeof(buffer));
if (size < 0)
{
pr_info("In %s, Read failed:%s", __FUNCTION__, strerror(errno));
close(fd_a2dp_cfg);
return FALSE;
}
buffer[sizeof(buffer) - 1] = 0;
char *ptr_a2dp_cfg = strchr(buffer, c);
if (!ptr_a2dp_cfg) {
pr_info("In %s, wrong a2dp_sink_enable value", __FUNCTION__);
close(fd_a2dp_cfg);
return FALSE;
}
ptr_a2dp_cfg++;
a2dp_sink_enable = atoi(ptr_a2dp_cfg);
close(fd_a2dp_cfg);
pr_info("Setting parameters to controller: a2dp_sink_enable=%d.", a2dp_sink_enable);
memset(cmd, 0x0, HCI_MAX_CMD_SIZE);
memset(rsp, 0x0, HCI_MAX_EVENT_SIZE);
cmd_hdr = (void *) (cmd + 1);
cmd[0] = HCI_COMMAND_PKT;
UINT16_TO_STREAM(cmd_hdr, TCI_WRITE_REG);
*cmd_hdr++ = 0x08; /* parameter length */
UINT32_TO_STREAM(cmd_hdr, 0xf03040); /* addr */
if (antenna_num == 1)
{
// UINT32_TO_STREAM(p, 0x10000000);
reg_data = 0x10000000;
}
else if (antenna_num == 2)
{
//UINT32_TO_STREAM(p, 0x20000000);
reg_data = 0x20000000;
}
if (a2dp_sink_enable == 1)
{
reg_data |= (1<<25); // bit25 means a2dp_sink_enable.
}
UINT32_TO_STREAM(cmd_hdr, reg_data);
size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + 0x08);
err = write(fd, cmd, size);
if (err != size) {
pr_err("Send failed with ret value: %d", err);
goto error;
}
/* Wait for command complete event */
err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE);
if ( err < 0) {
pr_err("Failed to set rf params");
goto error;
}
error:
return err;
}
static int aml_start_cpu_uart(int fd, callback func)
{
int size;
int err = -1;
unsigned char cmd[HCI_MAX_CMD_SIZE];
unsigned char rsp[HCI_MAX_EVENT_SIZE];
char *cmd_hdr = NULL;
memset(cmd, 0x0, HCI_MAX_CMD_SIZE);
memset(rsp, 0x0, HCI_MAX_EVENT_SIZE);
cmd_hdr = (void *) (cmd + 1);
cmd[0] = HCI_COMMAND_PKT;
UINT16_TO_STREAM(cmd_hdr, TCI_UPDATE_UART_BAUDRATE);
*cmd_hdr++ = 0x08;
UINT32_TO_STREAM(cmd_hdr, 0xf03058);
UINT32_TO_STREAM(cmd_hdr, 0x700);
/* Total length of the packet to be sent to the Controller */
size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + 0x08);
/* Send the HCI command packet to UART for transmission */
pr_info("HCI CMD: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",cmd[0], cmd[1], cmd[2], cmd[3],\
cmd[4], cmd[5], cmd[6], cmd[7], cmd[8], cmd[9], cmd[10], cmd[11]) ;
err = write(fd, cmd, size);
if (err != size) {
pr_err("Send failed with ret value: %d", err);
goto error;
}
/* Wait for command complete event */
err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE);
if ( err < 0) {
pr_err("Failed to set patch info on Controllern");
goto error;
}
if (rsp[4] != cmd[1] || rsp[5] != cmd[2] || rsp[6] != 0X00) {
pr_err("Failed to cpu_uart, command failure");
return -1;
}
pr_info("success");
ms_delay(MAC_DELAY);
pr_info("delay %d",MAC_DELAY);
if (!load_efuse && func != NULL)
{
err = func(fd);
if (err < 0)
{
pr_err("cmd send fail");
goto error;
}
}
else
{
pr_info("func is null");
}
error:
return err;
}
/******************************************************************************
** start cup cmd
******************************************************************************/
static int aml_start_cpu_before_cmd(int fd)
{
int size;
int err = -1;
unsigned char cmd[HCI_MAX_CMD_SIZE];
unsigned char rsp[HCI_MAX_EVENT_SIZE];
char *cmd_hdr = NULL;
memset(cmd, 0x0, HCI_MAX_CMD_SIZE);
memset(rsp, 0x0, HCI_MAX_EVENT_SIZE);
cmd_hdr = (void *) (cmd + 1);
cmd[0] = HCI_COMMAND_PKT;
UINT16_TO_STREAM(cmd_hdr, TCI_WRITE_REG);
*cmd_hdr++ = 0x08;
UINT32_TO_STREAM(cmd_hdr, 0xa7000c);
UINT32_TO_STREAM(cmd_hdr, 0x8000000);
/* Total length of the packet to be sent to the Controller */
size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + 0x08);
/* Send the HCI command packet to UART for transmission */
pr_info("HCI CMD: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",cmd[0], cmd[1], cmd[2], cmd[3],\
cmd[4], cmd[5], cmd[6], cmd[7], cmd[8], cmd[9], cmd[10], cmd[11]) ;
err = write(fd, cmd, size);
if (err != size) {
pr_err("Send failed with ret value: %d", err);
goto error;
}
/* Wait for command complete event */
err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE);
if ( err < 0) {
pr_err("Failed to set patch info on Controllern");
goto error;
}
if (rsp[4] != cmd[1] || rsp[5] != cmd[2] || rsp[6] != 0X00) {
pr_err("Failed to cpu_before_cmd, command failure");
return -1;
}
pr_info("success");
err = aml_start_cpu_uart(fd, aml_set_bdaddr); //aml_hci_reset);
if (err < 0)
{
pr_err("aml_start_cpu_uart cmd load fail");
goto error;
}
error:
return err;
}
/******************************************************************************
** disable download
******************************************************************************/
static int aml_disable_event(int fd)
{
int size;
int err = -1;
unsigned char cmd[HCI_MAX_CMD_SIZE];
unsigned char rsp[HCI_MAX_EVENT_SIZE];
hci_command_hdr *cmd_hdr;
memset(cmd, 0x0, HCI_MAX_CMD_SIZE);
memset(rsp, 0x0, HCI_MAX_EVENT_SIZE);
cmd_hdr = (void *) (cmd + 1);
cmd[0] = HCI_COMMAND_PKT;
cmd_hdr->opcode = TCI_WRITE_REG;
cmd_hdr->plen = 0x08;
cmd[4] = 0x14;
cmd[5] = 0x00;
cmd[6] = 0xa7;
cmd[7] = 0x00;
cmd[8] = 0x00;
cmd[9] = 0x00;
cmd[10]= 0x00;
cmd[11]= 0x00;
/* Total length of the packet to be sent to the Controller */
size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + cmd_hdr->plen);
/* Send the HCI command packet to UART for transmission */
pr_info("HCI CMD: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",cmd[0], cmd[1], cmd[2], cmd[3],\
cmd[4], cmd[5], cmd[6], cmd[7], cmd[8], cmd[9], cmd[10], cmd[11]) ;
err = write(fd, cmd, size);
if (err != size) {
pr_err("Send failed with ret value: %d", err);
goto error;
}
pr_info("Received HCI-Vendor Specific Event from SOC");
/* Wait for command complete event */
err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE);
if ( err < 0) {
pr_err("Failed to set patch info on Controllern");
goto error;
}
if (rsp[4] != cmd[1] || rsp[5] != cmd[2] || rsp[6] != 0X00) {
pr_err("Failed to disable_event, command failure");
return -1;
}
pr_info("success");
error:
return err;
}
#if CHECK_FW
/******************************************************************************
** check fw
******************************************************************************/
int iccm_read_off = 0;
int dccm_read_off = 0;
int iccm_j = 0;
int dccm_j = 0;
static int check_download_fwiccm(int fd)
{
char *p_tmp;
char *p_name;
int reg_data,cmp_data;
int BT_fwICCM_len;
int err = -1;
int size;
char * cmd_hdr = NULL;
unsigned char cmd[HCI_MAX_CMD_SIZE];
unsigned char rsp[HCI_MAX_EVENT_SIZE];
BT_fwICCM_len = (int)sizeof(BT_fwICCM);
while (iccm_j < BT_fwICCM_len)
{
memset(cmd, 0x0, HCI_MAX_CMD_SIZE);
iccm_read_off = iccm_j;
cmd_hdr = (void *) (cmd + 1);
cmd[0] = HCI_COMMAND_PKT;
UINT16_TO_STREAM(cmd_hdr, TCI_READ_REG);
*cmd_hdr++ = 0x04;
UINT32_TO_STREAM(cmd_hdr, iccm_read_off);
size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + 0x04);
err = write(fd, cmd, size);
if (err != size) {
pr_err("Send failed with ret value: %d", err);
goto error;
}
/*rsp deal with ok, handle to memset*/
memset(rsp, 0x0, HCI_MAX_EVENT_SIZE);
/*Wait for command complete event*/
err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE);
if ( err < 0) {
pr_err("Failed to set patch info on Controller\n");
goto error;
}
if (rsp[4] != cmd[1] || rsp[5] != cmd[2] || rsp[6] != 0X00) {
pr_err("Failed to tci_write, command failure");
return -1;
}
p_tmp = p_name = (char *)(rsp + 1) + \
HCI_EVT_CMD_CMPL_LOCAL_NAME_STRING;
reg_data = *p_tmp + ((*(p_tmp + 1)) << 8) + ((*(p_tmp + 2)) << 16) + ((*(p_tmp + 3)) << 24)
+((*(p_tmp + 4)) << 32) + ((*(p_tmp + 5)) << 40) + ((*(p_tmp + 6)) << 48) +((*(p_tmp + 7)) << 56);
cmp_data = (BT_fwICCM[iccm_read_off]) + (BT_fwICCM[iccm_read_off + 1] << 8)
+ (BT_fwICCM[iccm_read_off + 2] << 16) + (BT_fwICCM[iccm_read_off + 3] << 24)
+ (BT_fwICCM[iccm_read_off + 4] << 32) + (BT_fwICCM[iccm_read_off + 5] << 40)
+ (BT_fwICCM[iccm_read_off + 6] << 48) + (BT_fwICCM[iccm_read_off + 7] << 56);
pr_info("reg_data = %x,cmp_data = %x", reg_data, cmp_data);
if (cmp_data == reg_data)
{
pr_info("read iccm OK");
}
else
{
pr_err("read iccm Fail");
return -1;
}
iccm_j = iccm_j + 8;
}
pr_info("check iccm_fw is ok");
error:
iccm_read_off = 0;
iccm_j = 0;
return err;
}
static int check_download_dccmfw(int fd)
{
char *p_tmp;
char *p_name;
int reg_data = 0 ,cmp_data = 0;
int BT_fwDCCM_len = 0;
int err = -1;
int size;
char * cmd_hdr = NULL;
unsigned char cmd[HCI_MAX_CMD_SIZE];
unsigned char rsp[HCI_MAX_EVENT_SIZE];
BT_fwDCCM_len = (int)sizeof(BT_fwDCCM);
while (dccm_j < BT_fwDCCM_len)
{
memset(cmd, 0x0, HCI_MAX_CMD_SIZE);
dccm_read_off = dccm_j;
cmd_hdr = (void *) (cmd + 1);
cmd[0] = HCI_COMMAND_PKT;
UINT16_TO_STREAM(cmd_hdr, TCI_READ_REG);
*cmd_hdr++ = 0x04;
UINT32_TO_STREAM(cmd_hdr, dccm_read_off);
size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + 0x04);
err = write(fd, cmd, size);
if (err != size) {
pr_err("Send failed with ret value: %d", err);
goto error;
}
/*rsp deal with ok, handle to memset*/
memset(rsp, 0x0, HCI_MAX_EVENT_SIZE);
/*Wait for command complete event*/
err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE);
if ( err < 0) {
pr_err("Failed to set patch info on Controller\n");
goto error;
}
if (rsp[4] != cmd[1] || rsp[5] != cmd[2] || rsp[6] != 0X00) {
pr_err("Failed to tci_write, command failure");
return -1;
}
p_tmp = p_name = (char *)(rsp + 1) + \
HCI_EVT_CMD_CMPL_LOCAL_NAME_STRING;
reg_data = *p_tmp + ((*(p_tmp + 1)) << 8) + ((*(p_tmp + 2)) << 16) + ((*(p_tmp + 3)) << 24);
// +((*(p_tmp + 4)) << 32) + ((*(p_tmp + 5)) << 40) + ((*(p_tmp + 6)) << 48) +((*(p_tmp + 7)) << 56);
cmp_data = (BT_fwDCCM[dccm_read_off]) + (BT_fwDCCM[dccm_read_off + 1] << 8)
+ (BT_fwDCCM[dccm_read_off + 2] << 16) + (BT_fwDCCM[dccm_read_off + 3] << 24);
// + (BT_fwDCCM[dccm_read_off + 4] << 32) + (BT_fwDCCM[dccm_read_off + 5] << 40)
// + (BT_fwDCCM[dccm_read_off + 6] << 48) + (BT_fwDCCM[dccm_read_off + 7] << 56);
pr_info("reg_data = %x,cmp_data = %x", reg_data, cmp_data);
if (cmp_data == reg_data)
{
//pr_info("read dccm OK");
}
else
{
pr_err("read dccm Fail");
return -1;
}
dccm_j += 4;
}
pr_info("check dccm_fw is ok");
error:
dccm_read_off = 0;
dccm_j = 0;
return err;
}
#endif //END CHECK_FW
static int aml_send(int fd, char *buf, unsigned int buf_size, unsigned int offset, int diff)
{
unsigned int i;
int err = -1;
unsigned char cmd[HCI_MAX_CMD_SIZE];
unsigned char rsp[HCI_MAX_EVENT_SIZE];
int flags;
int n = 0;
char * cmd_hdr = NULL;
if (buf == NULL)
{
pr_err("buf is NULL");
return -1;
}
if (!diff)
{
pr_info("start download fw BT_fwICCM 0x%x %d", buf_size, n);
}
else
{
pr_info("start download fw BT_fwDCCM 0x%x %d", buf_size, n);
}
while (buf_size > 0)
{
unsigned int cmd_size = 0;
unsigned int data_len = 0;
unsigned int cmd_len = 0;
memset(cmd, 0x0, HCI_MAX_CMD_SIZE);
memset(rsp, 0x0, HCI_MAX_EVENT_SIZE);
/*fw download len */
data_len = (buf_size > RW_OPERATION_SIZE) ? RW_OPERATION_SIZE : buf_size;
cmd_len = data_len + 4;
cmd_hdr = (void *) (cmd + 1);
cmd[0] = HCI_COMMAND_PKT;
UINT16_TO_STREAM(cmd_hdr, TCI_DOWNLOAD_BT_FW);
/* parameter length */
*cmd_hdr++ = cmd_len;
if (!diff)
{
UINT32_TO_STREAM(cmd_hdr, ICCM_RAM_BASE + offset);
n++;
}
if (diff)
{
UINT32_TO_STREAM(cmd_hdr, DCCM_RAM_BASE + offset);
n++;
}
for (i = 0; i < data_len; i++)
{
cmd_hdr[i] = *(buf + offset + i);
}
/* Total length */
cmd_size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + cmd_len);
err = write(fd, cmd, cmd_size);
if (err != cmd_size) {
pr_err("Send failed with ret value: %d", err);
goto error;
}
/*Wait for command complete event*/
err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE);
if ( err < 0) {
pr_err("Failed to set patch info on Controller\n");
goto error;
}
if (rsp[4] != cmd[1] || rsp[5] != cmd[2] || rsp[6] != 0X00) {
pr_err("Failed to tci_write, command failure");
return -1;
}
offset += data_len;
buf_size -= data_len;
}
if (!diff)
{
pr_info("download fw BT_fwICCM SUCCESS times: %d", n);
}
else
{
pr_info("download fw BT_fwDCCM SUCCESS times: %d", n);
}
error:
return err;
}
/*******************************************************************************
**
** Function aml_userial_vendor_set_baud
**
** Description Set new baud rate
**
** Returns None
**
*******************************************************************************/
static void aml_userial_vendor_set_baud(unsigned char userial_baud)
{
unsigned int tcio_baud;
pr_info("## aml_userial_vendor_set_baud: %d", userial_baud);
if (tcgetattr(vnd_userial.fd, &vnd_userial.termios) < 0) {
perror("Can't get port settings");
return;
}
cfmakeraw(&vnd_userial.termios);
vnd_userial.termios.c_cflag |= CLOCAL;
vnd_userial.termios.c_cflag |= CREAD;
vnd_userial.termios.c_cflag |= CS8;
tcsetattr(vnd_userial.fd, TCSANOW, &vnd_userial.termios);
aml_userial_to_tcio_baud(userial_baud, &tcio_baud);
cfsetospeed(&vnd_userial.termios, tcio_baud);
cfsetispeed(&vnd_userial.termios, tcio_baud);
tcsetattr(vnd_userial.fd, TCSADRAIN, &vnd_userial.termios); /* don't change speed until last write done */
}
static int get_wifi_dev_type(char *dev_type)
{
int fd;
fd = open("/dev/wifi_power", O_RDWR);
if (fd < 0) {
return -1;
}
if (ioctl(fd, SDIO_GET_DEV_TYPE, dev_type) < 0) {
close(fd);
return -1;
}
close(fd);
return 0;
}
static int chip_to_module(char* chipid)
{
int i;
for (i = 0; i < (int)(ARRAY_SIZE(aml_chip)); i++)
{
if (!strncmp(chipid, aml_chip[i].chipid, 6))
{
return aml_chip[i].module_type;
}
}
return 0;
}
static int select_module(void)
{
char dev_type[10] = {'\0'};
char file_name[100] = {'\0'};
char pid_buf[128];
FILE *fp = NULL;
memset(pid_buf, 0, sizeof(pid_buf));
// sdio
get_wifi_dev_type(dev_type);
sprintf(file_name, "/sys/bus/mmc/devices/%s:0000/%s:0000:1/device", dev_type, dev_type);
fp = fopen(file_name, "r");
if (!fp) {
fprintf(stderr, "open sdio wifi file failed\n");
} else {
if (fread(pid_buf, 1, sizeof(pid_buf)-1, fp) > 0) {
goto out;
}
fclose(fp);
fprintf(stderr, "read sdio wifi pid failed\n");
}
// pcie
memset(file_name, 0, sizeof(file_name));
sprintf(file_name, "/sys/bus/pci/devices/0000:01:00.0/device");
fp = fopen(file_name, "r");
if (!fp) {
fprintf(stderr, "open pcie wifi file failed\n");
} else {
if (fread(pid_buf, 1, sizeof(pid_buf)-1, fp) > 0) {
goto out;
}
fclose(fp);
fprintf(stderr, "read pcie wifi pid failed\n");
}
// usb
/*
memset(file_name, 0, sizeof(file_name));
sprintf(file_name, "/sys/bus/usb/devices/%d-%d/idProduct",i,j);
// file_name ~ /sys/bus/usb/devices/1-1/idProduct
if (!fp) {
fprintf(stderr, "open usb wifi file failed\n");
} else {
if (fread(pid_buf, 1, sizeof(pid_buf)-1, fp) > 0) {
goto out;
}
fclose(fp);
fprintf(stderr, "read usb wifi pid failed\n");
}*/
out:
pid_buf[sizeof(pid_buf)-1] = '\0';
fclose(fp);
pr_info("chip id is %s",pid_buf);
return chip_to_module(pid_buf);
}
static int get_aml_wifi_module(void)
{
int i;
char aml_wifi_module[20];
int fd = open("/dev/wifi_power", O_RDWR);
if (fd < 0) {
pr_info("open /dev/wifi_power fail\n");
return -1;
}
if (ioctl (fd, GET_AML_WIFI_MODULE, aml_wifi_module) < 0) {
pr_info("ioctl GET_AML_WIFI_MODULE fail\n");
close(fd);
return -1;
}
close(fd);
for (i = 0; i < sizeof(aml_module)/sizeof(vnd_module_t); i++) {
if (!strcmp(aml_module[i].name, aml_wifi_module)) {
pr_info("match aml_module: %s\n", aml_module[i].name);
return i;
}
}
return -1;
}
static int select_firmware(char ** file)
{
int i, idx, module_type;
idx = get_aml_wifi_module();
if (idx < 0) {
module_type = select_module();
for (i = 0; i < sizeof(aml_module)/sizeof(vnd_module_t); i++)
{
if (aml_module[i].module_type == module_type) {
idx = i;
break;
}
}
}
if (idx >= 0) {
*file = aml_module[idx].fw_file;
AML_MODULE = aml_module[idx].module_type;
}
return idx;
}
static unsigned int hw_config_get_iccm_size(char * file)
{
int fd = 0;
unsigned int iccm_size = 0;
int size = 0;
if ((fd = open(file, O_RDONLY)) < 0)
return 0;
size = read(fd, &iccm_size, 4);
if (size < 0)
{
pr_err("--------- read error!---------");
close(fd);
return 0;
}
close(fd);
pr_info("--------- iccm_size %d---------\n", iccm_size);
return (iccm_size < ICCM_DCCM_MAX) ? iccm_size : ICCM_DCCM_MAX;
}
static unsigned int hw_config_get_dccm_size(char * file)
{
int fd = 0;
unsigned int dccm_size = 0;
int size = 0;
if ((fd = open(file, O_RDONLY)) < 0)
return 0;
if (lseek(fd, 4, SEEK_SET) != 4)
{
pr_err("skip 4 bytes iccm len fail");
close(fd);
return 0;
}
size = read(fd, &dccm_size, 4);
if (size < 0)
{
pr_err("--------- read error!---------");
close(fd);
return 0;
}
close(fd);
pr_info("--------- dccm_size %d---------\n", dccm_size);
return (dccm_size < ICCM_DCCM_MAX) ? dccm_size : ICCM_DCCM_MAX;
}
static int get_iccmbuf_dccmbuf(char **iccmbuf, char** dccmbuf, unsigned int iccmlen, unsigned int dccmlen, char * file)
{
int fd;
int ret =0;
char *p_iccmbuf = malloc(iccmlen + 1);
char *p_dccmbuf;
if (p_iccmbuf == NULL)
{
pr_err("malloc p_iccmbuf fail");
ret = 1;
goto error;
}
memset(p_iccmbuf, 0, iccmlen + 1);
p_dccmbuf = malloc(dccmlen + 1);
if (p_dccmbuf == NULL)
{
pr_err("malloc p_dccmbuf fail");
ret = 2;
goto error;
}
memset(p_dccmbuf, 0, dccmlen + 1);
fd = open(file, O_RDONLY);
if (fd <0)
{
pr_err("open fw_file fail");
ret = 3;
goto error;
}
if (lseek(fd, 8, SEEK_SET) != 8)
{
pr_err("skip 8byte len fail");
close(fd);
ret = 3;
goto error;
}
ret = read(fd, p_iccmbuf, iccmlen);
if (ret < 0)
{
pr_err("------ p_iccmbuf read error!------");
close(fd);
ret = 3;
goto error;
}
ret = read(fd, p_dccmbuf, dccmlen);
if (ret < 0)
{
pr_err("------ p_dccmbuf read error!------");
close(fd);
ret = 3;
goto error;
}
close(fd);
*iccmbuf = p_iccmbuf;
*dccmbuf = p_dccmbuf;
return 0;
error:
if (ret == 1)
{
//do nothing
}
else if (ret == 2)
{
free(p_iccmbuf);
}
else if (ret ==3)
{
free(p_iccmbuf);
free(p_dccmbuf);
}
return 1;
}
static int aml_download_fw_file(int fd, callback func)
{
int err = -1;
int idx = 0;
unsigned int fwICCM_len =0;
unsigned int fwICCM_size = 0 ;
unsigned int fwICCM_offset =0 ;
char * p_BT_fwICCM = NULL;
unsigned int fwDCCM_size = 0;
unsigned int fwDCCM_offset = 0;
char * p_BT_fwDCCM = NULL;
char *fw_file = NULL;
idx = select_firmware(&fw_file);
if (idx < 0)
{
pr_err("no matched fw\n");
return err;
}
pr_info("%s start download: %s",aml_module[idx].mod_type_name, fw_file);
fwICCM_len = hw_config_get_iccm_size(fw_file);
fwICCM_size = fwICCM_len;
fwICCM_size -= aml_module[idx].iccm_base * 1024;
pr_info("fw BT_fwICCM is total : 0x%x", fwICCM_size);
fwICCM_offset = aml_module[idx].iccm_base * 1024;
fwDCCM_size = hw_config_get_dccm_size(fw_file);
pr_info("fw BT_fwDCCM is total : 0x%x", fwDCCM_size);
if (get_iccmbuf_dccmbuf(&p_BT_fwICCM, &p_BT_fwDCCM, fwICCM_len, fwDCCM_size, fw_file))
{
pr_err("get_iccmbuf_dccmbuf fail");
return err;
}
err = aml_send(fd, p_BT_fwICCM, fwICCM_size, fwICCM_offset, fwICCM);
if (err < 0)
{
pr_err("write BT_fwICCM fail");
goto error;
}
#if CHECK_FW
pr_info("start check BT_fwICCM");
err = check_download_fwiccm(fd);
if (err < 0)
{
pr_err("check_download_fwiccm fail");
}
#endif
err = aml_send(fd, p_BT_fwDCCM, fwDCCM_size, fwDCCM_offset, fwDCCM);
if (err < 0)
{
pr_err("write BT_fwDCCM fail");
goto error;
}
#if CHECK_FW
pr_info("start check BT_fwDCCM");
err = check_download_dccmfw(fd);
if (err < 0)
{
pr_err("check_download_dccmfw fail");
}
#endif
if (func != NULL)
{
err = func(fd);
if (err < 0)
{
pr_err("cmd fail");
err = -1;
}
}
else
{
pr_err("func is NULL");
err = -1;
}
error:
free(p_BT_fwICCM);
free(p_BT_fwDCCM);
return err;
}
static void aml_flow_control(int fd, int opt)
{
struct termios c_opt;
ioctl(fd, TIOCMGET, &c_opt);
c_opt.c_cc[VTIME] = 0; /* inter-character timer unused */
c_opt.c_cc[VMIN] = 0; /* blocking read until 8 chars received */
c_opt.c_cflag &= ~CSIZE;
c_opt.c_cflag |= (CS8 | CLOCAL | CREAD);
if (MSM_ENABLE_FLOW_CTRL)
c_opt.c_cflag |= CRTSCTS;
else if (MSM_DISABLE_FLOW_CTRL)
c_opt.c_cflag |= ~CRTSCTS;
else {
pr_err("Incorrect option passed for TIOCMSET");
return;
}
c_opt.c_iflag = IGNPAR;
c_opt.c_oflag = 0;
c_opt.c_lflag = 0;
ioctl(fd, TIOCMSET, &c_opt);
}
static int aml_update_baudrate(int fd, callback tci_write, callback tci_read)
{
int size, err = 0;
unsigned char cmd[HCI_MAX_CMD_SIZE];
unsigned char rsp[HCI_MAX_EVENT_SIZE];
hci_command_hdr *cmd_hdr;
int flags;
memset(cmd, 0x0, HCI_MAX_CMD_SIZE);
cmd_hdr = (void *) (cmd + 1);
cmd[0] = HCI_COMMAND_PKT;
cmd_hdr->opcode = TCI_UPDATE_UART_BAUDRATE;
cmd_hdr->plen = 0x08;
cmd[4] = 0x28;
cmd[5] = 0x01;
cmd[6] = 0xa3;
cmd[7] = 0x00;
cmd[8] = 0x09;
cmd[9] = 0x70;
cmd[10]= 0x00;
cmd[11]= 0x00;
/* Total length */
size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + cmd_hdr->plen);
/* Send the HCI command packet to UART for transmission */
pr_info("HCI CMD: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",cmd[0], cmd[1], cmd[2], cmd[3],\
cmd[4], cmd[5], cmd[6], cmd[7], cmd[8], cmd[9], cmd[10], cmd[11]) ;
err = write(fd, cmd, size);
if (err != size) {
pr_err("Send failed with ret value: %d", err);
goto error;
}
pr_info("Received HCI-Vendor Specific Event from SOC");
/* Wait for command complete event */
err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE);
if ( err < 0) {
pr_err("Failed to set patch info on Controllern");
goto error;
}
/* Flow off during baudrate change */
aml_flow_control(fd, MSM_DISABLE_FLOW_CTRL);
/* Change Local UART baudrate to high speed UART */
aml_userial_vendor_set_baud(USERIAL_BAUD_4M);
/* Flow on after changing local uart baudrate */
aml_flow_control(fd, MSM_ENABLE_FLOW_CTRL);
pr_info("success");
if (tci_write != NULL)
{
err = tci_write(fd);
if (err < 0)
{
pr_err("tci_write cmd fail");
goto error;
}
}
else
{
pr_err("tci_write is NULL");
return -1;
}
if (tci_read != NULL)
{
err = tci_read(fd);
if (err < 0)
{
pr_err("tci_read cmd fail");
goto error;
}
}
else
{
pr_err("tci_read is NULL");
return -1;
}
error:
return err;
}
static int aml_tci_write_reg(int fd)
{
int size, err = 0;
unsigned char cmd[HCI_MAX_CMD_SIZE];
unsigned char rsp[HCI_MAX_EVENT_SIZE];
hci_command_hdr *cmd_hdr;
int flags;
memset(cmd, 0x0, HCI_MAX_CMD_SIZE);
cmd_hdr = (void *) (cmd + 1);
cmd[0] = HCI_COMMAND_PKT;
cmd_hdr->opcode = TCI_WRITE_REG;
cmd_hdr->plen = 0x08;
cmd[4] = 0x14;
cmd[5] = 0x00;
cmd[6] = 0xa7;
cmd[7] = 0x00;
cmd[8] = 0x00;
cmd[9] = 0x00;
cmd[10]= 0x00;
cmd[11]= 0x01;
/* Total length of the packet to be sent to the Controller */
size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + cmd_hdr->plen);
/* Send the HCI command packet to UART for transmission */
pr_info("HCI CMD: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",cmd[0], cmd[1], cmd[2], cmd[3],\
cmd[4], cmd[5], cmd[6], cmd[7], cmd[8], cmd[9], cmd[10], cmd[11]) ;
err = write(fd, cmd, size);
if (err != size) {
pr_err("Send failed with ret value: %d", err);
goto error;
}
/* Wait for command complete event */
err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE);
if ( err < 0) {
pr_err("Failed to set patch info on Controller\n");
goto error;
}
if (rsp[4] != cmd[1] || rsp[5] != cmd[2] || rsp[6] != 0X00) {
pr_err("Failed to tci_write, command failure");
return -1;
}
pr_info("continue tci_write");
memset(cmd, 0x0, HCI_MAX_CMD_SIZE);
memset(rsp, 0x0, HCI_MAX_EVENT_SIZE);
cmd_hdr = (void *) (cmd + 1);
cmd[0] = HCI_COMMAND_PKT;
cmd_hdr->opcode = TCI_WRITE_REG;
cmd_hdr->plen = 0x08;
cmd[4] = 0x50;
cmd[5] = 0x30;
cmd[6] = 0xf0;
cmd[7] = 0x00;
cmd[8] = 0x00;
cmd[9] = 0x00;
cmd[10]= 0x00;
cmd[11]= 0x00;
/*Total length of the packet*/
size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + cmd_hdr->plen);
pr_info("HCI CMD: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",cmd[0], cmd[1], cmd[2], cmd[3],\
cmd[4], cmd[5], cmd[6], cmd[7], cmd[8], cmd[9], cmd[10], cmd[11]) ;
err = write(fd, cmd, size);
if (err != size) {
pr_err("Send failed with ret value: %d", err);
goto error;
}
/* Wait for command complete event */
err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE);
if ( err < 0) {
pr_info("Failed to set patch info on Controller");
goto error;
}
if (rsp[4] != cmd[1] || rsp[5] != cmd[2] || rsp[6] != 0X00) {
pr_err("Failed to tci_write, command failure");
return -1;
}
pr_info("success");
error:
return err;
}
static int aml_tci_read_reg(int fd)
{
int size, err = -1;
unsigned char cmd[HCI_MAX_CMD_SIZE];
unsigned char rsp[HCI_MAX_EVENT_SIZE];
hci_command_hdr *cmd_hdr;
int flags;
memset(cmd, 0x0, HCI_MAX_CMD_SIZE);
cmd_hdr = (void *) (cmd + 1);
cmd[0] = HCI_COMMAND_PKT;
cmd_hdr->opcode = TCI_READ_REG;
cmd_hdr->plen = 0x04;
cmd[4] = 0x50;
cmd[5] = 0x30;
cmd[6] = 0xf0;
cmd[7] = 0x00;
/* Total length of the packet to be sent to the Controller */
size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + cmd_hdr->plen);
/* Send the HCI command packet to UART for transmission */
pr_info("HCI CMD: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",\
cmd[0], cmd[1], cmd[2], cmd[3],cmd[4], cmd[5], cmd[6], cmd[7]) ;
err = write(fd, cmd, size);
if (err != size) {
pr_err("Send failed with ret value: %d", err);
goto error;
}
/* Wait for command complete event */
err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE);
if ( err < 0) {
pr_err("Failed to set patch info on Controller");
goto error;
}
if (rsp[4] != cmd[1] || rsp[5] != cmd[2] || rsp[6] != 0X00) {
pr_err("Failed to tci_write, command failure");
return -1;
}
pr_info("success");
error:
return err;
}
static int aml_hci_reset(int fd)
{
int size, err = 0;
unsigned char cmd[HCI_MAX_CMD_SIZE];
unsigned char rsp[HCI_MAX_EVENT_SIZE];
hci_command_hdr *cmd_hdr;
int flags;
pr_info("HCI RESET");
memset(cmd, 0x0, HCI_MAX_CMD_SIZE);
cmd_hdr = (void *) (cmd + 1);
cmd[0] = HCI_COMMAND_PKT;
cmd_hdr->opcode = HCI_RESET;
cmd_hdr->plen = 0;
/* Total length of the packet to be sent to the Controller */
size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE);
/* Send the HCI command packet to UART for transmission */
pr_info("HCI CMD: 0x%x 0x%x 0x%x 0x%x", cmd[0], cmd[1], cmd[2], cmd[3]);
err = write(fd, cmd, size);
if (err != size) {
pr_err("Send failed with ret value: %d", err);
goto error;
}
pr_info("Received HCI-Vendor Specific Event from SOC");
/* Wait for command complete event */
err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE);
if ( err < 0) {
pr_err("Failed to set patch info on Controller");
goto error;
}
if (rsp[4] != cmd[1] || rsp[5] != cmd[2] || rsp[6] != 0X00) {
pr_err("Failed to tci_write, command failure");
return -1;
}
pr_info("success");
error:
return err;
}
static int aml_init(int fd, char *bdaddr)
{
int err = -1;
int size;
vnd_userial.fd = fd;
if (!get_config(AML_BT_CONFIG_RF_FILE)) {
pr_err("get_config fail,use default value");
}
/* update baud */
err = aml_update_baudrate(fd, aml_tci_write_reg, aml_tci_read_reg);
if (err < 0) {
pr_err("Baud rate change failed!");
goto error;
}
pr_info("Baud rate changed successfully");
/* Download fw files */
err = aml_download_fw_file(fd, aml_disable_event);
if (err < 0) {
pr_err("Download fw file failed!");
goto error;
}
pr_info("Download fw file successfully");
err = hw_config_set_rf_params(fd);
if (err < 0) {
pr_err("hw_config_set_rf_params failed!");
goto error;
}
/*start cup cmd*/
err = aml_start_cpu_before_cmd(fd);
if (err < 0) {
pr_err("cpu before cmd failed!");
goto error;
}
pr_info("cpu before cmd successfully");
err = aml_set_wake_manf_data(fd);
if (err < 0) {
pr_err("set wake manf data fail");
goto error;
}
/* Perform HCI reset here*/
err = aml_hci_reset(fd);
if ( err < 0 ) {
pr_err("HCI Reset Failed !!!");
goto error;
}
pr_info("HCI Reset is done");
error:
return err;
}
static int aml(int fd, struct uart_t *u, struct termios *ti)
{
return aml_init(fd, u->bdaddr);
}