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"