/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2000-2001 Qualcomm Incorporated * Copyright (C) 2002-2003 Maxim Krasnyansky * Copyright (C) 2002-2010 Marcel Holtmann * * * 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 #include #include #include #include #include #include #include #include //#include #include #include #include #include #include #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; }