Files
BPI-CM9-Linux/aml-comp/hardware/bluetooth/amlogic/aml_hciattach/hciattach_aml.c
T

1705 lines
48 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 _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 "hciattach_aml.h"
#include "hciattach.h"
#include "aml_multibt.h"
#include "aml_conf.h"
/******************************************************************************
** Macro Definition
******************************************************************************/
/*mac addr len */
#define MAC_DELAY 600
#define fwICCM 0 /*fwICCM is 0 to download*/
#define fwDCCM 1 /*fwDCCM is 1 to download*/
#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 HCI_VSC_WAKE_WRITE_DATA 0xFC22
#define ICCM_DCCM_MAX (32 * 1024 * 1024)
#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)
/******************************************************************************
** Variables
******************************************************************************/
//static int antenna_number = 2;
static int load_efuse = 0;
static unsigned int add_iccm = 0;
static int stpbt_fd = -1;
/******************************************************************************
** Extern variables
******************************************************************************/
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) {
ALOGE("write fail ret:%d,err:%s", ret, strerror(errno));
return ret;
} else if (ret == 0) {
ALOGE("write fail with ret:0,err:%s", strerror(errno));
return ret;
} else {
if (ret < write_len) {
ALOGE("write pending,do write ret:%d,err:%s", ret, strerror(errno));
write_len = write_len - ret;
write_offset = ret;
} else {
ALOGI("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) {
ALOGE("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) {
ALOGE("read fail,ret:%d", ret);
goto exit;
}
exit:
return ret;
}
static int amlbt_open_dev(void)
{
if (access(BT_DEVICE_PATH, F_OK) != 0) {
ALOGI("%s not found, exit", BT_DEVICE_PATH);
return -1;
}
int sdio_fd = open(BT_DEVICE_PATH, O_RDWR | O_NOCTTY);
if (sdio_fd < 0) {
ALOGE("open %s fail", BT_DEVICE_PATH);
return -1;
}
ALOGD("open %s success, sdio_fd: %d", BT_DEVICE_PATH, sdio_fd);
return sdio_fd;
}
void amlbt_open_dev_w1u(amlbt_idx idx)
{
if (idx == W1U_UART) {
stpbt_fd = amlbt_open_dev();
}
}
void amlbt_close_dev(void)
{
if (stpbt_fd != -1) {
close(stpbt_fd);
}
}
int amlbt_set_power(amlbt_idx idx, int status)
{
if (stpbt_fd < 0) {
ALOGE("Invalid ioctl fd");
return -1;
}
if (status != 0 && status != 1) {
ALOGE("Invalid status: %d", status);
return -1;
}
if (idx == W1U_UART) {
if (!amlbt_get_pwr_mode()) {
ALOGI("w1u pwr mode status %d skip",status);
return 0;
}
if (ioctl(stpbt_fd, IOCTL_SET_BT_POWER, &status) < 0) {
ALOGE("set bt power fail: %s (errno: %d)", strerror(errno), errno);
return -1;
}
ALOGI("set bt power: %d success", status);
} else {
ALOGD("amlbt_idx: %d, skip", idx);
}
return 0;
}
static int amlbt_set_conf_params(amlbt_idx idx)
{
int ret = 0;
if (idx == W1U_UART) {
if (stpbt_fd < 0) {
ALOGE("Invalid ioctl fd");
return -1;
}
int arg = 1;
ret =ioctl(stpbt_fd, IOCTL_SET_BT_OPEN, &arg);
if (ret < 0) {
ALOGE("IOCTL_SET_BT_OPEN fail: %s (errno: %d)", strerror(errno), errno);
goto exit;
}
ALOGI("W1U_UART: IOCTL_SET_BT_OPEN success");
} else if (idx == W2_UART || idx == W2L_UART) {
int sdio_fd = amlbt_open_dev();
if (sdio_fd < 0) {
ALOGE("amlbt_idx:%d open %s fail", idx, BT_DEVICE_PATH);
} else {
ALOGI("amlbt_idx:%d open %s success write conf params sdio_fd:%d", idx, BT_DEVICE_PATH, sdio_fd);
close(sdio_fd);
}
}
exit:
return ret;
}
int amlbt_set_woble_cfg(int fd, amlbt_idx idx)
{
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 (idx == W1_UART) {
ALOGI("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);
}
return 0;
}
static int aml_set_wake_manf_data_w1u(int fd, amlbt_idx idx)
{
int ret = 0;
unsigned char cmd[HCI_MAX_CMD_SIZE] = {0};
unsigned char rsp[HCI_MAX_EVENT_SIZE] = {0};
unsigned char *p = &cmd[1]; // cmd[0] = HCI_COMMAND_PKT
unsigned char *total_manf_data = NULL;
unsigned char default_manf_data[] = {0x01, 0x22, 0xFC, 0x05, 0x19, 0xff, 0x01, 0x0a, 0xb};
int total_len = 0;
int cnt_data = 0;
int cmd_size = 0;
int cnt = 0;
(void)idx;
ALOGD("set wake w1u_manf_data");
if (amlbt_manf_para == 0) {
ALOGD("amlbt_manf_para is 0, use default");
ALOGD("set wake default_manf_data");
ret = aml_hci_send_cmd(fd, (unsigned char *)default_manf_data,
sizeof(default_manf_data),(unsigned char *)rsp, HCI_MAX_EVENT_SIZE);
return 0;
}
total_manf_data = malloc(BUF_MAX_LEN);
if (!total_manf_data) {
ALOGE("Memory alloc fail");
return -ENOMEM;
}
memset(total_manf_data, 0, BUF_MAX_LEN);
while (cnt < MANF_ROW) {
//15 index->0/1/2/3
if ((BIT(cnt) & amlbt_manf_para) != 0) {
int group_len = w1u_manf_data[cnt][0] + 1; // param length + payload = 1 + 9
if ((total_len + group_len) > BUF_MAX_LEN) {
ALOGE("APCF buffer overflow!");
break;
} else {
memcpy(&total_manf_data[total_len], w1u_manf_data[cnt], group_len);
ALOGD("%#x %#x %#x %#x %#x %#x %#x %#x", total_manf_data[total_len], total_manf_data[total_len+1],
total_manf_data[total_len+2], total_manf_data[total_len+3],
total_manf_data[total_len+4], total_manf_data[total_len+5],
total_manf_data[total_len+6], total_manf_data[total_len+7]);
total_len += group_len;
ALOGD("%#x %#x %#x %#x %#x %#x %#x %#x", w1u_manf_data[cnt][0], w1u_manf_data[cnt][1],
w1u_manf_data[cnt][2], w1u_manf_data[cnt][3],
w1u_manf_data[cnt][4], w1u_manf_data[cnt][5],
w1u_manf_data[cnt][6], w1u_manf_data[cnt][7]);
cnt_data++;
}
}
cnt++;
}
if (total_len == 0 || cnt_data == 0) {
ALOGE("No w1uF manf data to send");
free(total_manf_data);
return -EINVAL;
}
//build HCI cmd
cmd[0] = HCI_COMMAND_PKT;
UINT16_TO_STREAM(p, HCI_VSC_WAKE_WRITE_DATA); // opcode
UINT8_TO_STREAM(p, total_len + 1); // total = all param length + 1(cnt_data)
UINT8_TO_STREAM(p, cnt_data); // cnt data
memcpy(p, total_manf_data, total_len);
cmd_size = HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + 1/*cnt_data*/ + total_len;
ret = aml_hci_send_cmd(fd, cmd, cmd_size, rsp, HCI_MAX_EVENT_SIZE);
if (ret < 0) {
ALOGE("Send w1u manf data fail");
} else {
ALOGI("Send w1u config success, group: %d, total_len: %d", cnt_data, total_len);
}
free(total_manf_data);
return ret;
}
static int aml_set_wake_manf_data(int fd, amlbt_idx idx)
{
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 (idx != W1_UART) {
ALOGI("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_set_wakeup_para(int fd, amlbt_idx idx)
{
int ret = 0;
if (idx == W1U_UART || idx == W2_UART || idx == W2L_UART) {
ret = aml_set_wake_manf_data_w1u(fd, idx); // w1u/w2/w2l use same wakup param
} else if (idx == W1_UART) {
ALOGD("W1_UART: wakeup param skip.");
} else {
ALOGE("Unsupported module index: %d", idx);
ret = -EINVAL;
}
return ret;
}
#if 0
static int antenna_number_act(const char * p_name, char * p_value)
{
antenna_number = strtol(p_value, NULL, 10);
if (antenna_number == 0) {
ALOGI("antenna_number use default value 2");
antenna_number = 2;
}
ALOGI("%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);
ALOGI("%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}
};
#endif
/*****************************************************************************
** 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 {
ALOGE("userial vendor open: unsupported baud idx %i", cfg_baud);
*baud = B115200;
return false;
}
return true;
}
/******************************************************************************
** 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);
}
/******************************************************************************
** set bdaddr
******************************************************************************/
static int aml_set_bdaddr(int fd)
{
int size;
int ret = -1;
char *cmd_hdr = NULL;
char buf[BT_MAC_BUF_LEN + 1] = {'\0'};
unsigned char local_addr[BT_MAC_LEN] = {0};
unsigned char cmd[HCI_MAX_CMD_SIZE] = {0};
unsigned char rsp[HCI_MAX_EVENT_SIZE] = {0};
if (amlbt_fw_mode == 2) {
ALOGD("15p4 only skip set bdaddr");
return 0;
}
if (!amlbt_read_addr(local_addr)) {
ALOGD("read bdaddr ok");
goto set_mac;
}
if (!amlbt_get_random_addr(local_addr, ADDR_FIXED_PREFIX)) {
snprintf(buf, sizeof(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]);
ret = amlbt_info_update(AMLBT_ADDR, buf);
if (ret < 0) {
ALOGE("update: %s fail", AMLBT_ADDR);
}
} else {
ALOGE("get random mac addr fail");
goto error;
}
set_mac:
ALOGI("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++ = BT_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 + BT_MAC_LEN);
ret = write(fd, cmd, size);
if (ret != size) {
ALOGE("Send fail with ret value: %d", ret);
goto error;
}
/* Wait for command complete event */
ret = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE);
if ( ret < 0) {
ALOGE("Read controller ack event fail");
goto error;
}
ALOGD("HCI rsp: %#x %#x %#x %#x %#x %#x %#x",
rsp[0], rsp[1], rsp[2], rsp[3], rsp[4], rsp[5], rsp[6]);
ALOGD("HCI rsp: %#x %#x %#x %#x %#x %#x %#x",
rsp[7], rsp[8], rsp[9], rsp[10], rsp[11], rsp[12], rsp[13]);
if (rsp[4] != cmd[1] || rsp[5] != cmd[2] || rsp[6] != 0X00) {
ALOGE("Failed to set_bdaddr, command failure");
goto error;
}
ret = amlbt_get_fw_ver(rsp);
if (ret < 0) {
ALOGE("get fw ver fail");
goto error;
}
ALOGD("success ret:%d", ret);
error:
return ret;
}
static int hw_config_set_rf_params(int fd)
{
int err = -1;
int size;
uint32_t reg_data = 0;
unsigned int antenna_num = 0;
unsigned int a2dp_sink_enable = 0;;
char *cmd_hdr = NULL;
unsigned char cmd[HCI_MAX_CMD_SIZE] = {0};
unsigned char rsp[HCI_MAX_EVENT_SIZE] = {0};
antenna_num = amlbt_rftype;
a2dp_sink_enable = amlbt_btsink;
ALOGD("Setting parameters to controller: antenna number=%d, a2dp_sink_enable=%d", antenna_num,a2dp_sink_enable);
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) {
reg_data = 0x10000000; //bit28 means RF_ANT_SINGLE
} else if (antenna_num == 2) {
reg_data = 0x20000000; //bit29 means RF_ANT_DOUBLE
}
if (a2dp_sink_enable == 1) {
reg_data |= (1<<25); // bit25 means a2dp_sink_enable.
}
ALOGD("reg_data=%x", reg_data); //0x12000000
UINT32_TO_STREAM(cmd_hdr, reg_data);
size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + 0x08);
err = write(fd, cmd, size);
if (err != size) {
ALOGE("Send fail 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) {
ALOGE("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;
char *cmd_hdr = NULL;
unsigned char cmd[HCI_MAX_CMD_SIZE] = {0};
unsigned char rsp[HCI_MAX_EVENT_SIZE] = {0};
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 */
ALOGD("HCI cmd: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
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) {
ALOGE("Send fail 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) {
ALOGE("Read controller ack event fail");
goto error;
}
ALOGD("HCI rsp: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", \
rsp[0], rsp[1], rsp[2], rsp[3], rsp[4], rsp[5], rsp[6]);
if (rsp[4] != cmd[1] || rsp[5] != cmd[2] || rsp[6] != 0X00) {
ALOGE("Failed to cpu_uart, command failure");
return -1;
}
ALOGD("success");
ms_delay(MAC_DELAY);
ALOGD("delay %d",MAC_DELAY);
if (!load_efuse && func != NULL) {
err = func(fd);
if (err < 0) {
ALOGE("cmd send fail");
goto error;
}
} else {
ALOGE("func is null");
}
error:
return err;
}
/******************************************************************************
** start cup cmd
******************************************************************************/
static int aml_start_cpu_before_cmd(int fd)
{
int size;
int err = -1;
char *cmd_hdr = NULL;
unsigned char cmd[HCI_MAX_CMD_SIZE] = {0};
unsigned char rsp[HCI_MAX_EVENT_SIZE] = {0};
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 */
ALOGD("HCI cmd: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
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) {
ALOGE("Send fail 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) {
ALOGE("Read controller ack event fail");
goto error;
}
ALOGD("HCI rsp: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", \
rsp[0], rsp[1], rsp[2], rsp[3], rsp[4], rsp[5], rsp[6]);
if (rsp[4] != cmd[1] || rsp[5] != cmd[2] || rsp[6] != 0X00) {
ALOGE("Failed to cpu_before_cmd, command failure");
return -1;
}
err = aml_start_cpu_uart(fd, aml_set_bdaddr); //aml_hci_reset);
if (err < 0) {
ALOGE("aml_start_cpu_uart cmd load fail");
goto error;
}
ALOGD("success");
error:
return err;
}
/******************************************************************************
** disable download
******************************************************************************/
static int aml_disable_event(int fd)
{
int size;
int err = -1;
hci_command_hdr *cmd_hdr;
unsigned char cmd[HCI_MAX_CMD_SIZE] = {0};
unsigned char rsp[HCI_MAX_EVENT_SIZE] = {0};
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 */
ALOGD("HCI cmd: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
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) {
ALOGE("Send fail 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) {
ALOGE("Read controller ack event fail");
goto error;
}
if (rsp[4] != cmd[1] || rsp[5] != cmd[2] || rsp[6] != 0X00) {
ALOGE("Failed to disable_event, command failure");
return -1;
}
ALOGD("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)
{
int reg_data,cmp_data;
int BT_fwICCM_len;
int err = -1;
int size;
char *p_tmp = NULL;
char *p_name = NULL;
char * cmd_hdr = NULL;
unsigned char cmd[HCI_MAX_CMD_SIZE] = {0};
unsigned char rsp[HCI_MAX_EVENT_SIZE] = {0};
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) {
ALOGE("Send fail 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) {
ALOGE("Read controller ack event fail");
goto error;
}
if (rsp[4] != cmd[1] || rsp[5] != cmd[2] || rsp[6] != 0X00) {
ALOGE("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);
ALOGI("reg_data = %x,cmp_data = %x", reg_data, cmp_data);
if (cmp_data == reg_data) {
ALOGI("read iccm OK");
} else {
ALOGE("read iccm Fail");
return -1;
}
iccm_j = iccm_j + 8;
}
ALOGI("check iccm_fw is ok");
error:
iccm_read_off = 0;
iccm_j = 0;
return err;
}
static int check_download_dccmfw(int fd)
{
int reg_data = 0 ,cmp_data = 0;
int BT_fwDCCM_len = 0;
int err = -1;
int size;
char *p_tmp = NULL;
char *p_name = NULL;
char * cmd_hdr = NULL;
unsigned char cmd[HCI_MAX_CMD_SIZE] = {0};
unsigned char rsp[HCI_MAX_EVENT_SIZE] = {0};
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) {
ALOGE("Send fail 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) {
ALOGE("Read controller ack event fail");
goto error;
}
if (rsp[4] != cmd[1] || rsp[5] != cmd[2] || rsp[6] != 0X00) {
ALOGE("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);
ALOGD("reg_data = %x,cmp_data = %x", reg_data, cmp_data);
if (cmp_data == reg_data) {
//ALOGI("read dccm OK");
} else {
ALOGE("read dccm Fail");
return -1;
}
dccm_j += 4;
}
ALOGD("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;
int flags;
int n = 0;
char * cmd_hdr = NULL;
unsigned char cmd[HCI_MAX_CMD_SIZE] = {0};
unsigned char rsp[HCI_MAX_EVENT_SIZE] = {0};
if (buf == NULL) {
ALOGE("buf is NULL");
return -1;
}
if (!diff) {
ALOGD("start download fw BT_fwICCM 0x%x %d", buf_size, n);
} else {
ALOGD("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) {
ALOGE("Send fail 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) {
ALOGE("Read controller ack event fail");
goto error;
}
if (rsp[4] != cmd[1] || rsp[5] != cmd[2] || rsp[6] != 0X00) {
ALOGE("Failed to tci_write, command failure");
return -1;
}
offset += data_len;
buf_size -= data_len;
}
if (!diff) {
ALOGD("download fw BT_fwICCM SUCCESS times: %d", n);
} else {
ALOGD("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(int fd, unsigned char userial_baud)
{
vnd_userial_cb_t vnd_userial = {0};
unsigned int tcio_baud;
ALOGD("userial_baud:%d", userial_baud);
vnd_userial.fd = fd;
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 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) {
ALOGE("--------- read error!---------");
close(fd);
return 0;
}
close(fd);
ALOGD("--------- iccm_size %d---------", iccm_size);
return (iccm_size < ICCM_DCCM_MAX) ? iccm_size : ICCM_DCCM_MAX;
}
static unsigned int hw_config_get_dccm_size(const dev_item *dev)
{
int fd = 0;
unsigned int dccm_size = 0;
//unsigned int add_iccm = 0;
int size = 0;
if ((fd = open(dev->fw_file, O_RDONLY)) < 0)
return 0;
if (lseek(fd, 4, SEEK_SET) != 4) {
ALOGE("skip 4 bytes iccm len fail");
close(fd);
return 0;
}
//W1U skip 15KB additional iccm
if (dev->idx == W1U_UART) {
size = read(fd, &add_iccm, 4);
if (size < 0) {
ALOGE("hw_config_get_dccm_size read error!---------");
close(fd);
return 0;
}
ALOGD("hw_config_get_add_iccm_size %#x---------", add_iccm);
}
size = read(fd, &dccm_size, 4);
if (size < 0) {
ALOGE("--------- read error!---------");
close(fd);
return 0;
}
close(fd);
if (dev->idx == W1U_UART) {
if (dccm_size == W1U_ROM_START_CODE) {
ALOGE("---------w1u sram code size 0---------");
dccm_size = add_iccm;
add_iccm = 0;
}
}
ALOGD("--------- dccm_size %d---------", 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) {
ALOGE("malloc p_iccmbuf fail");
ret = 1;
goto error;
}
memset(p_iccmbuf, 0, iccmlen + 1);
p_dccmbuf = malloc(dccmlen + 1);
if (p_dccmbuf == NULL) {
ALOGE("malloc p_dccmbuf fail");
ret = 2;
goto error;
}
memset(p_dccmbuf, 0, dccmlen + 1);
fd = open(file, O_RDONLY);
if (fd <0) {
ALOGE("open fw_file fail");
ret = 3;
goto error;
}
if (add_iccm) {
ALOGD("add iccm size %d",add_iccm);
if (lseek(fd, 12, SEEK_SET) != 12) {
ALOGE("skip 12byte len fail");
close(fd);
ret = 3;
goto error;
}
} else {
ALOGD("add iccm size 0");
if (lseek(fd, 8, SEEK_SET) != 8) {
ALOGE("skip 8byte len fail");
close(fd);
ret = 3;
goto error;
}
}
ret = read(fd, p_iccmbuf, iccmlen);
if (ret < 0) {
ALOGE("------ p_iccmbuf read error!------");
close(fd);
ret = 3;
goto error;
}
//W1U skip 15KB additional iccm
if (add_iccm) {
ALOGD("w1u skip %d additional iccm", add_iccm);
ret = lseek(fd, add_iccm, SEEK_CUR);
if (ret < 0) {
ALOGE("lseek add iccm fail:%s", strerror(errno));
close(fd);
ret = 3;
goto error;
}
ALOGD("w1u skip additional iccm result %d", ret);
}
ret = read(fd, p_dccmbuf, dccmlen);
if (ret < 0) {
ALOGE("------ 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(const dev_item *dev, 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;
ALOGD("%s start download: %s",dev->dev_name, dev->fw_file);
fwICCM_len = hw_config_get_iccm_size(dev->fw_file);
fwICCM_size = fwICCM_len;
fwICCM_size -= dev->iccm_base * 1024;
ALOGD("fw BT_fwICCM is total: 0x%x", fwICCM_size);
fwICCM_offset = dev->iccm_base * 1024;
fwDCCM_size = hw_config_get_dccm_size(dev);
ALOGD("fw BT_fwDCCM is total : 0x%x", fwDCCM_size);
if (get_iccmbuf_dccmbuf(&p_BT_fwICCM, &p_BT_fwDCCM, fwICCM_len, fwDCCM_size,
dev->fw_file)) {
ALOGE("get_iccmbuf_dccmbuf fail");
return err;
}
err = aml_send(fd, p_BT_fwICCM, fwICCM_size, fwICCM_offset, fwICCM);
if (err < 0) {
ALOGE("write BT_fwICCM fail");
goto error;
}
#if CHECK_FW
ALOGD("start check BT_fwICCM");
err = check_download_fwiccm(fd);
if (err < 0) {
ALOGE("check_download_fwiccm fail");
}
#endif
err = aml_send(fd, p_BT_fwDCCM, fwDCCM_size, fwDCCM_offset, fwDCCM);
if (err < 0) {
ALOGE("write BT_fwDCCM fail");
goto error;
}
#if CHECK_FW
ALOGD("start check BT_fwDCCM");
err = check_download_dccmfw(fd);
if (err < 0) {
ALOGE("check_download_dccmfw fail");
}
#endif
if (func != NULL) {
err = func(fd);
if (err < 0) {
ALOGE("cmd fail");
err = -1;
}
} else {
ALOGE("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 {
ALOGE("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;
int flags;
hci_command_hdr *cmd_hdr;
unsigned char cmd[HCI_MAX_CMD_SIZE] = {0};
unsigned char rsp[HCI_MAX_EVENT_SIZE] = {0};
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 */
ALOGD("HCI cmd: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
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) {
ALOGE("Send fail, ret: %d", err);
goto error;
}
/* Wait for command complete event */
err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE);
if ( err < 0) {
ALOGE("Read controller ack event fail");
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(fd, USERIAL_BAUD_4M);
/* Flow on after changing local uart baudrate */
aml_flow_control(fd, MSM_ENABLE_FLOW_CTRL);
ALOGD("success");
if (tci_write != NULL) {
err = tci_write(fd);
if (err < 0) {
ALOGE("tci_write cmd fail");
goto error;
}
} else {
ALOGE("tci_write is NULL");
return -1;
}
if (tci_read != NULL) {
err = tci_read(fd);
if (err < 0) {
ALOGE("tci_read cmd fail");
goto error;
}
} else {
ALOGE("tci_read is NULL");
return -1;
}
error:
return err;
}
static int aml_tci_write_reg(int fd)
{
int size, err = 0;
int flags;
hci_command_hdr *cmd_hdr;
unsigned char cmd[HCI_MAX_CMD_SIZE] = {0};
unsigned char rsp[HCI_MAX_EVENT_SIZE] = {0};
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 */
ALOGD("HCI cmd: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
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) {
ALOGE("Send fail 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) {
ALOGE("Read controller ack event fail");
goto error;
}
if (rsp[4] != cmd[1] || rsp[5] != cmd[2] || rsp[6] != 0X00) {
ALOGE("Failed to tci_write, command failure");
return -1;
}
ALOGD("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);
ALOGD("HCI cmd: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
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) {
ALOGE("Send fail 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) {
ALOGE("Read controller ack event fail");
goto error;
}
if (rsp[4] != cmd[1] || rsp[5] != cmd[2] || rsp[6] != 0X00) {
ALOGE("Failed to tci_write, command failure");
return -1;
}
ALOGD("success");
error:
return err;
}
static int aml_tci_read_reg(int fd)
{
int size, err = -1;
int flags;
hci_command_hdr *cmd_hdr;
unsigned char cmd[HCI_MAX_CMD_SIZE] = {0};
unsigned char rsp[HCI_MAX_EVENT_SIZE] = {0};
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 */
ALOGD("HCI cmd: %02x %02x %02x %02x %02x %02x %02x %02x",
cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7]);
err = write(fd, cmd, size);
if (err != size) {
ALOGE("Send fail 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) {
ALOGE("Read controller ack event fail");
goto error;
}
if (rsp[4] != cmd[1] || rsp[5] != cmd[2] || rsp[6] != 0X00) {
ALOGE("Failed to tci_write, command failure");
return -1;
}
ALOGD("success");
error:
return err;
}
static int aml_hci_reset(int fd)
{
int size, err = 0;
int flags;
hci_command_hdr *cmd_hdr;
unsigned char cmd[HCI_MAX_CMD_SIZE] = {0};
unsigned char rsp[HCI_MAX_EVENT_SIZE] = {0};
ALOGD("HCI RESET");
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 */
ALOGD("HCI cmd: %02x %02x %02x %02x", cmd[0], cmd[1], cmd[2], cmd[3]);
err = write(fd, cmd, size);
if (err != size) {
ALOGE("Send fail 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) {
ALOGE("Read controller ack event fail");
goto error;
}
if (rsp[4] != cmd[1] || rsp[5] != cmd[2] || rsp[6] != 0X00) {
ALOGE("Failed to tci_write, command failure");
return -1;
}
ALOGI("success");
error:
return err;
}
int aml_init(int fd, char *bdaddr)
{
dev_item *cur_dev = NULL;
int err = -1;
cur_dev = get_amlbt_dev_item();
if (!cur_dev) {
ALOGE("cur_dev is null");
goto error;
}
amlbt_open_dev_w1u(cur_dev->idx);
/* read aml_bt.conf */
amlbt_load_conf();
/*set bt pwr ctl Mode*/
amlbt_set_power(cur_dev->idx, 1);
/* update baud */
err = aml_update_baudrate(fd, aml_tci_write_reg, aml_tci_read_reg);
if (err < 0) {
ALOGE("Baudrate change fail");
goto error;
}
ALOGI("Baudrate change success");
/* Download fw files */
err = aml_download_fw_file(cur_dev, fd, aml_disable_event);
if (err < 0) {
ALOGE("Download fw file fail");
goto error;
}
ALOGI("Download fw file success");
/*
* Download firmware and write conf parameters:
*
* W1U_UART:
* Download firmware bin with size exceeding bt ram space
* Write conf parameters after download firmware
*
* W2_UART:
* Write conf parameters after download firmware
*
* W2L_UART:
* Write conf parameters after download firmware
*/
err = amlbt_set_conf_params(cur_dev->idx);
if (err < 0) {
ALOGE("amlbt_set_conf_params fail");
goto error;
}
/* set rf param */
err = hw_config_set_rf_params(fd);
if (err < 0) {
ALOGE("hw_config_set_rf_params fail");
goto error;
}
ALOGD("hw_config_set_rf_params success");
/* start cup cmd */
err = aml_start_cpu_before_cmd(fd);
if (err < 0) {
ALOGE("cpu before cmd fail");
goto error;
}
ALOGD("cpu before cmd success");
if (amlbt_fw_mode == 2) {
ALOGD("fw_mode %d (15p4 only) skip bt reset",amlbt_fw_mode);
} else {
/* send wakeup param */
err = aml_set_wakeup_para(fd, cur_dev->idx);
if (err < 0) {
ALOGE("set wake manf data fail");
goto error;
}
ALOGD("set wake manf data success");
/* Perform HCI reset here */
err = aml_hci_reset(fd);
if (err < 0) {
ALOGE("HCI Reset Failed !!!");
goto error;
}
ALOGD("HCI Reset is done");
}
error:
amlbt_close_dev();
return err;
}