/* * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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; }