#include #include #include #include #include #include #include #include #include #include #include #include #include "hciattach.h" /****************************************************************************** ** Constants & Macros ******************************************************************************/ #define LOG_STR "SPRD Bluetooth" #define DBG_ON 1 #define SPRD_DBG(fmt, arg...) \ do { \ if (DBG_ON) \ fprintf(stderr, "%s: " fmt "\n" , LOG_STR, ##arg); \ } while(0) #define SPRD_ERR(fmt, arg...) \ do { \ fprintf(stderr, "%s ERROR: " fmt "\n", LOG_STR, ##arg);\ perror(LOG_STR" ERROR reason"); \ } while(0) #define SPRD_DUMP(buffer, len) \ fprintf(stderr, "%s: ", LOG_STR); \ do { \ int i = 0; \ for (i = 0; i < len; i++) { \ if (i && !(i % 16)) { \ fprintf(stderr, "\n"); \ fprintf(stderr, "%s: ", LOG_STR); \ } \ fprintf(stderr, "%02x ", buffer[i]); \ } \ fprintf(stderr, "\n"); \ } while (0) #define CONF_ITEM_TABLE(ITEM, ACTION, BUF, LEN) \ { #ITEM, ACTION, &(BUF.ITEM), LEN, (sizeof(BUF.ITEM) / LEN) } #define UINT8_TO_STREAM(p, u8) \ { *(p)++ = (uint8_t)(u8); } #define STREAM_TO_UINT8(u8, p) \ { \ (u8) = (uint8_t)(*(p)); \ (p) += 1; \ } #define UINT16_TO_STREAM(p, u16) \ { \ *(p)++ = (uint8_t)(u16); \ *(p)++ = (uint8_t)((u16) >> 8); \ } #define STREAM_TO_UINT16(u16, p) \ { \ (u16) = ((uint16_t)(*(p)) + (((uint16_t)(*((p) + 1))) << 8)); \ (p) += 2; \ } #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 CONF_COMMENT '#' #define CONF_DELIMITERS " =\n\r\t" #define CONF_VALUES_DELIMITERS "=\n\r\t#" #define CONF_VALUES_PARTITION " ,=\n\r\t#" #define CONF_MAX_LINE_LEN 255 #define HCI_PSKEY 0xFCA0 #define HCI_VSC_ENABLE_COMMMAND 0xFCA1 #define HCI_RF_PARA 0xFCA2 #define RESPONSE_LENGTH 100 #define HCI_CMD_MAX_LEN 258 #define HCI_EVT_CMD_CMPL_OPCODE 3 #define HCI_PACKET_TYPE_COMMAND 1 #define HCI_CMD_PREAMBLE_SIZE 3 #define FW_NODE_BYTE 6 #define FW_DATE_D_BYTE 8 #define FW_DATE_M_BYTE 9 #define FW_DATE_Y_BYTE 10 #define BT_CONFIG_PATH "/lib/firmware" #define BT_HC_HDR_SIZE (sizeof(HC_BT_HDR)) #define BT_VND_OP_RESULT_SUCCESS 0 #define BT_VND_OP_RESULT_FAIL 1 #define MSG_STACK_TO_HC_HCI_CMD 0x2000 #define START_STOP_CMD_SIZE 3 #define DUAL_MODE 0 #define DISABLE_BT 0 #define ENABLE_BT 1 typedef void (*hci_cback)(void *); typedef int (conf_action_t)(char *p_conf_name, char *p_conf_value, void *buf, int len, int size); typedef struct { uint16_t event; uint16_t len; uint16_t offset; uint16_t layer_specific; uint8_t data[]; } HC_BT_HDR; typedef struct { uint32_t device_class; uint8_t feature_set[16]; uint8_t device_addr[6]; uint16_t comp_id; uint8_t g_sys_uart0_communication_supported; uint8_t cp2_log_mode; uint8_t LogLevel; uint8_t g_central_or_perpheral; uint16_t Log_BitMask; uint8_t super_ssp_enable; uint8_t common_rfu_b3; uint32_t common_rfu_w[2]; uint32_t le_rfu_w[2]; uint32_t lmp_rfu_w[2]; uint32_t lc_rfu_w[2]; uint16_t g_wbs_nv_117; uint16_t g_wbs_nv_118; uint16_t g_nbv_nv_117; uint16_t g_nbv_nv_118; uint8_t g_sys_sco_transmit_mode; uint8_t audio_rfu_b1; uint8_t audio_rfu_b2; uint8_t audio_rfu_b3; uint32_t audio_rfu_w[2]; uint8_t g_sys_sleep_in_standby_supported; uint8_t g_sys_sleep_master_supported; uint8_t g_sys_sleep_slave_supported; uint8_t power_rfu_b1; uint32_t power_rfu_w[2]; uint32_t win_ext; uint8_t edr_tx_edr_delay; uint8_t edr_rx_edr_delay; uint8_t tx_delay; uint8_t rx_delay; uint32_t bb_rfu_w[2]; uint8_t agc_mode; uint8_t diff_or_eq; uint8_t ramp_mode; uint8_t modem_rfu_b1; uint32_t modem_rfu_w[2]; uint32_t BQB_BitMask_1; uint32_t BQB_BitMask_2; uint16_t bt_coex_threshold[8]; uint32_t other_rfu_w[6]; } pskey_config_t; typedef struct { uint16_t g_GainValue_A[6]; uint16_t g_ClassicPowerValue_A[10]; uint16_t g_LEPowerValue_A[16]; uint16_t g_BRChannelpwrvalue_A[8]; uint16_t g_EDRChannelpwrvalue_A[8]; uint16_t g_LEChannelpwrvalue_A[8]; uint16_t g_GainValue_B[6]; uint16_t g_ClassicPowerValue_B[10]; uint16_t g_LEPowerValue_B[16]; uint16_t g_BRChannelpwrvalue_B[8]; uint16_t g_EDRChannelpwrvalue_B[8]; uint16_t g_LEChannelpwrvalue_B[8]; uint16_t LE_fix_powerword; uint8_t Classic_pc_by_channel; uint8_t LE_pc_by_channel; uint8_t RF_switch_mode; uint8_t Data_Capture_Mode; uint8_t Analog_IQ_Debug_Mode; uint8_t RF_common_rfu_b3; uint32_t RF_common_rfu_w[5]; } rf_config_t; typedef struct { const char *conf_entry; conf_action_t *p_action; void *buf; int len; int size; } conf_entry_t; static uint8_t local_bdaddr[6]={0x10, 0x11, 0x12, 0x13, 0x14, 0x15}; static pskey_config_t marlin3_pskey; static rf_config_t marlin3_rf_config; static int s_bt_fd = -1; static const conf_entry_t marlin3_pksey_table[] = { CONF_ITEM_TABLE(device_class, 0, marlin3_pskey, 1), CONF_ITEM_TABLE(feature_set, 0, marlin3_pskey, 16), CONF_ITEM_TABLE(device_addr, 0, marlin3_pskey, 6), CONF_ITEM_TABLE(comp_id, 0, marlin3_pskey, 1), CONF_ITEM_TABLE(g_sys_uart0_communication_supported, 0, marlin3_pskey, 1), CONF_ITEM_TABLE(cp2_log_mode, 0, marlin3_pskey, 1), CONF_ITEM_TABLE(LogLevel, 0, marlin3_pskey, 1), CONF_ITEM_TABLE(g_central_or_perpheral, 0, marlin3_pskey, 1), CONF_ITEM_TABLE(Log_BitMask, 0, marlin3_pskey, 1), CONF_ITEM_TABLE(super_ssp_enable, 0, marlin3_pskey, 1), CONF_ITEM_TABLE(common_rfu_b3, 0, marlin3_pskey, 1), CONF_ITEM_TABLE(common_rfu_w, 0, marlin3_pskey, 2), CONF_ITEM_TABLE(le_rfu_w, 0, marlin3_pskey, 2), CONF_ITEM_TABLE(lmp_rfu_w, 0, marlin3_pskey, 2), CONF_ITEM_TABLE(lc_rfu_w, 0, marlin3_pskey, 2), CONF_ITEM_TABLE(g_wbs_nv_117, 0, marlin3_pskey, 1), CONF_ITEM_TABLE(g_wbs_nv_118, 0, marlin3_pskey, 1), CONF_ITEM_TABLE(g_nbv_nv_117, 0, marlin3_pskey, 1), CONF_ITEM_TABLE(g_nbv_nv_118, 0, marlin3_pskey, 1), CONF_ITEM_TABLE(g_sys_sco_transmit_mode, 0, marlin3_pskey, 1), CONF_ITEM_TABLE(audio_rfu_b1, 0, marlin3_pskey, 1), CONF_ITEM_TABLE(audio_rfu_b2, 0, marlin3_pskey, 1), CONF_ITEM_TABLE(audio_rfu_b3, 0, marlin3_pskey, 1), CONF_ITEM_TABLE(audio_rfu_w, 0, marlin3_pskey, 2), CONF_ITEM_TABLE(g_sys_sleep_in_standby_supported, 0, marlin3_pskey, 1), CONF_ITEM_TABLE(g_sys_sleep_master_supported, 0, marlin3_pskey, 1), CONF_ITEM_TABLE(g_sys_sleep_slave_supported, 0, marlin3_pskey, 1), CONF_ITEM_TABLE(power_rfu_b1, 0, marlin3_pskey, 1), CONF_ITEM_TABLE(power_rfu_w, 0, marlin3_pskey, 2), CONF_ITEM_TABLE(win_ext, 0, marlin3_pskey, 1), CONF_ITEM_TABLE(edr_tx_edr_delay, 0, marlin3_pskey, 1), CONF_ITEM_TABLE(edr_rx_edr_delay, 0, marlin3_pskey, 1), CONF_ITEM_TABLE(tx_delay, 0, marlin3_pskey, 1), CONF_ITEM_TABLE(rx_delay, 0, marlin3_pskey, 1), CONF_ITEM_TABLE(bb_rfu_w, 0, marlin3_pskey, 2), CONF_ITEM_TABLE(agc_mode, 0, marlin3_pskey, 1), CONF_ITEM_TABLE(diff_or_eq, 0, marlin3_pskey, 1), CONF_ITEM_TABLE(ramp_mode, 0, marlin3_pskey, 1), CONF_ITEM_TABLE(modem_rfu_b1, 0, marlin3_pskey, 1), CONF_ITEM_TABLE(modem_rfu_w, 0, marlin3_pskey, 2), CONF_ITEM_TABLE(BQB_BitMask_1, 0, marlin3_pskey, 1), CONF_ITEM_TABLE(BQB_BitMask_2, 0, marlin3_pskey, 1), CONF_ITEM_TABLE(bt_coex_threshold, 0, marlin3_pskey, 8), CONF_ITEM_TABLE(other_rfu_w, 0, marlin3_pskey, 6), {0, 0, 0, 0, 0} }; static const conf_entry_t marlin3_rf_table[] = { CONF_ITEM_TABLE(g_GainValue_A, 0, marlin3_rf_config, 6), CONF_ITEM_TABLE(g_ClassicPowerValue_A, 0, marlin3_rf_config, 10), CONF_ITEM_TABLE(g_LEPowerValue_A, 0, marlin3_rf_config, 16), CONF_ITEM_TABLE(g_BRChannelpwrvalue_A, 0, marlin3_rf_config, 8), CONF_ITEM_TABLE(g_EDRChannelpwrvalue_A, 0, marlin3_rf_config, 8), CONF_ITEM_TABLE(g_LEChannelpwrvalue_A, 0, marlin3_rf_config, 8), CONF_ITEM_TABLE(g_GainValue_B, 0, marlin3_rf_config, 6), CONF_ITEM_TABLE(g_ClassicPowerValue_B, 0, marlin3_rf_config, 10), CONF_ITEM_TABLE(g_LEPowerValue_B, 0, marlin3_rf_config, 16), CONF_ITEM_TABLE(g_BRChannelpwrvalue_B, 0, marlin3_rf_config, 8), CONF_ITEM_TABLE(g_EDRChannelpwrvalue_B, 0, marlin3_rf_config, 8), CONF_ITEM_TABLE(g_LEChannelpwrvalue_B, 0, marlin3_rf_config, 8), CONF_ITEM_TABLE(LE_fix_powerword, 0, marlin3_rf_config, 1), CONF_ITEM_TABLE(Classic_pc_by_channel, 0, marlin3_rf_config, 1), CONF_ITEM_TABLE(LE_pc_by_channel, 0, marlin3_rf_config, 1), CONF_ITEM_TABLE(RF_switch_mode, 0, marlin3_rf_config, 1), CONF_ITEM_TABLE(Data_Capture_Mode, 0, marlin3_rf_config, 1), CONF_ITEM_TABLE(Analog_IQ_Debug_Mode, 0, marlin3_rf_config, 1), CONF_ITEM_TABLE(RF_common_rfu_b3, 0, marlin3_rf_config, 1), CONF_ITEM_TABLE(RF_common_rfu_w, 0, marlin3_rf_config, 5), {0, 0, 0, 0, 0} }; static void log_bin_to_hexstr(uint8_t *bin, uint8_t binsz, const char *log_tag) { SPRD_DBG("%s", log_tag); SPRD_DUMP(bin, binsz); } static void parse_number(char *p_conf_name, char *p_conf_value, void *buf, int len, int size) { uint8_t *dest = (uint8_t *)buf; char *sub_value, *p; uint32_t value; (void)p_conf_name; sub_value = strtok_r(p_conf_value, CONF_VALUES_PARTITION, &p); do { if (sub_value == NULL) break; if (sub_value[0] == '0' && (sub_value[1] == 'x' || sub_value[1] == 'X')) value = strtoul(sub_value, 0, 16) & 0xFFFFFFFF; else value = strtoul(sub_value, 0, 10) & 0xFFFFFFFF; switch (size) { case sizeof(uint8_t): *dest = value & 0xFF; dest += size; break; case sizeof(uint16_t): *((uint16_t *)dest) = value & 0xFFFF; dest += size; break; case sizeof(uint32_t): *((uint32_t *)dest) = value & 0xFFFFFFFF; dest += size; break; default: break; } sub_value = strtok_r(NULL, CONF_VALUES_PARTITION, &p); } while (--len); } static unsigned char compare_char(unsigned char ch) { unsigned char data = 0x0; switch(ch) { case 0: case '0': data = 0x0; break; case 1: case '1': data = 0x1; break; case 2: case '2': data = 0x2; break; case 3: case '3': data = 0x3; break; case 4: case '4': data = 0x4; break; case 5: case '5': data = 0x5; break; case 6: case '6': data = 0x6; break; case 7: case '7': data = 0x7; break; case 8: case '8': data = 0x8; break; case 9: case '9': data = 0x9; break; case 10: case 'a': case 'A': data = 0xA; break; case 11: case 'b': case 'B': data = 0xB; break; case 12: case 'c': case 'C': data = 0xC; break; case 13: case 'd': case 'D': data = 0xD; break; case 14: case 'e': case 'E': data = 0xE; break; case 15: case 'f': case 'F': data = 0xF; break; } return data; } static void set_mac_address(uint8_t *addr) { int i = 0; FILE *fp = fopen("/sys/class/net/wlan0/address", "r"); unsigned char buff[255]; unsigned char tmp[5]; unsigned char str, str2; SPRD_DBG("%s", __func__); fscanf(fp, "%s", buff); fclose(fp); for (i=0; i<6; i++) { sprintf(tmp, "%c%c", buff[3*i], buff[3*i+1]); str = compare_char(tmp[0]); str2 = compare_char(tmp[1]); local_bdaddr[i] = (str << 4) | str2; } for (i = 0; i < 6; i++) addr[5-i] = (unsigned char)local_bdaddr[i]; addr[0] += 1; addr[1] += 1; } static void vnd_load_configure(const char *p_path, const conf_entry_t *entry) { FILE *p_file; char *p_name, *p_value, *p; conf_entry_t *p_entry; char line[CONF_MAX_LINE_LEN + 1]; /* add 1 for \0 char */ SPRD_DBG("Attempt to load conf from %s", p_path); if ((p_file = fopen(p_path, "r")) != NULL) { /* read line by line */ while (fgets(line, CONF_MAX_LINE_LEN + 1, p_file) != NULL) { if (line[0] == CONF_COMMENT) continue; p_name = strtok_r(line, CONF_DELIMITERS, &p); if (NULL == p_name) { continue; } p_value = strtok_r(NULL, CONF_VALUES_DELIMITERS, &p); if (NULL == p_value) { SPRD_DBG("vnd_load_conf: missing value for name: %s", p_name); continue; } p_entry = (conf_entry_t*)entry; while (p_entry->conf_entry != NULL) { if (strcmp(p_entry->conf_entry, (const char *)p_name) == 0) { if (p_entry->p_action) { p_entry->p_action(p_name, p_value, p_entry->buf, p_entry->len, p_entry->size); } else { SPRD_DBG("%s -> %s", p_name, p_value); parse_number(p_name, p_value, p_entry->buf, p_entry->len, p_entry->size); } break; } p_entry++; } } fclose(p_file); } else { SPRD_DBG("vnd_load_conf file >%s< not found", p_path); } } static size_t H4Protocol_Send(uint8_t type, const uint8_t* data, size_t length) { struct iovec iov[] = { {&type, sizeof(type)}, {(uint8_t *)data, length}}; ssize_t ret = 0; do { ret = writev(s_bt_fd, iov, sizeof(iov) / sizeof(iov[0])); } while (-1 == ret && EAGAIN == errno); if (ret == -1) { SPRD_ERR("%s error writing to UART (%s)", __func__, strerror(errno)); } else if (ret < length + 1) { SPRD_ERR("%s: %d / %d bytes written - something went wrong...", __func__, ret, length + 1); } return ret; } static void *bt_vendor_alloc(int size) { void *p = (uint8_t *)malloc(size); return p; } static void bt_vendor_free(void *buffer) { free(buffer); } static uint8_t bt_vendor_xmit(uint16_t opcode, void* buffer, hci_cback callback) { uint8_t type = HCI_PACKET_TYPE_COMMAND; (void)opcode; HC_BT_HDR* bt_hdr = (HC_BT_HDR *)buffer; H4Protocol_Send(type, bt_hdr->data, bt_hdr->len); return BT_VND_OP_RESULT_SUCCESS; } static uint8_t sprd_vnd_send_hci_vsc(uint16_t cmd, uint8_t *payload, uint8_t len, hci_cback cback) { HC_BT_HDR *p_buf; uint8_t *p, ret; p_buf = (HC_BT_HDR *)bt_vendor_alloc( BT_HC_HDR_SIZE + HCI_CMD_PREAMBLE_SIZE + len); if (p_buf) { p_buf->event = MSG_STACK_TO_HC_HCI_CMD; p_buf->offset = 0; p_buf->layer_specific = 0; p_buf->len = HCI_CMD_PREAMBLE_SIZE + len; p = (uint8_t *)(p_buf + 1); UINT16_TO_STREAM(p, cmd); *p++ = len; memcpy(p, payload, len); log_bin_to_hexstr((uint8_t *)(p_buf + 1), HCI_CMD_PREAMBLE_SIZE + len, __FUNCTION__); ret = bt_vendor_xmit(cmd, p_buf, cback); bt_vendor_free(p_buf); return ret; } return BT_VND_OP_RESULT_FAIL; } static void hw_core_cback(void *p_mem) { uint8_t *p_evt_buf = (uint8_t *)p_mem; uint8_t *p, status; uint16_t opcode, mode; p = (uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OPCODE; STREAM_TO_UINT16(opcode,p); STREAM_TO_UINT16(mode,p); STREAM_TO_UINT8(status,p); SPRD_DBG("%s hw_core_cback response: [0x%04X, 0x%04X, 0x%02X]", __func__, opcode, mode, status); bt_vendor_free(p_evt_buf); } static void hw_core_enable(unsigned char enable) { uint8_t *p, msg_req[HCI_CMD_MAX_LEN]; p = msg_req; UINT16_TO_STREAM(p, DUAL_MODE); UINT8_TO_STREAM(p, enable ? ENABLE_BT : DISABLE_BT); sprd_vnd_send_hci_vsc(HCI_VSC_ENABLE_COMMMAND, msg_req, (uint8_t)(p - msg_req), NULL); } static void hw_rf_cback(void *p_mem) { uint8_t *p_evt_buf = (uint8_t *)p_mem, len; uint8_t *p, status; uint16_t opcode, mode = 0; p = (uint8_t *)(p_evt_buf + 1) + 1; STREAM_TO_UINT8(len, p); p = (uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OPCODE; STREAM_TO_UINT16(opcode, p); if (len == 6) STREAM_TO_UINT16(mode, p); STREAM_TO_UINT8(status, p); SPRD_DBG("%s hw_rf_cback response: [0x%04X, 0x%04X, 0x%02X]", __func__, opcode, mode, status); /* Must free the RX event buffer */ bt_vendor_free(p_evt_buf); } static int marlin3_rf_preload() { uint8_t *p, msg_req[HCI_CMD_MAX_LEN]; int i; SPRD_DBG("yujian.qin %s", __FUNCTION__); p = msg_req; for (i = 0; i < 6; i++) UINT16_TO_STREAM(p, marlin3_rf_config.g_GainValue_A[i]); for (i = 0; i < 10; i++) UINT16_TO_STREAM(p, marlin3_rf_config.g_ClassicPowerValue_A[i]); for (i = 0; i < 16; i++) UINT16_TO_STREAM(p, marlin3_rf_config.g_LEPowerValue_A[i]); for (i = 0; i < 8; i++) UINT16_TO_STREAM(p, marlin3_rf_config.g_BRChannelpwrvalue_A[i]); for (i = 0; i < 8; i++) UINT16_TO_STREAM(p, marlin3_rf_config.g_EDRChannelpwrvalue_A[i]); for (i = 0; i < 8; i++) UINT16_TO_STREAM(p, marlin3_rf_config.g_LEChannelpwrvalue_A[i]); for (i = 0; i < 6; i++) UINT16_TO_STREAM(p, marlin3_rf_config.g_GainValue_B[i]); for (i = 0; i < 10; i++) UINT16_TO_STREAM(p, marlin3_rf_config.g_ClassicPowerValue_B[i]); for (i = 0; i < 16; i++) UINT16_TO_STREAM(p, marlin3_rf_config.g_LEPowerValue_B[i]); for (i = 0; i < 8; i++) UINT16_TO_STREAM(p, marlin3_rf_config.g_BRChannelpwrvalue_B[i]); for (i = 0; i < 8; i++) UINT16_TO_STREAM(p, marlin3_rf_config.g_EDRChannelpwrvalue_B[i]); for (i = 0; i < 8; i++) UINT16_TO_STREAM(p, marlin3_rf_config.g_LEChannelpwrvalue_B[i]); UINT16_TO_STREAM(p, marlin3_rf_config.LE_fix_powerword); UINT8_TO_STREAM(p, marlin3_rf_config.Classic_pc_by_channel); UINT8_TO_STREAM(p, marlin3_rf_config.LE_pc_by_channel); UINT8_TO_STREAM(p, marlin3_rf_config.RF_switch_mode); UINT8_TO_STREAM(p, marlin3_rf_config.Data_Capture_Mode); UINT8_TO_STREAM(p, marlin3_rf_config.Analog_IQ_Debug_Mode); UINT8_TO_STREAM(p, marlin3_rf_config.RF_common_rfu_b3); for (i = 0; i < 5; i++) UINT32_TO_STREAM(p, marlin3_rf_config.RF_common_rfu_w[i]); sprd_vnd_send_hci_vsc(HCI_RF_PARA, msg_req, (uint8_t)(p - msg_req), NULL); return 0; } static void marlin3_pskey_cback(void *p_mem) { uint8_t *p_evt_buf = (uint8_t *)p_mem; uint16_t opcode, node, year; uint8_t *p, month, day; (void)opcode; p = (uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OPCODE; STREAM_TO_UINT16(opcode, p); p = (uint8_t *)(p_evt_buf + 1) + FW_NODE_BYTE; STREAM_TO_UINT16(node, p); p = (uint8_t *)(p_evt_buf + 1) + FW_DATE_Y_BYTE; STREAM_TO_UINT16(year, p); p = (uint8_t *)(p_evt_buf + 1) + FW_DATE_M_BYTE; STREAM_TO_UINT8(month, p); p = (uint8_t *)(p_evt_buf + 1) + FW_DATE_D_BYTE; STREAM_TO_UINT8(day, p); SPRD_DBG("Bluetooth Firmware Node: %04X Date: %04x-%02x-%02x", node, year, month, day); /* Must free the RX event buffer */ bt_vendor_free(p_evt_buf); } static int marlin3_pskey_preload(void *arg) { uint8_t *p, msg_req[HCI_CMD_MAX_LEN]; int i; (void)arg; SPRD_DBG("%s", __FUNCTION__); p = msg_req; UINT32_TO_STREAM(p, marlin3_pskey.device_class); for (i = 0; i < 16; i++) UINT8_TO_STREAM(p, marlin3_pskey.feature_set[i]); for (i = 0; i < 6; i++) UINT8_TO_STREAM(p, marlin3_pskey.device_addr[i]); UINT16_TO_STREAM(p, marlin3_pskey.comp_id); UINT8_TO_STREAM(p, marlin3_pskey.g_sys_uart0_communication_supported); UINT8_TO_STREAM(p, marlin3_pskey.cp2_log_mode); UINT8_TO_STREAM(p, marlin3_pskey.LogLevel); UINT8_TO_STREAM(p, marlin3_pskey.g_central_or_perpheral); UINT16_TO_STREAM(p, marlin3_pskey.Log_BitMask); UINT8_TO_STREAM(p, marlin3_pskey.super_ssp_enable); UINT8_TO_STREAM(p, marlin3_pskey.common_rfu_b3); for (i = 0; i < 2; i++) UINT32_TO_STREAM(p, marlin3_pskey.common_rfu_w[i]); for (i = 0; i < 2; i++) UINT32_TO_STREAM(p, marlin3_pskey.le_rfu_w[i]); for (i = 0; i < 2; i++) UINT32_TO_STREAM(p, marlin3_pskey.lmp_rfu_w[i]); for (i = 0; i < 2; i++) UINT32_TO_STREAM(p, marlin3_pskey.lc_rfu_w[i]); UINT16_TO_STREAM(p, marlin3_pskey.g_wbs_nv_117); UINT16_TO_STREAM(p, marlin3_pskey.g_wbs_nv_118); UINT16_TO_STREAM(p, marlin3_pskey.g_nbv_nv_117); UINT16_TO_STREAM(p, marlin3_pskey.g_nbv_nv_118); UINT8_TO_STREAM(p, marlin3_pskey.g_sys_sco_transmit_mode); UINT8_TO_STREAM(p, marlin3_pskey.audio_rfu_b1); UINT8_TO_STREAM(p, marlin3_pskey.audio_rfu_b2); UINT8_TO_STREAM(p, marlin3_pskey.audio_rfu_b3); for (i = 0; i < 2; i++) UINT32_TO_STREAM(p, marlin3_pskey.audio_rfu_w[i]); UINT8_TO_STREAM(p, marlin3_pskey.g_sys_sleep_in_standby_supported); UINT8_TO_STREAM(p, marlin3_pskey.g_sys_sleep_master_supported); UINT8_TO_STREAM(p, marlin3_pskey.g_sys_sleep_slave_supported); UINT8_TO_STREAM(p, marlin3_pskey.power_rfu_b1); for (i = 0; i < 2; i++) UINT32_TO_STREAM(p, marlin3_pskey.power_rfu_w[i]); UINT32_TO_STREAM(p, marlin3_pskey.win_ext); UINT8_TO_STREAM(p, marlin3_pskey.edr_tx_edr_delay); UINT8_TO_STREAM(p, marlin3_pskey.edr_rx_edr_delay); UINT8_TO_STREAM(p, marlin3_pskey.tx_delay); UINT8_TO_STREAM(p, marlin3_pskey.rx_delay); for (i = 0; i < 2; i++) UINT32_TO_STREAM(p, marlin3_pskey.bb_rfu_w[i]); UINT8_TO_STREAM(p, marlin3_pskey.agc_mode); UINT8_TO_STREAM(p, marlin3_pskey.diff_or_eq); UINT8_TO_STREAM(p, marlin3_pskey.ramp_mode); UINT8_TO_STREAM(p, marlin3_pskey.modem_rfu_b1); for (i = 0; i < 2; i++) UINT32_TO_STREAM(p, marlin3_pskey.modem_rfu_w[i]); UINT32_TO_STREAM(p, marlin3_pskey.BQB_BitMask_1); UINT32_TO_STREAM(p, marlin3_pskey.BQB_BitMask_2); for (i = 0; i < 8; i++) UINT16_TO_STREAM(p, marlin3_pskey.bt_coex_threshold[i]); for (i = 0; i < 6; i++) UINT32_TO_STREAM(p, marlin3_pskey.other_rfu_w[i]); sprd_vnd_send_hci_vsc(HCI_PSKEY, msg_req, (uint8_t)(p - msg_req), NULL); return 0; } int sprd_config_init(int fd, struct uart_t *u, struct termios *ti) { uint8_t *recv = NULL; int len = 0; s_bt_fd = fd; memset(&marlin3_pskey, 0, sizeof(marlin3_pskey)); memset(&marlin3_rf_config, 0, sizeof(marlin3_rf_config)); vnd_load_configure(BT_CONFIG_PATH "/bt_configure_pskey.ini", &marlin3_pksey_table[0]); vnd_load_configure(BT_CONFIG_PATH "/bt_configure_rf.ini", &marlin3_rf_table[0]); set_mac_address(marlin3_pskey.device_addr); marlin3_pskey_preload(NULL); recv = bt_vendor_alloc(RESPONSE_LENGTH); len = read_hci_event(s_bt_fd, recv, RESPONSE_LENGTH); SPRD_DBG("Received event, len: %d", len); SPRD_DUMP(recv, len); marlin3_pskey_cback(recv); marlin3_rf_preload(); recv = bt_vendor_alloc(RESPONSE_LENGTH); len = read_hci_event(s_bt_fd, recv, RESPONSE_LENGTH); SPRD_DBG("Received event, len: %d", len); SPRD_DUMP(recv, len); hw_rf_cback(recv); hw_core_enable(1); recv = bt_vendor_alloc(RESPONSE_LENGTH); len = read_hci_event(s_bt_fd, recv, RESPONSE_LENGTH); SPRD_DBG("Received event, len: %d", len); SPRD_DUMP(recv, len); hw_core_cback(recv); return 0; } int sprd_config_post(int fd, struct uart_t *u, struct termios *ti) { SPRD_DBG("Done setting line discpline"); return 0; }