From 88832b9d5ba836a7535243a91a4822f08c30547c Mon Sep 17 00:00:00 2001
From: Satish kumar sugasi <ssugas@codeaurora.org>
Date: Mon, 21 Dec 2015 18:52:29 -0800
Subject: [PATCH] FM : Add new hci commands and compile changes

Added HAL changes for hci commands like peek, poke, get/set of
SINR sample/threshold.Compile time changes for adding correct
includes based on new bluetooth stack structure, code cleanup
and indendation.

Change-Id: I5e48f0c0dc6165d61335c6d8cc269891e26dd548
---
 Android.mk                     |   2 +-
 fm_hci/Android.mk              |   4 +-
 fm_hci/fm_hci.c                | 357 +++++++++++++++++----------------
 fm_hci/fm_hci.h                |   1 +
 helium/radio-helium-commands.h |  16 ++
 helium/radio-helium.h          |  36 +++-
 helium/radio_helium_hal.c      | 230 +++++++++++++++++++--
 helium/radio_helium_hal_cmds.c |  74 +++++++
 jni/android_hardware_fm.cpp    |  26 ++-
 qcom/fmradio/FmRxRdsData.java  |   1 +
 10 files changed, 557 insertions(+), 190 deletions(-)

diff --git a/Android.mk b/Android.mk
index 5b79fbf..fc3a54e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -19,6 +19,7 @@ include $(BUILD_JAVA_LIBRARY)
 include $(LOCAL_PATH)/jni/Android.mk
 LOCAL_PATH := $(LOCAL_DIR_PATH)
 include $(LOCAL_PATH)/fmapp2/Android.mk
+
 #LOCAL_PATH := $(LOCAL_DIR_PATH)
 #include $(LOCAL_PATH)/FMRecord/Android.mk
 
@@ -32,5 +33,4 @@ LOCAL_PATH := $(LOCAL_DIR_PATH)
 include $(LOCAL_PATH)/libfm_jni/Android.mk
 #endif # is-vendor-board-platform
 #endif # BOARD_HAVE_QCOM_FM
-
 #endif # Not (TARGET_USES_AOSP)
diff --git a/fm_hci/Android.mk b/fm_hci/Android.mk
index 1c4b949..2546902 100644
--- a/fm_hci/Android.mk
+++ b/fm_hci/Android.mk
@@ -11,7 +11,7 @@ else
   bdroid_CFLAGS += -DHAS_NO_BDROID_BUILDCFG
 endif
 
-BDROID_DIR:= external/bluetooth/bluedroid
+BDROID_DIR:= system/bt
 
 LOCAL_CFLAGS += $(bdroid_CFLAGS)
 
@@ -28,6 +28,8 @@ LOCAL_CFLAGS += -std=c99
 
 LOCAL_C_INCLUDES += \
         $(BDROID_DIR)/hci/include \
+        $(BDROID_DIR)/stack/include \
+        $(BDROID_DIR)/osi/include \
         $(LOCAL_PATH)/../helium
 
 LOCAL_MODULE := libfm-hci
diff --git a/fm_hci/fm_hci.c b/fm_hci/fm_hci.c
index 1394565..e0294ee 100644
--- a/fm_hci/fm_hci.c
+++ b/fm_hci/fm_hci.c
@@ -34,18 +34,24 @@
 
 #include "bt_hci_bdroid.h"
 #include "bt_vendor_lib.h"
-#include "hci.h"
 #include "userial.h"
-#include "utils.h"
 #include "fm_hci.h"
 #include "wcnss_hci.h"
 #include <dlfcn.h>
 #include <sys/eventfd.h>
 #include <errno.h>
+#include <string.h>
 
 int fm_fd;
 fm_hal_cb *hal_cb;
 
+// 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
+};
+
 void event_notification(uint16_t event)
 {
     pthread_mutex_lock(&fmHCIControlBlock.event_lock);
@@ -84,90 +90,90 @@ volatile uint16_t command_credits;
 /* De-queues the FM CMD from the TX_Q */
 void dequeue_fm_tx_cmd()
 {
-	TX_Q *new_first, *new_last;
-	static int cmd_count = 0;
-	static uint8_t credits = 0;
-	uint8_t i;
-	uint8_t temp_1 = 0x11;
-
-	if (cmd_count >= MAX_FM_CMD_CNT) {
-		ALOGI("\n\n\t\tReached Max. CMD COUNT!!\n\n");
-		lib_running = 0;
-		return;
-	}
-
-	/*
-	 * Save the 'first' pointer and make it NULL.
-	 * This is to allow the FM-HAL to enqueue more CMDs to the TX_Q
-	 * without having to contend for the 'tx_q_lock' with the FM-HCI thread.
-	 * Once the pointer to the 'first' element in the TX_Q is available,
-	 * send all the commands in the queue to WCNSS FILTER based on the
-	 * command credits provided by the Controller. If command credits are
-	 * not available, then wait for the same.
-	 */
-	pthread_mutex_lock(&fmHCIControlBlock.tx_q_lock);
-	if (!fmHCIControlBlock.first) {
-		ALOGI("No FM CMD available in the Q\n");
-		pthread_mutex_unlock(&fmHCIControlBlock.tx_q_lock);
-		return;
-	}
-	else {
-		new_first = fmHCIControlBlock.first;
-		new_last  = fmHCIControlBlock.last;
-		fmHCIControlBlock.first = fmHCIControlBlock.last = NULL;
-	}
-	pthread_mutex_unlock(&fmHCIControlBlock.tx_q_lock);
-
-	//credits = command_credits;
-
-	TX_Q *temp = new_first;
-	while(temp != NULL) {
+    TX_Q *new_first, *new_last;
+    static int cmd_count = 0;
+    static uint8_t credits = 0;
+    uint8_t i;
+    uint8_t temp_1 = 0x11;
+
+    if (cmd_count >= MAX_FM_CMD_CNT) {
+        ALOGI("\n\n\t\tReached Max. CMD COUNT!!\n\n");
+        lib_running = 0;
+        return;
+    }
+
+    /*
+     * Save the 'first' pointer and make it NULL.
+     * This is to allow the FM-HAL to enqueue more CMDs to the TX_Q
+     * without having to contend for the 'tx_q_lock' with the FM-HCI thread.
+     * Once the pointer to the 'first' element in the TX_Q is available,
+     * send all the commands in the queue to WCNSS FILTER based on the
+     * command credits provided by the Controller. If command credits are
+     * not available, then wait for the same.
+     */
+    pthread_mutex_lock(&fmHCIControlBlock.tx_q_lock);
+    if (!fmHCIControlBlock.first) {
+        ALOGI("No FM CMD available in the Q\n");
+        pthread_mutex_unlock(&fmHCIControlBlock.tx_q_lock);
+        return;
+    }
+    else {
+        new_first = fmHCIControlBlock.first;
+        new_last  = fmHCIControlBlock.last;
+        fmHCIControlBlock.first = fmHCIControlBlock.last = NULL;
+    }
+    pthread_mutex_unlock(&fmHCIControlBlock.tx_q_lock);
+
+    //credits = command_credits;
+
+    TX_Q *temp = new_first;
+    while(temp != NULL) {
 
 wait_for_cmd_credits:
-		pthread_mutex_lock(&fmHCIControlBlock.credit_lock);
-		while (command_credits == 0) {
-			ALOGI("\n\n\t\tWaiting for COMMAND CREDITS from CONTROLLER\n\n");
-			pthread_cond_wait(&fmHCIControlBlock.cmd_credits_cond, &fmHCIControlBlock.credit_lock);
-		}
-		pthread_mutex_unlock(&fmHCIControlBlock.credit_lock);
-
-		/* Check if we really got the command credits */
-		//REVISIT this area
-		//if (credits) {
-		if (command_credits) {
-			ALOGI("%s: Sending the FM-CMD(prot_byte: 0x%x): 0x%x dequeued from TX_Q\n", __func__, temp->hdr->protocol_byte, temp->hdr->opcode);
-
-			if (temp->hdr->plen) {
-				ALOGI("%s: CMD-PARAMS:", __func__);
-				for (i = 0; i < temp->hdr->plen; i++)
-					ALOGI(" <0x%x> ", temp->hdr->cmd_params[i]);
-			} else
-				ALOGE("%s: NO CMD-PARAMS available for this command", __func__);
-
-			ALOGE("%s: Sizeof FM_HDR: %d", __func__, (int)sizeof(temp->hdr));
-			/* Use socket 'fd' to send the command down to WCNSS Filter */
-			write(fm_fd, (uint8_t *)temp->hdr, (sizeof(FM_HDR) + temp->hdr->plen));
-			//write(fd, &temp_1, 1);
-
-			/* Decrement cmd credits by '1' after sending the cmd*/
-			command_credits--;
-
-			/* TODO:
-			 * Initialize 'cmd_cnt' to MAX_FM_CMD(?). Should we have any limit on the
-			 * number of outstanding commands in the TX-Q ??
-			 */
-			cmd_count--;
-
-			/* Fetch the next cmd to be sent */
-			temp = temp->next;
-		} else {
-			if (!lib_running)
-				break;
-
-			ALOGI("\n\n\t\tFalse wakeup: Yet to get COMMAND CREDITS from CONTROLLER\n\n");
-			goto wait_for_cmd_credits;
-		}
-	}
+        pthread_mutex_lock(&fmHCIControlBlock.credit_lock);
+        while (command_credits == 0) {
+              ALOGI("\n\n\t\tWaiting for COMMAND CREDITS from CONTROLLER\n\n");
+              pthread_cond_wait(&fmHCIControlBlock.cmd_credits_cond, &fmHCIControlBlock.credit_lock);
+        }
+        pthread_mutex_unlock(&fmHCIControlBlock.credit_lock);
+
+        /* Check if we really got the command credits */
+        //REVISIT this area
+        //if (credits) {
+        if (command_credits) {
+            ALOGI("%s: Sending the FM-CMD(prot_byte: 0x%x): 0x%x dequeued from TX_Q\n", __func__, temp->hdr->protocol_byte, temp->hdr->opcode);
+
+            if (temp->hdr->plen) {
+                ALOGI("%s: CMD-PARAMS:", __func__);
+                for (i = 0; i < temp->hdr->plen; i++)
+                    ALOGI(" <0x%x> ", temp->hdr->cmd_params[i]);
+            } else
+                ALOGE("%s: NO CMD-PARAMS available for this command", __func__);
+
+            ALOGE("%s: Sizeof FM_HDR: %d", __func__, (int)sizeof(temp->hdr));
+            /* Use socket 'fd' to send the command down to WCNSS Filter */
+            write(fm_fd, (uint8_t *)temp->hdr, (sizeof(FM_HDR) + temp->hdr->plen));
+            //write(fd, &temp_1, 1);
+
+            /* Decrement cmd credits by '1' after sending the cmd*/
+            command_credits--;
+
+            /* TODO:
+             * Initialize 'cmd_cnt' to MAX_FM_CMD(?). Should we have any limit on the
+             * number of outstanding commands in the TX-Q ??
+             */
+            cmd_count--;
+
+            /* Fetch the next cmd to be sent */
+            temp = temp->next;
+        } else {
+            if (!lib_running)
+                break;
+
+            ALOGI("\n\n\t\tFalse wakeup: Yet to get COMMAND CREDITS from CONTROLLER\n\n");
+            goto wait_for_cmd_credits;
+        }
+    }
 }
 
 
@@ -218,30 +224,29 @@ static int read_fm_event(int fd, FM_EVT_HDR *pbuf, int len)
         FD_SET(event_fd, &readFds);
         int fd_max = (event_fd > fd ? event_fd : fd);
 
-        ALOGE("%s: Waiting for events from WCNSS FILTER...\n", __func__);
+        ALOGV("%s: Waiting for events from WCNSS FILTER...\n", __func__);
 
         /* Wait for event/data from WCNSS Filter */
         n = select(fd_max+1, &readFds, NULL, NULL, NULL);
         if (n > 0)
         {
             /* Check if event is available or not */
-#if 1
             if (FD_ISSET(fd, &readFds)) {
                 ret = read(fd, (uint8_t *)pbuf, (size_t)(sizeof(FM_EVT_HDR) + MAX_FM_EVT_PARAMS));
                 if (0 == ret) {
-                    ALOGE("%s: read() returned '0' bytes\n", __func__);
+                    ALOGD("%s: read() returned '0' bytes\n", __func__);
                 }
                 else {
-                    ALOGE("%s: read() returned %d bytes of FM event/data\n", __func__, ret);
+                    ALOGV("%s: read() returned %d bytes of FM event/data\n", __func__, ret);
                     while (ret > 0) {
                         if (pbuf->evt_code == FM_CMD_COMPLETE) {
-                            ALOGE("\n\t%s: Received %d bytes of CC event data from WCNSS FILTER!!!\n\t"
+                            ALOGV("\n\t%s: Received %d bytes of CC event data from WCNSS FILTER!!!\n\t"
                                 "Evt type\t: 0x%x \n\tEvt Code\t: 0x%x \n\tEvt len\t\t: 0x%x \n\topcode\t\t: 0x%x%x \n\tCmd Credits\t: 0x%x \n\tStatus\t\t: 0x%x\n",
                                 __func__, ret, pbuf->protocol_byte, pbuf->evt_code, pbuf->evt_len, pbuf->cmd_params[2], pbuf->cmd_params[1],
                             pbuf->cmd_params[0], pbuf->cmd_params[3]);
                             evt_type = FM_CMD_COMPLETE;
                         } else if (pbuf->evt_code == FM_CMD_STATUS) {
-                            ALOGE("\n\t%s: Received %d bytes of CS event data from WCNSS FILTER!!!\n\t"
+                            ALOGV("\n\t%s: Received %d bytes of CS event data from WCNSS FILTER!!!\n\t"
                                 "Evt type\t: 0x%x \n\tEvt Code\t: 0x%x \n\tEvt len\t\t: 0x%x \n\topcode\t\t: 0x%x%x \n\tCmd Credits\t: 0x%x \n\tStatus\t\t: 0x%x\n",
                                 __func__, ret, pbuf->protocol_byte, pbuf->evt_code, pbuf->evt_len, pbuf->cmd_params[3], pbuf->cmd_params[2],
                             pbuf->cmd_params[1], pbuf->cmd_params[0]);
@@ -251,7 +256,6 @@ static int read_fm_event(int fd, FM_EVT_HDR *pbuf, int len)
                               lib_running =0;
                               // commented till bt vendor include added
                              // fm_vnd_if->ssr_cleanup();
-
                         } else {
                             ALOGI("%s: Not CS/CC Event: Recvd. Event Code: 0x%2x", __func__, pbuf->evt_code);
                             evt_type = -1;
@@ -260,7 +264,7 @@ static int read_fm_event(int fd, FM_EVT_HDR *pbuf, int len)
                         evt_len = pbuf->evt_len;
 
                         /* Notify 'fmHCITask' about availability of event or data */
-                        ALOGE("%s: \nNotifying 'fmHCITask' availability of FM event or data...\n", __func__);
+                        ALOGI("%s: \nNotifying 'fmHCITask' availability of FM event or data...\n", __func__);
                         event_notification(HC_EVENT_RX);
 
                         if (hal_cb && hal_cb->fm_evt_notify != NULL)
@@ -272,11 +276,11 @@ static int read_fm_event(int fd, FM_EVT_HDR *pbuf, int len)
                             /* Provide command credits to allow fmHCITask to send cmds */
                             pthread_mutex_lock(&fmHCIControlBlock.credit_lock);
                             if (evt_type == FM_CMD_COMPLETE) {
-                                ALOGE("\n%s: Command Credit(s): '%d' received as part of CC Event for FM-CMD: 0x%x%x \n", __func__, pbuf->cmd_params[0],
+                                ALOGD("\n%s: Command Credit(s): '%d' received as part of CC Event for FM-CMD: 0x%x%x \n", __func__, pbuf->cmd_params[0],
                                      pbuf->cmd_params[2], pbuf->cmd_params[1]);
                                 command_credits = pbuf->cmd_params[0];
                             } else if (evt_type == FM_CMD_STATUS) {
-                                ALOGE("\n%s: Command Credit(s): '%d' received as part of CS Event for FM-CMD: 0x%x%x \n", __func__, pbuf->cmd_params[1],
+                                ALOGI("\n%s: Command Credit(s): '%d' received as part of CS Event for FM-CMD: 0x%x%x \n", __func__, pbuf->cmd_params[1],
                                     pbuf->cmd_params[3], pbuf->cmd_params[2]);
                                 command_credits = pbuf->cmd_params[1];
                             }
@@ -297,8 +301,7 @@ static int read_fm_event(int fd, FM_EVT_HDR *pbuf, int len)
                 } //end of processing the event
 
             } else
-                ALOGE("%s: No data available, though select returned!!!\n", __func__);
-#endif
+                ALOGV("%s: No data available, though select returned!!!\n", __func__);
         }
         else if (n < 0) {
            ALOGE("%s: select() failed with return value: %d", __func__, ret);
@@ -313,19 +316,19 @@ static int read_fm_event(int fd, FM_EVT_HDR *pbuf, int len)
 
 static void *userial_read_thread(void *arg)
 {
-	int length;
-
-       FM_EVT_HDR *evt_buf = (FM_EVT_HDR *) malloc(sizeof(FM_EVT_HDR) + MAX_FM_EVT_PARAMS);
-
-       ALOGE("%s: Wait for events from the WCNSS Filter", __func__);
-       length = read_fm_event(fm_fd, evt_buf, sizeof(FM_EVT_HDR) + MAX_FM_EVT_PARAMS);
-       ALOGE("length=%d\n",length);
-       if(length <=0){
-         lib_running =0;
-       }
-       ALOGE("%s: Leaving userial_read_thread()", __func__);
-       pthread_exit(NULL);
-       return arg;
+    int length;
+
+    FM_EVT_HDR *evt_buf = (FM_EVT_HDR *) malloc(sizeof(FM_EVT_HDR) + MAX_FM_EVT_PARAMS);
+
+    ALOGE("%s: Wait for events from the WCNSS Filter", __func__);
+    length = read_fm_event(fm_fd, evt_buf, sizeof(FM_EVT_HDR) + MAX_FM_EVT_PARAMS);
+    ALOGE("length=%d\n",length);
+    if(length <=0) {
+       lib_running =0;
+    }
+    ALOGE("%s: Leaving userial_read_thread()", __func__);
+    pthread_exit(NULL);
+    return arg;
 }
 
 /*
@@ -334,29 +337,37 @@ static void *userial_read_thread(void *arg)
  */
 static void* fmHCITask(void *arg)
 {
-	static uint16_t events;
-
-	while (lib_running) {
-		pthread_mutex_lock(&fmHCIControlBlock.event_lock);
-		while (ready_events == 0) {
-			pthread_cond_wait(&fmHCIControlBlock.event_cond, &fmHCIControlBlock.event_lock);
-		}
-
-		events = ready_events;
-		ready_events = 0;
-		pthread_mutex_unlock(&fmHCIControlBlock.event_lock);
-
-		if ((events & 0xFFF8) == HC_EVENT_TX) {
-			ALOGI("\n@@@@@ FM-HCI Task : EVENT_TX available @@@@@\n");
-			dequeue_fm_tx_cmd();
-		}
-		if ((events & 0xFFF4) == HC_EVENT_RX) {
-			ALOGI("\n##### FM-HCI Task : EVENT_RX available #####\n");
-			//TODO: Notify FM-HAL about event/data availablity
-		}
-	}
-        ALOGE("%s: ##### Exiting fmHCITask Worker thread!!! #####", __func__);
-	return arg;
+    static uint16_t events;
+    uint16_t ret;
+    while (lib_running) {
+        pthread_mutex_lock(&fmHCIControlBlock.event_lock);
+        while (ready_events == 0) {
+            pthread_cond_wait(&fmHCIControlBlock.event_cond, &fmHCIControlBlock.event_lock);
+        }
+        events = ready_events;
+        ready_events = 0;
+        pthread_mutex_unlock(&fmHCIControlBlock.event_lock);
+
+        if ((events & 0xFFF8) == HC_EVENT_TX) {
+        ALOGI("\n@@@@@ FM-HCI Task : EVENT_TX available @@@@@\n");
+        dequeue_fm_tx_cmd();
+        }
+        if ((events & 0xFFF4) == HC_EVENT_RX) {
+             ALOGI("\n##### FM-HCI Task : EVENT_RX available #####\n");
+        }
+    }
+
+    ALOGE("%s: ##### Exiting fmHCITask Worker thread!!! #####", __func__);
+    ret = pthread_mutex_unlock(&fmHCIControlBlock.credit_lock);
+    ALOGE("%s: credit lock ret value =%d #####", __func__, ret);
+    pthread_mutex_destroy(&fmHCIControlBlock.credit_lock);
+    ret = pthread_mutex_unlock(&fmHCIControlBlock.tx_q_lock);
+    ALOGE("%s: tx queue lock ret value =%d #####", __func__, ret);
+    pthread_mutex_destroy(&fmHCIControlBlock.tx_q_lock);
+    ret = pthread_mutex_unlock(&fmHCIControlBlock.event_lock);
+    ALOGE("%s: event lock ret value =%d #####", __func__, ret);
+    pthread_mutex_destroy(&fmHCIControlBlock.event_lock);
+    return arg;
 }
 
 int fm_hci_init(fm_hal_cb *p_cb)
@@ -470,34 +481,34 @@ err:
 void enqueue_fm_tx_cmd(FM_HDR *pbuf)
 {
 
-	pthread_mutex_lock(&fmHCIControlBlock.tx_q_lock);
-
-	if (!fmHCIControlBlock.first) {
-		fmHCIControlBlock.first = (TX_Q *) malloc(sizeof(TX_Q));
-		if (!fmHCIControlBlock.first) {
-			printf("Failed to allocate memory for first!!\n");
-			pthread_mutex_unlock(&fmHCIControlBlock.tx_q_lock);
-			return;
-		}
-		fmHCIControlBlock.first->hdr = pbuf;
-		fmHCIControlBlock.first->next = NULL;
-		fmHCIControlBlock.last = fmHCIControlBlock.first;
+    pthread_mutex_lock(&fmHCIControlBlock.tx_q_lock);
+
+    if (!fmHCIControlBlock.first) {
+        fmHCIControlBlock.first = (TX_Q *) malloc(sizeof(TX_Q));
+        if (!fmHCIControlBlock.first) {
+            printf("Failed to allocate memory for first!!\n");
+            pthread_mutex_unlock(&fmHCIControlBlock.tx_q_lock);
+            return;
+        }
+        fmHCIControlBlock.first->hdr = pbuf;
+        fmHCIControlBlock.first->next = NULL;
+        fmHCIControlBlock.last = fmHCIControlBlock.first;
                 ALOGI("%s: FM-CMD ENQUEUED SUCCESSFULLY", __func__);
-	} else {
-		TX_Q *element =  (TX_Q *) malloc(sizeof(TX_Q));
-		if (!element) {
-			printf("Failed to allocate memory for element!!\n");
-			pthread_mutex_unlock(&fmHCIControlBlock.tx_q_lock);
-			return;
-		}
-		fmHCIControlBlock.last->next = element;
-		element->hdr = pbuf;
-		element->next = NULL;
-		fmHCIControlBlock.last = element;
+    } else {
+        TX_Q *element =  (TX_Q *) malloc(sizeof(TX_Q));
+        if (!element) {
+            printf("Failed to allocate memory for element!!\n");
+            pthread_mutex_unlock(&fmHCIControlBlock.tx_q_lock);
+            return;
+        }
+        fmHCIControlBlock.last->next = element;
+        element->hdr = pbuf;
+        element->next = NULL;
+        fmHCIControlBlock.last = element;
                 ALOGI("%s: fm-cmd enqueued successfully", __func__);
-	}
+    }
 
-	pthread_mutex_unlock(&fmHCIControlBlock.tx_q_lock);
+    pthread_mutex_unlock(&fmHCIControlBlock.tx_q_lock);
 }
 
 /** Transmit frame */
@@ -510,8 +521,8 @@ void transmit(FM_HDR *pbuf)
 void userial_close_reader(void) {
     // Join the reader thread if it is still running.
     if (lib_running) {
-   //     send_event(USERIAL_RX_EXIT);
-        int result = pthread_join(&fmHCIControlBlock.fmRxTaskThreadId, NULL);
+        fm_send_event(USERIAL_RX_EXIT);
+        int result = pthread_join(fmHCIControlBlock.fmRxTaskThreadId, NULL);
         if (result)
             ALOGE("%s failed to join reader thread: %d", __func__, result);
         return;
@@ -520,13 +531,23 @@ void userial_close_reader(void) {
 }
 
 void fm_userial_close(void) {
-   if (lib_running) {
-       int result = pthread_join(&fmHCIControlBlock.fmRxTaskThreadId, NULL);
-       if (result)
-           ALOGE("%s failed to join reader thread: %d", __func__, result);
-   }
-   fm_vnd_if->op(BT_VND_OP_FM_USERIAL_CLOSE, NULL);
-   // Free all buffers still waiting in the RX queue.
-   //  TODO: use list data structure and clean this up.
-   fm_fd = -1;
+
+    pthread_cond_signal(&fmHCIControlBlock.event_cond);
+    pthread_cond_destroy(&fmHCIControlBlock.event_cond);
+    pthread_cond_signal(&fmHCIControlBlock.cmd_credits_cond);
+    pthread_cond_destroy(&fmHCIControlBlock.cmd_credits_cond);
+
+    // Join the reader thread if it's still running.
+    if (lib_running) {
+        fm_send_event(USERIAL_RX_EXIT);
+        int result = pthread_join(fmHCIControlBlock.fmRxTaskThreadId, NULL);
+        if (result)
+            ALOGE("%s failed to join reader thread: %d", __func__, result);
+    }
+    lib_running =0;
+    ALOGE("%s  close fm userial ", __func__);
+    fm_vnd_if->op(BT_VND_OP_FM_USERIAL_CLOSE, NULL);
+    // Free all buffers still waiting in the RX queue.
+    //  TODO: use list data structure and clean this up.
+    fm_fd = -1;
 }
diff --git a/fm_hci/fm_hci.h b/fm_hci/fm_hci.h
index 431179b..8ffbf04 100644
--- a/fm_hci/fm_hci.h
+++ b/fm_hci/fm_hci.h
@@ -102,6 +102,7 @@ void transmit(FM_HDR *pbuf);
 int  fm_hci_init(fm_hal_cb *);
 void fm_power(fm_power_state state);
 int open_serial_port(void);
+void fm_userial_close(void);
 
 typedef struct {
     pthread_mutex_t tx_q_lock;
diff --git a/helium/radio-helium-commands.h b/helium/radio-helium-commands.h
index c480ea0..f76b7d2 100644
--- a/helium/radio-helium-commands.h
+++ b/helium/radio-helium-commands.h
@@ -76,6 +76,22 @@ enum helium_cmd_t {
     HCI_FM_HELIUM_DO_CALIBRATION,
     HCI_FM_HELIUM_SRCH_ALGORITHM,
     HCI_FM_HELIUM_GET_SINR,
+    HCI_FM_HELIUM_INTF_LOW_THRESHOLD,
+    HCI_FM_HELIUM_INTF_HIGH_THRESHOLD,
+    HCI_FM_HELIUM_SINR_THRESHOLD,
+    HCI_FM_HELIUM_SINR_SAMPLES,
+    HCI_FM_HELIUM_SPUR_FREQ,
+    HCI_FM_HELIUM_SPUR_FREQ_RMSSI,
+    HCI_FM_HELIUM_SPUR_SELECTION,
+    HCI_FM_HELIUM_UPDATE_SPUR_TABLE,
+    HCI_FM_HELIUM_VALID_CHANNEL,
+    HCI_FM_HELIUM_AF_RMSSI_TH,
+    HCI_FM_HELIUM_AF_RMSSI_SAMPLES,
+    HCI_FM_HELIUM_GOOD_CH_RMSSI_TH,
+    HCI_FM_HELIUM_SRCHALGOTYPE,
+    HCI_FM_HELIUM_CF0TH12,
+    HCI_FM_HELIUM_SINRFIRSTSTAGE,
+    HCI_FM_HELIUM_RMSSIFIRSTSTAGE,
     HCI_FM_HELIUM_RXREPEATCOUNT,
     HCI_FM_HELIUM_RSSI_TH,
     HCI_FM_HELIUM_AF_JUMP_RSSI_TH,
diff --git a/helium/radio-helium.h b/helium/radio-helium.h
index 8599316..5c21bdd 100644
--- a/helium/radio-helium.h
+++ b/helium/radio-helium.h
@@ -160,6 +160,9 @@ typedef void (*ert_cb)(char *ert);
 typedef void (*disable_cb)();
 typedef void (*callback_thread_event)(unsigned int evt);
 typedef void (*rds_grp_cntrs_cb)(char *rds_params);
+typedef void (*fm_peek_cb)(char *peek_rsp);
+typedef void (*fm_ssbi_peek_cb)(char *ssbi_peek_rsp);
+typedef void (*fm_ch_det_th_cb)(char *ch_det_rsp);
 
 typedef struct {
     size_t  size;
@@ -179,6 +182,9 @@ typedef struct {
     ert_cb  ert_update_cb;
     disable_cb  disabled_cb;
     rds_grp_cntrs_cb rds_grp_cntrs_rsp_cb;
+    fm_peek_cb fm_peek_rsp_cb;
+    fm_ssbi_peek_cb fm_ssbi_peek_rsp_cb;
+    fm_ch_det_th_cb fm_ch_det_th_rsp_cb;
     callback_thread_event thread_evt_cb;
 } fm_vendor_callbacks_t;
 
@@ -499,7 +505,6 @@ struct hci_fm_blend_table {
 #define HCI_EV_RADIO_TEXT_PLUS_TAG      0x19
 #define HCI_EV_HW_ERR_EVENT             0x1A
 
-
 #define HCI_REQ_DONE      0
 #define HCI_REQ_PEND      1
 #define HCI_REQ_CANCELED  2
@@ -1157,5 +1162,34 @@ struct helium_device {
     enum hlm_region_t region;
     struct hci_fm_dbg_param_rsp st_dbg_param;
     struct hci_ev_srch_list_compl srch_st_result;
+    struct hci_fm_riva_poke   riva_data_req;
+    struct hci_fm_ssbi_req    ssbi_data_accs;
+    struct hci_fm_ssbi_peek   ssbi_peek_reg;
+    struct hci_fm_ch_det_threshold ch_det_threshold;
 };
+int hci_fm_disable_recv_req();
+int helium_search_list(struct hci_fm_search_station_list_req *s_list);
+int helium_search_rds_stations(struct hci_fm_search_rds_station_req *rds_srch);
+int helium_search_stations(struct hci_fm_search_station_req *srch);
+int helium_cancel_search_req();
+int hci_fm_set_recv_conf_req (struct hci_fm_recv_conf_req *conf);
+int hci_fm_get_program_service_req ();
+int hci_fm_get_rds_grpcounters_req (int val);
+int hci_fm_set_notch_filter_req (int val);
+int helium_set_sig_threshold_req(char th);
+int helium_rds_grp_mask_req(struct hci_fm_rds_grp_req *rds_grp_msk);
+int helium_rds_grp_process_req(int rds_grp);
+int helium_set_event_mask_req(char e_mask);
+int helium_set_antenna_req(char ant);
+int helium_set_fm_mute_mode_req(struct hci_fm_mute_mode_req *mute);
+int hci_fm_tune_station_req(int param);
+int hci_set_fm_stereo_mode_req(struct hci_fm_stereo_mode_req *param);
+int hci_peek_data(struct hci_fm_riva_data *data);
+int hci_poke_data(struct hci_fm_riva_poke *data);
+int hci_ssbi_poke_reg(struct hci_fm_ssbi_req *data);
+int hci_ssbi_peek_reg(struct hci_fm_ssbi_peek *data);
+int hci_fm_get_ch_det_th();
+int set_ch_det_thresholds_req(struct hci_fm_ch_det_threshold *ch_det_th);
+
+
 #endif /* __UAPI_RADIO_HCI_CORE_H */
diff --git a/helium/radio_helium_hal.c b/helium/radio_helium_hal.c
index a9aa9f0..fd673ab 100644
--- a/helium/radio_helium_hal.c
+++ b/helium/radio_helium_hal.c
@@ -29,6 +29,8 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <stdio.h>
 #include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
 #include <utils/Log.h>
 #include "radio-helium-commands.h"
 #include "radio-helium.h"
@@ -38,6 +40,7 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 fm_vendor_callbacks_t *jni_cb;
 int hci_fm_get_signal_threshold();
 int hci_fm_enable_recv_req();
+int hci_fm_mute_mode_req(struct hci_fm_mute_mode_req );
 struct helium_device *radio;
 static int oda_agt;
 static int grp_mask;
@@ -98,14 +101,18 @@ static void hci_cc_fm_disable_rsp(char *ev_buff)
         ALOGE("%s:%s, buffer is null\n", LOG_TAG, __func__);
         return;
     }
+    ALOGE("%s:enetred %s calling ", LOG_TAG, __func__);
     status = (char) *ev_buff;
     radio_hci_req_complete(status);
     if (radio->mode == FM_TURNING_OFF) {
         jni_cb->disabled_cb();
         radio->mode = FM_OFF;
+        jni_cb->disabled_cb();
+        jni_cb->thread_evt_cb(1);
         //close the userial port and power off the chip
-      fm_userial_close();
-      fm_power(FM_RADIO_DISABLE);
+        ALOGE("%s:calling fm userial close\n", LOG_TAG );
+        fm_userial_close();
+    //  fm_power(FM_RADIO_DISABLE);
     }
 }
 
@@ -138,6 +145,57 @@ static void hci_cc_rds_grp_cntrs_rsp(char *ev_buff)
     jni_cb->rds_grp_cntrs_rsp_cb(&ev_buff[1]);
 }
 
+static void hci_cc_riva_peek_rsp(char *ev_buff)
+{
+    char status;
+
+    if (ev_buff == NULL) {
+        ALOGE("%s:%s, buffer is null\n", LOG_TAG, __func__);
+        return;
+    }
+    status = ev_buff[0];
+    ALOGE("%s:%s, status =%d\n", LOG_TAG, __func__,status);
+    if (status < 0) {
+        ALOGE("%s:%s, peek failed=%d\n", LOG_TAG, __func__, status);
+    }
+    jni_cb->fm_peek_rsp_cb(&ev_buff[PEEK_DATA_OFSET]);
+    radio_hci_req_complete(status);
+}
+
+static void hci_cc_ssbi_peek_rsp(char *ev_buff)
+{
+    char status;
+
+    if (ev_buff == NULL) {
+        ALOGE("%s:%s, buffer is null\n", LOG_TAG, __func__);
+        return;
+    }
+    status = ev_buff[0];
+    ALOGE("%s:%s, status =%d\n", LOG_TAG, __func__,status);
+    if (status < 0) {
+        ALOGE("%s:%s,ssbi peek failed=%d\n", LOG_TAG, __func__, status);
+    }
+    jni_cb->fm_ssbi_peek_rsp_cb(&ev_buff[PEEK_DATA_OFSET]);
+    radio_hci_req_complete(status);
+}
+
+static void hci_cc_get_ch_det_threshold_rsp(char *ev_buff)
+{
+    char status;
+
+    if (ev_buff == NULL) {
+        ALOGE("%s:%s, buffer is null\n", LOG_TAG, __func__);
+        return;
+    }
+    status = ev_buff[0];
+    ALOGE("%s:%s, status =%d\n", LOG_TAG, __func__,status);
+    if (status < 0) {
+        ALOGE("%s:%s,ssbi peek failed=%d\n", LOG_TAG, __func__, status);
+    }
+    memcpy(&radio->ch_det_threshold, &ev_buff[1],
+                        sizeof(struct hci_fm_ch_det_threshold));
+    radio_hci_req_complete(status);
+}
 
 static inline void hci_cmd_complete_event(char *buff)
 {
@@ -192,12 +250,18 @@ static inline void hci_cmd_complete_event(char *buff)
     case hci_status_param_op_pack(HCI_OCF_FM_READ_GRP_COUNTERS):
             hci_cc_rds_grp_cntrs_rsp(pbuf);
             break;
-/*    case hci_common_cmd_op_pack(HCI_OCF_FM_GET_SPUR_TABLE):
-            hci_cc_get_spur_tbl(buff);
+    case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_PEEK_DATA):
+            hci_cc_riva_peek_rsp(buff);
             break;
     case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_SSBI_PEEK_REG):
             hci_cc_ssbi_peek_rsp(buff);
             break;
+    case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_CH_DET_THRESHOLD):
+            hci_cc_get_ch_det_threshold_rsp(buff);
+            break;
+/*    case hci_common_cmd_op_pack(HCI_OCF_FM_GET_SPUR_TABLE):
+            hci_cc_get_spur_tbl(buff);
+            break;
     case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_SIGNAL_THRESHOLD):
             hci_cc_sig_threshold_rsp(buff);
             break;
@@ -222,10 +286,6 @@ static inline void hci_cmd_complete_event(char *buff)
             hci_cc_riva_read_default_rsp(buff);
             break;
 
-    case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_PEEK_DATA):
-            hci_cc_riva_peek_rsp(buff);
-            break;
-
     case hci_common_cmd_op_pack(HCI_OCF_FM_GET_FEATURE_LIST):
             hci_cc_feature_list_rsp(buff);
             break;
@@ -240,9 +300,6 @@ static inline void hci_cmd_complete_event(char *buff)
             hci_cc_do_calibration_rsp(buff);
             break;
 
-    case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_CH_DET_THRESHOLD):
-            hci_cc_get_ch_det_threshold_rsp(buff);
-            break;
     case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_BLND_TBL):
             hci_cc_get_blend_tbl_rsp(buff);
             break;
@@ -364,6 +421,7 @@ static inline void hci_ev_radio_text(char *buff)
 
     while ((buff[len+RDS_OFFSET] != 0x0d) && (len < MAX_RT_LENGTH))
            len++;
+    ALOGV("%s:%s: radio text length=%d\n", LOG_TAG, __func__,len);
     data = malloc(len+RDS_OFFSET);
     if (!data) {
         ALOGE("%s:Failed to allocate memory", LOG_TAG);
@@ -521,7 +579,8 @@ static void hci_ev_hw_error(char *buff)
 {
    ALOGE("%s:%s: start", LOG_TAG, __func__);
    jni_cb->disabled_cb();
-    fm_userial_close();
+   jni_cb->thread_evt_cb(1);
+   fm_userial_close();
 }
 
 static void hci_buff_ert(struct rds_grp_data *rds_buf)
@@ -646,7 +705,7 @@ static void hci_ev_raw_rds_group_data(char *buff)
          //    hci_ev_rt_plus(temp);
         }
         else if (carrier == ert_carrier) {
-             ALOGE("%s:: calling event ert", __func__);
+             ALOGI("%s:: calling event ert", __func__);
              hci_buff_ert(&temp);
        }
     }
@@ -711,9 +770,9 @@ void radio_hci_event_packet(char *evt_buf)
     case HCI_EV_RADIO_TEXT_PLUS_TAG:
         hci_ev_rt_plus_tag(((FM_EVT_HDR *)evt_buf)->cmd_params);
         break;
-	case HCI_EV_HW_ERR_EVENT:
-		hci_ev_hw_error(((FM_EVT_HDR *)evt_buf)->cmd_params);
-		break;
+    case HCI_EV_HW_ERR_EVENT:
+	    hci_ev_hw_error(((FM_EVT_HDR *)evt_buf)->cmd_params);
+	    break;
     default:
         break;
     }
@@ -1063,6 +1122,125 @@ static int set_fm_ctrl(int cmd, int val)
         radio->stereo_mode.stereo_mode = ~val;
         hci_set_fm_stereo_mode_req(&radio->stereo_mode);
         break;
+    case HCI_FM_HELIUM_RIVA_ACCS_ADDR:
+        radio->riva_data_req.cmd_params.start_addr = val;
+        break;
+    case HCI_FM_HELIUM_RIVA_ACCS_LEN:
+        if (is_valid_peek_len(val)) {
+            radio->riva_data_req.cmd_params.length = val;
+        } else {
+            ret = -1;
+            ALOGE("%s: riva access len is not valid\n", LOG_TAG);
+            goto END;
+        }
+        break;
+    case HCI_FM_HELIUM_RIVA_PEEK:
+        radio->riva_data_req.cmd_params.subopcode = RIVA_PEEK_OPCODE;
+        val = hci_peek_data(&radio->riva_data_req.cmd_params);
+        break;
+    case HCI_FM_HELIUM_RIVA_POKE:
+         if (radio->riva_data_req.cmd_params.length <=
+                    MAX_RIVA_PEEK_RSP_SIZE) {
+             radio->riva_data_req.cmd_params.subopcode =
+                                                RIVA_POKE_OPCODE;
+             ret = hci_poke_data(&radio->riva_data_req);
+         } else {
+             ALOGE("%s: riva access len is not valid for poke\n", LOG_TAG);
+             ret = -1;
+             goto END;
+         }
+         break;
+    case HCI_FM_HELIUM_SSBI_ACCS_ADDR:
+        radio->ssbi_data_accs.start_addr = val;
+        break;
+    case HCI_FM_HELIUM_SSBI_POKE:
+        radio->ssbi_data_accs.data = val;
+        ret = hci_ssbi_poke_reg(&radio->ssbi_data_accs);
+        break;
+    case HCI_FM_HELIUM_SSBI_PEEK:
+        radio->ssbi_peek_reg.start_address = val;
+        hci_ssbi_peek_reg(&radio->ssbi_peek_reg);
+        break;
+    case HCI_FM_HELIUM_SINR_SAMPLES:
+         if (!is_valid_sinr_samples(val)) {
+             ALOGE("%s: sinr samples count is not valid\n", __func__);
+             ret = -1;
+             goto END;
+         }
+         ret = hci_fm_get_ch_det_th();
+         if (ret < 0) {
+             ALOGE("Failed to get chnl det thresholds  %d", ret);
+             goto END;
+         }
+         saved_val = radio->ch_det_threshold.sinr_samples;
+         radio->ch_det_threshold.sinr_samples = val;
+         ret = set_ch_det_thresholds_req(&radio->ch_det_threshold);
+         if (ret < 0) {
+             ALOGE("Failed to set SINR samples  %d", ret);
+             radio->ch_det_threshold.sinr_samples = saved_val;
+             goto END;
+         }
+         break;
+    case HCI_FM_HELIUM_SINR_THRESHOLD:
+         if (!is_valid_sinr_th(val)) {
+             ALOGE("%s: sinr threshold is not valid\n");
+             ret = -1;
+             goto END;
+         }
+         ret = hci_fm_get_ch_det_th();
+         if (ret < 0) {
+             ALOGE("Failed to get chnl det thresholds  %d", ret);
+             goto END;
+         }
+         saved_val = radio->ch_det_threshold.sinr;
+         radio->ch_det_threshold.sinr = val;
+         ret = set_ch_det_thresholds_req(&radio->ch_det_threshold);
+         if (ret < 0) {
+             ALOGE("Failed to set SINR threshold %d", ret);
+             radio->ch_det_threshold.sinr = saved_val;
+             goto END;
+         }
+         break;
+    case HCI_FM_HELIUM_INTF_LOW_THRESHOLD:
+         if (!is_valid_intf_det_low_th(val)) {
+             ALOGE("%s: intf det low threshold is not valid\n", __func__);
+             ret = -1;
+             goto END;
+         }
+         ret = hci_fm_get_ch_det_th();
+         if (ret < 0) {
+             ALOGE("Failed to get chnl det thresholds  %d", ret);
+             goto END;
+         }
+         saved_val = radio->ch_det_threshold.low_th;
+         radio->ch_det_threshold.low_th = val;
+         ret = set_ch_det_thresholds_req(&radio->ch_det_threshold);
+         if (ret < 0) {
+             ALOGE("Failed to Set Low det threshold %d", ret);
+             radio->ch_det_threshold.low_th = saved_val;
+             goto END;
+         }
+         break;
+    case HCI_FM_HELIUM_INTF_HIGH_THRESHOLD:
+         if (!is_valid_intf_det_hgh_th(val)) {
+             ALOGE("%s: intf high threshold is not valid\n", __func__);
+             ret = -1;
+             goto END;
+         }
+         ret = hci_fm_get_ch_det_th();
+         if (ret < 0) {
+             ALOGE("Failed to get chnl det thresholds  %d", ret);
+             goto END;
+         }
+         saved_val = radio->ch_det_threshold.high_th;
+         radio->ch_det_threshold.high_th = val;
+         ret = set_ch_det_thresholds_req(&radio->ch_det_threshold);
+         if (ret < 0) {
+             ALOGE("Failed to set High det threshold %d ", ret);
+             radio->ch_det_threshold.high_th = saved_val;
+             goto END;
+         }
+         break;
     default:
         ALOGE("%s:%s: Not a valid FM CMD!!", LOG_TAG, __func__);
         ret = 0;
@@ -1088,6 +1266,26 @@ static void get_fm_ctrl(int cmd, int val)
     case HCI_FM_HELIUM_LOWER_BAND:
         val = radio->recv_conf.band_low_limit;
         break;
+    case HCI_FM_HELIUM_SINR_SAMPLES:
+        ret = hci_fm_get_ch_det_th();
+         if (ret == 0)
+             val = radio->ch_det_threshold.sinr_samples;
+        break;
+    case HCI_FM_HELIUM_SINR_THRESHOLD:
+        ret = hci_fm_get_ch_det_th();
+        if (ret == 0)
+            val = radio->ch_det_threshold.sinr;
+        break;
+    case HCI_FM_HELIUM_INTF_LOW_THRESHOLD:
+        ret = hci_fm_get_ch_det_th();
+        if (ret == 0)
+            val = radio->ch_det_threshold.low_th;
+        break;
+    case HCI_FM_HELIUM_INTF_HIGH_THRESHOLD:
+        ret = hci_fm_get_ch_det_th();
+        if (ret == 0)
+            val = radio->ch_det_threshold.high_th;
+        break;
     default:
         break;
     }
diff --git a/helium/radio_helium_hal_cmds.c b/helium/radio_helium_hal_cmds.c
index 1d422d1..df79d75 100644
--- a/helium/radio_helium_hal_cmds.c
+++ b/helium/radio_helium_hal_cmds.c
@@ -29,6 +29,9 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <stdio.h>
 #include <utils/Log.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
 #include "radio-helium-commands.h"
 #include "radio-helium.h"
 #include "fm_hci.h"
@@ -282,3 +285,74 @@ int hci_set_fm_stereo_mode_req(struct hci_fm_stereo_mode_req *param)
                                               stereo_mode_req);
 }
 
+int hci_peek_data(struct hci_fm_riva_data *data)
+{
+    uint16_t opcode = 0;
+
+    if (data == NULL) {
+        ALOGE("%s:%s, peek data req is null\n", LOG_TAG, __func__);
+        return -1;
+    }
+    opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
+                HCI_OCF_FM_PEEK_DATA);
+    return send_fm_cmd_pkt(opcode, sizeof((*data)), data);
+}
+
+int hci_poke_data(struct hci_fm_riva_poke *data)
+{
+    uint16_t opcode = 0;
+
+    if (data == NULL) {
+        ALOGE("%s:%s, poke data req is null\n", LOG_TAG, __func__);
+        return -1;
+    }
+    opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
+                HCI_OCF_FM_POKE_DATA);
+    return send_fm_cmd_pkt(opcode, sizeof((*data)), data);
+}
+
+int hci_ssbi_poke_reg(struct hci_fm_ssbi_req *data)
+{
+    uint16_t opcode = 0;
+
+    if (data == NULL) {
+        ALOGE("%s:%s,SSBI poke data req is null\n", LOG_TAG, __func__);
+        return -1;
+    }
+    opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
+                HCI_OCF_FM_SSBI_POKE_REG);
+    return send_fm_cmd_pkt(opcode, sizeof((*data)), data);
+}
+
+int hci_ssbi_peek_reg(struct hci_fm_ssbi_peek *data)
+{
+    uint16_t opcode = 0;
+
+    if (data == NULL) {
+        ALOGE("%s:%s,SSBI peek data req is null\n", LOG_TAG, __func__);
+        return -1;
+    }
+    opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
+                HCI_OCF_FM_SSBI_PEEK_REG);
+   return send_fm_cmd_pkt(opcode, sizeof((*data)), data);
+}
+
+int hci_fm_get_ch_det_th()
+{
+    uint16_t opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+			HCI_OCF_FM_GET_CH_DET_THRESHOLD);
+    return send_fm_cmd_pkt(opcode, 0, NULL);
+}
+
+int set_ch_det_thresholds_req(struct hci_fm_ch_det_threshold *ch_det_th)
+{
+    uint16_t opcode = 0;
+
+    if (ch_det_th == NULL) {
+        ALOGE("%s,%s channel det thrshld is null\n", LOG_TAG,  __func__);
+        return -1;
+    }
+    opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+                            HCI_OCF_FM_SET_CH_DET_THRESHOLD);
+    return send_fm_cmd_pkt(opcode, sizeof((*ch_det_th)), ch_det_th);
+}
diff --git a/jni/android_hardware_fm.cpp b/jni/android_hardware_fm.cpp
index 36199f6..7503ced 100644
--- a/jni/android_hardware_fm.cpp
+++ b/jni/android_hardware_fm.cpp
@@ -102,7 +102,9 @@ typedef void (*ert_cb)(char *ert);
 typedef void (*disable_cb)();
 typedef void (*callback_thread_event)(unsigned int evt);
 typedef void (*rds_grp_cntrs_cb)(char *rds_params);
-
+typedef void (*fm_peek_cb)(char *peek_rsp);
+typedef void (*fm_ssbi_peek_cb)(char *ssbi_peek_rsp);
+typedef void (*fm_ch_det_th_cb)(char *ch_det_rsp);
 
 static JNIEnv *mCallbackEnv = NULL;
 static jobject mCallbacksObj = NULL;
@@ -315,8 +317,20 @@ void rds_grp_cntrs_rsp_cb(char * evt_buffer)
 
 void fm_disabled_cb()
 {
-   ALOGE("DISABLE");
-   mCallbackEnv->CallVoidMethod(mCallbacksObj, method_disableCallback);
+    ALOGE("DISABLE");
+    mCallbackEnv->CallVoidMethod(mCallbacksObj, method_disableCallback);
+}
+
+void fm_peek_rsp_cb(char *peek_rsp) {
+    ALOGE("fm_peek_rsp_cb");
+}
+
+void fm_ssbi_peek_rsp_cb(char *ssbi_peek_rsp){
+    ALOGE("fm_ssbi_peek_rsp_cb");
+}
+
+void fm_ch_det_th_rsp_cb(char *ch_det_rsp){
+    ALOGE("fm_ch_det_th_rsp_cb");
 }
 
 static void fm_thread_evt_cb(unsigned int event) {
@@ -355,6 +369,9 @@ typedef struct {
    ert_cb  ert_update_cb;
    disable_cb  disabled_cb;
    rds_grp_cntrs_cb rds_grp_cntrs_rsp_cb;
+   fm_peek_cb fm_peek_rsp_cb;
+   fm_ssbi_peek_cb fm_ssbi_peek_rsp_cb;
+   fm_ch_det_th_cb fm_ch_det_th_rsp_cb;
    callback_thread_event thread_evt_cb;
 } fm_vendor_callbacks_t;
 
@@ -383,6 +400,9 @@ static   fm_vendor_callbacks_t fm_callbacks = {
     fm_ert_update_cb,
     fm_disabled_cb,
     rds_grp_cntrs_rsp_cb,
+    fm_peek_rsp_cb,
+    fm_ssbi_peek_rsp_cb,
+    fm_ch_det_th_rsp_cb,
     fm_thread_evt_cb
 };
 
diff --git a/qcom/fmradio/FmRxRdsData.java b/qcom/fmradio/FmRxRdsData.java
index a504007..f0e5b9e 100644
--- a/qcom/fmradio/FmRxRdsData.java
+++ b/qcom/fmradio/FmRxRdsData.java
@@ -149,6 +149,7 @@ public class FmRxRdsData {
 
          rds_group_mask  = ((rdsMask & 0x000000FF));
 
+        Log.d(LOGTAG, "In rdsOptions: rds_group_mask : " + rds_group_mask);
         re = FmReceiverJNI.setControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC, rds_group_mask);
         return re;
     }
-- 
GitLab