From d4a1bd480003f3e1a0590bc46fbcb24f05652ca7 Mon Sep 17 00:00:00 2001
From: tzh <tanzhtanzh@gmail.com>
Date: Thu, 15 Aug 2024 06:56:47 +0000
Subject: [PATCH] feat(wfit/bt): update aic8800 wifi/bt drive and hal

---
 android/hardware/aic/libbt/src/userial_vendor.c | 2310 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 2,281 insertions(+), 29 deletions(-)

diff --git a/android/hardware/aic/libbt/src/userial_vendor.c b/android/hardware/aic/libbt/src/userial_vendor.c
index 3fea92c..6df4649 100755
--- a/android/hardware/aic/libbt/src/userial_vendor.c
+++ b/android/hardware/aic/libbt/src/userial_vendor.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- *  Copyright (C) 2019-2027 AIC Corporation
+ *  Copyright (C) 2019-2021 Aicsemi Corporation
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -23,7 +23,7 @@
  *  Description:   Contains vendor-specific userial functions
  *
  ******************************************************************************/
-
+#undef NDEBUG
 #define LOG_TAG "bt_userial_vendor"
 
 #include <utils/Log.h>
@@ -31,18 +31,30 @@
 #include <fcntl.h>
 #include <errno.h>
 #include <stdio.h>
-#include <string.h>
-#include "bt_vendor_aicbt.h"
+#include <sys/eventfd.h>
 #include "userial.h"
 #include "userial_vendor.h"
-#include <unistd.h>
+#include "aic_socket.h"
+#include <cutils/sockets.h>
+#include "upio.h"
 
+#ifdef CONFIG_SCO_OVER_HCI
+#include "sbc.h"
+#ifdef CONFIG_SCO_MSBC_PLC
+#include "sbcplc.h"
+unsigned char indices0[] = {0xad, 0x0, 0x0, 0xc5, 0x0, 0x0, 0x0, 0x0, 0x77, 0x6d,
+                    0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d,
+                    0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d,
+                    0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d,
+                    0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c, 0x00}; //padding at the end
+#endif
+#endif
 /******************************************************************************
 **  Constants & Macros
 ******************************************************************************/
 
 #ifndef VNDUSERIAL_DBG
-#define VNDUSERIAL_DBG FALSE
+#define VNDUSERIAL_DBG TRUE
 #endif
 
 #if (VNDUSERIAL_DBG == TRUE)
@@ -53,22 +65,208 @@
 
 #define VND_PORT_NAME_MAXLEN    256
 
+#ifndef BT_CHIP_HW_FLOW_CTRL_ON
+#define BT_CHIP_HW_FLOW_CTRL_ON TRUE
+#endif
+
+/******************************************************************************
+**  Extern functions
+******************************************************************************/
+extern char aicbt_transtype;
+extern void Heartbeat_cleanup();
+extern void Heartbeat_init();
+extern int AIC_btservice_init();
+
 /******************************************************************************
 **  Local type definitions
 ******************************************************************************/
+#if !defined(EFD_SEMAPHORE)
+#  define EFD_SEMAPHORE (1 << 0)
+#endif
+
+#define AIC_DATA_RECEIVED 1
+#define AIC_DATA_SEND     0
+struct aic_object_t {
+  int fd;                              // the file descriptor to monitor for events.
+  void *context;                       // a context that's passed back to the *_ready functions..
+  pthread_mutex_t lock;                // protects the lifetime of this object and all variables.
+
+  void (*read_ready)(void *context);   // function to call when the file descriptor becomes readable.
+  void (*write_ready)(void *context);  // function to call when the file descriptor becomes writeable.
+};
 
 /* vendor serial control block */
 typedef struct {
     int fd;                     /* fd to Bluetooth device */
+    int uart_fd[2];
+    int signal_fd[2];
+    int epoll_fd;
+    int cpoll_fd;
+    int event_fd;
     struct termios termios;     /* serial terminal of BT port */
     char port_name[VND_PORT_NAME_MAXLEN];
+    pthread_t thread_socket_id;
+    pthread_t thread_uart_id;
+    pthread_t thread_coex_id;
+    bool thread_running;
+
+    RTB_QUEUE_HEAD *recv_data;
+    RTB_QUEUE_HEAD *send_data;
+    RTB_QUEUE_HEAD *data_order;
+    volatile bool  btdriver_state;
 } vnd_userial_cb_t;
 
+#ifdef CONFIG_SCO_OVER_HCI
+
+enum esco_coding_format {
+    ESCO_CODING_FORMAT_ULAW     = 0x00,
+    ESCO_CODING_FORMAT_ALAW     = 0x01,
+    ESCO_CODING_FORMAT_CVSD     = 0x02,
+    ESCO_CODING_FORMAT_TRANSPNT = 0x03,
+    ESCO_CODING_FORMAT_LINEAR   = 0x04, // PCM raw data
+    ESCO_CODING_FORMAT_MSBC     = 0x05,
+    ESCO_CODING_FORMAT_VS       = 0xFF,
+};
+
+enum esco_data_path {
+    ESCO_DATA_PATH_HCI  = 0x00,
+    ESCO_DATA_PATH_PCM  = 0x01,
+    ESCO_DATA_PATH_TEST = 0xFF,
+};
+
+struct coding_format_t {
+    uint8_t coding_format;
+    uint8_t reserved[4];
+} __attribute__ ((packed));
+
+struct esco_para_t {
+    uint32_t transmit_bandwidth;
+    uint32_t receive_bandwidth;
+    struct   coding_format_t transmit_coding_format;
+    struct   coding_format_t receive_coding_format;
+    uint16_t transmit_codec_frame_size;
+    uint16_t receive_codec_frame_size;
+    uint32_t input_bandwidth;
+    uint32_t output_bandwidth;
+    struct   coding_format_t input_coding_format;
+    struct   coding_format_t output_coding_format;
+    uint16_t input_coded_data_size;
+    uint16_t output_coded_data_size;
+    uint8_t  input_pcm_data_format;
+    uint8_t  output_pcm_data_format;
+    uint8_t  input_pcm_sample_payload_msb_pos;
+    uint8_t  output_pcm_sample_payload_msb_pos;
+    uint8_t  input_data_path;
+    uint8_t  output_data_path;
+    uint8_t  input_transport_unit_size;
+    uint8_t  output_transport_unit_size;
+    uint16_t max_latency;
+    uint16_t packet_types;
+    uint8_t  retransmission_effort;
+} __attribute__ ((packed));
+
+struct codec_para_t {
+    uint8_t  input_format;
+    uint8_t  input_channels;
+    uint8_t  input_bits;
+    uint16_t input_rate;
+    uint8_t  output_format;
+    uint8_t  output_channels;
+    uint8_t  output_bits;
+    uint16_t output_rate;
+} __attribute__ ((packed));
+
+uint16_t btui_msbc_h2[] = {0x0801,0x3801,0xc801,0xf801};
+typedef struct {
+    pthread_mutex_t sco_recv_mutex;
+    pthread_cond_t  sco_recv_cond;
+    pthread_mutex_t sco_send_mutex;
+    pthread_t thread_socket_sco_id;
+    pthread_t thread_recv_sco_id;
+    pthread_t thread_send_sco_id;
+    uint16_t  sco_handle;
+    bool thread_sco_running;
+    bool thread_recv_sco_running;
+    bool thread_send_sco_running;
+    uint16_t voice_settings;
+    RTB_QUEUE_HEAD *recv_sco_data;
+    RTB_QUEUE_HEAD *send_sco_data;
+    unsigned char enc_data[480];
+    unsigned int current_pos;
+    uint16_t sco_packet_len;
+    struct esco_para_t esco_para;
+    struct codec_para_t codec_para;
+    int ctrl_fd, data_fd;
+    sbc_t sbc_dec, sbc_enc;
+    uint32_t pcm_enc_seq;
+    int8_t pcm_dec_seq;
+    uint32_t pcm_dec_frame;
+    int signal_fd[2];
+} sco_cb_t;
+#endif
+
+/******************************************************************************
+**  Static functions
+******************************************************************************/
+static void h5_data_ready_cb(serial_data_type_t type, unsigned int total_length);
+static uint16_t h5_int_transmit_data_cb(serial_data_type_t type, uint8_t *data, uint16_t length) ;
+extern void AIC_btservice_destroyed();
+static uint16_t h4_int_transmit_data(uint8_t *data, uint16_t total_length);
+static int close_state = -1;
 /******************************************************************************
 **  Static variables
 ******************************************************************************/
-
+#ifdef CONFIG_SCO_OVER_HCI
+static sco_cb_t sco_cb = {
+    .codec_para = {
+        .input_channels = 1,
+        .input_bits = 16,
+        .input_rate = 8000,
+        .output_channels = 1,
+        .output_bits = 16,
+        .output_rate = 8000,
+    },
+};
+#endif
 static vnd_userial_cb_t vnd_userial;
+static const hci_h5_t *h5_int_interface;
+static int packet_recv_state = AICBT_PACKET_IDLE;
+static unsigned int packet_bytes_need = 0;
+static serial_data_type_t current_type = 0;
+static struct aic_object_t aic_socket_object;
+static struct aic_object_t aic_coex_object;
+static unsigned char h4_read_buffer[2048] = {0};
+static int h4_read_length = 0;
+
+static int coex_packet_recv_state = AICBT_PACKET_IDLE;
+static int coex_packet_bytes_need = 0;
+static serial_data_type_t coex_current_type = 0;
+static unsigned char coex_resvered_buffer[2048] = {0};
+static int coex_resvered_length = 0;
+
+#ifdef AIC_HANDLE_EVENT
+static int received_packet_state = AICBT_PACKET_IDLE;
+static unsigned int received_packet_bytes_need = 0;
+static serial_data_type_t recv_packet_current_type = 0;
+static unsigned char received_resvered_header[2048] = {0};
+static int received_resvered_length = 0;
+static aicbt_version_t aicbt_version;
+static aicbt_lescn_t  aicbt_adv_con;
+#endif
+
+static aic_parse_manager_t *aic_parse_manager = NULL;
+
+static hci_h5_callbacks_t h5_int_callbacks = {
+    .h5_int_transmit_data_cb = h5_int_transmit_data_cb,
+    .h5_data_ready_cb = h5_data_ready_cb,
+};
+
+static const uint8_t hci_preamble_sizes[] = {
+    COMMAND_PREAMBLE_SIZE,
+    ACL_PREAMBLE_SIZE,
+    SCO_PREAMBLE_SIZE,
+    EVENT_PREAMBLE_SIZE
+};
 
 /*****************************************************************************
 **   Helper Functions
@@ -143,16 +341,6 @@
 {
     uint32_t bt_wake_state;
 
-#if (BT_WAKE_USERIAL_LDISC==TRUE)
-    int ldisc = N_AICBT_HCI; /* acibt sleep mode support line discipline */
-
-    /* attempt to load enable discipline driver */
-    if (ioctl(vnd_userial.fd, TIOCSETD, &ldisc) < 0) {
-        VNDUSERIALDBG("USERIAL_Open():fd %d, TIOCSETD failed: error %d for ldisc: %d",
-                      fd, errno, ldisc);
-    }
-#endif
-
     /* assert BT_WAKE through ioctl */
     ioctl(fd, USERIAL_IOCTL_BT_WAKE_ASSERT, NULL);
     ioctl(fd, USERIAL_IOCTL_BT_WAKE_GET_ST, &bt_wake_state);
@@ -165,6 +353,25 @@
 /*****************************************************************************
 **   Userial Vendor API Functions
 *****************************************************************************/
+static void userial_send_hw_error()
+{
+    unsigned char p_buf[100];
+    int length;
+    p_buf[0] = HCIT_TYPE_EVENT;//event
+    p_buf[1] = HCI_VSE_SUBCODE_DEBUG_INFO_SUB_EVT;//firmwre event log
+    p_buf[3] = 0x01;// host log opcode
+    length = sprintf((char *)&p_buf[4], "host stack: userial error \n");
+    p_buf[2] = length + 2;//len
+    length = length + 1 + 4;
+    userial_recv_rawdata_hook(p_buf,length);
+
+    length = 4;
+    p_buf[0] = HCIT_TYPE_EVENT;//event
+    p_buf[1] = HCI_HARDWARE_ERROR_EVT;//hardware error
+    p_buf[2] = 0x01;//len
+    p_buf[3] = USERIAL_HWERR_CODE_AIC;//userial error code
+    userial_recv_rawdata_hook(p_buf,length);
+}
 
 /*******************************************************************************
 **
@@ -175,12 +382,59 @@
 ** Returns         None
 **
 *******************************************************************************/
-void userial_vendor_init(void)
+void userial_vendor_init(char *bt_device_node)
 {
+#ifdef AIC_HANDLE_EVENT
+    memset(&aicbt_adv_con, 0, sizeof(aicbt_lescn_t));
+#endif
+    memset(&vnd_userial, 0, sizeof(vnd_userial_cb_t));
     vnd_userial.fd = -1;
+    char value[100];
     snprintf(vnd_userial.port_name, VND_PORT_NAME_MAXLEN, "%s", \
-            BLUETOOTH_UART_DEVICE_PORT);
+            bt_device_node);
+    if (aicbt_transtype & AICBT_TRANS_H5) {
+        h5_int_interface = hci_get_h5_int_interface();
+        h5_int_interface->h5_int_init(&h5_int_callbacks);
+    }
+    aic_parse_manager = NULL;
+    property_get("persist.vendor.bluetooth.aiccoex", value, "true");
+    if (strncmp(value, "true", 4) == 0) {
+        aic_parse_manager = aic_parse_manager_get_interface();
+        aic_parse_manager->aic_parse_init();
+    }
+    vnd_userial.data_order = RtbQueueInit();
+    vnd_userial.recv_data = RtbQueueInit();
+    vnd_userial.send_data = RtbQueueInit();
+
+    //reset coex gloable variables
+    coex_packet_recv_state = AICBT_PACKET_IDLE;
+    coex_packet_bytes_need = 0;
+    coex_current_type = 0;
+    coex_resvered_length = 0;
+
+#ifdef AIC_HANDLE_EVENT
+    //reset handle event gloable variables
+    received_packet_state = AICBT_PACKET_IDLE;
+    received_packet_bytes_need = 0;
+    recv_packet_current_type = 0;
+    received_resvered_length = 0;
+#endif
+
+#ifdef CONFIG_SCO_OVER_HCI
+    sco_cb.recv_sco_data = RtbQueueInit();
+    sco_cb.send_sco_data = RtbQueueInit();
+    pthread_mutex_init(&sco_cb.sco_recv_mutex, NULL);
+    pthread_cond_init(&sco_cb.sco_recv_cond, NULL);
+    pthread_mutex_init(&sco_cb.sco_send_mutex, NULL);
+    memset(&sco_cb.sbc_enc, 0, sizeof(sbc_t));
+    sbc_init_msbc(&sco_cb.sbc_enc, 0L);
+    sco_cb.sbc_enc.endian = SBC_LE;
+    memset(&sco_cb.sbc_dec, 0, sizeof(sbc_t));
+    sbc_init_msbc(&sco_cb.sbc_dec, 0L);
+    sco_cb.sbc_dec.endian = SBC_LE;
+#endif
 }
+
 
 /*******************************************************************************
 **
@@ -265,9 +519,120 @@
     userial_ioctl_init_bt_wake(vnd_userial.fd);
 #endif
 
+    vnd_userial.btdriver_state = true;
     ALOGI("device fd = %d open", vnd_userial.fd);
 
     return vnd_userial.fd;
+}
+
+static void userial_socket_close(void)
+{
+    int result;
+
+    if ((vnd_userial.uart_fd[0] > 0) && (result = close(vnd_userial.uart_fd[0])) < 0)
+        ALOGE( "%s (fd:%d) FAILED result:%d", __func__, vnd_userial.uart_fd[0], result);
+
+    if (epoll_ctl(vnd_userial.epoll_fd, EPOLL_CTL_DEL, vnd_userial.uart_fd[1], NULL) == -1)
+        ALOGE("%s unable to unregister fd %d from epoll set: %s", __func__, vnd_userial.uart_fd[1], strerror(errno));
+
+    if (epoll_ctl(vnd_userial.epoll_fd, EPOLL_CTL_DEL, vnd_userial.signal_fd[1], NULL) == -1)
+        ALOGE("%s unable to unregister signal fd %d from epoll set: %s", __func__, vnd_userial.signal_fd[1], strerror(errno));
+
+    if ((vnd_userial.uart_fd[1] > 0) && (result = close(vnd_userial.uart_fd[1])) < 0)
+        ALOGE( "%s (fd:%d) FAILED result:%d", __func__, vnd_userial.uart_fd[1], result);
+
+    if (vnd_userial.thread_socket_id != -1){
+        if ((result = pthread_join(vnd_userial.thread_socket_id, NULL)) < 0)
+            ALOGE("%s vnd_userial.thread_socket_id pthread_join_failed", __func__);
+        else {
+            vnd_userial.thread_socket_id = -1;
+            ALOGD("%s vnd_userial.thread_socket_id pthread_join_success", __func__);
+        }
+    }
+    if (vnd_userial.epoll_fd > 0)
+        close(vnd_userial.epoll_fd);
+
+    if ((vnd_userial.signal_fd[0] > 0) && (result = close(vnd_userial.signal_fd[0])) < 0)
+        ALOGE( "%s (signal fd[0]:%d) FAILED result:%d", __func__, vnd_userial.signal_fd[0], result);
+    if ((vnd_userial.signal_fd[1] > 0) && (result = close(vnd_userial.signal_fd[1])) < 0)
+        ALOGE( "%s (signal fd[1]:%d) FAILED result:%d", __func__, vnd_userial.signal_fd[1], result);
+
+    vnd_userial.epoll_fd = -1;
+    vnd_userial.uart_fd[0] = -1;
+    vnd_userial.uart_fd[1] = -1;
+    vnd_userial.signal_fd[0] = -1;
+    vnd_userial.signal_fd[1] = -1;
+}
+
+static void userial_uart_close(void)
+{
+    int result;
+    if ((vnd_userial.fd > 0) && (result = close(vnd_userial.fd)) < 0)
+        ALOGE( "%s (fd:%d) FAILED result:%d", __func__, vnd_userial.fd, result);
+    if (vnd_userial.thread_uart_id != -1)
+      pthread_join(vnd_userial.thread_uart_id, NULL);
+}
+
+static void userial_coex_close(void)
+{
+    int result;
+
+    if (epoll_ctl(vnd_userial.cpoll_fd, EPOLL_CTL_DEL, vnd_userial.event_fd, NULL) == -1)
+        ALOGE("%s unable to unregister fd %d from cpoll set: %s", __func__, vnd_userial.event_fd, strerror(errno));
+
+    if (epoll_ctl(vnd_userial.cpoll_fd, EPOLL_CTL_DEL, vnd_userial.signal_fd[1], NULL) == -1)
+        ALOGE("%s unable to unregister fd %d from cpoll set: %s", __func__, vnd_userial.signal_fd[1], strerror(errno));
+
+    if ((result = close(vnd_userial.event_fd)) < 0)
+        ALOGE( "%s (fd:%d) FAILED result:%d", __func__, vnd_userial.event_fd, result);
+
+    close(vnd_userial.cpoll_fd);
+    if (vnd_userial.thread_coex_id != -1){
+        if (pthread_join(vnd_userial.thread_coex_id, NULL) != 0) {
+            ALOGE("%s vnd_userial.thread_coex_id pthread_join_failed", __func__);
+        } else {
+            vnd_userial.thread_coex_id = -1;
+            ALOGD("%s vnd_userial.thread_coex_id pthread_join_success", __func__);
+        }
+    }
+    vnd_userial.cpoll_fd = -1;
+    vnd_userial.event_fd = -1;
+}
+
+void userial_send_close_signal(void)
+{
+    unsigned char close_signal = 1;
+    ssize_t ret;
+    AIC_NO_INTR(ret = write(vnd_userial.signal_fd[0], &close_signal, 1));
+}
+
+void userial_quene_close(void)
+{
+    RtbQueueFree(vnd_userial.data_order);
+    RtbQueueFree(vnd_userial.recv_data);
+    RtbQueueFree(vnd_userial.send_data);
+}
+
+void close_with_hci_reset(void)
+{
+    uint8_t hci_reset[] = { 0x01, 0x03, 0x0c, 0x00 };
+    int i = 0;
+    ALOGD("%s, start send hci reset command", __func__);
+    upio_set(UPIO_BT_WAKE, UPIO_DEASSERT, 1);
+    upio_set(UPIO_BT_WAKE, UPIO_ASSERT, 1);
+    h4_int_transmit_data(hci_reset, sizeof(hci_reset));
+    close_state = 0;
+    for (i = 0; i < 5; i++) {
+        if (close_state == 1) {
+            ALOGD("%s, hci reset done", __func__);
+            upio_set(UPIO_BT_WAKE, UPIO_DEASSERT, 1);
+            close_state = -1;
+            return;
+        }
+        usleep(100000);
+    }
+    upio_set(UPIO_BT_WAKE, UPIO_DEASSERT, 1);
+    ALOGD("%s, send hci reset command timeout", __func__);
 }
 
 /*******************************************************************************
@@ -281,23 +646,52 @@
 *******************************************************************************/
 void userial_vendor_close(void)
 {
-    int result;
+    close_with_hci_reset();
 
     if (vnd_userial.fd == -1)
         return;
 
+    if ((aicbt_transtype & AICBT_TRANS_UART) && (aicbt_transtype & AICBT_TRANS_H5)) {
 #if (BT_WAKE_VIA_USERIAL_IOCTL==TRUE)
-    /* de-assert bt_wake BEFORE closing port */
-    ioctl(vnd_userial.fd, USERIAL_IOCTL_BT_WAKE_DEASSERT, NULL);
+        /* de-assert bt_wake BEFORE closing port */
+        ioctl(vnd_userial.fd, USERIAL_IOCTL_BT_WAKE_DEASSERT, NULL);
 #endif
+        //h5_int_interface->h5_int_cleanup();
 
-    ALOGI("device fd = %d close", vnd_userial.fd);
-    // flush Tx before close to make sure no chars in buffer
-    tcflush(vnd_userial.fd, TCIOFLUSH);
-    if ((result = close(vnd_userial.fd)) < 0)
-        ALOGE( "close(fd:%d) FAILED result:%d", vnd_userial.fd, result);
+    }
+
+    vnd_userial.thread_running = false;
+#ifdef CONFIG_SCO_OVER_HCI
+    if (sco_cb.thread_sco_running) {
+        sco_cb.thread_sco_running = false;
+        unsigned char close_signal = 1;
+        ssize_t ret;
+        AIC_NO_INTR(ret = write(sco_cb.signal_fd[0], &close_signal, 1));
+        pthread_join(sco_cb.thread_socket_sco_id, NULL);
+    }
+#endif
+    Heartbeat_cleanup();
+    AIC_btservice_destroyed();
+    userial_send_close_signal();
+    userial_uart_close();
+    userial_coex_close();
+    userial_socket_close();
+    userial_quene_close();
+    if ((aicbt_transtype & AICBT_TRANS_UART) && (aicbt_transtype & AICBT_TRANS_H5)) {
+        h5_int_interface->h5_int_cleanup();
+    }
 
     vnd_userial.fd = -1;
+    vnd_userial.btdriver_state = false;
+    if (aic_parse_manager) {
+        aic_parse_manager->aic_parse_cleanup();
+    }
+    aic_parse_manager = NULL;
+#ifdef CONFIG_SCO_OVER_HCI
+    sbc_finish(&sco_cb.sbc_enc);
+    sbc_finish(&sco_cb.sbc_dec);
+#endif
+    ALOGD("%s finish", __func__);
 }
 
 /*******************************************************************************
@@ -331,15 +725,16 @@
 *******************************************************************************/
 void userial_vendor_ioctl(userial_vendor_ioctl_op_t op, void *p_data)
 {
+    AIC_UNUSED(p_data);
     switch (op) {
 #if (BT_WAKE_VIA_USERIAL_IOCTL==TRUE)
         case USERIAL_OP_ASSERT_BT_WAKE:
-            VNDUSERIALDBG("## userial_vendor_ioctl: Asserting BT_Wake ##");
+            VNDUSERIALDBG("## userial_vendor_ioctl: Asserting BT_Wake##");
             ioctl(vnd_userial.fd, USERIAL_IOCTL_BT_WAKE_ASSERT, NULL);
             break;
 
         case USERIAL_OP_DEASSERT_BT_WAKE:
-            VNDUSERIALDBG("## userial_vendor_ioctl: De-asserting BT_Wake ##");
+            VNDUSERIALDBG("## userial_vendor_ioctl: De-asserting BT_Wake##");
             ioctl(vnd_userial.fd, USERIAL_IOCTL_BT_WAKE_DEASSERT, NULL);
             break;
 
@@ -365,8 +760,1865 @@
 *******************************************************************************/
 int userial_set_port(char *p_conf_name, char *p_conf_value, int param)
 {
+    AIC_UNUSED(p_conf_name);
+    AIC_UNUSED(param);
     strcpy(vnd_userial.port_name, p_conf_value);
 
     return 0;
 }
 
+/*******************************************************************************
+**
+** Function        userial_vendor_set_hw_fctrl
+**
+** Description     Conduct vendor-specific close work
+**
+** Returns         None
+**
+*******************************************************************************/
+void userial_vendor_set_hw_fctrl(uint8_t hw_fctrl)
+{
+    struct termios termios_old;
+
+    if (vnd_userial.fd == -1) {
+        ALOGE("vnd_userial.fd is -1");
+        return;
+    }
+
+    tcgetattr(vnd_userial.fd, &termios_old);
+    if (hw_fctrl) {
+        if (termios_old.c_cflag & CRTSCTS) {
+            BTVNDDBG("userial_vendor_set_hw_fctrl already hw flowcontrol on");
+            return;
+        } else {
+            termios_old.c_cflag |= CRTSCTS;
+            tcsetattr(vnd_userial.fd, TCSANOW, &termios_old);
+            BTVNDDBG("userial_vendor_set_hw_fctrl set hw flowcontrol on");
+        }
+    } else {
+        if (termios_old.c_cflag & CRTSCTS) {
+            termios_old.c_cflag &= ~CRTSCTS;
+            tcsetattr(vnd_userial.fd, TCSANOW, &termios_old);
+            return;
+        } else {
+            ALOGI("userial_vendor_set_hw_fctrl set hw flowcontrol off");
+            return;
+        }
+    }
+}
+
+static uint16_t h4_int_transmit_data(uint8_t *data, uint16_t total_length) {
+    assert(data != NULL);
+    assert(total_length > 0);
+
+    uint16_t length = total_length;
+    uint16_t transmitted_length = 0;
+    while (length > 0 && vnd_userial.btdriver_state) {
+        ssize_t ret = write(vnd_userial.fd, data + transmitted_length, length);
+        switch (ret) {
+            case -1:
+                ALOGE("In %s, error writing to the uart serial port: %s", __func__, strerror(errno));
+                goto done;
+            case 0:
+                // If we wrote nothing, don't loop more because we
+                // can't go to infinity or beyond, ohterwise H5 can resend data
+                ALOGE("%s, ret %zd", __func__, ret);
+                goto done;
+            default:
+                transmitted_length += ret;
+                length -= ret;
+                break;
+        }
+    }
+
+done:
+    return transmitted_length;
+}
+
+static void userial_enqueue_coex_rawdata(unsigned char *buffer, int length, bool is_recved)
+{
+    AIC_BUFFER *skb_data = RtbAllocate(length, 0);
+    AIC_BUFFER *skb_type = RtbAllocate(1, 0);
+    memcpy(skb_data->Data, buffer, length);
+    skb_data->Length = length;
+    if (is_recved) {
+        *skb_type->Data = AIC_DATA_RECEIVED;
+        skb_type->Length = 1;
+        RtbQueueTail(vnd_userial.recv_data, skb_data);
+        RtbQueueTail(vnd_userial.data_order, skb_type);
+    } else {
+        *skb_type->Data = AIC_DATA_SEND;
+        skb_type->Length = 1;
+        RtbQueueTail(vnd_userial.send_data, skb_data);
+        RtbQueueTail(vnd_userial.data_order, skb_type);
+    }
+
+    if (eventfd_write(vnd_userial.event_fd, 1) == -1) {
+        ALOGE("%s unable to write for coex event fd.", __func__);
+    }
+}
+
+#ifdef AIC_HANDLE_EVENT
+static void userial_send_cmd_to_controller(unsigned char *recv_buffer, int total_length)
+{
+    if (aicbt_transtype & AICBT_TRANS_H4) {
+        h4_int_transmit_data(recv_buffer, total_length);
+    } else {
+        h5_int_interface->h5_send_cmd(DATA_TYPE_COMMAND, &recv_buffer[1], (total_length - 1));
+    }
+    userial_enqueue_coex_rawdata(recv_buffer, total_length, false);
+}
+#endif
+
+static void userial_send_acl_to_controller(unsigned char *recv_buffer, int total_length)
+{
+    if (aicbt_transtype & AICBT_TRANS_H4) {
+        h4_int_transmit_data(recv_buffer, total_length);
+    } else {
+        h5_int_interface->h5_send_acl_data(DATA_TYPE_ACL, &recv_buffer[1], (total_length - 1));
+    }
+    userial_enqueue_coex_rawdata(recv_buffer, total_length, false);
+}
+
+static void userial_send_sco_to_controller(unsigned char *recv_buffer, int total_length)
+{
+    if (aicbt_transtype & AICBT_TRANS_H4) {
+        h4_int_transmit_data(recv_buffer, total_length);
+    } else {
+        h5_int_interface->h5_send_sco_data(DATA_TYPE_SCO, &recv_buffer[1], (total_length - 1));
+    }
+    userial_enqueue_coex_rawdata(recv_buffer, total_length, false);
+}
+
+
+static int userial_coex_recv_data_handler(unsigned char *recv_buffer, int total_length)
+{
+    serial_data_type_t type = 0;
+    unsigned char *p_data = recv_buffer;
+    int length = total_length;
+    HC_BT_HDR *p_buf;
+    uint8_t boundary_flag;
+    uint16_t len, handle, acl_length, l2cap_length;
+    switch (coex_packet_recv_state) {
+        case AICBT_PACKET_IDLE:
+            coex_packet_bytes_need = 1;
+            while(length) {
+                type = p_data[0];
+                length--;
+                p_data++;
+                assert((type > DATA_TYPE_COMMAND) && (type <= DATA_TYPE_EVENT));
+                if (type < DATA_TYPE_ACL || type > DATA_TYPE_EVENT) {
+                    ALOGE("%s invalid data type: %d", __func__, type);
+                    if (!length)
+                        return total_length;
+
+                    continue;
+                }
+                break;
+            }
+            coex_current_type = type;
+            coex_packet_recv_state = AICBT_PACKET_TYPE;
+            //fall through
+
+        case AICBT_PACKET_TYPE:
+            if (coex_current_type == DATA_TYPE_ACL) {
+                coex_packet_bytes_need = 4;
+            } else if (coex_current_type == DATA_TYPE_EVENT) {
+                coex_packet_bytes_need = 2;
+            } else {
+                coex_packet_bytes_need = 3;
+            }
+            coex_resvered_length = 0;
+            coex_packet_recv_state = AICBT_PACKET_HEADER;
+            //fall through
+
+        case AICBT_PACKET_HEADER:
+            if (length >= coex_packet_bytes_need) {
+                memcpy(&coex_resvered_buffer[coex_resvered_length], p_data, coex_packet_bytes_need);
+                coex_resvered_length += coex_packet_bytes_need;
+                length -= coex_packet_bytes_need;
+                p_data += coex_packet_bytes_need;
+            } else {
+                memcpy(&coex_resvered_buffer[coex_resvered_length], p_data, length);
+                coex_resvered_length += length;
+                coex_packet_bytes_need -= length;
+                length = 0;
+                return total_length;
+            }
+            coex_packet_recv_state = AICBT_PACKET_CONTENT;
+
+            if (coex_current_type == DATA_TYPE_ACL) {
+                coex_packet_bytes_need = *(uint16_t *)&coex_resvered_buffer[2];
+            } else if (coex_current_type == DATA_TYPE_EVENT){
+                coex_packet_bytes_need = coex_resvered_buffer[1];
+            } else {
+                coex_packet_bytes_need = coex_resvered_buffer[2];
+            }
+            //fall through
+
+        case AICBT_PACKET_CONTENT:
+            if (length >= coex_packet_bytes_need) {
+                memcpy(&coex_resvered_buffer[coex_resvered_length], p_data, coex_packet_bytes_need);
+                length -= coex_packet_bytes_need;
+                p_data += coex_packet_bytes_need;
+                coex_resvered_length += coex_packet_bytes_need;
+                coex_packet_bytes_need = 0;
+            } else {
+                memcpy(&coex_resvered_buffer[coex_resvered_length], p_data, length);
+                coex_resvered_length += length;
+                coex_packet_bytes_need -= length;
+                length = 0;
+                return total_length;
+            }
+            coex_packet_recv_state = AICBT_PACKET_END;
+            //fall through
+
+        case AICBT_PACKET_END:
+            {
+                len = BT_HC_HDR_SIZE + coex_resvered_length;
+                uint8_t packet[len];
+                p_buf = (HC_BT_HDR *) packet;
+                p_buf->offset = 0;
+                p_buf->layer_specific = 0;
+                p_buf->len = coex_resvered_length;
+                memcpy((uint8_t *)(p_buf + 1), coex_resvered_buffer, coex_resvered_length);
+                switch (coex_current_type) {
+                    case DATA_TYPE_EVENT:
+                        p_buf->event = MSG_HC_TO_STACK_HCI_EVT;
+                        if (aic_parse_manager)
+                            aic_parse_manager->aic_parse_internal_event_intercept(coex_resvered_buffer);
+                    break;
+
+                    case DATA_TYPE_ACL:
+                        p_buf->event = MSG_HC_TO_STACK_HCI_ACL;
+                        handle =  *(uint16_t *)coex_resvered_buffer;
+                        acl_length = *(uint16_t *)&coex_resvered_buffer[2];
+                        l2cap_length = *(uint16_t *)&coex_resvered_buffer[4];
+                        boundary_flag = AIC_GET_BOUNDARY_FLAG(handle);
+                        if (aic_parse_manager)
+                            aic_parse_manager->aic_parse_l2cap_data(coex_resvered_buffer, 0);
+                    break;
+
+                    case DATA_TYPE_SCO:
+                        p_buf->event = MSG_HC_TO_STACK_HCI_SCO;
+                    break;
+
+                    default:
+                        p_buf->event = MSG_HC_TO_STACK_HCI_ERR;
+                    break;
+                }
+                aic_btsnoop_capture(p_buf, true);
+            }
+            break;
+
+        default:
+            break;
+    }
+
+    coex_packet_recv_state = AICBT_PACKET_IDLE;
+    coex_packet_bytes_need = 0;
+    coex_current_type = 0;
+    coex_resvered_length = 0;
+
+    return (total_length - length);
+}
+
+static void userial_coex_send_data_handler(unsigned char *send_buffer, int total_length)
+{
+    serial_data_type_t type = 0;
+    type = send_buffer[0];
+    int length = total_length;
+    HC_BT_HDR *p_buf;
+    uint8_t boundary_flag;
+    uint16_t len, handle, acl_length, l2cap_length;
+
+    len = BT_HC_HDR_SIZE + (length - 1);
+    uint8_t packet[len];
+    p_buf = (HC_BT_HDR *) packet;
+    p_buf->offset = 0;
+    p_buf->layer_specific = 0;
+    p_buf->len = total_length -1;
+    memcpy((uint8_t *)(p_buf + 1), &send_buffer[1], length - 1);
+
+    switch (type) {
+        case DATA_TYPE_COMMAND:
+            p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+            if (aic_parse_manager)
+                aic_parse_manager->aic_parse_command(&send_buffer[1]);
+        break;
+
+        case DATA_TYPE_ACL:
+            p_buf->event = MSG_STACK_TO_HC_HCI_ACL;
+            handle =  *(uint16_t *)&send_buffer[1];
+            acl_length = *(uint16_t *)&send_buffer[3];
+            l2cap_length = *(uint16_t *)&send_buffer[5];
+            boundary_flag = AIC_GET_BOUNDARY_FLAG(handle);
+            if (aic_parse_manager)
+                aic_parse_manager->aic_parse_l2cap_data(&send_buffer[1], 1);
+
+        break;
+
+        case DATA_TYPE_SCO:
+            p_buf->event = MSG_STACK_TO_HC_HCI_SCO;
+        break;
+        default:
+            p_buf->event = 0;
+            ALOGE("%s invalid data type: %d", __func__, type);
+        break;
+    }
+    aic_btsnoop_capture(p_buf, false);
+}
+
+static void userial_coex_handler(void *context)
+{
+    AIC_UNUSED(context);
+    AIC_BUFFER *skb_data;
+    AIC_BUFFER *skb_type;
+    eventfd_t value;
+    unsigned int read_length = 0;
+    eventfd_read(vnd_userial.event_fd, &value);
+    if (!value && !vnd_userial.thread_running) {
+        return;
+    }
+
+    while (!RtbQueueIsEmpty(vnd_userial.data_order)) {
+        read_length = 0;
+        skb_type = RtbDequeueHead(vnd_userial.data_order);
+        if (skb_type) {
+            if (*(skb_type->Data) == AIC_DATA_RECEIVED) {
+                skb_data = RtbDequeueHead(vnd_userial.recv_data);
+                if (skb_data) {
+                    do {
+                        read_length += userial_coex_recv_data_handler((skb_data->Data + read_length), (skb_data->Length - read_length));
+                    } while(read_length < skb_data->Length);
+                    RtbFree(skb_data);
+                }
+            } else {
+                skb_data = RtbDequeueHead(vnd_userial.send_data);
+                if (skb_data) {
+                    userial_coex_send_data_handler(skb_data->Data, skb_data->Length);
+                    RtbFree(skb_data);
+                }
+            }
+            RtbFree(skb_type);
+        }
+    }
+}
+
+#ifdef CONFIG_SCO_OVER_HCI
+//receive sco encode or non-encode data over hci, we need to decode msbc data to pcm, and send it to sco audio hal
+static void *userial_recv_sco_thread(void *arg)
+{
+    AIC_UNUSED(arg);
+    AIC_BUFFER *skb_sco_data;
+    unsigned char dec_data[480];
+    unsigned char pcm_data[960];
+    int index = 0;
+    //uint16_t sco_packet_len = 60;
+    uint8_t *p_data = NULL;
+    int res = 0;
+    size_t writen = 0;
+    prctl(PR_SET_NAME, (unsigned long)"userial_recv_sco_thread", 0, 0, 0);
+    sco_cb.pcm_dec_seq = -1;
+    sco_cb.pcm_dec_frame = 0;
+#ifdef CONFIG_SCO_MSBC_PLC
+    unsigned char plc_data[480];
+    struct PLC_State plc_state;
+    InitPLC(&plc_state);
+#endif
+    /*
+    FILE *file;
+    unsigned char enc_data[60];
+    file = fopen("/data/misc/bluedroid/sco_capture.raw", "rb");
+    FILE *file2;
+    file2 = fopen("/data/misc/bluedroid/sco_capture.pcm", "wb");
+    if (!file) {
+        ALOGE("Unable to create file");
+        return NULL;
+    }
+    */
+    //RtbEmptyQueue(sco_cb.recv_sco_data);
+    pthread_mutex_lock(&sco_cb.sco_recv_mutex);
+    while (RtbGetQueueLen(sco_cb.recv_sco_data) > 60) {
+        AIC_BUFFER *sco_data = RtbDequeueHead(sco_cb.recv_sco_data);
+        if (sco_data)
+            RtbFree(sco_data);
+    }
+    pthread_mutex_unlock(&sco_cb.sco_recv_mutex);
+
+    ALOGD("userial_recv_sco_thread start");
+    while (sco_cb.thread_recv_sco_running) {
+        pthread_mutex_lock(&sco_cb.sco_recv_mutex);
+        while (RtbQueueIsEmpty(sco_cb.recv_sco_data) && sco_cb.thread_sco_running) {
+            pthread_cond_wait(&sco_cb.sco_recv_cond, &sco_cb.sco_recv_mutex);
+        }
+        pthread_mutex_unlock(&sco_cb.sco_recv_mutex);
+        skb_sco_data = RtbDequeueHead(sco_cb.recv_sco_data);
+        if (!skb_sco_data)
+            continue;
+        p_data = skb_sco_data->Data;
+
+        switch (sco_cb.codec_para.input_format) {
+        case ESCO_CODING_FORMAT_LINEAR:  // PCM raw data
+        case ESCO_CODING_FORMAT_CVSD:    // Cvsd codec
+            res = Skt_Send_noblock(sco_cb.data_fd, p_data, sco_cb.sco_packet_len);
+            if (res < 0) {
+                ALOGE("userial_recv_sco_thread, send noblock error");
+            }
+            break;
+        case ESCO_CODING_FORMAT_MSBC: {
+                /*
+                //if (fwrite(skb_sco_data->Data, 1, 60, file) != 60) {
+                    //ALOGE("Error capturing sample");
+                //}
+                if (fread(enc_data, 1, 60, file) > 0) {
+                    ALOGD("userial_recv_sco_thread, fread data");
+                    res = sbc_decode(&sco_cb.sbc_dec, &enc_data[2], 58, dec_data, 240, &writen);
+                } else {
+                    fseek(file, 0L, SEEK_SET);
+                    if (fread(enc_data, 1, 60, file) > 0) {
+                        res = sbc_decode(&sco_cb.sbc_dec, &enc_data[2], 58, dec_data, 240, &writen);
+                    }
+                } */
+                uint8_t seq = (p_data[1] >> 4) & 0x0F;
+                uint32_t last_dec_frame = sco_cb.pcm_dec_frame;
+                if (sco_cb.pcm_dec_seq == -1) {
+                    uint8_t step = 0;
+                    sco_cb.pcm_dec_seq = (int8_t)seq;
+                    step += (seq & 0x03)/2;
+                    step += ((seq >> 2) & 0x03) / 2;
+                    sco_cb.pcm_dec_frame += step;
+                } else {
+                    do {
+                        sco_cb.pcm_dec_seq = (uint8_t)((btui_msbc_h2[(++sco_cb.pcm_dec_frame) % 4] >> 12) & 0x0F);
+                        if (sco_cb.pcm_dec_frame - last_dec_frame > 100) {
+                            // fix package loss.
+                            ALOGE("lost frame: %d, may use the plc function", (sco_cb.pcm_dec_frame - last_dec_frame));
+                            break;
+                        }
+                    } while (sco_cb.pcm_dec_seq != seq);
+
+                    if ((last_dec_frame + 1) != sco_cb.pcm_dec_frame) {
+#ifdef CONFIG_SCO_MSBC_PLC
+                        uint8_t lost_frame = sco_cb.pcm_dec_frame - last_dec_frame - 1;
+                        int i = 0;
+                        for (i = 0; i < lost_frame; i++) {
+                            sbc_decode(&sco_cb.sbc_dec, indices0, 58, dec_data, 240, &writen);
+                            PLC_bad_frame(&plc_state, (short*)dec_data, (short*)plc_data);
+                            memcpy(&pcm_data[240 * index], plc_data, 240);
+                            index = (index + 1) % 4;
+                            if (index == 0) {
+                                Skt_Send_noblock(sco_cb.data_fd, pcm_data, 960);
+                            }
+                        }
+#endif
+                    }
+                }
+
+                res = sbc_decode(&sco_cb.sbc_dec, (p_data + 2), 58, dec_data, 240, &writen);
+                if (res > 0) {
+#ifdef CONFIG_SCO_MSBC_PLC
+                    PLC_good_frame(&plc_state, (short*)dec_data, (short*)plc_data);
+                    memcpy(&pcm_data[240 * index], plc_data, 240);
+#else
+                    memcpy(&pcm_data[240 * index], dec_data, 240);
+#endif
+                    //if (fwrite(dec_data, 240, 1, file2) != 240) {
+                    //    ALOGE("Error capturing sample");
+                    //}
+                    index = (index + 1) % 4;
+                    if (index == 0) {
+                        Skt_Send_noblock(sco_cb.data_fd, pcm_data, 960);
+                    }
+                } else {
+                    ALOGE("msbc decode fail! May use PLC function");
+#ifdef CONFIG_SCO_MSBC_PLC
+                    sbc_decode(&sco_cb.sbc_dec, indices0, 58, dec_data, 240, &writen);
+                    PLC_bad_frame(&plc_state, (short*)dec_data, (short*)plc_data);
+                    memcpy(&pcm_data[240 * index], plc_data, 240);
+                    index = (index + 1) % 4;
+                    if (index == 0) {
+                        Skt_Send_noblock(sco_cb.data_fd, pcm_data, 960);
+                    }
+#endif
+                }
+            }
+            break;
+        default:
+            ALOGE("Unsupport coding format: 0x%02X", sco_cb.codec_para.input_format);
+            break;
+        }
+        RtbFree(skb_sco_data);
+    }
+    ALOGD("userial_recv_sco_thread exit");
+    RtbEmptyQueue(sco_cb.recv_sco_data);
+    return NULL;
+}
+
+static void *userial_send_sco_thread(void *arg)
+{
+    AIC_UNUSED(arg);
+    unsigned char enc_data[240];
+    unsigned char pcm_data[960 * 2];
+    unsigned char send_data[240];
+    int writen = 0;
+    int num_read;
+    prctl(PR_SET_NAME, (unsigned long)"userial_send_sco_thread", 0, 0, 0);
+    sco_cb.pcm_enc_seq = 0;
+    int i;
+    int need_read = sco_cb.sco_packet_len;
+
+    if (sco_cb.codec_para.output_format == ESCO_CODING_FORMAT_MSBC)
+        need_read = 240;
+
+    /*
+    FILE *file;
+    file = fopen("/data/misc/bluedroid/sco_playback.raw", "rb");
+    if (!file) {
+        ALOGE("Unable to create file");
+        return NULL;
+    }
+    */
+    //when start sco send thread, first send 6 sco data to controller
+    if (sco_cb.codec_para.output_format == ESCO_CODING_FORMAT_CVSD) {
+        memset(pcm_data, 0, (48*6));
+        for (i = 0; i < 6; i++) {
+            send_data[0] = DATA_TYPE_SCO;
+            send_data[3] = 48;
+            *(uint16_t *)&send_data[1] = sco_cb.sco_handle;
+            memcpy(&send_data[4], &pcm_data[i*48], 48);
+            userial_send_sco_to_controller(send_data, 52);
+        }
+    }
+    ALOGD("userial_send_sco_thread start");
+    while (sco_cb.thread_send_sco_running) {
+        num_read = Skt_Read(sco_cb.data_fd, pcm_data, need_read, &sco_cb.thread_send_sco_running);
+        if (!num_read)
+            continue;
+
+        switch (sco_cb.codec_para.output_format) {
+            case ESCO_CODING_FORMAT_LINEAR:
+                send_data[0] = DATA_TYPE_SCO;
+                send_data[3] = sco_cb.sco_packet_len;
+                *(uint16_t *)&send_data[1] = sco_cb.sco_handle;
+                memcpy(&send_data[4], &pcm_data[0], sco_cb.sco_packet_len);
+                userial_send_sco_to_controller(send_data, sco_cb.sco_packet_len + 4);
+                break;
+            case ESCO_CODING_FORMAT_CVSD:
+                for (i = 0; i < 5; i++) {
+                    send_data[0] = DATA_TYPE_SCO;
+                    send_data[3] = 48;
+                    *(uint16_t *)&send_data[1] = sco_cb.sco_handle;
+                    memcpy(&send_data[4], &pcm_data[i*48], 48);
+                    userial_send_sco_to_controller(send_data, 52);
+                }
+                break;
+            case ESCO_CODING_FORMAT_MSBC:
+                if (sbc_encode(&sco_cb.sbc_enc, &pcm_data[0], 240, &enc_data[2], 58, (ssize_t *)&writen) <= 0) {
+                    ALOGE("sbc encode error!");
+                } else {
+                    *(uint16_t*)(&(enc_data[0])) = btui_msbc_h2[sco_cb.pcm_enc_seq % 4];
+                    sco_cb.pcm_enc_seq++;
+                    enc_data[59] = 0x00;    //padding
+                }
+
+                send_data[0] = DATA_TYPE_SCO;
+                send_data[3] = sco_cb.sco_packet_len;
+                *(uint16_t *)&send_data[1] = sco_cb.sco_handle;
+                memcpy(&send_data[4], &enc_data[0], sco_cb.sco_packet_len);
+                userial_send_sco_to_controller(send_data, sco_cb.sco_packet_len + 4);
+                break;
+            default:
+                ALOGE("%s(%d), unsupport coding format: 0x%02X", __func__, __LINE__, sco_cb.codec_para.output_format);
+                break;
+        }
+    }
+    ALOGD("userial_send_sco_thread exit");
+    return NULL;
+}
+
+static void userial_sco_send_socket_stop()
+{
+    ALOGD("%s", __func__);
+    pthread_mutex_lock(&sco_cb.sco_send_mutex);
+    if (sco_cb.thread_send_sco_running) {
+        sco_cb.thread_send_sco_running = false;
+    } else {
+        pthread_mutex_unlock(&sco_cb.sco_send_mutex);
+        return;
+    }
+    pthread_mutex_unlock(&sco_cb.sco_send_mutex);
+
+    if (sco_cb.thread_send_sco_id != -1) {
+        pthread_join(sco_cb.thread_send_sco_id, NULL);
+        sco_cb.thread_send_sco_id = -1;
+    }
+}
+
+static void userial_sco_recv_socket_stop()
+{
+    ALOGD("%s", __func__);
+    pthread_mutex_lock(&sco_cb.sco_recv_mutex);
+    if (sco_cb.thread_recv_sco_running) {
+        sco_cb.thread_recv_sco_running = false;
+        pthread_cond_signal(&sco_cb.sco_recv_cond);
+    } else {
+        pthread_mutex_unlock(&sco_cb.sco_recv_mutex);
+        return;
+
+    }
+    pthread_mutex_unlock(&sco_cb.sco_recv_mutex);
+
+    if (sco_cb.thread_recv_sco_id != -1) {
+        pthread_join(sco_cb.thread_recv_sco_id, NULL);
+        sco_cb.thread_recv_sco_id = -1;
+    }
+
+}
+
+static void userial_sco_socket_stop()
+{
+    ALOGD("%s", __func__);
+    userial_sco_send_socket_stop();
+    userial_sco_recv_socket_stop();
+    if (sco_cb.ctrl_fd > 0) {
+        close(sco_cb.ctrl_fd);
+        sco_cb.ctrl_fd = -1;
+    }
+
+    if (sco_cb.data_fd > 0) {
+        close(sco_cb.data_fd);
+        sco_cb.data_fd = -1;
+    }
+    RtbEmptyQueue(sco_cb.recv_sco_data);
+}
+
+static void userial_sco_ctrl_skt_handle()
+{
+    uint8_t cmd = 0, ack = 0;;
+    int result = Skt_Read(sco_cb.ctrl_fd, &cmd, 1, NULL);
+
+    if (result == 0) {
+        userial_sco_socket_stop();
+        return;
+    }
+
+    ALOGD("%s, cmd: %d", __func__, cmd);
+    switch (cmd) {
+        case SCO_CTRL_CMD_CHECK_READY:
+            break;
+
+        case SCO_CTRL_CMD_OUT_START:
+            {
+                pthread_attr_t thread_attr;
+                pthread_attr_init(&thread_attr);
+                pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
+                sco_cb.thread_send_sco_running = true;
+                if (pthread_create(&sco_cb.thread_send_sco_id, &thread_attr, userial_send_sco_thread, NULL) != 0 ) {
+                    ALOGE("pthread_create : %s", strerror(errno));
+                }
+            }
+            break;
+
+        case SCO_CTRL_CMD_IN_START:
+            {
+                pthread_attr_t thread_attr;
+                pthread_attr_init(&thread_attr);
+                pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
+                sco_cb.thread_recv_sco_running = true;
+                if (pthread_create(&sco_cb.thread_recv_sco_id, &thread_attr, userial_recv_sco_thread, NULL) != 0 ) {
+                    ALOGE("pthread_create : %s", strerror(errno));
+                }
+            }
+            break;
+
+        case SCO_CTRL_CMD_OUT_STOP:
+            userial_sco_send_socket_stop();
+            break;
+
+        case SCO_CTRL_CMD_IN_STOP:
+            userial_sco_recv_socket_stop();
+            break;
+
+        case SCO_CTRL_CMD_SUSPEND:
+            break;
+
+        case SCO_CTRL_GET_AUDIO_CONFIG:
+            ack = sco_cb.codec_para.input_format;
+            Skt_Send(sco_cb.ctrl_fd, (uint8_t *)&sco_cb.codec_para, sizeof(struct codec_para_t));
+            break;
+
+        case SCO_CTRL_CMD_CLOSE:
+            userial_sco_socket_stop();
+            break;
+
+        default:
+            break;
+    }
+}
+
+static void *userial_socket_sco_thread(void *arg)
+{
+    AIC_UNUSED(arg);
+    struct sockaddr_un addr, remote;
+    //socklen_t alen;
+    socklen_t len = sizeof(struct sockaddr_un);
+    fd_set read_set, active_set;
+    int result, max_fd;
+    int s_ctrl = socket(AF_LOCAL, SOCK_STREAM, 0);
+    if (s_ctrl < 0) {
+        ALOGE("ctrl socket create fail");
+        return NULL;
+    }
+
+    int s_data = socket(AF_LOCAL, SOCK_STREAM, 0);
+    if (s_data < 0) {
+        ALOGE("data socket create fail");
+        close(s_ctrl);
+        return NULL;
+    }
+
+    prctl(PR_SET_NAME, (unsigned long)"userial_socket_sco_thread", 0, 0, 0);
+
+    if ((socketpair(AF_UNIX, SOCK_STREAM, 0, sco_cb.signal_fd)) < 0) {
+        ALOGE("%s, errno : %s", __func__, strerror(errno));
+        goto socket_close;
+    }
+
+    if (socket_local_server_bind(s_ctrl, SCO_CTRL_PATH, ANDROID_SOCKET_NAMESPACE_ABSTRACT) < 0) {
+        ALOGE("ctrl socket failed to create (%s)", strerror(errno));
+        goto signal_close;
+    }
+
+    if (listen(s_ctrl, 5) < 0) {
+        ALOGE("userial_socket_sco_thread, listen ctrl socket error : %s", strerror(errno));
+        goto signal_close;
+    }
+
+    if (socket_local_server_bind(s_data, SCO_DATA_PATH, ANDROID_SOCKET_NAMESPACE_ABSTRACT) < 0) {
+        ALOGE("data socket failed to create (%s)", strerror(errno));
+        goto signal_close;
+    }
+
+    if (listen(s_data, 5) < 0) {
+        ALOGE("userial_socket_sco_thread, listen data socket error : %s", strerror(errno));
+        goto signal_close;
+    }
+
+    ALOGD("userial_socket_sco_thread");
+    FD_ZERO(&read_set);
+    FD_ZERO(&active_set);
+    FD_SET(s_ctrl, &active_set);
+    FD_SET(s_data, &active_set);
+    FD_SET(sco_cb.signal_fd[1], &active_set);
+    max_fd = MAX(s_ctrl, s_data);
+    max_fd = MAX(max_fd, sco_cb.signal_fd[1]) + 1;
+    while (sco_cb.thread_sco_running) {
+        read_set = active_set;
+        result = select(max_fd, &read_set, NULL, NULL, NULL);
+        if (result == 0) {
+            ALOGE("select timeout");
+            continue;
+        }
+        if (result < 0) {
+            if (errno != EINTR)
+                ALOGE("select failed %d (%s)", errno, strerror(errno));
+            if (errno != EBADF)
+                continue;
+        }
+        if (FD_ISSET(s_ctrl, &read_set)) {
+            if (sco_cb.ctrl_fd > 0) {
+                ALOGE("Already has connect a control fd: %d", sco_cb.ctrl_fd);
+                FD_SET(sco_cb.ctrl_fd, &read_set);
+                close(sco_cb.ctrl_fd);
+            }
+            AIC_NO_INTR(sco_cb.ctrl_fd = accept(s_ctrl, (struct sockaddr *)&remote, &len));
+            if (sco_cb.ctrl_fd == -1) {
+                ALOGE("sock accept failed (%s)", strerror(errno));
+                continue;
+            }
+            const int size = (512);
+            setsockopt(sco_cb.ctrl_fd, SOL_SOCKET, SO_RCVBUF, (char*)&size, (int)sizeof(size));
+            FD_SET(sco_cb.ctrl_fd, &active_set);
+            max_fd = (MAX(max_fd, sco_cb.ctrl_fd)) + 1;
+        }
+
+        if (FD_ISSET(s_data, &read_set)) {
+            if (sco_cb.data_fd > 0) {
+                ALOGE("Already has connect a control fd: %d", sco_cb.data_fd);
+                close(sco_cb.data_fd);
+            }
+            AIC_NO_INTR(sco_cb.data_fd = accept(s_data, (struct sockaddr *)&remote, &len));
+            if (sco_cb.data_fd == -1) {
+                ALOGE("socket accept failed (%s)", strerror(errno));
+                continue;
+            }
+            const int size = (30 * 960);
+            int ret = setsockopt(sco_cb.data_fd, SOL_SOCKET, SO_RCVBUF, (char*)&size, (int)sizeof(size));
+            ret = setsockopt(sco_cb.data_fd, SOL_SOCKET, SO_SNDBUF, (char*)&size, (int)sizeof(size));
+        }
+
+        if (sco_cb.ctrl_fd > 0 && FD_ISSET(sco_cb.ctrl_fd, &read_set)) {
+            userial_sco_ctrl_skt_handle();
+        }
+    }
+
+    userial_sco_socket_stop();
+signal_close:
+    close(sco_cb.signal_fd[0]);
+    close(sco_cb.signal_fd[1]);
+socket_close:
+    close(s_ctrl);
+    close(s_data);
+
+    memset(&addr, 0, sizeof(addr));
+    strcpy((addr.sun_path + 1), SCO_DATA_PATH);
+    addr.sun_path[0] = 0;
+    unlink(addr.sun_path);
+
+    memset(&addr, 0, sizeof(addr));
+    strcpy((addr.sun_path + 1), SCO_CTRL_PATH);
+    addr.sun_path[0] = 0;
+    unlink(addr.sun_path);
+    ALOGD("userial_socket_sco_thread exit");
+    return NULL;
+}
+#endif
+
+#ifdef AIC_HANDLE_CMD
+static void userial_handle_cmd(unsigned char *recv_buffer, int total_length)
+{
+    AIC_UNUSED(total_length);
+    uint16_t opcode = *(uint16_t*)recv_buffer;
+    uint16_t scan_int, scan_win;
+    static uint16_t voice_settings;
+    char prop_value[100];
+    switch (opcode) {
+        case HCI_BLE_WRITE_SCAN_PARAMS :
+            scan_int = *(uint16_t*)&recv_buffer[4];
+            scan_win = *(uint16_t*)&recv_buffer[6];
+            if (scan_win > 20){
+                if ((scan_int/scan_win) > 2) {
+                    *(uint16_t*)&recv_buffer[4] = (scan_int * 20) / scan_win;
+                    *(uint16_t*)&recv_buffer[6] = 20;
+                } else {
+                    *(uint16_t*)&recv_buffer[4] = 40;
+                    *(uint16_t*)&recv_buffer[6] = 20;
+                }
+            } else if (scan_win == scan_int) {
+                *(uint16_t*)&recv_buffer[4] = (scan_int * 5) & 0xFE;
+            } else if ((scan_int/scan_win) <= 2) {
+                *(uint16_t*)&recv_buffer[4] = (scan_int * 3) & 0xFE;
+            }
+            break;
+
+        case HCI_LE_SET_EXTENDED_SCAN_PARAMETERS:
+            scan_int = *(uint16_t*)&recv_buffer[7];
+            scan_win = *(uint16_t*)&recv_buffer[9];
+            if (scan_win > 20){
+                if ((scan_int/scan_win) > 2) {
+                    *(uint16_t*)&recv_buffer[7] = (scan_int * 20) / scan_win;
+                    *(uint16_t*)&recv_buffer[9] = 20;
+                } else {
+                    *(uint16_t*)&recv_buffer[7] = 40;
+                    *(uint16_t*)&recv_buffer[9] = 20;
+                }
+            } else if (scan_win == scan_int) {
+                *(uint16_t*)&recv_buffer[7] = (scan_int * 5) & 0xFE;
+            } else if ((scan_int/scan_win) <= 2) {
+                *(uint16_t*)&recv_buffer[9] = (scan_int * 3) & 0xFE;
+            }
+            break;
+
+        case HCI_WRITE_VOICE_SETTINGS :
+            voice_settings = *(uint16_t*)&recv_buffer[3];
+            if (aicbt_transtype & AICBT_TRANS_USB) {
+                userial_vendor_usb_ioctl(SET_ISO_CFG, &voice_settings);
+            }
+#ifdef CONFIG_SCO_OVER_HCI
+            sco_cb.voice_settings = voice_settings;
+#endif
+            break;
+
+#ifdef CONFIG_SCO_OVER_HCI
+        case HCI_SETUP_ESCO_CONNECTION :
+            ALOGD("%s, HCI_SETUP_ESCO_CONNECTION", __func__);
+            sco_cb.voice_settings = *(uint16_t*)&recv_buffer[15];
+            if (sco_cb.voice_settings & 0x0003) {
+                sco_cb.codec_para.input_format  = ESCO_CODING_FORMAT_MSBC;
+                sco_cb.codec_para.output_format = ESCO_CODING_FORMAT_MSBC;
+                sco_cb.codec_para.input_rate    = 16000;
+                sco_cb.codec_para.output_rate   = 16000;
+            } else {
+                sco_cb.codec_para.input_format  = ESCO_CODING_FORMAT_LINEAR;
+                sco_cb.codec_para.output_format = ESCO_CODING_FORMAT_LINEAR;
+                sco_cb.codec_para.input_rate    = 8000;
+                sco_cb.codec_para.output_rate   = 8000;
+            }
+            sco_cb.ctrl_fd = -1;
+            sco_cb.data_fd = -1;
+            break;
+
+        case HCI_ENH_SETUP_ESCO_CONNECTION:
+            ALOGD("%s, HCI_ENH_SETUP_ESCO_CONNECTION", __func__);
+            memcpy(&sco_cb.esco_para, &recv_buffer[5], sizeof(sco_cb.esco_para));
+
+            switch (sco_cb.esco_para.transmit_coding_format.coding_format) {
+                case ESCO_CODING_FORMAT_ULAW:
+                case ESCO_CODING_FORMAT_ALAW:
+                case ESCO_CODING_FORMAT_CVSD:
+                    if (sco_cb.esco_para.output_coding_format.coding_format == ESCO_CODING_FORMAT_LINEAR)
+                        sco_cb.codec_para.output_format = ESCO_CODING_FORMAT_LINEAR;
+                    else
+                        sco_cb.codec_para.output_format = sco_cb.esco_para.transmit_coding_format.coding_format;
+                    sco_cb.codec_para.output_rate   = 8000;
+                    break;
+                case ESCO_CODING_FORMAT_MSBC: // stack bugs
+                    sco_cb.esco_para.transmit_coding_format.coding_format = ESCO_CODING_FORMAT_TRANSPNT;
+                case ESCO_CODING_FORMAT_TRANSPNT:
+                    sco_cb.codec_para.output_format = ESCO_CODING_FORMAT_MSBC;
+                    sco_cb.codec_para.output_rate   = 16000;
+                    break;
+                default:
+                    ALOGD("Unsupport transmit coding format");
+                    break;
+            }
+
+            switch (sco_cb.esco_para.receive_coding_format.coding_format) {
+                case ESCO_CODING_FORMAT_ULAW:
+                case ESCO_CODING_FORMAT_ALAW:
+                case ESCO_CODING_FORMAT_CVSD:
+                    if (sco_cb.esco_para.input_coding_format.coding_format == ESCO_CODING_FORMAT_LINEAR)
+                        sco_cb.codec_para.input_format = ESCO_CODING_FORMAT_LINEAR;
+                    else
+                        sco_cb.codec_para.input_format = sco_cb.esco_para.receive_coding_format.coding_format;
+                    sco_cb.codec_para.input_rate   = 8000;
+                    break;
+                case ESCO_CODING_FORMAT_MSBC: // stack bugs
+                    sco_cb.esco_para.receive_coding_format.coding_format = ESCO_CODING_FORMAT_TRANSPNT;
+                case ESCO_CODING_FORMAT_TRANSPNT:
+                    sco_cb.codec_para.input_format = ESCO_CODING_FORMAT_MSBC;
+                    sco_cb.codec_para.input_rate   = 16000;
+                    break;
+                default:
+                    ALOGD("Unsupport receive coding format");
+                    break;
+            }
+
+            sco_cb.esco_para.input_data_path  = ESCO_DATA_PATH_HCI; // input data path, set to VOHCI
+            sco_cb.esco_para.output_data_path = ESCO_DATA_PATH_HCI; // output data path, set to VOHCI
+            memcpy(&recv_buffer[5], &sco_cb.esco_para, sizeof(sco_cb.esco_para));
+
+            sco_cb.ctrl_fd = -1;
+            sco_cb.data_fd = -1;
+            break;
+#endif
+
+        case HCI_SET_EVENT_MASK:
+            ALOGD("set event mask, it should bt stack init, set coex bt on");
+            if (aic_parse_manager) {
+                aic_parse_manager->aic_set_bt_on(1);
+            }
+            Heartbeat_init();
+            break;
+
+        case HCI_ACCEPT_CONNECTION_REQUEST:
+            property_get("persist.vendor.bluetooth.prefferedrole", prop_value, "none");
+            if (strcmp(prop_value, "none") != 0) {
+                int role = recv_buffer[9];
+                if (role == 0x01 && (strcmp(prop_value, "master") == 0))
+                    recv_buffer[9] = 0x00;
+                else if (role == 0x00 && (strcmp(prop_value, "slave") == 0))
+                    recv_buffer[9] = 0x01;
+            }
+            break;
+
+        case HCI_BLE_WRITE_ADV_PARAMS:
+            if (aicbt_version.hci_version> HCI_PROTO_VERSION_4_2) {
+                break;
+            }
+            aicbt_adv_con.adverting_type = recv_buffer[7];
+            property_get("persist.vendor.aicbtadvdisable", prop_value, "false");
+            if (aicbt_adv_con.adverting_type == 0x00 && (strcmp(prop_value, "true") == 0)) {
+                recv_buffer[7] = 0x03;
+                aicbt_adv_con.adverting_type = 0x03;
+            }
+            break;
+
+        case HCI_BLE_WRITE_ADV_ENABLE:
+            if (aicbt_version.hci_version > HCI_PROTO_VERSION_4_2) {
+                break;
+            }
+            if (recv_buffer[3] == 0x01) {
+                aicbt_adv_con.adverting_start = TRUE;
+            } else if (recv_buffer[3] == 0x00) {
+                aicbt_adv_con.adverting_type = 0;
+                aicbt_adv_con.adverting_enable = FALSE;
+                aicbt_adv_con.adverting_start = FALSE;
+            }
+            break;
+
+        case HCI_BLE_CREATE_LL_CONN:
+            if (aicbt_version.hci_version > HCI_PROTO_VERSION_4_2) {
+                break;
+            }
+            if (aicbt_adv_con.adverting_enable &&
+                ((aicbt_adv_con.adverting_type == 0x00) ||
+                (aicbt_adv_con.adverting_type == 0x01) ||
+                (aicbt_adv_con.adverting_type == 0x04))) {
+                uint8_t disable_adv_cmd[5] = {0x01, 0x0A, 0x20, 0x01, 0x00};
+                aicbt_adv_con.adverting_enable = FALSE;
+                userial_send_cmd_to_controller(disable_adv_cmd, 5);
+            }
+            break;
+
+        default:
+            break;
+    }
+}
+#endif
+
+
+//This recv data from bt process. The data type only have ACL/SCO/COMMAND
+// direction  BT HOST ----> CONTROLLER
+static void userial_recv_H4_rawdata(void *context)
+{
+    AIC_UNUSED(context);
+    serial_data_type_t type = 0;
+    ssize_t bytes_read;
+    uint16_t opcode;
+    uint16_t transmitted_length = 0;
+    //unsigned char *buffer = NULL;
+
+    switch (packet_recv_state) {
+        case AICBT_PACKET_IDLE:
+            packet_bytes_need = 1;
+            do {
+                AIC_NO_INTR(bytes_read = read(vnd_userial.uart_fd[1], &type, 1));
+                if (bytes_read == -1) {
+                    ALOGE("%s, state = %d, read error %s", __func__, packet_recv_state, strerror(errno));
+                    return;
+                }
+                if (!bytes_read && packet_bytes_need) {
+                    ALOGE("%s, state = %d, bytes_read 0", __func__, packet_recv_state);
+                    return;
+                }
+
+                if (type < DATA_TYPE_COMMAND || type > DATA_TYPE_SCO) {
+                    ALOGE("%s invalid data type: %d", __func__, type);
+                    assert((type >= DATA_TYPE_COMMAND) && (type <= DATA_TYPE_SCO));
+                } else {
+                    packet_bytes_need -= bytes_read;
+                    packet_recv_state = AICBT_PACKET_TYPE;
+                    current_type = type;
+                    h4_read_buffer[0] = type;
+                }
+            } while(packet_bytes_need);
+            // fall through
+
+        case AICBT_PACKET_TYPE:
+            packet_bytes_need = hci_preamble_sizes[HCI_PACKET_TYPE_TO_INDEX(current_type)];
+            h4_read_length = 0;
+            packet_recv_state = AICBT_PACKET_HEADER;
+            // fall through
+
+        case AICBT_PACKET_HEADER:
+            do {
+                AIC_NO_INTR(bytes_read = read(vnd_userial.uart_fd[1], &h4_read_buffer[h4_read_length + 1], packet_bytes_need));
+                if (bytes_read == -1) {
+                    ALOGE("%s, state = %d, read error %s", __func__, packet_recv_state, strerror(errno));
+                    return;
+                }
+                if (!bytes_read && packet_bytes_need) {
+                    ALOGE("%s, state = %d, bytes_read 0, type : %d", __func__, packet_recv_state, current_type);
+                    return;
+                }
+                packet_bytes_need -= bytes_read;
+                h4_read_length += bytes_read;
+            }while(packet_bytes_need);
+            packet_recv_state = AICBT_PACKET_CONTENT;
+
+            if (current_type == DATA_TYPE_ACL) {
+                packet_bytes_need = *(uint16_t *)&h4_read_buffer[COMMON_DATA_LENGTH_INDEX];
+            } else if (current_type == DATA_TYPE_EVENT) {
+                packet_bytes_need = h4_read_buffer[EVENT_DATA_LENGTH_INDEX];
+            } else {
+                packet_bytes_need = h4_read_buffer[COMMON_DATA_LENGTH_INDEX];
+            }
+            // fall through
+
+        case AICBT_PACKET_CONTENT:
+            while(packet_bytes_need) {
+                AIC_NO_INTR(bytes_read = read(vnd_userial.uart_fd[1], &h4_read_buffer[h4_read_length + 1], packet_bytes_need));
+                if (bytes_read == -1) {
+                    ALOGE("%s, state = %d, read error %s", __func__, packet_recv_state, strerror(errno));
+                    return;
+                }
+                if (!bytes_read) {
+                    ALOGE("%s, state = %d, bytes_read 0", __func__, packet_recv_state);
+                    return;
+                }
+
+                packet_bytes_need -= bytes_read;
+                h4_read_length += bytes_read;
+            }
+            packet_recv_state = AICBT_PACKET_END;
+            // fall through
+
+        case AICBT_PACKET_END:
+            switch (current_type) {
+                case DATA_TYPE_COMMAND:
+#ifdef AIC_HANDLE_CMD
+                    userial_handle_cmd(&h4_read_buffer[1], h4_read_length);
+#endif
+                    if (aicbt_transtype & AICBT_TRANS_H4) {
+                        h4_int_transmit_data(h4_read_buffer, (h4_read_length + 1));
+                    } else {
+                        opcode = *(uint16_t *)&h4_read_buffer[1];
+                        if (opcode == HCI_VSC_H5_INIT) {
+                            h5_int_interface->h5_send_sync_cmd(opcode, NULL, h4_read_length);
+                        } else {
+                            transmitted_length = h5_int_interface->h5_send_cmd(type, &h4_read_buffer[1], h4_read_length);
+                        }
+                    }
+                    userial_enqueue_coex_rawdata(h4_read_buffer,(h4_read_length + 1), false);
+                    break;
+
+                case DATA_TYPE_ACL:
+                    userial_send_acl_to_controller(h4_read_buffer, (h4_read_length + 1));
+                    break;
+
+                case DATA_TYPE_SCO:
+                    userial_send_sco_to_controller(h4_read_buffer, (h4_read_length + 1));
+                    break;
+
+                default:
+                    ALOGE("%s invalid data type: %d", __func__, current_type);
+                    userial_enqueue_coex_rawdata(h4_read_buffer,(h4_read_length + 1), false);
+                    break;
+            }
+            break;
+
+        default:
+            break;
+    }
+
+    packet_recv_state = AICBT_PACKET_IDLE;
+    packet_bytes_need = 0;
+    current_type = 0;
+    h4_read_length = 0;
+}
+
+static uint16_t h5_int_transmit_data_cb(serial_data_type_t type, uint8_t *data, uint16_t length) {
+    assert(data != NULL);
+    assert(length > 0);
+
+    if (type != DATA_TYPE_H5) {
+        ALOGE("%s invalid data type: %d", __func__, type);
+        return 0;
+    }
+
+    uint16_t transmitted_length = 0;
+    while (length > 0 && vnd_userial.btdriver_state) {
+        ssize_t ret = write(vnd_userial.fd, data + transmitted_length, length);
+        switch (ret) {
+            case -1:
+                ALOGE("In %s, error writing to the uart serial port: %s", __func__, strerror(errno));
+                goto done;
+
+            case 0:
+                // If we wrote nothing, don't loop more because we
+                // can't go to infinity or beyond, ohterwise H5 can resend data
+                ALOGE("%s, ret %zd", __func__, ret);
+                goto done;
+
+            default:
+                transmitted_length += ret;
+                length -= ret;
+                break;
+        }
+    }
+
+done:
+    return transmitted_length;
+
+}
+
+#ifdef AIC_HANDLE_EVENT
+static void userial_handle_event(unsigned char *recv_buffer, int total_length)
+{
+    AIC_UNUSED(total_length);
+    uint8_t event;
+    uint8_t *p_data = recv_buffer;
+    event = p_data[0];
+    switch (event) {
+    case HCI_COMMAND_COMPLETE_EVT:
+    {
+        uint16_t opcode = *((uint16_t*)&p_data[3]);
+        uint8_t *stream = &p_data[6];
+        if (opcode == HCI_READ_LOCAL_VERSION_INFO) {
+            STREAM_TO_UINT8(aicbt_version.hci_version, stream);
+            STREAM_TO_UINT16(aicbt_version.hci_revision, stream);
+            STREAM_TO_UINT8(aicbt_version.lmp_version, stream);
+            STREAM_TO_UINT16(aicbt_version.manufacturer, stream);
+            STREAM_TO_UINT16(aicbt_version.lmp_subversion, stream);
+        } else if (opcode == HCI_BLE_WRITE_ADV_ENABLE){
+            if (aicbt_version.hci_version > HCI_PROTO_VERSION_4_2) {
+                break;
+            }
+            if (aicbt_adv_con.adverting_start &&(p_data[5] == HCI_SUCCESS)) {
+                aicbt_adv_con.adverting_enable = TRUE;
+                aicbt_adv_con.adverting_start = FALSE;
+            }
+        } else if (opcode == HCI_RESET) {
+            if (close_state == 0) {
+                ALOGD("hci reset event received before serial close");
+                close_state = 1;
+            }
+        }
+    }
+    break;
+#ifdef CONFIG_SCO_OVER_HCI
+    case HCI_ESCO_CONNECTION_COMP_EVT: {
+        ALOGD("%s, HCI_ESCO_CONNECTION_COMP_EVT", __func__);
+        if (p_data[2] != 0) {
+            sco_cb.thread_sco_running = false;
+            sco_cb.thread_recv_sco_running = false;
+            sco_cb.thread_send_sco_running = false;
+            sco_cb.data_fd = -1;
+            sco_cb.ctrl_fd = -1;
+        } else {
+            sco_cb.sco_handle = *((uint16_t *)&p_data[3]);
+            pthread_attr_t thread_attr;
+            pthread_attr_init(&thread_attr);
+            pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
+            sco_cb.thread_sco_running = true;
+            sco_cb.thread_recv_sco_running = false;
+            sco_cb.thread_send_sco_running = false;
+            sco_cb.data_fd = -1;
+            sco_cb.ctrl_fd = -1;
+            if (pthread_create(&sco_cb.thread_socket_sco_id, &thread_attr, userial_socket_sco_thread, NULL)!= 0 ) {
+                ALOGE("pthread_create : %s", strerror(errno));
+            }
+
+            RtbEmptyQueue(sco_cb.recv_sco_data);
+            switch (sco_cb.codec_para.input_format) {
+                case ESCO_CODING_FORMAT_LINEAR:
+                    sco_cb.sco_packet_len = 120;    // Get from esco data package, how decide it dynamic?
+                    break;
+                case ESCO_CODING_FORMAT_CVSD:
+                    sco_cb.sco_packet_len = 240;    // every 5 cvsd packets form a sco pcm data
+                    break;
+                case ESCO_CODING_FORMAT_MSBC:
+                    sco_cb.sco_packet_len = 60;
+                    break;
+                default:
+                    ALOGE("%s(%d), unsupport coding format: 0x%02X", __func__, __LINE__, sco_cb.codec_para.input_format);
+                    break;
+            }
+            sco_cb.current_pos = 0;
+        }
+
+        ALOGD("userial_handle_event sco_handle: %d", sco_cb.sco_handle);
+    }
+    break;
+
+    case HCI_DISCONNECTION_COMP_EVT: {
+        if ((*((uint16_t *)&p_data[3])) == sco_cb.sco_handle) {
+            sco_cb.sco_handle = 0;
+            RtbEmptyQueue(sco_cb.recv_sco_data);
+            if (sco_cb.thread_sco_running) {
+                sco_cb.thread_sco_running = false;
+                unsigned char close_signal = 1;
+                ssize_t ret;
+                AIC_NO_INTR(ret = write(sco_cb.signal_fd[0], &close_signal, 1));
+            }
+        }
+    }
+    break;
+#endif
+    default :
+    break;
+  }
+}
+
+#ifdef CONFIG_SCO_OVER_HCI
+static void userial_enqueue_recv_sco_data(unsigned char *recv_buffer, int total_length)
+{
+    AIC_UNUSED(total_length);
+    uint8_t sco_length;
+    uint8_t *p_data = recv_buffer;
+    AIC_BUFFER *skb_sco_data;
+    int i;
+    uint16_t sco_handle = (*((uint16_t *)p_data)) & 0x0FFF;
+    uint8_t  packet_flag = (uint8_t)((sco_handle >> 12) & 0x0003);
+    uint16_t current_pos = sco_cb.current_pos;
+    uint16_t sco_packet_len = sco_cb.sco_packet_len;
+
+    if (sco_handle == sco_cb.sco_handle) {
+        sco_length = p_data[SCO_PREAMBLE_SIZE - 1];
+        p_data += SCO_PREAMBLE_SIZE;
+
+        switch (sco_cb.codec_para.input_format) {
+            case ESCO_CODING_FORMAT_LINEAR:  // PCM raw data
+                skb_sco_data = RtbAllocate(sco_length, 0);
+                memcpy(skb_sco_data->Data, p_data, sco_length);
+                RtbAddTail(skb_sco_data, sco_length);
+                pthread_mutex_lock(&sco_cb.sco_recv_mutex);
+                RtbQueueTail(sco_cb.recv_sco_data, skb_sco_data);
+                pthread_cond_signal(&sco_cb.sco_recv_cond);
+                pthread_mutex_unlock(&sco_cb.sco_recv_mutex);
+                return;
+            case ESCO_CODING_FORMAT_CVSD:    // CVSD codec
+            case ESCO_CODING_FORMAT_MSBC:    // MSBC codec
+                if (packet_flag != 0x00)
+                    ALOGE("sco data receive wrong packet_flag : %d", packet_flag);
+                if (current_pos) {
+                    if ((sco_packet_len - current_pos) <= sco_length) {
+                        memcpy(&sco_cb.enc_data[current_pos], p_data, (sco_packet_len - current_pos));
+                        skb_sco_data = RtbAllocate(sco_packet_len, 0);
+                        memcpy(skb_sco_data->Data, sco_cb.enc_data, sco_packet_len);
+                        RtbAddTail(skb_sco_data, sco_packet_len);
+                        pthread_mutex_lock(&sco_cb.sco_recv_mutex);
+                        RtbQueueTail(sco_cb.recv_sco_data, skb_sco_data);
+                        pthread_cond_signal(&sco_cb.sco_recv_cond);
+                        pthread_mutex_unlock(&sco_cb.sco_recv_mutex);
+                        sco_cb.current_pos = 0;
+                        p_data += (sco_packet_len - current_pos);
+                        sco_length -= (sco_packet_len - current_pos);
+                    } else {
+                        memcpy(&sco_cb.enc_data[current_pos], p_data, sco_length);
+                        sco_cb.current_pos += sco_length;
+                        return;
+                    }
+                }
+                break;
+            default:
+                ALOGE("%s(%d), unsupport coding format: 0x%02X", __func__, __LINE__, sco_cb.codec_para.input_format);
+                return;
+        }
+
+        switch (sco_cb.codec_para.input_format) {
+            case ESCO_CODING_FORMAT_CVSD:    // Cvsd codec
+                for (i = 0; i < (sco_length/sco_packet_len); i++) {
+                    skb_sco_data = RtbAllocate(sco_packet_len, 0);
+                    memcpy(skb_sco_data->Data, p_data + i*sco_packet_len, sco_packet_len);
+                    RtbAddTail(skb_sco_data, sco_packet_len);
+                    RtbQueueTail(sco_cb.recv_sco_data, skb_sco_data);
+                }
+                if ((sco_length/sco_packet_len)) {
+                    pthread_mutex_lock(&sco_cb.sco_recv_mutex);
+                    pthread_cond_signal(&sco_cb.sco_recv_cond);
+                    pthread_mutex_unlock(&sco_cb.sco_recv_mutex);
+                }
+                i = (sco_length % sco_packet_len);
+                current_pos = sco_length - i;
+                if (i) {
+                    memcpy(sco_cb.enc_data, p_data + current_pos, i);
+                    sco_cb.current_pos = i;
+                }
+                break;
+            case ESCO_CODING_FORMAT_MSBC:
+                for (i = 0; i < sco_length; i++) {
+                    if ((p_data[i] == 0x01) && ((p_data[i+1] & 0x0f) == 0x08) && (p_data[i+2] == 0xAD)) {
+                        if ((sco_length - i) < sco_packet_len) {
+                            memcpy(sco_cb.enc_data, &p_data[i], (sco_length - i));
+                            sco_cb.current_pos = sco_length - i;
+                            return;
+                        } else {
+                            memcpy(sco_cb.enc_data, &p_data[i], sco_packet_len);   //complete msbc data
+                            skb_sco_data = RtbAllocate(sco_packet_len, 0);
+                            memcpy(skb_sco_data->Data, sco_cb.enc_data, sco_packet_len);
+                            RtbAddTail(skb_sco_data, sco_packet_len);
+                            pthread_mutex_lock(&sco_cb.sco_recv_mutex);
+                            RtbQueueTail(sco_cb.recv_sco_data, skb_sco_data);
+                            pthread_cond_signal(&sco_cb.sco_recv_cond);
+                            pthread_mutex_unlock(&sco_cb.sco_recv_mutex);
+                            sco_cb.current_pos = 0;
+                            i += (sco_packet_len - 1);
+                        }
+                    }
+                }
+                break;
+            default:
+                ALOGE("%s(%d), unsupport coding format: 0x%02X", __func__, __LINE__, sco_cb.codec_para.input_format);
+                break;
+            }
+    }
+}
+#endif
+
+static int userial_handle_recv_data(unsigned char *recv_buffer, unsigned int total_length)
+{
+    serial_data_type_t type = 0;
+    unsigned char *p_data = recv_buffer;
+    unsigned int length = total_length;
+    uint8_t event;
+
+    if (!length){
+        ALOGE("%s, length is 0, return immediately", __func__);
+        return total_length;
+    }
+    switch (received_packet_state) {
+        case AICBT_PACKET_IDLE:
+            received_packet_bytes_need = 1;
+            while(length) {
+                type = p_data[0];
+                length--;
+                p_data++;
+                if (type < DATA_TYPE_ACL || type > DATA_TYPE_EVENT) {
+                    ALOGE("%s invalid data type: %d", __func__, type);
+                    assert((type > DATA_TYPE_COMMAND) && (type <= DATA_TYPE_EVENT));
+                    if (!length)
+                        return total_length;
+
+                    continue;
+                }
+                break;
+            }
+            recv_packet_current_type = type;
+            received_packet_state = AICBT_PACKET_TYPE;
+            //fall through
+
+        case AICBT_PACKET_TYPE:
+            received_packet_bytes_need = hci_preamble_sizes[HCI_PACKET_TYPE_TO_INDEX(recv_packet_current_type)];
+            received_resvered_length = 0;
+            received_packet_state = AICBT_PACKET_HEADER;
+            //fall through
+
+        case AICBT_PACKET_HEADER:
+            if (length >= received_packet_bytes_need) {
+                memcpy(&received_resvered_header[received_resvered_length], p_data, received_packet_bytes_need);
+                received_resvered_length += received_packet_bytes_need;
+                length -= received_packet_bytes_need;
+                p_data += received_packet_bytes_need;
+            } else {
+                memcpy(&received_resvered_header[received_resvered_length], p_data, length);
+                received_resvered_length += length;
+                received_packet_bytes_need -= length;
+                length = 0;
+                return total_length;
+            }
+            received_packet_state = AICBT_PACKET_CONTENT;
+
+            if (recv_packet_current_type == DATA_TYPE_ACL) {
+                received_packet_bytes_need = *(uint16_t *)&received_resvered_header[2];
+            } else if (recv_packet_current_type == DATA_TYPE_EVENT){
+                received_packet_bytes_need = received_resvered_header[1];
+            } else {
+                received_packet_bytes_need = received_resvered_header[2];
+            }
+            //fall through
+
+        case AICBT_PACKET_CONTENT:
+            if (recv_packet_current_type == DATA_TYPE_EVENT) {
+                event = received_resvered_header[0];
+
+                if (event == HCI_COMMAND_COMPLETE_EVT) {
+                    if (received_resvered_length == 2) {
+                        if (length >= 1) {
+                            *p_data = 1;
+                        }
+                    }
+                } else if (event == HCI_COMMAND_STATUS_EVT) {
+                    if (received_resvered_length < 4) {
+                        unsigned int act_len = 4 - received_resvered_length;
+                        if (length >= act_len) {
+                            *(p_data + act_len -1) = 1;
+                        }
+                    }
+                }
+            }
+            if (length >= received_packet_bytes_need) {
+                memcpy(&received_resvered_header[received_resvered_length], p_data, received_packet_bytes_need);
+                length -= received_packet_bytes_need;
+                p_data += received_packet_bytes_need;
+                received_resvered_length += received_packet_bytes_need;
+                received_packet_bytes_need = 0;
+            } else {
+                memcpy(&received_resvered_header[received_resvered_length], p_data, length);
+                received_resvered_length += length;
+                received_packet_bytes_need -= length;
+                length = 0;
+                return total_length;
+            }
+            received_packet_state = AICBT_PACKET_END;
+            //fall through
+
+        case AICBT_PACKET_END:
+            switch (recv_packet_current_type) {
+                case DATA_TYPE_EVENT :
+                    userial_handle_event(received_resvered_header, received_resvered_length);
+                break;
+#ifdef CONFIG_SCO_OVER_HCI
+                case DATA_TYPE_SCO :
+                    userial_enqueue_recv_sco_data(received_resvered_header, received_resvered_length);
+                break;
+#endif
+                default :
+
+                break;
+            }
+            break;
+
+        default:
+            break;
+    }
+
+    received_packet_state = AICBT_PACKET_IDLE;
+    received_packet_bytes_need = 0;
+    recv_packet_current_type = 0;
+    received_resvered_length = 0;
+
+    return (total_length - length);
+}
+#endif
+
+static void h5_data_ready_cb(serial_data_type_t type, unsigned int total_length)
+{
+    unsigned char buffer[1028] = {0};
+    int length = 0;
+    length = h5_int_interface->h5_int_read_data(&buffer[1], total_length);
+    if (length == -1) {
+        ALOGE("%s, error read length", __func__);
+        assert(length != -1);
+    }
+    buffer[0] = type;
+    length++;
+    uint16_t transmitted_length = 0;
+    unsigned int real_length = length;
+#ifdef AIC_HANDLE_EVENT
+    unsigned int read_length = 0;
+    do {
+        read_length += userial_handle_recv_data(buffer + read_length, real_length - read_length);
+    } while (vnd_userial.thread_running && read_length < total_length);
+#endif
+
+    while (length > 0) {
+        ssize_t ret;
+        AIC_NO_INTR(ret = write(vnd_userial.uart_fd[1], buffer + transmitted_length, length));
+        switch (ret) {
+            case -1:
+                ALOGE("In %s, error writing to the uart serial port: %s", __func__, strerror(errno));
+                goto done;
+            case 0:
+                // If we wrote nothing, don't loop more because we
+                // can't go to infinity or beyond
+                goto done;
+            default:
+                transmitted_length += ret;
+                length -= ret;
+                break;
+        }
+    }
+done:
+    if (real_length)
+        userial_enqueue_coex_rawdata(buffer, real_length, true);
+    return;
+}
+
+//This recv data from driver which is sent or recv by the controller. The data type have ACL/SCO/EVENT
+// direction CONTROLLER -----> BT HOST
+static void userial_recv_uart_rawdata(unsigned char *buffer, unsigned int total_length)
+{
+    unsigned int length = total_length;
+    uint16_t transmitted_length = 0;
+#ifdef AIC_HANDLE_EVENT
+    unsigned int read_length = 0;
+    do {
+        read_length += userial_handle_recv_data(buffer + read_length, total_length - read_length);
+    } while(read_length < total_length);
+#endif
+    while (length > 0 && vnd_userial.thread_running) {
+        ssize_t ret;
+        AIC_NO_INTR(ret = write(vnd_userial.uart_fd[1], buffer + transmitted_length, length));
+        switch (ret) {
+            case -1:
+                ALOGE("In %s, error writing to the uart serial port: %s", __func__, strerror(errno));
+                goto done;
+            case 0:
+                // If we wrote nothing, don't loop more because we
+                // can't go to infinity or beyond
+                goto done;
+            default:
+                transmitted_length += ret;
+                length -= ret;
+                break;
+        }
+    }
+done:
+    if (total_length)
+        userial_enqueue_coex_rawdata(buffer, total_length, true);
+    return;
+}
+
+void userial_recv_rawdata_hook(unsigned char *buffer, unsigned int total_length)
+{
+      uint16_t transmitted_length = 0;
+      unsigned int real_length = total_length;
+
+      while (vnd_userial.thread_running && (total_length > 0)) {
+          ssize_t ret;
+          AIC_NO_INTR(ret = write(vnd_userial.uart_fd[1], buffer + transmitted_length, total_length));
+          switch (ret) {
+              case -1:
+                  ALOGE("In %s, error writing to the uart serial port: %s", __func__, strerror(errno));
+                  goto done;
+              case 0:
+                  // If we wrote nothing, don't loop more because we
+                  // can't go to infinity or beyond
+                  goto done;
+              default:
+                  transmitted_length += ret;
+                  total_length -= ret;
+                  break;
+          }
+      }
+  done:
+      if (real_length && vnd_userial.thread_running)
+          userial_enqueue_coex_rawdata(buffer, real_length, true);
+      return;
+
+}
+
+static void *userial_recv_socket_thread(void *arg)
+{
+    AIC_UNUSED(arg);
+    struct epoll_event events[64];
+    int j;
+    while (vnd_userial.thread_running) {
+        int ret;
+        do {
+            ret = epoll_wait(vnd_userial.epoll_fd, events, 32, 500);
+        } while(vnd_userial.thread_running && ret == -1 && errno == EINTR);
+
+        if (ret == -1) {
+            ALOGE("%s error in epoll_wait: %s", __func__, strerror(errno));
+        }
+        for (j = 0; j < ret; ++j) {
+            struct aic_object_t *object = (struct aic_object_t *)events[j].data.ptr;
+            if (events[j].data.ptr == NULL)
+                continue;
+            else {
+                if (events[j].events & (EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR) && object->read_ready)
+                    object->read_ready(object->context);
+                if (events[j].events & EPOLLOUT && object->write_ready)
+                    object->write_ready(object->context);
+            }
+        }
+    }
+    //vnd_userial.thread_socket_id = -1;
+    ALOGD("%s exit", __func__);
+    return NULL;
+}
+
+static void *userial_recv_uart_thread(void *arg)
+{
+    AIC_UNUSED(arg);
+    struct pollfd pfd[2];
+    pfd[0].events = POLLIN|POLLHUP|POLLERR|POLLRDHUP;
+    pfd[0].fd = vnd_userial.signal_fd[1];
+    pfd[1].events = POLLIN|POLLHUP|POLLERR|POLLRDHUP;
+    pfd[1].fd = vnd_userial.fd;
+    int ret;
+    unsigned char read_buffer[2056] = {0};
+    ssize_t bytes_read;
+    while (vnd_userial.thread_running) {
+        do {
+            ret = poll(pfd, 2, 500);
+        } while (ret == -1 && errno == EINTR && vnd_userial.thread_running);
+
+        //exit signal is always at first index
+        if (pfd[0].revents && !vnd_userial.thread_running) {
+            ALOGD("receive exit signal and stop thread");
+            return NULL;
+        }
+
+        if (pfd[1].revents & POLLIN) {
+            AIC_NO_INTR(bytes_read = read(vnd_userial.fd, read_buffer, sizeof(read_buffer)));
+            if (!bytes_read)
+                continue;
+            if (bytes_read < 0) {
+                ALOGE("%s, read fail, error : %s", __func__, strerror(errno));
+                continue;
+            }
+
+            if (aicbt_transtype & AICBT_TRANS_H5) {
+                h5_int_interface->h5_recv_msg(read_buffer, bytes_read);
+            } else {
+                userial_recv_uart_rawdata(read_buffer, bytes_read);
+            }
+        }
+
+        if (pfd[1].revents & (POLLERR|POLLHUP)) {
+            ALOGE("%s poll error, fd : %d", __func__, vnd_userial.fd);
+            vnd_userial.btdriver_state = false;
+            close(vnd_userial.fd);
+            userial_send_hw_error();
+            return NULL;
+        }
+        if (ret < 0) {
+            ALOGE("%s : error (%d)", __func__, ret);
+            continue;
+        }
+    }
+    vnd_userial.thread_uart_id = -1;
+    ALOGD("%s exit", __func__);
+    return NULL;
+}
+
+static void *userial_coex_thread(void *arg)
+{
+    AIC_UNUSED(arg);
+    struct epoll_event events[64];
+    int j;
+    while(vnd_userial.thread_running) {
+        int ret;
+        do {
+            ret = epoll_wait(vnd_userial.cpoll_fd, events, 64, 500);
+        } while (ret == -1 && errno == EINTR && vnd_userial.thread_running);
+        if (ret == -1) {
+            ALOGE("%s error in epoll_wait: %s", __func__, strerror(errno));
+        }
+        for (j = 0; j < ret; ++j) {
+            struct aic_object_t *object = (struct aic_object_t *)events[j].data.ptr;
+            if (events[j].data.ptr == NULL)
+                continue;
+            else {
+                if (events[j].events & (EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR) && object->read_ready)
+                    object->read_ready(object->context);
+                if (events[j].events & EPOLLOUT && object->write_ready)
+                    object->write_ready(object->context);
+            }
+        }
+    }
+    // vnd_userial.thread_coex_id = -1;
+    ALOGD("%s exit", __func__);
+    return NULL;
+}
+
+int userial_socket_open()
+{
+    int ret = 0;
+    struct epoll_event event;
+    if ((ret = socketpair(AF_UNIX, SOCK_STREAM, 0, vnd_userial.uart_fd)) < 0) {
+        ALOGE("%s, errno : %s", __func__, strerror(errno));
+        return ret;
+    }
+
+    if ((ret = socketpair(AF_UNIX, SOCK_STREAM, 0, vnd_userial.signal_fd)) < 0) {
+        ALOGE("%s, errno : %s", __func__, strerror(errno));
+        return ret;
+    }
+
+    vnd_userial.epoll_fd = epoll_create(64);
+    if (vnd_userial.epoll_fd == -1) {
+        ALOGE("%s unable to create epoll instance: %s", __func__, strerror(errno));
+        return -1;
+    }
+
+    aic_socket_object.fd = vnd_userial.uart_fd[1];
+    aic_socket_object.read_ready = userial_recv_H4_rawdata;
+    memset(&event, 0, sizeof(event));
+    event.events |= EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR;
+    event.data.ptr = (void *)&aic_socket_object;
+    if (epoll_ctl(vnd_userial.epoll_fd, EPOLL_CTL_ADD, vnd_userial.uart_fd[1], &event) == -1) {
+        ALOGE("%s unable to register fd %d to epoll set: %s", __func__, vnd_userial.uart_fd[1], strerror(errno));
+        close(vnd_userial.epoll_fd);
+        vnd_userial.epoll_fd = -1;
+        return -1;
+    }
+
+    event.data.ptr = NULL;
+    if (epoll_ctl(vnd_userial.epoll_fd, EPOLL_CTL_ADD, vnd_userial.signal_fd[1], &event) == -1) {
+        ALOGE("%s unable to register signal fd %d to epoll set: %s", __func__, vnd_userial.signal_fd[1], strerror(errno));
+        close(vnd_userial.epoll_fd);
+        vnd_userial.epoll_fd = -1;
+        return -1;
+    }
+    pthread_attr_t thread_attr;
+    pthread_attr_init(&thread_attr);
+    pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
+    vnd_userial.thread_running = true;
+    if (pthread_create(&vnd_userial.thread_socket_id, &thread_attr, userial_recv_socket_thread, NULL) != 0) {
+        ALOGE("pthread_create : %s", strerror(errno));
+        close(vnd_userial.epoll_fd);
+        vnd_userial.epoll_fd = -1;
+        vnd_userial.thread_socket_id = -1;
+        return -1;
+    }
+
+
+    if (pthread_create(&vnd_userial.thread_uart_id, &thread_attr, userial_recv_uart_thread, NULL) != 0) {
+        ALOGE("pthread_create : %s", strerror(errno));
+        close(vnd_userial.epoll_fd);
+        vnd_userial.thread_running = false;
+        pthread_join(vnd_userial.thread_socket_id, NULL);
+        vnd_userial.thread_socket_id = -1;
+        return -1;
+    }
+
+    vnd_userial.cpoll_fd = epoll_create(64);
+    assert (vnd_userial.cpoll_fd != -1);
+
+    vnd_userial.event_fd = eventfd(10, EFD_NONBLOCK);
+    assert(vnd_userial.event_fd != -1);
+    if (vnd_userial.event_fd != -1) {
+        aic_coex_object.fd = vnd_userial.event_fd;
+        aic_coex_object.read_ready = userial_coex_handler;
+        memset(&event, 0, sizeof(event));
+        event.events |= EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR;
+        event.data.ptr = (void *)&aic_coex_object;
+        if (epoll_ctl(vnd_userial.cpoll_fd, EPOLL_CTL_ADD, vnd_userial.event_fd, &event) == -1) {
+            ALOGE("%s unable to register fd %d to cpoll set: %s", __func__, vnd_userial.event_fd, strerror(errno));
+            assert(false);
+        }
+
+        event.data.ptr = NULL;
+        if (epoll_ctl(vnd_userial.cpoll_fd, EPOLL_CTL_ADD, vnd_userial.signal_fd[1], &event) == -1) {
+            ALOGE("%s unable to register fd %d to cpoll set: %s", __func__, vnd_userial.signal_fd[1], strerror(errno));
+            assert(false);
+        }
+
+        if (pthread_create(&vnd_userial.thread_coex_id, &thread_attr, userial_coex_thread, NULL) != 0) {
+            ALOGE("pthread create  coex : %s", strerror(errno));
+            vnd_userial.thread_coex_id = -1;
+            assert(false);
+        }
+    }
+
+    AIC_btservice_init();
+    ret = vnd_userial.uart_fd[0];
+    return ret;
+}
+
+int userial_vendor_usb_ioctl(int operation, void *param)
+{
+    int retval;
+    ALOGD("aic userial_vendor_usb_ioctl %d", operation);
+    retval = ioctl(vnd_userial.fd, operation, param);
+    if (retval == -1)
+        ALOGE("%s: error: %d : %s", __func__,errno, strerror(errno));
+    return retval;
+}
+
+int userial_vendor_usb_open(void)
+{
+    if ((vnd_userial.fd = open(vnd_userial.port_name, O_RDWR)) == -1) {
+        ALOGE("%s: unable to open %s: %s", __func__, vnd_userial.port_name, strerror(errno));
+        return -1;
+    }
+
+    vnd_userial.btdriver_state = true;
+    ALOGI("device fd = %d open", vnd_userial.fd);
+
+    return vnd_userial.fd;
+}
+
+void userial_set_bt_interface_state(int bt_on)
+{
+    if (aic_parse_manager) {
+        aic_parse_manager->aic_set_bt_on(bt_on);
+    }
+}
+

--
Gitblit v1.6.2