1705 lines
48 KiB
C
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;
|
|
}
|
|
|