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

1227 lines
35 KiB
C

/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2000-2001 Qualcomm Incorporated
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <getopt.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/termios.h>
#include <sys/ioctl.h>
//#include <sys/io.h>
#include <limits.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <time.h>
#include "hciattach.h"
#include "aml_comm.h"
#include "hciattach_aml_usb.h"
#include "aml_multibt.h"
#include "aml_conf.h"
#define UINT8_TO_STREAM(p, u8) { *(p)++ = (char)(u8); }
#define UINT16_TO_STREAM(p, u16) { *(p)++ = (char)(u16); *(p)++ = (char)((u16) >> 8); }
#define CMD_TEST_FW _IOR('A', 2, int)
#define MAC_DELAY 350
static int debug = 0;
extern int g_usb_fd;
unsigned char *BT_fwICCM = NULL;
unsigned char *BT_fwDCCM = NULL;
unsigned int ICCM_LEN = 0;
unsigned int DCCM_LEN = 0;
//#define W2L_CHIPSET
//#define W2_CHIPSET
#define W1U_CHIPSET
#if defined(W2L_CHIPSET)
#define CHIP_OFFSET (384 * 1024)
#elif defined(W1U_CHIPSET) || defined(W2_CHIPSET)
#define CHIP_OFFSET (256 * 1024)
#else
#error "No chipset defined. Please define W1U_CHIPSET, W2_CHIPSET, or W2L_CHIPSET."
#endif
static void ms_delay(unsigned int 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);
}
static void aml_insert_uint32(unsigned char *p_buffer, unsigned int value_32_bit)
{
p_buffer[0] = (unsigned char)_SYS_GET_CHAR_8_BITS(value_32_bit);
p_buffer[1] = (unsigned char)_SYS_GET_CHAR_8_BITS(value_32_bit >> 8);
p_buffer[2] = (unsigned char)_SYS_GET_CHAR_8_BITS(value_32_bit >> 16);
p_buffer[3] = (unsigned char)_SYS_GET_CHAR_8_BITS(value_32_bit >> 24);
}
static unsigned int aml_get_uint32(unsigned char *p_pdu)
{
return (*p_pdu) + ((*(p_pdu + 1)) << 8) + ((*(p_pdu + 2)) << 16) + ((*(p_pdu + 3)) << 24);
}
static void dump(unsigned char *out, int len)
{
int i;
for (i = 0; i < len; i++) {
if (i && !(i % 16)) {
ALOGD("\n");
}
ALOGD("%02x ", out[i]);
}
ALOGD("\n");
}
#if 0
int get_usb_fd_with_retry(const char *dev, int max_retry, int delay_ms)
{
int usb_fd = -1;
int retry = 0;
ALOGI("Trying to open BT USB Device: %s max_retry: %d delay_ms %d", dev, max_retry, delay_ms);
while (retry < max_retry) {
usb_fd = open(dev, O_RDWR | O_NOCTTY);
if (usb_fd >= 0) {
ALOGI("BT USB Device %s opened successfully on retry %d with fd %d", dev, retry, usb_fd);
return usb_fd;
} else { // error = 2 ENOENT error = 13 EACCES
ALOGE("Attempt %d: Failed to open %s, error: %d (%s)", retry + 1, dev, errno, strerror(errno));
ms_delay(delay_ms);
retry++;
}
}
ALOGE("Failed to open %s after %d retries", dev, max_retry);
return -1;
}
#endif
int get_usb_fd(const char *dev)
{
int usb_fd = -1;
ALOGD("amlbt usb dev:%s", dev);
usb_fd = open(dev, O_RDWR | O_NOCTTY);
if (usb_fd == -1) {
ALOGE("open:%s fail, error:%d", dev, errno);
return -1;
}
ALOGI("amlbt usb dev:%s open success, usb_fd:%d", dev, usb_fd);
return usb_fd;
}
static void hex_dump(char *pref, int width, unsigned char *buf, int len)
{
register int i,n;
for (i = 0, n = 1; i < len; i++, n++) {
if (n == 1)
ALOGD("%s", pref);
printf("%2.2X ", buf[i]);
if (n == width) {
ALOGD("\n");
n = 0;
}
}
if (i && n!= 1)
ALOGD("\n");
}
static int read_event(unsigned char *buffer)
{
int rx_len = 0;
int timeout_cnt = 0;
int event_cnt = 0;
unsigned int event_parameter_len = 0;
fd_set read_fds;
int evt_state = 0;
int rval;
struct timeval wait_time = {0, 200000};
enum
{
EVT_TYPE,
EVT_HEAD,
EVT_PLAYLOAD,
EVT_END
};
while (evt_state < EVT_END) {
FD_ZERO(&read_fds);
FD_SET(g_usb_fd, &read_fds);
rval = select(g_usb_fd + 1, &read_fds, NULL, NULL, &wait_time);
if (rval > 0) {
switch (evt_state)
{
case EVT_TYPE:
rx_len = read(g_usb_fd, &buffer[event_cnt], 1);
if (rx_len <= 0) {
ALOGE("EVT_TYPE read failed: rx_len %d", rx_len);
return -1;
}
event_cnt += rx_len;
evt_state++;
break;
case EVT_HEAD:
rx_len = read(g_usb_fd, &buffer[event_cnt], 2);
if (rx_len <= 0) {
ALOGE("EVT_HEAD read failed: rx_len %d", rx_len);
return -1;
}
event_cnt += rx_len;
event_parameter_len = buffer[2];
evt_state++;
case EVT_PLAYLOAD:
rx_len = read(g_usb_fd, &buffer[event_cnt], event_parameter_len);
if (rx_len <= 0) {
ALOGE("EVT_PLAYLOAD read failed: rx_len %d", rx_len);
return -1;
}
event_cnt += rx_len;
evt_state++;
break;
default:
break;
}
}
else if (rval == 0) {
timeout_cnt++;
if (timeout_cnt > 150) {
ALOGE("Rx event parameter timeout");
return 0;
}
}
wait_time.tv_sec = 0;
wait_time.tv_usec = 200000;
FD_ZERO(&read_fds);
FD_SET(g_usb_fd, &read_fds);
}
if (debug)
dump(buffer, event_cnt);
return event_cnt;
}
static int read_event_with_retry(unsigned char *buffer, int max_retry, int delay_ms)
{
int ret = 0;
int retry = 0;
ALOGD("max_retry:%d, delay:%d", max_retry, delay_ms);
while (retry < max_retry) {
ms_delay(delay_ms);
ret = read_event(buffer);
if (ret > 0) {
ALOGI("read event success ret:%d retry:%d",ret, retry);
break;
} else {
ALOGE("read_event failed ret:%d",ret);
}
retry++;
}
if (ret <= 0) {
ALOGE("still fail after max_retry:%d", max_retry);
}
return ret;
}
static int hci_send_cmd(unsigned char *buf, int len)
{
int write_bytes = 0;
//unsigned char hcitype[] = {HCI_pduCOMMAND};
//write_bytes = write(g_usb_fd, hcitype, 1);
write_bytes = write(g_usb_fd, buf, len);
if (write_bytes) {
//write_bytes = write(g_usb_fd, buf + 1, len -1);
if (debug) {
ALOGD("writing");
dump(buf, len);
if (write_bytes == -1) {
ALOGE("write bytes fail, error:%d",errno);
}
}
//ALOGI("Send hcicommand success! write_bytes:%d", write_bytes);
//return 0;
} else {
ALOGE("send hci command fail");
return -1;
}
return 0;
}
static unsigned int read_bt_register(unsigned int address)
{
int ret = 0;
unsigned char pdu[8] = {0};
unsigned int data = 0;
unsigned char recv_data[256] = {0};
pdu[0] = HCI_pduCOMMAND;
pdu[1] = TCI_DBG_READ_REG;
pdu[2] = PROP_OGF;
pdu[3] = READ_BT_REG_LEN;
aml_insert_uint32(&pdu[4], address);
hci_send_cmd(pdu, sizeof(pdu));
ret = read_event(recv_data);
if (ret > 0) {
if ((recv_data[0] == 0x04) &&
(recv_data[4] == TCI_DBG_READ_REG) &&
(recv_data[5] == PROP_OGF)) {
data = aml_get_uint32(&recv_data[7]);
return data;
}
}
ALOGE("Read BT register 0x%06x failed", address);
return 0;
}
static void write_bt_register(unsigned int address, unsigned int value)
{
int ret = 0;
unsigned char pdu[12] = {0};
unsigned char recv_data[256] = {0};
pdu[0] = HCI_pduCOMMAND;
pdu[1] = TCI_DBG_WRITE_REG;
pdu[2] = PROP_OGF;
pdu[3] = WRITE_BT_REG_LEN;
aml_insert_uint32(&pdu[4], address);
aml_insert_uint32(&pdu[8], value);
hci_send_cmd(pdu, sizeof(pdu));
ret = read_event(recv_data);
if (ret > 0) {
if ((recv_data[0] == 0x04) &&
(recv_data[4] == TCI_DBG_WRITE_REG) &&
(recv_data[5] == PROP_OGF)) {
goto WriteSuccess;
}
}
ALOGE("Write BT register 0x%06x failed", address);
WriteSuccess:
return;
}
static int aml_tci_load_bt_fw_cmd(int opcode, unsigned char data_len, unsigned int addr, unsigned char* data)
{
unsigned char pdu[300] = { 0 };
unsigned short length = 0;
int i = 0;
int rx_len = 0;
unsigned char rx_buff[1024] = {0};
unsigned char *temp_data = (unsigned char*)malloc(300);
if (!temp_data) {
ALOGE("New space fail");
return -1;
}
pdu[0] = (unsigned char)(opcode & 0xFF);
pdu[1] = (unsigned char)((opcode >> 8) & 0xFF);
pdu[2] = data_len;
length = pdu[2] + 3;
aml_insert_uint32(pdu + 3, addr);
for (i = 0; i < data_len; i += 1) {
pdu[i + 7] = *(data + i);
}
//temp_data[0] = HCI_pduCOMMAND;
//memcpy(temp_data + 1, pdu, length);
//hci_send_cmd(temp_data, length + 1);
memcpy(temp_data, pdu, length);
hci_send_cmd(temp_data, length);
//dump(temp_data, length + 1);
rx_len = read_event(rx_buff);
if (rx_len > 0) {
free(temp_data);
return 0;
}
free(temp_data);
return -1;
}
static int aml_usb_download_fw_img()
{
int count = 0;
int result = 0;
unsigned char* bufferICCM = BT_fwICCM;
unsigned char* bufferDCCM = BT_fwDCCM;
int len = 0, offset = 0, offset_in_bt =0;
unsigned int cmd_len = 0;
unsigned int data_len = 0;
int cnt = 1;
offset_in_bt = CHIP_OFFSET;
offset = CHIP_OFFSET;
len = ICCM_LEN - offset_in_bt;//ALIGN(sizeof(BT_fwICCM), 4) -256*1024;
ALOGI("BT start iccm copy, total=0x%x ", len);
if (len == 0)
goto DCC_START;
ALOGI("BT iccm base 0x%x ", ICCM_RAM_BASE);
do
{
data_len = (len > RW_OPERATION_SIZE) ? RW_OPERATION_SIZE : len;
cmd_len = data_len + 4;
result = aml_tci_load_bt_fw_cmd(TCI_DOWNLOAD_BT_FW, cmd_len,
ICCM_RAM_BASE + offset, bufferICCM + offset);
if (result) {
ALOGE("Download iccm data error");
return FAILED;
}
cnt++;
offset += data_len;
len -= data_len;
count++;
} while (len > 0);
ALOGI("Download iccm data success");
DCC_START:
len = DCCM_LEN;//ALIGN(sizeof(BT_fwDCCM), 4);
offset = 0;
cnt = 1;
data_len = 0;
cmd_len = 0;
ALOGI("start dccm copy, total=0x%x", len);
do
{
data_len = (len > RW_OPERATION_SIZE) ? RW_OPERATION_SIZE : len;
cmd_len = data_len + 4;
result = aml_tci_load_bt_fw_cmd(TCI_DOWNLOAD_BT_FW, cmd_len, DCCM_RAM_BASE + offset, bufferDCCM + offset);
if (result) {
ALOGE("Download dccm data error");
return -1;
}
cnt++;
offset += data_len;
len -= data_len;
count++;
} while (len > 0);
ALOGI("Download dccm data sunccess");
return SUCCESS;
}
static int aml_tci_write_register(int opcode, unsigned int address, unsigned int value)
{
unsigned char pdu[30] = { 0 };
unsigned char *data = (unsigned char*)malloc(30);
unsigned char tmp_buff[4096] = { 0 };
int rx_len = 0;
unsigned short length = 0;
if (!data) {
ALOGE("New space fail");
return TCI_WRITE_READ_FAILED;
}
pdu[0] = (unsigned char)(opcode & 0xFF);
pdu[1] = (unsigned char)((opcode >> 8) & 0xFF);
pdu[2] = 8;
length = pdu[2] + 3;
aml_insert_uint32(pdu + 3, address);
aml_insert_uint32(pdu + 7, value);
//data[0] = HCI_pduCOMMAND;
//memcpy(data + 1, pdu, length);
//hci_send_cmd(data, length + 1);
memcpy(data, pdu, length);
hci_send_cmd(data, length);
rx_len = read_event(tmp_buff);
dump(tmp_buff, rx_len);
free(data);
ALOGI("success");
return TCI_WRITE_READ_SUCCESS;
}
static int aml_get_a2dp_sink_enable(void)
{
int size;
int fd_a2dp_cfg = 0;
char buffer[255] = { 0 };
char c = '=';
unsigned char a2dp_sink_enable = 0;
fd_a2dp_cfg = open(AML_A2DP_CFG_FILE, O_RDONLY);
if (fd_a2dp_cfg < 0) {
ALOGE("In %s, Open failed:%s", __FUNCTION__, strerror(errno));
return -1;
}
size = read(fd_a2dp_cfg, buffer, sizeof(buffer));
if (size < 0) {
ALOGE("In %s, Read failed:%s", __FUNCTION__, strerror(errno));
close(fd_a2dp_cfg);
return -1;
}
buffer[sizeof(buffer) - 1] = 0;
char *ptr_a2dp_cfg = strchr(buffer, c);
if (!ptr_a2dp_cfg) {
ALOGE("In %s, wrong a2dp_sink_enable value", __FUNCTION__);
close(fd_a2dp_cfg);
return -1;
}
ptr_a2dp_cfg++;
a2dp_sink_enable = atoi(ptr_a2dp_cfg);
close(fd_a2dp_cfg);
ALOGI("Setting parameters to controller: a2dp_sink_enable=%d.", a2dp_sink_enable);
return a2dp_sink_enable;
}
static int aml_get_antenna_number(void)
{
int size;
char c = '=';
unsigned char antenna_num = 0;
int fd_ant_num = 0;
char buffer[255] = { 0 };
fd_ant_num = open(AML_BT_CONFIG_RF_FILE, O_RDONLY);
if (fd_ant_num < 0) {
ALOGE("In %s, Open failed:%s", __FUNCTION__, strerror(errno));
return -1;
}
size = read(fd_ant_num, buffer, sizeof(buffer));
if (size < 0) {
ALOGE("In %s, Read failed:%s", __FUNCTION__, strerror(errno));
close(fd_ant_num);
return -1;
}
buffer[sizeof(buffer) - 1] = 0;
char *ptr_a2dp_cfg = strchr(buffer, c);
if (!ptr_a2dp_cfg) {
ALOGE("In %s, wrong a2dp_sink_enable value", __FUNCTION__);
close(fd_ant_num);
return -1;
}
ptr_a2dp_cfg++;
antenna_num = atoi(ptr_a2dp_cfg);
close(fd_ant_num);
ALOGI("Setting parameters to controller: antenna number=%d.", antenna_num);
return antenna_num;
}
static int aml_get_config_params(void)
{
unsigned int reg_data = 0;
unsigned char a2dp_sink = 0;
unsigned char ant_num = 0;
a2dp_sink = aml_get_a2dp_sink_enable();
ant_num = aml_get_antenna_number();
ALOGI("a2dp_sink_enable=%d ,antenna number=%d", a2dp_sink,ant_num);
if (ant_num == 1) {
reg_data = 0x10000000; //bit28 means RF_ANT_SINGLE
} else if (ant_num == 2) {
reg_data = 0x20000000; //bit29 means RF_ANT_DOUBLE
}
if (a2dp_sink == 1) {
reg_data |= (1<<25); // bit25 means a2dp_sink_enable.
}
ALOGI("reg_data=%x", reg_data);//0x12000000
return reg_data;
}
static int aml_hci_reset(int fd)
{
int size, err = 0;
int write_bytes = 0;
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]);
unsigned char hcitype[] = {HCI_pduCOMMAND};
write_bytes = write(fd, hcitype, 1);
if (write_bytes) {
err = write(fd, cmd +1, size-1);
if (err != size-1) {
ALOGE("Send fail, ret: %d", err);
goto error;
}
} else {
ALOGE("hci set hcitype err");
goto error;
}
/* Wait for command complete event */
err = read_event(rsp);
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", 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 tci_write, command failure");
return -1;
}
ALOGI("reset success");
return err;
error:
return err;
}
static int aml_set_wakeup_param_roku(int fd)
{
int total_len = 0;
int cnt_data = 0;
int cmd_size = 0;
int write_bytes = 0;
int err = -1;
int cnt = 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};
ALOGI("set wake apcf_manf_data");
if (apcf_manf_para == 0) {
ALOGE("apcf_manf_para is 0, use default");
//ALOGI("set wake default_manf_data");
//err = 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 failed!");
return -ENOMEM;
}
memset(total_manf_data, 0, BUF_MAX_LEN);
while (cnt < MANF_ROW) {
//15 index->0/1/2/3
if ((BIT(cnt) & apcf_manf_para) != 0) {
int group_len = apcf_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], apcf_manf_data[cnt], group_len);
ALOGD("%#x %#x %#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_manf_data[total_len+8], total_manf_data[total_len+9]);
total_len += group_len;
ALOGD("%#x %#x %#x %#x %#x %#x %#x %#x %#x %#x", apcf_manf_data[cnt][0], apcf_manf_data[cnt][1],
apcf_manf_data[cnt][2], apcf_manf_data[cnt][3],
apcf_manf_data[cnt][4], apcf_manf_data[cnt][5],
apcf_manf_data[cnt][6], apcf_manf_data[cnt][7],
apcf_manf_data[cnt][8], apcf_manf_data[cnt][9]);
cnt_data++;
}
}
cnt++;
}
if (total_len == 0 || cnt_data == 0) {
ALOGE("No apcf 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;
ALOGD("HCI cmd: %02x %02x %02x %02x", cmd[0], cmd[1], cmd[2], cmd[3]);
unsigned char hcitype[] = {HCI_pduCOMMAND};
write_bytes = write(fd, hcitype, 1);
if (write_bytes) {
err = write(fd, cmd + 1, cmd_size - 1);
if (err != cmd_size - 1) {
ALOGE("Send failed with ret value: %d", err);
goto error;
}
} else {
ALOGE("hci set hcitype err");
goto error;
}
err = read_event_with_retry(rsp, 5, 10);
if (err < 0) {
ALOGE("Failed to set apcf_manf_data config on Controller");
goto error;
}
ALOGI("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]);
ALOGI("hci set apcf_manf_data success %d", err);
free(total_manf_data);
return err;
error:
free(total_manf_data);
return err;
}
static int aml_set_wakeup_param_w1u(int fd)
{
int total_len = 0;
int cnt_data = 0;
int cmd_size = 0;
int write_bytes = 0;
int err = -1;
int cnt = 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};
ALOGI("set wake w1u_manf_data");
if (amlbt_manf_para == 0) {
ALOGD("amlbt_manf_para is 0, use default");
ALOGI("set wake default_manf_data");
//err = 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 failed!");
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;
ALOGD("HCI cmd: %02x %02x %02x %02x %02x", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4]);
unsigned char hcitype[] = {HCI_pduCOMMAND};
write_bytes = write(fd, hcitype, 1);
if (write_bytes) {
err = write(fd, cmd + 1, cmd_size - 1);
if (err != cmd_size - 1) {
ALOGE("Send failed with ret value: %d", err);
goto error;
}
} else {
ALOGE("hci set hcitype err");
goto error;
}
err = read_event_with_retry(rsp, 5, 10);
if (err < 0) {
ALOGE("Failed to set w1u_manf_data config on Controller");
goto error;
}
ALOGD("HCI rsp: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",rsp[0], rsp[1], rsp[2], rsp[3], rsp[4], rsp[5]);
ALOGI("hci set w1u_manf_data success %d", err);
free(total_manf_data);
return err;
error:
return err;
}
static int aml_set_wakeup_param_public(int fd)
{
int size;
int err = -1;
int write_bytes = 0;
char *cmd_hdr = NULL;
unsigned char APCF_config_manf_data[] = {0x01, 0x22, 0xFC, 0x05, 0x19, 0xff, 0x01, 0x0a, 0xb};
unsigned char cmd[HCI_MAX_CMD_SIZE] = {0};
unsigned char rsp[HCI_MAX_EVENT_SIZE] = {0};
ALOGI("set ManfData_public: %02x:%02x:%02x:%02x:%02x:%02x",
APCF_config_manf_data[0], APCF_config_manf_data[1], APCF_config_manf_data[2],
APCF_config_manf_data[3], APCF_config_manf_data[4], APCF_config_manf_data[5]);
cmd_hdr = (void *) (cmd + 1);
cmd[0] = HCI_COMMAND_PKT;
UINT16_TO_STREAM(cmd_hdr, HCI_VSC_WAKE_WRITE_DATA);
*cmd_hdr++ = 5;
*cmd_hdr++ = APCF_config_manf_data[4];
*cmd_hdr++ = APCF_config_manf_data[5];
*cmd_hdr++ = APCF_config_manf_data[6];
*cmd_hdr++ = APCF_config_manf_data[7];
*cmd_hdr++ = APCF_config_manf_data[8];
size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + 5);
ALOGD("HCI cmd: %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]);
unsigned char hcitype[] = {HCI_pduCOMMAND};
write_bytes = write(fd, hcitype, 1);
if (write_bytes) {
err = write(fd, cmd + 1, size - 1);
if (err != size - 1) {
ALOGE("Send failed with ret value: %d", err);
goto error;
}
} else {
ALOGE("hci set hcitype err");
goto error;
}
err = read_event_with_retry(rsp, 5, 10);
if (err < 0) {
ALOGE("Failed to set ManfData_public config on Controller");
goto error;
}
ALOGD("HCI rsp: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", rsp[0], rsp[1], rsp[2], rsp[3], rsp[4], rsp[5]);
ALOGD("HCI rsp: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", rsp[6], rsp[7], rsp[8], rsp[9], rsp[10], rsp[11]);
ALOGI("hci set ManfData_public success");
return err;
error:
return err;
}
static int aml_set_wakeup_param(int fd, amlbt_idx idx)
{
int ret = 0;
#ifdef ROKU_PROJECT
ret = aml_set_wakeup_param_roku(fd);
#elif defined(LINUX_PUBLIC) || defined(CAMERA_PROJECT)
if (idx == W1U_USB || idx == W2L_USB) {
ret = aml_set_wakeup_param_w1u(fd);
} else if (idx == W2_USB) {
ALOGD("send w2 usb wakeup param in driver, skip");
ret = 0;
} else {
ALOGE("Unsupported module index: %d", idx);
ret = -EINVAL;
}
#elif defined(AUDIO_PROJECT)
#warning "AUDIO_PROJECT ignore select APCF config"
return 0;
#else
#error "No defined configuration macros to select correct APCF config"
#endif
return ret;
}
int aml_set_register_hci0(int fd, amlbt_idx idx)
{
int arg = 1;
if (idx == W2L_USB) {
ALOGD("trig hci0 device register for W2L_USB...\n");
if (fd < 0) {
ALOGE("Invalid file descriptor\n");
return -1;
}
if (ioctl(fd, IOCTL_REGISTER_HCI0, &arg) < 0) {
ALOGE("Failed to register hci0 %s (errno: %d)\n", strerror(errno), errno);
return -1;
}
ALOGD("register hci0 success\n");
} else {
ALOGD("skip hci0 registration for chip idx: %d\n", idx);
}
return 0;
}
/******************************************************************************
** check efuse bdaddr
******************************************************************************/
static int aml_check_efuse_bdaddr(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, HCI_READ_BD_ADDR);
*cmd_hdr++ = 0;
size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE);
err = write(fd, cmd, size);
if (err != size) {
ALOGE("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) {
ALOGE("Read controller ack event fail");
goto error;
}
if ((rsp[7] == 0x00)
&& (rsp[8] == 0xff)
&& (rsp[9] == 0x00)
&& (rsp[10] == 0x22)
&& (rsp[11] == 0x2d)
&& (rsp[12] == 0xae)
|| (rsp[2] == 0x01)) {
ALOGE("No valid mac in efuse");
err = -1;
}
ALOGI("done");
error:
return err;
}
static int aml_set_bdaddr(int fd)
{
int size;
int ret = -1;
int write_bytes = 0;
char *cmd_hdr = NULL;
char buf[BT_MAC_BUF_LEN + 1];
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 (aml_check_efuse_bdaddr(fd) > 0 ) {
ALOGI("use mac in efuse");
memset(local_addr, 0, MAC_LEN);
goto set_mac;
} else */
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);
/* Send the HCI command packet to UART for transmission */
ALOGD("HCI cmd: %#x %#x %#x %#x", cmd[0], cmd[1], cmd[2], cmd[3]);
unsigned char hcitype[] = {HCI_pduCOMMAND};
write_bytes = write(fd, hcitype, 1);
if (write_bytes) {
ret = write(fd, cmd + 1, size - 1);
if (ret != size - 1) {
ALOGE("Send failed with ret value: %d", ret);
goto error;
}
} else {
ALOGE("hci set hcitype err");
goto error;
}
ret = read_event_with_retry(rsp, 5, 10);
if ( ret < 0) {
ALOGE("Read controller ack event fail");
goto error;
}
ALOGD("HCI rsp: %#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", 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");
return -1;
}
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 aml_download_firmware(char* firmware_file_path)
{
int binfile_fd = -1;
unsigned int iccm_size = 0;
unsigned int dccm_size = 0;
int size = 0;
char fw_bin_file[384];
int result = 0;
//int revData = -1;
unsigned int reg_data = 0;
int err = -1;
int success = 1;
memset(fw_bin_file, 0, sizeof(fw_bin_file));
if ((binfile_fd = open(firmware_file_path, O_RDONLY)) < 0) {
ALOGE("open:%s fail", firmware_file_path);
return err;
}
ALOGI("open firmware file success binfile_fd:%d", binfile_fd);
size = read(binfile_fd, &iccm_size, 4);
ALOGI("hw_config_get_iccm_size iccm_size:%d size:%d", iccm_size,size);
if (size < 0) {
ALOGE("---------1hw_config_get_iccm_size read error!---------");
close(binfile_fd);
return err;
}
ALOGI("---------2hw_config_get_iccm_size iccm_size %d---------", iccm_size);
size = read(binfile_fd, &dccm_size, 4);
if (size < 0) {
ALOGE("---------hw_config_get_dccm_size read error!---------");
close(binfile_fd);
return err;
}
ALOGI("---------hw_config_get_dccm_size dccm_size %d---------", dccm_size);
BT_fwICCM = (unsigned char*)malloc(iccm_size);
BT_fwDCCM = (unsigned char*)malloc(dccm_size);
if ((!BT_fwICCM) ||(!BT_fwDCCM)) {
ALOGE("Malloc fail");
return err;
}
size = read(binfile_fd, BT_fwICCM, iccm_size);
if (size < 0) {
ALOGE("---------hw_config_get_iccm_data error!---------");
close(binfile_fd);
free(BT_fwICCM);
free(BT_fwDCCM);
return err;
}
size = read(binfile_fd, BT_fwDCCM, dccm_size);
if (size < 0) {
ALOGE("---------hw_config_get_dccm_data error!---------");
close(binfile_fd);
free(BT_fwICCM);
free(BT_fwDCCM);
return err;
}
ICCM_LEN = iccm_size;
DCCM_LEN = dccm_size;
if (aml_usb_download_fw_img() == FAILED) return err;
result = aml_tci_write_register(TCI_WRITE_REG, 0xa70014, 0x0000000);
if (!result) {
ALOGE("close fw load");
} else {
ALOGE("close fw load failed");
return err;
}
reg_data = aml_get_config_params();
ALOGI("0xf03040 reg_data=%u", reg_data);
result = aml_tci_write_register(TCI_WRITE_REG, 0xf03040, reg_data);
if (result == TCI_WRITE_READ_FAILED) {
ALOGE("BT CPU can't work");
return err;
}
result = aml_tci_write_register(TCI_WRITE_REG, 0xf03058, 0x0000000);
if (result == TCI_WRITE_READ_FAILED) {
ALOGE("reset controller failed");
return err;
}
free(BT_fwICCM);
free(BT_fwDCCM);
//revData = ioctl(g_usb_fd, CMD_TEST_FW, 101);
//printf("receive data=%d\n", revData);
close(binfile_fd);
return success;
}
/*
1.download fw files
2.0xa70014 set rf calibration
3.0xf03040 set config params REG_PMU_POWER_CFG
4.0xf03058 cpu start REG_DEV_RESET
5.0xfc1a set bdaddr HCI_VSC_WRITE_BD_ADDR
6.0xfc22 set wake up param HCI_VSC_WAKE_WRITE_DATA
*/
int aml_usb_init(int fd)
{
dev_item *cur_dev = NULL;
int ret = -1;
#if 0
err = aml_download_firmware(AML_W1U_BT_FW_USB_FILE);
if (err < 0) {
ALOGE("Download fw file failed!");
goto error;
}
ALOGI("Download fw file successfully");
#endif
cur_dev = get_amlbt_dev_item();
if (!cur_dev) {
ALOGE("cur_dev is null");
goto error;
}
ms_delay(MAC_DELAY);
ALOGD("delay %d ms wait cpu start", MAC_DELAY);
/* read aml_bt.conf */
amlbt_load_conf();
ret = aml_set_bdaddr(fd);
if (ret < 0) {
ALOGE("HCI set bdaddr failed");
goto error;
}
ALOGD("HCI set bdaddr is done");
ret = aml_set_wakeup_param(fd, cur_dev->idx);
if (ret < 0) {
ALOGE("HCI set wakeup manf data failed");
goto error;
}
ALOGD("HCI set wakeup manf data is done");
ret = aml_set_register_hci0(fd, cur_dev->idx);
if (ret < 0) {
ALOGE("HCI set register hci0 failed");
goto error;
}
ALOGI("aml_usb_init success ret:%d", ret);
close(fd);
return ret;
error:
close(fd);
return ret;
}