FM: Add HIDL support on O release

Add fm HIDL support on O release.

CRs-fixed: 2019165
Change-Id: I49b3294cdefbf763e5ad2e8f5776e9fc6393400c
diff --git a/Android.mk b/Android.mk
index 20c88ef..c5b42d9 100644
--- a/Android.mk
+++ b/Android.mk
@@ -34,7 +34,7 @@
 include $(LOCAL_PATH)/helium/Android.mk
 
 LOCAL_PATH := $(LOCAL_DIR_PATH)
-include $(LOCAL_PATH)/fmhalService/Android.mk
+#include $(LOCAL_PATH)/fmhalService/Android.mk
 
 #endif # is-vendor-board-platform
 #endif # BOARD_HAVE_QCOM_FM
diff --git a/fm_hci/Android.mk b/fm_hci/Android.mk
index f0e620e..8e76406 100644
--- a/fm_hci/Android.mk
+++ b/fm_hci/Android.mk
@@ -2,35 +2,24 @@
 
 include $(CLEAR_VARS)
 
-# Setup bdroid local make variables for handling configuration
-ifneq ($(BOARD_BLUETOOTH_BDROID_BUILDCFG_INCLUDE_DIR),)
-  bdroid_C_INCLUDES := $(BOARD_BLUETOOTH_BDROID_BUILDCFG_INCLUDE_DIR)
-  bdroid_CFLAGS += -DHAS_BDROID_BUILDCFG
-else
-  bdroid_C_INCLUDES :=
-  bdroid_CFLAGS += -DHAS_NO_BDROID_BUILDCFG
-endif
-
-BDROID_DIR:= system/bt
-
-LOCAL_CFLAGS += $(bdroid_CFLAGS)
-
 LOCAL_SRC_FILES := \
-    fm_hci.c
+    fm_hci.cpp
 
 LOCAL_SHARED_LIBRARIES := \
          libdl \
+         libcutils \
+         libbase \
+         libhidlbase \
+         libhidltransport \
+         libhwbinder \
          liblog \
-         libcutils
+         libutils \
+         android.hidl.base@1.0 \
+         vendor.qti.hardware.fm@1.0 \
 
 LOCAL_CFLAGS := -Wno-unused-parameter
 
-LOCAL_CFLAGS += -std=c99
-
 LOCAL_C_INCLUDES += \
-        $(BDROID_DIR)/hci/include \
-        $(BDROID_DIR)/stack/include \
-        $(BDROID_DIR)/osi/include \
         $(LOCAL_PATH)/../helium \
         $(LOCAL_PATH)/fm_hci
 
diff --git a/fm_hci/fm_hci.cpp b/fm_hci/fm_hci.cpp
new file mode 100644
index 0000000..5b4475c
--- /dev/null
+++ b/fm_hci/fm_hci.cpp
@@ -0,0 +1,689 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *        * Redistributions of source code must retain the above copyright
+ *            notice, this list of conditions and the following disclaimer.
+ *        * Redistributions in binary form must reproduce the above
+ *            copyright notice, this list of conditions and the following
+ *            disclaimer in the documentation and/or other materials provided
+ *            with the distribution.
+ *        * Neither the name of The Linux Foundation nor the names of its
+ *            contributors may be used to endorse or promote products derived
+ *            from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*****************************************************************************
+ *
+ *  This file contains main functions to support FM HCI interface to send
+ *  commands and  recieved events.
+ *
+ *****************************************************************************/
+
+#define LOG_TAG "fm_hci"
+
+#include <queue>          // std::queue
+#include <mutex>              // std::mutex, std::unique_lock
+#include <condition_variable> // std::condition_variable
+#include <cstdlib>
+#include <thread>
+
+#include <utils/Log.h>
+
+#include <vendor/qti/hardware/fm/1.0/IFmHci.h>
+#include <vendor/qti/hardware/fm/1.0/IFmHciCallbacks.h>
+#include <vendor/qti/hardware/fm/1.0/types.h>
+#include "fm_hci.h"
+
+#include <hwbinder/ProcessState.h>
+
+using vendor::qti::hardware::fm::V1_0::IFmHci;
+using vendor::qti::hardware::fm::V1_0::IFmHciCallbacks;
+using vendor::qti::hardware::fm::V1_0::HciPacket;
+using vendor::qti::hardware::fm::V1_0::Status;
+using android::hardware::ProcessState;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+
+static struct fm_hci_t hci;
+
+typedef std::unique_lock<std::mutex> Lock;
+android::sp<IFmHci> fmHci;
+
+static int enqueue_fm_rx_event(struct fm_event_header_t *hdr);
+static void dequeue_fm_rx_event();
+static int enqueue_fm_tx_cmd(struct fm_command_header_t *hdr);
+static void dequeue_fm_tx_cmd();
+static void  hci_tx_thread();
+static void hci_rx_thread();
+static int start_tx_thread();
+static void stop_tx_thread();
+static int start_rx_thread();
+static void stop_rx_thread();
+static void cleanup_threads();
+static bool hci_initialize();
+static void hci_transmit(struct fm_command_header_t *hdr);
+static void hci_close();
+
+/*******************************************************************************
+**
+** Function         enqueue_fm_rx_event
+**
+** Description      This function is called in the hal daemon context to queue
+**                  FM events in RX queue.
+**
+** Parameters:      hdr - contains the fm event header pointer
+**
+**
+** Returns          int
+**
+*******************************************************************************/
+static int enqueue_fm_rx_event(struct fm_event_header_t *hdr)
+{
+
+    hci.rx_queue_mtx.lock();
+    hci.rx_event_queue.push(hdr);
+    hci.rx_queue_mtx.unlock();
+
+    if (hci.is_rx_processing == false) {
+        hci.rx_cond.notify_all();
+    }
+
+    ALOGI("%s: FM-Event ENQUEUED SUCCESSFULLY", __func__);
+
+    return FM_HC_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function         dequeue_fm_rx_event
+**
+** Description      This function is called in the rx thread context to dequeue
+**                  FM events from RX queue & processing the FM event.
+**
+** Parameters:      void
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void dequeue_fm_rx_event()
+{
+    fm_event_header_t *evt_buf;
+
+    ALOGI("%s", __func__);
+    while (1) {
+        hci.rx_queue_mtx.lock();
+        if (hci.rx_event_queue.empty()) {
+            ALOGI("No more FM Events are available in the RX Queue");
+            hci.is_rx_processing = false;
+            hci.rx_queue_mtx.unlock();
+            return;
+        } else {
+            hci.is_rx_processing = true;
+        }
+
+        evt_buf = hci.rx_event_queue.front();
+        hci.rx_event_queue.pop();
+        hci.rx_queue_mtx.unlock();
+
+        hci.credit_mtx.lock();
+        if (evt_buf->evt_code == FM_CMD_COMPLETE) {
+            ALOGI("%s: %d Credits got from the SOC", __func__, evt_buf->params[0]);
+            hci.command_credits += evt_buf->params[0];
+            hci.cmd_credits_cond.notify_all();
+        } else if (evt_buf->evt_code == FM_CMD_STATUS) {
+            ALOGI("%s: %d Credits got from the SOC", __func__, evt_buf->params[1]);
+            hci.command_credits += evt_buf->params[1];
+            hci.cmd_credits_cond.notify_all();
+        } else if (evt_buf->evt_code == FM_HW_ERR_EVENT) {
+            ALOGI("%s: FM H/w Err Event Recvd. Event Code: 0x%x", __func__, evt_buf->evt_code);
+        } else {
+            ALOGE("%s: Not CS/CC Event: Recvd. Event Code: 0x%x", __func__, evt_buf->evt_code);
+        }
+
+        hci.credit_mtx.unlock();
+        if (hci.cb && hci.cb->process_event) {
+            ALOGI("%s: processing the event", __func__);
+            hci.cb->process_event(NULL, (uint8_t *)evt_buf);
+        }
+
+        free(evt_buf);
+        evt_buf = NULL;
+    }
+
+}
+
+/*******************************************************************************
+**
+** Function         enqueue_fm_tx_cmd
+**
+** Description      This function is called in the application JNI context to
+**                  queue FM commands in TX queue.
+**
+** Parameters:      hdr - contains the fm command header pointer
+**
+**
+** Returns          int
+**
+*******************************************************************************/
+static int enqueue_fm_tx_cmd(struct fm_command_header_t *hdr)
+{
+    ALOGI("%s:  opcode 0x%x len:%d", __func__,  hdr->opcode, hdr->len);
+
+    hci.tx_queue_mtx.lock();
+    hci.tx_cmd_queue.push(hdr);
+    hci.tx_queue_mtx.unlock();
+
+    if (hci.is_tx_processing == false) {
+        hci.tx_cond.notify_all();
+    }
+
+    ALOGI("%s: FM-CMD ENQUEUED SUCCESSFULLY", __func__);
+
+    return FM_HC_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function         dequeue_fm_tx_cmd
+**
+** Description      This function is called in the tx thread context to dequeue
+**                  & transmitting FM command to to HAL daemon.
+**
+** Parameters:      void
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void dequeue_fm_tx_cmd()
+{
+    fm_command_header_t *hdr;
+
+    ALOGI("%s", __func__);
+
+    while (1) {
+        hci.tx_queue_mtx.lock();
+        if(hci.tx_cmd_queue.empty()){
+            ALOGI("No more FM CMDs are available in the Queue");
+            hci.is_tx_processing = false;
+            hci.tx_queue_mtx.unlock();
+            return;
+        } else {
+            hci.is_tx_processing = true;
+        }
+
+        hdr = hci.tx_cmd_queue.front();
+        hci.tx_cmd_queue.pop();
+        hci.tx_queue_mtx.unlock();
+
+        Lock lk(hci.credit_mtx);
+        while (hci.command_credits == 0) {
+            ALOGI("%s: waiting for credits", __func__);
+            hci.cmd_credits_cond.wait(lk);
+            ALOGI("%s: %d Credits Remaining", __func__, hci.command_credits);
+            if (hci.command_credits) {
+                 break;
+            }
+        }
+        hci.command_credits--;
+        hci_transmit(hdr);
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         hci_tx_thread
+**
+** Description      This function is main function of tx worker thread.
+**
+** Parameters:      void
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void  hci_tx_thread()
+{
+    ALOGI("%s: ##### starting hci_tx_thread Worker thread!!! #####", __func__);
+
+    while (hci.state != FM_RADIO_DISABLING && hci.state != FM_RADIO_DISABLED) {
+        //wait  for tx cmd
+        Lock lk(hci.tx_cond_mtx);
+        hci.tx_cond.wait(lk);
+        ALOGV("%s: dequeueing the tx cmd!!!" , __func__);
+        dequeue_fm_tx_cmd();
+    }
+
+    ALOGI("%s: ##### Exiting hci_tx_thread Worker thread!!! #####", __func__);
+}
+
+/*******************************************************************************
+**
+** Function         hci_rx_thread
+**
+** Description      This function is main function of tx worker thread.
+**
+** Parameters:      void
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void hci_rx_thread()
+{
+
+    ALOGI("%s: ##### starting hci_rx_thread Worker thread!!! #####", __func__);
+
+    while (hci.state != FM_RADIO_DISABLING && hci.state != FM_RADIO_DISABLED) {
+        //wait for rx event
+        Lock lk(hci.rx_cond_mtx);
+        hci.rx_cond.wait(lk);
+        dequeue_fm_rx_event();
+    }
+
+    ALOGI("%s: ##### Exiting hci_rx_thread Worker thread!!! #####", __func__);
+}
+
+/*******************************************************************************
+**
+** Function         start_tx_thread
+**
+** Description      This function is called to start tx worker thread.
+**
+** Parameters:      void
+**
+**
+** Returns          int
+**
+*******************************************************************************/
+static int start_tx_thread()
+{
+
+    ALOGI("FM-HCI: Creating the FM-HCI  TX TASK...");
+    hci.tx_thread_ = std::thread(hci_tx_thread);
+    if (!hci.tx_thread_.joinable()) {
+        ALOGE("tx thread is not joinable");
+        return FM_HC_STATUS_FAIL;
+    }
+
+    return FM_HC_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function         stop_tx_thread
+**
+** Description      This function is called to stop tx worker thread.
+**
+** Parameters:      void
+**
+**
+** Returns          int
+**
+*******************************************************************************/
+static void stop_tx_thread()
+{
+    int ret;
+
+    ALOGI("%s:stop_tx_thread ++", __func__);
+    if (hci.is_tx_processing == false) {
+        hci.tx_cond.notify_all();
+    }
+
+    hci.tx_thread_.join();
+    ALOGI("%s:stop_tx_thread --", __func__);
+}
+
+/*******************************************************************************
+**
+** Function         start_rx_thread
+**
+** Description      This function is called to start rx worker thread.
+**
+** Parameters:      void
+**
+**
+** Returns          int
+**
+*******************************************************************************/
+static int start_rx_thread()
+{
+    int ret = FM_HC_STATUS_SUCCESS;
+    ALOGI("FM-HCI: Creating the FM-HCI RX TASK...");
+
+    hci.rx_thread_ = std::thread(hci_rx_thread);
+    if (!hci.rx_thread_.joinable()) {
+        ALOGE("rx thread is not joinable");
+        return FM_HC_STATUS_FAIL;
+    }
+
+    return ret;
+}
+
+/*******************************************************************************
+**
+** Function         stop_rx_thread
+**
+** Description      This function is called to stop rx worker thread.
+**
+** Parameters:      void
+**
+**
+** Returns          int
+**
+*******************************************************************************/
+static void stop_rx_thread()
+{
+    ALOGI("%s:stop_rx_thread ++", __func__);
+    if (hci.is_rx_processing == false) {
+        hci.rx_cond.notify_all();
+    }
+
+    hci.rx_thread_.join();
+    ALOGI("%s:stop_rx_thread --", __func__);
+}
+
+/*******************************************************************************
+**
+** Function         cleanup_threads
+**
+** Description      This function is called to cleanup rx & tx worker thread.
+**
+** Parameters:      void
+**
+**
+** Returns          int
+**
+*******************************************************************************/
+static void cleanup_threads()
+{
+    stop_rx_thread();
+    stop_tx_thread();
+}
+
+/*******************************************************************************
+**
+** Function         initialization_complete
+**
+** Description      This function is called, when initialization complete
+**                  callback is called by hal daemon.
+**
+** Parameters:      hdr - contains the fm event header pointer
+**
+**
+** Returns          int
+**
+*******************************************************************************/
+static void initialization_complete(bool is_hci_initialize)
+{
+    int ret;
+    ALOGI("++%s: is_hci_initialize: %d", __func__, is_hci_initialize);
+
+    while (is_hci_initialize) {
+        ret = start_tx_thread();
+        if (ret)
+        {
+            cleanup_threads();
+            hci.state = FM_RADIO_DISABLING;
+            break;
+        }
+
+        ret = start_rx_thread();
+        if (ret)
+        {
+            cleanup_threads();
+            hci.state = FM_RADIO_DISABLING;
+            break;
+        }
+
+        hci.state = FM_RADIO_ENABLED;
+        break;
+    }
+
+    hci.on_cond.notify_all();
+    ALOGI("--%s: is_hci_initialize: %d", __func__, is_hci_initialize);
+
+}
+
+/*******************************************************************************
+**
+** Class            FmHciCallbacks
+**
+** Description      This is main class, which has the implemention for FM HCI
+**                  callback functions.
+**
+** Member callback Functions:      initializationComplete, hciEventReceived
+**
+**
+** Returns          int
+**
+*******************************************************************************/
+class FmHciCallbacks : public IFmHciCallbacks {
+    public:
+        FmHciCallbacks() {
+        };
+        virtual ~FmHciCallbacks() = default;
+
+        Return<void> initializationComplete(Status status) {
+            if(status == Status::SUCCESS)
+            {
+                initialization_complete(true);
+            } else {
+                initialization_complete(false);
+            }
+
+            return Void();
+        }
+
+        Return<void> hciEventReceived(const hidl_vec<uint8_t>& event) {
+            struct fm_event_header_t *temp = (struct fm_event_header_t *) malloc(event.size());
+            memcpy(temp, event.data(), event.size());
+            ALOGI("%s: evt_code:  0x%x", __func__, temp->evt_code);
+            enqueue_fm_rx_event(temp);
+
+            return Void();
+        }
+};
+
+/*******************************************************************************
+**
+** Function         hci_initialize
+**
+** Description      This function is used to initialize fm hci hidl transport.
+**                  It makes a binder call to hal daemon
+**
+** Parameters:      void
+**
+**
+** Returns          bool
+**
+*******************************************************************************/
+static bool hci_initialize()
+{
+    ALOGI("%s", __func__);
+
+    fmHci = IFmHci::getService();
+
+    if (fmHci != nullptr) {
+        hci.state = FM_RADIO_ENABLING;
+        android::sp<IFmHciCallbacks> callbacks = new FmHciCallbacks();
+        fmHci->initialize(callbacks);
+        return true;
+    } else {
+        return false;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         hci_transmit
+**
+** Description      This function is used to send fm command to fm hci hidl transport.
+**                  It makes a binder call to hal daemon.
+**
+** Parameters:      void
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void hci_transmit(struct fm_command_header_t *hdr) {
+    HciPacket data;
+
+    ALOGI("%s: opcode 0x%x len:%d", __func__, hdr->opcode, hdr->len);
+
+    if (fmHci != nullptr) {
+        data.setToExternal((uint8_t *)hdr, 3 + hdr->len);
+        fmHci->sendHciCommand(data);
+    } else {
+        ALOGI("%s: fmHci is NULL", __func__);
+    }
+
+    free(hdr);
+}
+
+/*******************************************************************************
+**
+** Function         hci_close
+**
+** Description      This function is used to close fm hci hidl transport.
+**                  It makes a binder call to hal daemon
+**
+** Parameters:      void
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void hci_close()
+{
+    ALOGI("%s", __func__);
+
+    if (fmHci != nullptr) {
+        fmHci->close();
+        fmHci = nullptr;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         fm_hci_init
+**
+** Description      This function is used to intialize fm hci
+**
+** Parameters:     hci_hal - contains the fm helium hal hci pointer
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+int fm_hci_init(fm_hci_hal_t *hci_hal)
+{
+    int ret = FM_HC_STATUS_FAIL;
+
+    ALOGD("++%s", __func__);
+
+    if (!hci_hal || !hci_hal->hal) {
+        ALOGE("NULL input argument");
+        return FM_HC_STATUS_NULL_POINTER;
+    }
+
+    memset(&hci, 0, sizeof(struct fm_hci_t));
+
+    hci.cb = hci_hal->cb;
+    hci.command_credits = 1;
+    hci.is_tx_processing = false;
+    hci.is_rx_processing = false;
+    hci.state = FM_RADIO_DISABLED;
+    hci_hal->hci = &hci;
+
+    if (hci_initialize()) {
+        //wait for iniialization complete
+        ALOGD("--%s waiting for iniialization complete hci state: %d ",
+                __func__, hci.state);
+        if(hci.state == FM_RADIO_ENABLING){
+            Lock lk(hci.on_mtx);
+            hci.on_cond.wait(lk);
+        }
+    }
+
+    if (hci.state == FM_RADIO_ENABLED) {
+        ALOGD("--%s success", __func__);
+        ret = FM_HC_STATUS_SUCCESS;
+    } else {
+       ALOGD("--%s failed", __func__);
+       hci_close();
+       hci.state = FM_RADIO_DISABLED;
+    }
+    return ret;
+}
+
+/*******************************************************************************
+**
+** Function         fm_hci_transmit
+**
+** Description      This function is called by helium hal & is used enqueue the
+**                  tx commands in tx queue.
+**
+** Parameters:      p_hci - contains the fm helium hal hci pointer
+**                  hdr - contains the fm command header pointer
+**
+** Returns          void
+**
+*******************************************************************************/
+int fm_hci_transmit(void *p_hci, struct fm_command_header_t *hdr)
+{
+    if (!hdr) {
+        ALOGE("NULL input arguments");
+        return FM_HC_STATUS_NULL_POINTER;
+    }
+
+    return enqueue_fm_tx_cmd(hdr);
+}
+
+/*******************************************************************************
+**
+** Function         fm_hci_close
+**
+** Description      This function is used to close & cleanup hci
+**
+** Parameters:      p_hci - contains the fm hci pointer
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void fm_hci_close(void *p_hci)
+{
+    ALOGI("%s", __func__);
+    hci.state = FM_RADIO_DISABLING;
+
+    hci_close();
+    stop_tx_thread();
+
+    if (hci.cb && hci.cb->fm_hci_close_done) {
+        ALOGI("%s:Notify FM OFF to hal", __func__);
+        hci.cb->fm_hci_close_done();
+    }
+
+    hci.state = FM_RADIO_DISABLED;
+}
+
diff --git a/fm_hci/fm_hci.h b/fm_hci/fm_hci.h
index 2cfb30e..92c5942 100644
--- a/fm_hci/fm_hci.h
+++ b/fm_hci/fm_hci.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2017 The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -30,72 +30,41 @@
 #ifndef __FM_HCI__
 #define __FM_HCI__
 
-#include "bt_hci_bdroid.h"
-#include "bt_vendor_lib.h"
 #include "fm_hci_api.h"
 
-/* Host/Controller lib internal event ID */
-#define HC_EVENT_PRELOAD               0x0001
-#define HC_EVENT_POSTLOAD              0x0002
-#define HC_EVENT_RX                    0x0004
-#define HC_EVENT_TX                    0x0008
-#define HC_EVENT_LPM_ENABLE            0x0010
-#define HC_EVENT_LPM_DISABLE           0x0020
-#define HC_EVENT_LPM_WAKE_DEVICE       0x0040
-#define HC_EVENT_LPM_ALLOW_SLEEP       0x0080
-#define HC_EVENT_LPM_IDLE_TIMEOUT      0x0100
-#define HC_EVENT_EXIT                  0x0200
-#define HC_EVENT_EPILOG                0x0400
-#define HC_EVENT_EXIT_DONE             0x8000
-
-#define MAX_FM_CMD_CNT                 100
-#define FM_CMD                         0x11
-#define FM_EVT                         0x14
-#define MAX_FM_EVT_PARAMS              255
-
 #define FM_CMD_COMPLETE 0x0f
 #define FM_CMD_STATUS   0x10
 #define FM_HW_ERR_EVENT 0x1A
 
-/* TODO: move inside context */
-static volatile uint8_t lib_running = 0;
-static volatile uint16_t ready_events = 0;
-
-// The set of events one can send to the userial read thread.
-// Note that the values must be >= 0x8000000000000000 to guarantee delivery
-// of the message (see eventfd(2) for details on blocking behaviour).
-enum {
-    USERIAL_RX_EXIT     = 0x8000000000000000ULL
-};
-
-struct transmit_queue_t {
-    struct fm_command_header_t *hdr;
-    struct transmit_queue_t *next;
-};
-
 struct fm_hci_t {
-    int fd;
-    pthread_mutex_t credit_lock;
-    pthread_cond_t cmd_credits_cond;
+    public:
+        fm_power_state_t state;
+        std::condition_variable on_cond;
+        std::mutex on_mtx;
 
-    pthread_mutex_t event_lock;
-    pthread_cond_t event_cond;
+        bool is_tx_processing;
+        bool is_rx_processing;
 
-    pthread_t hal_thread;
-    pthread_t tx_thread;
-    pthread_t rx_thread;
-    pthread_t mon_thread;
+        std::condition_variable tx_cond;
+        std::mutex tx_cond_mtx;
 
-    pthread_mutex_t tx_q_lock;
-    struct transmit_queue_t *first;
-    struct transmit_queue_t *last;
+        std::condition_variable rx_cond;
+        std::mutex rx_cond_mtx;
 
-    void *dlhandle;
-    bt_vendor_interface_t *vendor;
+        std::mutex tx_queue_mtx;
+        std::mutex rx_queue_mtx;
 
-    struct fm_hci_callbacks_t *cb;
-    void *private_data;
-    volatile uint16_t command_credits;
+        std::mutex credit_mtx;
+        std::condition_variable cmd_credits_cond;
+
+        std::queue<struct fm_command_header_t *> tx_cmd_queue;
+        std::queue<struct fm_event_header_t *> rx_event_queue;
+
+        volatile uint16_t command_credits;
+        struct fm_hci_callbacks_t *cb;
+
+        std::thread tx_thread_;
+        std::thread rx_thread_;
 };
 
 #endif
diff --git a/fm_hci/fm_hci_api.h b/fm_hci/fm_hci_api.h
index 67a866b..01298f0 100644
--- a/fm_hci/fm_hci_api.h
+++ b/fm_hci/fm_hci_api.h
@@ -57,14 +57,19 @@
 }
 
 typedef enum {
-    FM_RADIO_DISABLE,
-    FM_RADIO_ENABLE
+    FM_RADIO_DISABLED,
+    FM_RADIO_DISABLING,
+    FM_RADIO_ENABLED,
+    FM_RADIO_ENABLING
 } fm_power_state_t;
 
 typedef int (*event_notification_cb_t)(void *hal, unsigned char *buf);
+typedef int (*hci_close_done_cb_t)();
+
 
 struct fm_hci_callbacks_t {
     event_notification_cb_t process_event;
+    hci_close_done_cb_t fm_hci_close_done;
 };
 
 typedef struct {
@@ -74,20 +79,65 @@
 }fm_hci_hal_t;
 
 struct fm_command_header_t {
-    uint8_t  pi;                /* packet indicator */
     uint16_t opcode;
     uint8_t  len;
     uint8_t  params[];
 }__attribute__((packed));
 
 struct fm_event_header_t {
-    uint8_t pi;                /* packet indicator */
     uint8_t evt_code;
     uint8_t evt_len;
     uint8_t params[];
 }__attribute__((packed));
+#ifdef __cplusplus
+extern "C"
+{
+#endif
 
+/*******************************************************************************
+**
+** Function         fm_hci_init
+**
+** Description      This function is used to intialize fm hci
+**
+** Parameters:     hci_hal: contains the fm helium hal hci pointer
+**
+**
+** Returns          void
+**
+*******************************************************************************/
 int fm_hci_init(fm_hci_hal_t *hal_hci);
-int fm_hci_transmit(void *hci, struct fm_command_header_t *buf);
-void fm_hci_close(void *hci);
+
+/*******************************************************************************
+**
+** Function         fm_hci_transmit
+**
+** Description      This function is called by helium hal & is used enqueue the
+**                      tx commands in tx queue.
+**
+** Parameters:     p_hci - contains the fm helium hal hci pointer
+**                      hdr - contains the fm command header pointer
+**
+** Returns          void
+**
+*******************************************************************************/
+int fm_hci_transmit(void *p_hci, struct fm_command_header_t *hdr);
+/*******************************************************************************
+**
+** Function         fm_hci_close
+**
+** Description      This function is used to close & cleanup hci
+**
+** Parameters:      p_hci: contains the fm hci pointer
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void fm_hci_close(void *p_hci);
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif
diff --git a/fmapp2/src/com/caf/fmradio/FMRadioService.java b/fmapp2/src/com/caf/fmradio/FMRadioService.java
index 76904eb..cbd713a 100644
--- a/fmapp2/src/com/caf/fmradio/FMRadioService.java
+++ b/fmapp2/src/com/caf/fmradio/FMRadioService.java
@@ -1691,6 +1691,8 @@
 
    /* Show the FM Notification */
    public void startNotification() {
+      Log.d(LOGTAG,"startNotification");
+
       RemoteViews views = new RemoteViews(getPackageName(), R.layout.statusbar);
       views.setImageViewResource(R.id.icon, R.drawable.stat_notify_fm);
       if (isFmOn())
diff --git a/helium/Android.mk b/helium/Android.mk
index 068308b..4008dd6 100644
--- a/helium/Android.mk
+++ b/helium/Android.mk
@@ -5,8 +5,8 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-	radio_helium_hal.c \
-	radio_helium_hal_cmds.c
+        radio_helium_hal.c \
+        radio_helium_hal_cmds.c
 
 LOCAL_SHARED_LIBRARIES := \
          libfm-hci \
diff --git a/helium/radio_helium_hal.c b/helium/radio_helium_hal.c
index 5d9137e..1109ca3 100644
--- a/helium/radio_helium_hal.c
+++ b/helium/radio_helium_hal.c
@@ -116,9 +116,6 @@
     if (hal->radio->mode == FM_TURNING_OFF) {
         ALOGD("%s:calling fm close\n", LOG_TAG );
         fm_hci_close(hal->private_data);
-        hal->radio->mode = FM_OFF;
-        hal->jni_cb->disabled_cb();
-        hal->jni_cb->thread_evt_cb(1);
     }
 }
 
@@ -823,8 +820,6 @@
 {
    ALOGE("%s:%s: start", LOG_TAG, __func__);
    fm_hci_close(hal->private_data);
-   hal->jni_cb->disabled_cb();
-   hal->jni_cb->thread_evt_cb(1);
 }
 
 static void hci_buff_ert(struct rds_grp_data *rds_buf)
@@ -1034,6 +1029,18 @@
     return 0;
 }
 
+int fm_hci_close_done()
+{
+    ALOGI("fm_hci_close_done");
+    if(hal != NULL){
+        ALOGI("Notifying FM OFF to JNI");
+        hal->radio->mode = FM_OFF;
+        hal->jni_cb->disabled_cb();
+        hal->jni_cb->thread_evt_cb(1);
+    }
+    return 0;
+}
+
 int helium_search_req(int on, int direct)
 {
     int retval = 0;
@@ -1132,7 +1139,8 @@
 
 /* Callback function to be registered with FM-HCI for event notification */
 static struct fm_hci_callbacks_t hal_cb = {
-    process_event
+    process_event,
+    fm_hci_close_done
 };
 
 int hal_init(fm_hal_callbacks_t *cb)
diff --git a/helium/radio_helium_hal_cmds.c b/helium/radio_helium_hal_cmds.c
index b783c53..a8fc305 100644
--- a/helium/radio_helium_hal_cmds.c
+++ b/helium/radio_helium_hal_cmds.c
@@ -41,19 +41,19 @@
 
 static int send_fm_cmd_pkt(uint16_t opcode,  uint32_t len, void *param)
 {
-    int p_len = 4 + len;
+    int p_len = 3 + len;
     int ret = 0;
     ALOGV("Send_fm_cmd_pkt, opcode: %x", opcode);
-//    pthread_mutex_lock(&fm_hal);
+
     struct fm_command_header_t *hdr = (struct fm_command_header_t *) malloc(p_len);
     if (!hdr) {
         ALOGE("%s:hdr allocation failed", LOG_TAG);
         return -FM_HC_STATUS_NOMEM;
     }
 
+    memset(hdr, 0, p_len);
     ALOGV("%s:opcode: %x", LOG_TAG, opcode);
 
-    hdr->pi = RADIO_HCI_COMMAND_PKT;
     hdr->opcode = opcode;
     hdr->len = len;
     if (len)
diff --git a/jni/android_hardware_fm.cpp b/jni/android_hardware_fm.cpp
index 3846589..516e0e4 100644
--- a/jni/android_hardware_fm.cpp
+++ b/jni/android_hardware_fm.cpp
@@ -30,7 +30,7 @@
 
 #include "jni.h"
 #include "JNIHelp.h"
-#include "utils/Log.h"
+#include <utils/Log.h>
 #include "utils/misc.h"
 #include "FmIoctlsInterface.h"
 #include "ConfigFmThs.h"