/****************************************************************************** * * Copyright (C) 2020-2021 SeekWave Technology * * Licensed under the Apache License, Version 2.0 (the "License"); * ******************************************************************************/ /****************************************************************************** * * Filename: bt_vendor_skw.c * * Description: SeekWave vendor specific library implementation * ******************************************************************************/ #undef NDEBUG #define LOG_TAG "libbt_vendor" #include #include "bt_vendor_skw.h" #include "scom_vendor.h" #include "skw_btsnoop.h" #include "skw_log.h" #include "skw_gen_addr.h" #include "skw_common.h" #include #include "skw_ext.h" #define SKWBT_CONFIG_FILE "/vendor/etc/bluetooth/skwbt.conf" bt_vendor_callbacks_t *bt_vendor_cbacks = NULL; uint8_t vnd_local_bd_addr[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t port_cnts = 0; char skwbt_transtype = 0; static char skwbt_device_node[BT_COM_PORT_SIZE][DEVICE_NODE_MAX_LEN + 1]; int btboot_fp = -1; int btpw_fp = -1; char btsnoop_log_en = FALSE; char btcp_log_en = FALSE; char skwlog_slice = FALSE; char skwdriverlog_en = TRUE; char skwbtuartonly = TRUE; char skwbtNoSleep = FALSE; //No Sleep extern char skw_btsnoop_path[]; extern char btsnoop_save_log; extern Wakeup_ADV_Info_St wakeup_ADV_Info; static char *trim(char *str) { while (isspace(*str)) { ++str; } if (!*str) { return str; } char *end_str = str + strlen(str) - 1; while (end_str > str && isspace(*end_str)) { --end_str; } end_str[1] = '\0'; return str; } static void load_skwbt_conf() { memset(skwbt_device_node, 0, sizeof(skwbt_device_node)); FILE *fp = fopen(SKWBT_CONFIG_FILE, "rt"); if (!fp) { //ALOGE("%s unable to open file '%s': %s", __func__, SKWBT_CONFIG_FILE, strerror(errno)); strcpy(skwbt_device_node[0], "/dev/ttyS0"); return ; } char *split; char line[1024]; int port_index = BT_COM_PORT_CMDEVT; while (fgets(line, sizeof(line), fp)) { char *line_ptr = trim(line); // Skip blank and comment lines. if (*line_ptr == '\0' || *line_ptr == '#' || *line_ptr == '[') { continue; } split = strchr(line_ptr, '='); if (!split) { ALOGE("%s no key/value separator found", __func__); fclose(fp); return; } *split = '\0'; split ++; if((!strcmp(trim(line_ptr), "BtDeviceNode")) && (port_index < BT_COM_PORT_SIZE)) { int mode = O_RDWR; char *str_ptr = trim(split); int len = strlen(str_ptr); #if 0 if(strstr(split, "BTDATA")) { port_index = BT_COM_PORT_ACL; } else if(strstr(split, "BTAUDIO")) { port_index = BT_COM_PORT_AUDIO; } else if(strstr(split, "BTISOC")) { port_index = BT_COM_PORT_ISO; } #endif if(len > DEVICE_NODE_MAX_LEN) { len = DEVICE_NODE_MAX_LEN; str_ptr[DEVICE_NODE_MAX_LEN] = 0x00; } memcpy(skwbt_device_node[port_index], str_ptr, len); scomm_vendor_set_port_name(port_index, skwbt_device_node[port_index], mode); port_index ++; } } fclose(fp); skwbt_transtype = SKWBT_TRANS_TYPE_H4; if(skwbt_device_node[0][0] == '?') { int i = 0; while(skwbt_device_node[0][i] != '\0') { skwbt_device_node[0][i] = skwbt_device_node[0][i + 1]; i++; } scomm_vendor_set_port_name(0, skwbt_device_node[0], O_RDWR); skwbt_transtype |= SKWBT_TRANS_TYPE_UART; } } char skwbt_boot_open() { btboot_fp = open("/dev/BTBOOT", O_RDWR); if (btboot_fp < 0) { ALOGE("%s: unable to open : %s", __func__, strerror(errno)); return FALSE; } return TRUE; } static void load_skwbt_stack_conf() { FILE *fp = fopen(SKWBT_CONFIG_FILE, "rt"); if (!fp) { ALOGE("%s unable to open file '%s': %s", __func__, SKWBT_CONFIG_FILE, strerror(errno)); return; } char *split; int line_num = 0; char line[1024]; while (fgets(line, sizeof(line), fp)) { char *line_ptr = trim(line); ++line_num; // Skip blank and comment lines. if (*line_ptr == '\0' || *line_ptr == '#' || *line_ptr == '[') { continue; } split = strchr(line_ptr, '='); if (!split) { ALOGE("%s no key/value separator found on line %d.", __func__, line_num); continue; } *split = '\0'; if(!strcmp(trim(line_ptr), "SkwBtsnoopDump")) { if(!strcmp(trim(split + 1), "true")) { btsnoop_log_en = TRUE; } else { btsnoop_log_en = FALSE; } } else if(!strcmp(trim(line_ptr), "BtSnoopFileName")) { sprintf(skw_btsnoop_path, "%s", trim(split + 1)); } else if(!strcmp(trim(line_ptr), "BtSnoopSaveLog")) { if(!strcmp(trim(split + 1), "true")) { btsnoop_save_log = TRUE; } else { btsnoop_save_log = FALSE; } } else if(!strcmp(trim(line_ptr), "SkwBtcplog")) { if(!strcmp(trim(split + 1), "true")) { btcp_log_en = TRUE; } else { btcp_log_en = FALSE; } } else if(!strcmp(trim(line_ptr), "SkwLogSlice")) { if(!strcmp(trim(split + 1), "true")) { skwlog_slice = TRUE; } else { skwlog_slice = FALSE; } } else if(!strcmp(trim(line_ptr), "SkwBtDrvlog")) { if(!strcmp(trim(split + 1), "false")) { skwdriverlog_en = FALSE; } } else if(!strcmp(trim(line_ptr), "SkwBtUartOnly")) { if(!strcmp(trim(split + 1), "false"))//SkwBtUartOnly is false { skwbtuartonly = FALSE; } } else if(!strcmp(trim(line_ptr), "SkwBtNoSleep")) { if(strcmp(trim(split + 1), "true") == 0)//SkwBtNoSleep is true { skwbtNoSleep = TRUE; } } else if(!strcmp(trim(line_ptr), "WakeupADVData")) { char *data_str = trim(split + 1); if(data_str) { scomm_vendor_parse_wakeup_adv_conf(data_str); } } } fclose(fp); } /***************************************************************************** ** ** BLUETOOTH VENDOR INTERFACE LIBRARY FUNCTIONS ** *****************************************************************************/ /** initialise **/ static int init(const bt_vendor_callbacks_t *p_cb, unsigned char *local_bdaddr) { ALOGI("SeekWave BlueTooth Version: %s", SKW_LIBBT_VERSION); if (p_cb == NULL) { ALOGE("init failed with no user callbacks!"); return -1; } scomm_vendor_init(); load_skwbt_conf(); load_skwbt_stack_conf(); skwlog_init(); bt_vendor_cbacks = (bt_vendor_callbacks_t *) p_cb;//save callback memcpy(vnd_local_bd_addr, local_bdaddr, 6); if(btsnoop_log_en) { //enable btsnoop log skw_btsnoop_init(); } skw_addr_gen_init(); return 0; } /** operations **/ static int op(bt_vendor_opcode_t opcode, void *param) { int retval = 0; ALOGD("op for %d", opcode); switch(opcode) { case BT_VND_OP_POWER_CTRL: { if(skwbt_transtype & SKWBT_TRANS_TYPE_UART) { int *state = (int *) param; if (*state == BT_VND_PWR_OFF) { usleep(200000); ALOGD("set power off and delay 200ms"); } else if (*state == BT_VND_PWR_ON) { usleep(200000); ALOGD("set power on and delay 200ms"); } } } break; case BT_VND_OP_FW_CFG: { scomm_vendor_config_start(); } break; case BT_VND_OP_SCO_CFG: { retval = -1; } break; case BT_VND_OP_USERIAL_OPEN: { int fd = -1, idx = 0; int (*fd_array)[] = (int (*)[]) param; if(skwbt_transtype & SKWBT_TRANS_TYPE_UART) { if(skwbtuartonly == FALSE) { SKWBT_LOG("open boot"); if(!skwbt_boot_open()) { retval = 0; break; } btpw_fp = open("/dev/BTDATA", O_RDWR); } if(scomm_vendor_uart_open(0) != -1) { retval = 1; fd = scomm_vendor_socket_open(0); } } else { int tFd = -1; //uint8_t log_enable = 0; if(!skwbt_boot_open()) { retval = 0; break; } #if 0 if(ioctl(btboot_fp, IOCTL_CMD_LOG_EN_GET, &log_enable) == 0) { ALOGD("SKWBT log_enable res:%d, btcp_log_en:%d, btsnoop_log_en:%d", log_enable, btcp_log_en, btsnoop_log_en); if(btcp_log_en && log_enable)//0:default, 1:release version; 2:debug version { btcp_log_en = log_enable == 2; } if(btsnoop_log_en && log_enable) { btsnoop_log_en = log_enable == 2; } } #endif #ifdef IOCTL_CMD_WAKEUP_ADV_EN if(wakeup_ADV_Info.grp_nums > 0) { int res = ioctl(btboot_fp, IOCTL_CMD_WAKEUP_ADV_EN); ALOGD("%s, wakeup adv en res:%d", __func__, res); } #endif for (idx = 0; idx < BT_COM_PORT_SIZE; idx++) { if(scomm_vendor_check_port_valid(idx) == FALSE) { continue; } if(scomm_vendor_usbsdio_open(idx) != -1) { tFd = scomm_vendor_socket_open(idx); ALOGD("idx:%d, tFd:%d, fd:%d", idx, tFd, fd); if((tFd != -1) && (fd == -1)) { fd = tFd; } } else { break; } } if(idx <= BT_COM_PORT_ACL) { skwbt_transtype |= SKWBT_TRANS_TYPE_USB; } else { skwbt_transtype |= SKWBT_TRANS_TYPE_SDIO; } } ALOGD("retval:%d, fd:%d, idx:%d", retval, fd, idx); if (fd != -1) { retval = 1; for (idx = 0; idx < CH_MAX; idx++) { (*fd_array)[idx] = fd; } skw_ext_inotify_thread_init(); property_set("SKWBT.OPEN.STATE", "1"); } else { retval = 0; } } break; case BT_VND_OP_USERIAL_CLOSE: { if(btboot_fp > 0) { scomm_vendor_write_bt_state(); close(btboot_fp); btboot_fp = -1; } scomm_vendor_close(); skw_ext_inotify_thread_exit(); property_set("SKWBT.OPEN.STATE", "0"); } break; case BT_VND_OP_GET_LPM_IDLE_TIMEOUT: { } break; case BT_VND_OP_LPM_SET_MODE: { } break; case BT_VND_OP_LPM_WAKE_SET_STATE: { } break; case BT_VND_OP_EPILOG: { if(bt_vendor_cbacks) { bt_vendor_cbacks->epilog_cb(BT_VND_OP_RESULT_SUCCESS); } } break; default: break; } return retval; } /** Close **/ static void cleanup( void ) { ALOGD("bt_vendor_skw.c cleanup"); if(btsnoop_log_en) { skw_btsnoop_close(); } skwlog_close(); btsnoop_log_en = FALSE; bt_vendor_cbacks = NULL; skwbt_transtype = 0; } // Entry point const bt_vendor_interface_t BLUETOOTH_VENDOR_LIB_INTERFACE = {sizeof(bt_vendor_interface_t), init, op, cleanup };