From 644b4888d44d3dbdd9861235cb432ebb3b11899c Mon Sep 17 00:00:00 2001
From: Satish kumar sugasi <ssugas@codeaurora.org>
Date: Wed, 4 May 2016 20:15:31 -0700
Subject: [PATCH] FM-HAL: Add support for FM Core functionalities

FM-HAL Layer contains the core FM Functionality required
for carrying out various FM operations such as FM Enable,
FM Tune, FM Seek, FM Search, FM Disable etc..
FM-HAL layer interacts with the FM-HCI layer for sending
commands and receiving events to and from Controller.

Change-Id: I0ac1c9c80671e43aafa30ce2b68f5ee695c9d764
---
 Android.mk                      |   12 +-
 helium/Android.mk               |   29 +
 helium/radio-helium-commands.h  |   99 +++
 helium/radio-helium.h           | 1137 +++++++++++++++++++++++++++++++
 helium/radio_helium_hal.c       | 1067 +++++++++++++++++++++++++++++
 helium/radio_helium_hal_cmds.c  |  256 +++++++
 jni/Android.mk                  |    2 +
 jni/FmConst.h                   |    8 +
 jni/android_hardware_fm.cpp     |  504 +++++++++++++-
 qcom/fmradio/FmReceiver.java    |   33 +-
 qcom/fmradio/FmReceiverJNI.java |  173 ++++-
 qcom/fmradio/FmTransceiver.java |    6 +-
 12 files changed, 3275 insertions(+), 51 deletions(-)
 create mode 100644 helium/Android.mk
 create mode 100644 helium/radio-helium-commands.h
 create mode 100644 helium/radio-helium.h
 create mode 100644 helium/radio_helium_hal.c
 create mode 100644 helium/radio_helium_hal_cmds.c

diff --git a/Android.mk b/Android.mk
index 4777981..5b79fbf 100644
--- a/Android.mk
+++ b/Android.mk
@@ -21,10 +21,16 @@ LOCAL_PATH := $(LOCAL_DIR_PATH)
 include $(LOCAL_PATH)/fmapp2/Android.mk
 #LOCAL_PATH := $(LOCAL_DIR_PATH)
 #include $(LOCAL_PATH)/FMRecord/Android.mk
-#endif # is-vendor-board-platform
-#endif # BOARD_HAVE_QCOM_FM
 
-#endif # Not (TARGET_USES_AOSP)
+LOCAL_PATH := $(LOCAL_DIR_PATH)
+include $(LOCAL_PATH)/fm_hci/Android.mk
+
+LOCAL_PATH := $(LOCAL_DIR_PATH)
+include $(LOCAL_PATH)/helium/Android.mk
 
 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/helium/Android.mk b/helium/Android.mk
new file mode 100644
index 0000000..5cbc551
--- /dev/null
+++ b/helium/Android.mk
@@ -0,0 +1,29 @@
+#ifeq ($(BOARD_HAVE_QCOM_FM),true)
+#ifneq (,$(filter $(QCOM_BOARD_PLATFORMS),$(TARGET_BOARD_PLATFORM)))
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	radio_helium_hal.c \
+	radio_helium_hal_cmds.c
+
+LOCAL_SHARED_LIBRARIES := \
+         libfm-hci \
+         libdl \
+         libnativehelper \
+         libcutils
+
+FM_HCI_DIR:= vendor/qcom/opensource/fm
+
+LOCAL_C_INCLUDES += $(FM_HCI_DIR)/fm_hci
+
+LOCAL_MODULE := fm_helium
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
+
+#endif # is-vendor-board-platform
+#endif # BOARD_HAVE_QCOM_FM
+
+
diff --git a/helium/radio-helium-commands.h b/helium/radio-helium-commands.h
new file mode 100644
index 0000000..85acf16
--- /dev/null
+++ b/helium/radio-helium-commands.h
@@ -0,0 +1,99 @@
+/*
+Copyright (c) 2015, 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.
+*/
+
+#ifndef __RADIO_CHEROKEE_COMMANDS_H
+#define __RADIO_CHEROKEE_COMMANDS_H
+
+enum helium_cmd_t {
+    HCI_FM_HELIUM_SRCHMODE = 0x8000000 + 1,
+    HCI_FM_HELIUM_SCANDWELL,
+    HCI_FM_HELIUM_SRCHON,
+    HCI_FM_HELIUM_STATE,
+    HCI_FM_HELIUM_TRANSMIT_MODE,
+    HCI_FM_HELIUM_RDSGROUP_MASK,
+    HCI_FM_HELIUM_REGION,
+    HCI_FM_HELIUM_SIGNAL_TH,
+    HCI_FM_HELIUM_SRCH_PTY,
+    HCI_FM_HELIUM_SRCH_PI,
+    HCI_FM_HELIUM_SRCH_CNT,
+    HCI_FM_HELIUM_EMPHASIS,
+    HCI_FM_HELIUM_RDS_STD,
+    HCI_FM_HELIUM_SPACING,
+    HCI_FM_HELIUM_RDSON,
+    HCI_FM_HELIUM_RDSGROUP_PROC,
+    HCI_FM_HELIUM_LP_MODE,
+    HCI_FM_HELIUM_ANTENNA,
+    HCI_FM_HELIUM_RDSD_BUF,
+    HCI_FM_HELIUM_PSALL,
+
+    /*v4l2 Tx controls*/
+    HCI_FM_HELIUM_IOVERC,
+    HCI_FM_HELIUM_INTDET,
+    HCI_FM_HELIUM_MPX_DCC,
+    HCI_FM_HELIUM_AF_JUMP,
+    HCI_FM_HELIUM_RSSI_DELTA,
+    HCI_FM_HELIUM_HLSI,
+
+    /*Diagnostic commands*/
+    HCI_FM_HELIUM_SOFT_MUTE,
+    HCI_FM_HELIUM_RIVA_ACCS_ADDR,
+    HCI_FM_HELIUM_RIVA_ACCS_LEN,
+    HCI_FM_HELIUM_RIVA_PEEK,
+    HCI_FM_HELIUM_RIVA_POKE,
+    HCI_FM_HELIUM_SSBI_ACCS_ADDR,
+    HCI_FM_HELIUM_SSBI_PEEK,
+    HCI_FM_HELIUM_SSBI_POKE,
+    HCI_FM_HELIUM_TX_TONE,
+    HCI_FM_HELIUM_RDS_GRP_COUNTERS,
+    HCI_FM_HELIUM_SET_NOTCH_FILTER, /* 0x8000028 */
+    HCI_FM_HELIUM_SET_AUDIO_PATH,
+    HCI_FM_HELIUM_DO_CALIBRATION,
+    HCI_FM_HELIUM_SRCH_ALGORITHM,
+    HCI_FM_HELIUM_GET_SINR,
+    HCI_FM_HELIUM_RXREPEATCOUNT,
+    HCI_FM_HELIUM_RSSI_TH,
+    HCI_FM_HELIUM_AF_JUMP_RSSI_TH,
+    HCI_FM_HELIUM_BLEND_SINRHI,
+    HCI_FM_HELIUM_BLEND_RMSSIHI,
+
+    /*using private CIDs under userclass*/
+    HCI_FM_HELIUM_READ_DEFAULT = 0x00980928,
+    HCI_FM_HELIUM_WRITE_DEFAULT,
+    HCI_FM_HELIUM_SET_CALIBRATION,
+    HCI_FM_HELIUM_SET_SPURTABLE = 0x0098092D,
+    HCI_FM_HELIUM_GET_SPUR_TBL  = 0x0098092E,
+    HCI_FM_HELIUM_FREQ,
+    HCI_FM_HELIUM_SEEK,
+    HCI_FM_HELIUM_UPPER_BAND,
+    HCI_FM_HELIUM_LOWER_BAND,
+    HCI_FM_HELIUM_AUDIO_MODE,
+    HCI_FM_HELIUM_AUDIO_MUTE,
+};
+
+#endif /* __RADIO_CHEROKEE_COMMANDS_H */
diff --git a/helium/radio-helium.h b/helium/radio-helium.h
new file mode 100644
index 0000000..cb85bcc
--- /dev/null
+++ b/helium/radio-helium.h
@@ -0,0 +1,1137 @@
+/*
+Copyright (c) 2015, 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.
+*/
+
+#ifndef __UAPI_RADIO_HCI_CORE_H
+#define __UAPI_RADIO_HCI_CORE_H
+
+#pragma pack(1)
+
+#include <stdbool.h>
+
+pthread_mutex_t fm_hal;
+#define MIN_TX_TONE_VAL  0x00
+#define MAX_TX_TONE_VAL  0x07
+#define MIN_HARD_MUTE_VAL  0x00
+#define MAX_HARD_MUTE_VAL  0x03
+#define MIN_SRCH_MODE  0x00
+#define MAX_SRCH_MODE  0x09
+#define MIN_SCAN_DWELL  0x00
+#define MAX_SCAN_DWELL  0x0F
+#define MIN_SIG_TH  0x00
+#define MAX_SIG_TH  0x03
+#define MIN_PTY  0X00
+#define MAX_PTY  0x1F
+#define MIN_PI  0x0000
+#define MAX_PI  0xFFFF
+#define MIN_SRCH_STATIONS_CNT  0x00
+#define MAX_SRCH_STATIONS_CNT  0x14
+#define MIN_CHAN_SPACING  0x00
+#define MAX_CHAN_SPACING  0x02
+#define MIN_EMPHASIS  0x00
+#define MAX_EMPHASIS  0x01
+#define MIN_RDS_STD  0x00
+#define MAX_RDS_STD  0x02
+#define MIN_ANTENNA_VAL  0x00
+#define MAX_ANTENNA_VAL  0x01
+#define MIN_TX_PS_REPEAT_CNT  0x01
+#define MAX_TX_PS_REPEAT_CNT  0x0F
+#define MIN_SOFT_MUTE  0x00
+#define MAX_SOFT_MUTE  0x01
+#define MIN_PEEK_ACCESS_LEN  0x01
+#define MAX_PEEK_ACCESS_LEN  0xF9
+#define MIN_RESET_CNTR  0x00
+#define MAX_RESET_CNTR  0x01
+#define MIN_HLSI  0x00
+#define MAX_HLSI  0x02
+#define MIN_NOTCH_FILTER  0x00
+#define MAX_NOTCH_FILTER  0x02
+#define MIN_INTF_DET_OUT_LW_TH  0x00
+#define MAX_INTF_DET_OUT_LW_TH  0xFF
+#define MIN_INTF_DET_OUT_HG_TH  0x00
+#define MAX_INTF_DET_OUT_HG_TH  0xFF
+#define MIN_SINR_TH  -128
+#define MAX_SINR_TH  127
+#define MIN_SINR_SAMPLES  0x01
+#define MAX_SINR_SAMPLES  0xFF
+#define MIN_BLEND_HI  -128
+#define MAX_BLEND_HI  127
+
+
+/* ---- HCI Packet structures ---- */
+#define RADIO_HCI_COMMAND_HDR_SIZE sizeof(struct radio_hci_command_hdr)
+#define RADIO_HCI_EVENT_HDR_SIZE   sizeof(struct radio_hci_event_hdr)
+
+/* HCI data types */
+#define RADIO_HCI_COMMAND_PKT   0x11
+#define RADIO_HCI_EVENT_PKT     0x14
+/*HCI reponce packets*/
+#define MAX_RIVA_PEEK_RSP_SIZE   251
+/* default data access */
+#define DEFAULT_DATA_OFFSET 2
+#define DEFAULT_DATA_SIZE 249
+/* Power levels are 0-7, but SOC will expect values from 0-255
+ * So the each level step size will be 255/7 = 36 */
+#define FM_TX_PWR_LVL_STEP_SIZE 36
+#define FM_TX_PWR_LVL_0         0 /* Lowest power lvl that can be set for Tx */
+#define FM_TX_PWR_LVL_MAX       7 /* Max power lvl for Tx */
+#define FM_TX_PHY_CFG_MODE   0x3c
+#define FM_TX_PHY_CFG_LEN    0x10
+#define FM_TX_PWR_GAIN_OFFSET 14
+/**RDS CONFIG MODE**/
+#define FM_RDS_CNFG_MODE	0x0f
+#define FM_RDS_CNFG_LEN		0x10
+#define AF_RMSSI_TH_LSB_OFFSET	10
+#define AF_RMSSI_TH_MSB_OFFSET	11
+#define AF_RMSSI_SAMPLES_OFFSET	15
+/**RX CONFIG MODE**/
+#define FM_RX_CONFG_MODE	0x15
+#define FM_RX_CNFG_LEN		0x20
+#define GD_CH_RMSSI_TH_OFFSET	12
+#define MAX_GD_CH_RMSSI_TH	127
+#define SRCH_ALGO_TYPE_OFFSET  25
+#define SINRFIRSTSTAGE_OFFSET  26
+#define RMSSIFIRSTSTAGE_OFFSET 27
+#define CF0TH12_BYTE1_OFFSET   8
+#define CF0TH12_BYTE2_OFFSET   9
+#define CF0TH12_BYTE3_OFFSET   10
+#define CF0TH12_BYTE4_OFFSET   11
+#define MAX_SINR_FIRSTSTAGE	127
+#define MAX_RMSSI_FIRSTSTAGE	127
+#define RDS_PS0_XFR_MODE 0x01
+#define RDS_PS0_LEN 6
+#define RX_REPEATE_BYTE_OFFSET 5
+#define FM_SPUR_TBL_SIZE 240
+#define SPUR_DATA_LEN 16
+#define ENTRIES_EACH_CMD 15
+#define SPUR_DATA_INDEX 2
+#define FM_AF_LIST_MAX_SIZE   200
+#define AF_LIST_MAX     (FM_AF_LIST_MAX_SIZE / 4) /* Each AF frequency consist
+							of sizeof(int) bytes */
+#define MAX_BLEND_INDEX 49
+/* HCI timeouts */
+#define RADIO_HCI_TIMEOUT	(10000)	/* 10 seconds */
+
+typedef enum {
+    ASSOCIATE_JVM,
+    DISASSOCIATE_JVM
+} bt_cb_thread_evt;
+
+#define TUNE_PARAM 16
+#define SIZE_ARRAY(x)  (sizeof(x) / sizeof((x)[0]))
+typedef void (*enb_result_cb)();
+typedef void (*tune_rsp_cb)(int Freq);
+typedef void (*seek_rsp_cb)(int Freq);
+typedef void (*scan_rsp_cb)();
+typedef void (*srch_list_rsp_cb)(uint16_t *scan_tbl);
+typedef void (*stereo_mode_cb)(bool status);
+typedef void (*rds_avl_sts_cb)(bool status);
+typedef void (*af_list_cb)(uint16_t *af_list);
+typedef void (*rt_cb)(char *rt);
+typedef void (*ps_cb)(char *ps);
+typedef void (*oda_cb)();
+typedef void (*rt_plus_cb)(char *rt_plus);
+typedef void (*ert_cb)(char *ert);
+typedef void (*disable_cb)();
+typedef void (*callback_thread_event)(unsigned int evt);
+
+typedef struct {
+    size_t  size;
+
+    enb_result_cb  enabled_cb;
+    tune_rsp_cb tune_cb;
+    seek_rsp_cb  seek_cmpl_cb;
+    scan_rsp_cb  scan_next_cb;
+    srch_list_rsp_cb  srch_list_cb;
+    stereo_mode_cb  stereo_status_cb;
+    rds_avl_sts_cb  rds_avail_status_cb;
+    af_list_cb  af_list_update_cb;
+    rt_cb  rt_update_cb;
+    ps_cb  ps_update_cb;
+    oda_cb  oda_update_cb;
+    rt_plus_cb  rt_plus_update_cb;
+    ert_cb  ert_update_cb;
+    disable_cb  disabled_cb;
+    callback_thread_event thread_evt_cb;
+} fm_vendor_callbacks_t;
+
+pthread_mutex_t radio_fm_cmd;
+typedef struct {
+    int (*init)(const fm_vendor_callbacks_t *p_cb);
+    int (*set_fm_ctrl)(int opcode, int val);
+    void (*Get_fm_ctrl) (int opcode, int val);
+} fm_interface_t;
+
+typedef int (*fm_evt_notify_cb)(unsigned char *p_buf);
+
+typedef struct {
+    fm_evt_notify_cb fm_evt_notify;
+} fm_hal_cb;
+
+struct radio_hci_command_hdr {
+    short  opcode; /* OCF & OGF */
+    char   plen;
+} ;
+
+struct radio_hci_event_hdr {
+    char  evt;
+    char  plen;
+} ;
+
+struct radio_hci_dev {
+    char  name[8];
+    unsigned long  flags;
+    short  id;
+    char  bus;
+    char  dev_type;
+    char  dev_name[248];
+    char  dev_class[3];
+    char  features[8];
+    char  commands[64];
+    unsigned int  data_block_len;
+    unsigned long  cmd_last_tx;
+    int  req_status;
+    int  req_result;
+};
+
+/* Opcode OCF */
+/* HCI recv control commands opcode */
+#define HCI_OCF_FM_ENABLE_RECV_REQ          0x0001
+#define HCI_OCF_FM_DISABLE_RECV_REQ         0x0002
+#define HCI_OCF_FM_GET_RECV_CONF_REQ        0x0003
+#define HCI_OCF_FM_SET_RECV_CONF_REQ        0x0004
+#define HCI_OCF_FM_SET_MUTE_MODE_REQ        0x0005
+#define HCI_OCF_FM_SET_STEREO_MODE_REQ      0x0006
+#define HCI_OCF_FM_SET_ANTENNA              0x0007
+#define HCI_OCF_FM_SET_SIGNAL_THRESHOLD     0x0008
+#define HCI_OCF_FM_GET_SIGNAL_THRESHOLD     0x0009
+#define HCI_OCF_FM_GET_STATION_PARAM_REQ    0x000A
+#define HCI_OCF_FM_GET_PROGRAM_SERVICE_REQ  0x000B
+#define HCI_OCF_FM_GET_RADIO_TEXT_REQ       0x000C
+#define HCI_OCF_FM_GET_AF_LIST_REQ          0x000D
+#define HCI_OCF_FM_SEARCH_STATIONS          0x000E
+#define HCI_OCF_FM_SEARCH_RDS_STATIONS      0x000F
+#define HCI_OCF_FM_SEARCH_STATIONS_LIST     0x0010
+#define HCI_OCF_FM_CANCEL_SEARCH            0x0011
+#define HCI_OCF_FM_RDS_GRP                  0x0012
+#define HCI_OCF_FM_RDS_GRP_PROCESS          0x0013
+#define HCI_OCF_FM_EN_WAN_AVD_CTRL          0x0014
+#define HCI_OCF_FM_EN_NOTCH_CTRL            0x0015
+#define HCI_OCF_FM_SET_EVENT_MASK           0x0016
+#define HCI_OCF_FM_SET_CH_DET_THRESHOLD     0x0017
+#define HCI_OCF_FM_GET_CH_DET_THRESHOLD     0x0018
+#define HCI_OCF_FM_SET_BLND_TBL             0x001B
+#define HCI_OCF_FM_GET_BLND_TBL             0x001C
+/* HCI trans control commans opcode*/
+#define HCI_OCF_FM_ENABLE_TRANS_REQ         0x0001
+#define HCI_OCF_FM_DISABLE_TRANS_REQ        0x0002
+#define HCI_OCF_FM_GET_TRANS_CONF_REQ       0x0003
+#define HCI_OCF_FM_SET_TRANS_CONF_REQ       0x0004
+#define HCI_OCF_FM_RDS_RT_REQ               0x0008
+#define HCI_OCF_FM_RDS_PS_REQ               0x0009
+
+
+/* HCI common control commands opcode */
+#define HCI_OCF_FM_TUNE_STATION_REQ         0x0001
+#define HCI_OCF_FM_DEFAULT_DATA_READ        0x0002
+#define HCI_OCF_FM_DEFAULT_DATA_WRITE       0x0003
+#define HCI_OCF_FM_RESET                    0x0004
+#define HCI_OCF_FM_GET_FEATURE_LIST         0x0005
+#define HCI_OCF_FM_DO_CALIBRATION           0x0006
+#define HCI_OCF_FM_SET_CALIBRATION          0x0007
+#define HCI_OCF_FM_SET_SPUR_TABLE           0x0008
+#define HCI_OCF_FM_GET_SPUR_TABLE           0x0009
+
+/*HCI Status parameters commands*/
+#define HCI_OCF_FM_READ_GRP_COUNTERS        0x0001
+
+/*HCI Diagnostic commands*/
+#define HCI_OCF_FM_PEEK_DATA                0x0002
+#define HCI_OCF_FM_POKE_DATA                0x0003
+#define HCI_OCF_FM_SSBI_PEEK_REG            0x0004
+#define HCI_OCF_FM_SSBI_POKE_REG            0x0005
+#define HCI_OCF_FM_STATION_DBG_PARAM        0x0007
+#define HCI_FM_SET_INTERNAL_TONE_GENRATOR   0x0008
+
+/* Opcode OGF */
+#define HCI_OGF_FM_RECV_CTRL_CMD_REQ            0x0013
+#define HCI_OGF_FM_TRANS_CTRL_CMD_REQ           0x0014
+#define HCI_OGF_FM_COMMON_CTRL_CMD_REQ          0x0015
+#define HCI_OGF_FM_STATUS_PARAMETERS_CMD_REQ    0x0016
+#define HCI_OGF_FM_TEST_CMD_REQ                 0x0017
+#define HCI_OGF_FM_DIAGNOSTIC_CMD_REQ           0x003F
+
+/* Command opcode pack/unpack */
+#define hci_opcode_pack(ogf, ocf)    (short) ((ocf & 0x03ff)|(ogf << 10))
+#define hci_opcode_ogf(op)    (op >> 10)
+#define hci_opcode_ocf(op)    (op & 0x03ff)
+#define hci_recv_ctrl_cmd_op_pack(ocf) \
+     (short) hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ, ocf)
+#define hci_trans_ctrl_cmd_op_pack(ocf) \
+     (short) hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ, ocf)
+#define hci_common_cmd_op_pack(ocf)	\
+     (short) hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ, ocf)
+#define hci_status_param_op_pack(ocf)	\
+     (short) hci_opcode_pack(HCI_OGF_FM_STATUS_PARAMETERS_CMD_REQ, ocf)
+#define hci_diagnostic_cmd_op_pack(ocf)	\
+     (short) hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ, ocf)
+
+
+/* HCI commands with no arguments*/
+#define HCI_FM_ENABLE_RECV_CMD 1
+#define HCI_FM_DISABLE_RECV_CMD 2
+#define HCI_FM_GET_RECV_CONF_CMD 3
+#define HCI_FM_GET_STATION_PARAM_CMD 4
+#define HCI_FM_GET_SIGNAL_TH_CMD 5
+#define HCI_FM_GET_PROGRAM_SERVICE_CMD 6
+#define HCI_FM_GET_RADIO_TEXT_CMD 7
+#define HCI_FM_GET_AF_LIST_CMD 8
+#define HCI_FM_CANCEL_SEARCH_CMD 9
+#define HCI_FM_RESET_CMD 10
+#define HCI_FM_GET_FEATURES_CMD 11
+#define HCI_FM_STATION_DBG_PARAM_CMD 12
+#define HCI_FM_ENABLE_TRANS_CMD 13
+#define HCI_FM_DISABLE_TRANS_CMD 14
+#define HCI_FM_GET_TX_CONFIG 15
+#define HCI_FM_GET_DET_CH_TH_CMD 16
+#define HCI_FM_GET_BLND_TBL_CMD 17
+
+/* Defines for FM TX*/
+#define TX_PS_DATA_LENGTH 108
+#define TX_RT_DATA_LENGTH 64
+#define PS_STRING_LEN     9
+
+/* ----- HCI Command request ----- */
+struct hci_fm_recv_conf_req {
+    char  emphasis;
+    char  ch_spacing;
+    char  rds_std;
+    char  hlsi;
+    int	  band_low_limit;
+    int	  band_high_limit;
+} ;
+
+/* ----- HCI Command request ----- */
+struct hci_fm_trans_conf_req_struct {
+    char  emphasis;
+    char  rds_std;
+    int	  band_low_limit;
+    int   band_high_limit;
+} ;
+
+
+/* ----- HCI Command request ----- */
+struct hci_fm_tx_ps {
+    char   ps_control;
+    short  pi;
+    char   pty;
+    char   ps_repeatcount;
+    char   ps_num;
+    char   ps_data[TX_PS_DATA_LENGTH];
+} ;
+
+struct hci_fm_tx_rt {
+    char    rt_control;
+    short   pi;
+    char    pty;
+    char    rt_len;
+    char    rt_data[TX_RT_DATA_LENGTH];
+} ;
+
+struct hci_fm_mute_mode_req {
+    char  hard_mute;
+    char  soft_mute;
+} ;
+
+struct hci_fm_stereo_mode_req {
+    char    stereo_mode;
+    char    sig_blend;
+    char    intf_blend;
+    char    most_switch;
+} ;
+
+struct hci_fm_search_station_req {
+    char    srch_mode;
+    char    scan_time;
+    char    srch_dir;
+} ;
+
+struct hci_fm_search_rds_station_req {
+    struct hci_fm_search_station_req srch_station;
+    char    srch_pty;
+    short   srch_pi;
+} ;
+
+struct hci_fm_search_station_list_req {
+    char    srch_list_mode;
+    char    srch_list_dir;
+    int   srch_list_max;
+    char    srch_pty;
+} ;
+
+struct hci_fm_rds_grp_req {
+    int   rds_grp_enable_mask;
+    int   rds_buf_size;
+    char    en_rds_change_filter;
+} ;
+
+struct hci_fm_en_avd_ctrl_req {
+    char    no_freqs;
+    char    freq_index;
+    char    lo_shft;
+    short   freq_min;
+    short   freq_max;
+} ;
+
+struct hci_fm_def_data_rd_req {
+    char    mode;
+    char    length;
+    char    param_len;
+    char    param;
+} ;
+
+struct hci_fm_def_data_wr_req {
+    char    mode;
+    char    length;
+    char   data[DEFAULT_DATA_SIZE];
+} ;
+
+struct hci_fm_riva_data {
+    char subopcode;
+    int   start_addr;
+    char    length;
+} ;
+
+struct hci_fm_riva_poke {
+    struct hci_fm_riva_data cmd_params;
+    char    data[MAX_RIVA_PEEK_RSP_SIZE];
+} ;
+
+struct hci_fm_ssbi_req {
+    short   start_addr;
+    char    data;
+} ;
+struct hci_fm_ssbi_peek {
+    short start_address;
+} ;
+
+struct hci_fm_ch_det_threshold {
+    char sinr;
+    char sinr_samples;
+    char low_th;
+    char high_th;
+
+} ;
+
+struct hci_fm_blend_table {
+    char ucBlendType;
+    char ucBlendRampRateUp;
+    char ucBlendDebounceNumSampleUp;
+    char ucBlendDebounceIdxUp;
+    char ucBlendSinrIdxSkipStep;
+    char scBlendSinrHi;
+    char scBlendRmssiHi;
+    char ucBlendIndexHi;
+    char ucBlendIndex[MAX_BLEND_INDEX];
+} ;
+
+/*HCI events*/
+#define HCI_EV_TUNE_STATUS              0x01
+#define HCI_EV_RDS_LOCK_STATUS          0x02
+#define HCI_EV_STEREO_STATUS            0x03
+#define HCI_EV_SERVICE_AVAILABLE        0x04
+#define HCI_EV_SEARCH_PROGRESS          0x05
+#define HCI_EV_SEARCH_RDS_PROGRESS      0x06
+#define HCI_EV_SEARCH_LIST_PROGRESS     0x07
+#define HCI_EV_RDS_RX_DATA              0x08
+#define HCI_EV_PROGRAM_SERVICE          0x09
+#define HCI_EV_RADIO_TEXT               0x0A
+#define HCI_EV_FM_AF_LIST               0x0B
+#define HCI_EV_TX_RDS_GRP_AVBLE         0x0C
+#define HCI_EV_TX_RDS_GRP_COMPL         0x0D
+#define HCI_EV_TX_RDS_CONT_GRP_COMPL    0x0E
+#define HCI_EV_CMD_COMPLETE             0x0F
+#define HCI_EV_CMD_STATUS               0x10
+#define HCI_EV_TUNE_COMPLETE            0x11
+#define HCI_EV_SEARCH_COMPLETE          0x12
+#define HCI_EV_SEARCH_RDS_COMPLETE      0x13
+#define HCI_EV_SEARCH_LIST_COMPLETE     0x14
+
+#define HCI_REQ_DONE      0
+#define HCI_REQ_PEND      1
+#define HCI_REQ_CANCELED  2
+#define HCI_REQ_STATUS    3
+
+#define MAX_RAW_RDS_GRPS     21
+
+#define RDSGRP_DATA_OFFSET   0x1
+
+/*RT PLUS*/
+#define DUMMY_CLASS             0
+#define RT_PLUS_LEN_1_TAG       3
+#define RT_ERT_FLAG_BIT	        5
+
+/*TAG1*/
+#define TAG1_MSB_OFFSET	        3
+#define TAG1_MSB_MASK	        7
+#define TAG1_LSB_OFFSET	        5
+#define TAG1_POS_MSB_MASK       31
+#define TAG1_POS_MSB_OFFSET     1
+#define TAG1_POS_LSB_OFFSET     7
+#define TAG1_LEN_OFFSET	        1
+#define TAG1_LEN_MASK           63
+
+/*TAG2*/
+#define TAG2_MSB_OFFSET	        5
+#define TAG2_MSB_MASK           1
+#define TAG2_LSB_OFFSET	        3
+#define TAG2_POS_MSB_MASK       7
+#define TAG2_POS_MSB_OFFSET     3
+#define TAG2_POS_LSB_OFFSET     5
+#define TAG2_LEN_MASK           31
+
+#define AGT_MASK                31
+/*Extract 5 left most bits of lsb of 2nd block*/
+#define AGT(x) 	             (x & AGT_MASK)
+/*16 bits of 4th block*/
+#define AID(lsb, msb)        ((msb << 8) | (lsb))
+/*Extract 5 right most bits of msb of 2nd block*/
+#define GTC(blk2msb)         (blk2msb >> 3)
+
+#define GRP_3A               0x6
+#define RT_PLUS_AID          0x4bd7
+
+/*ERT*/
+#define ERT_AID	             0x6552
+#define CARRIAGE_RETURN	     0x000D
+#define MAX_ERT_SEGMENT	     31
+#define ERT_FORMAT_DIR_BIT   1
+
+#define EXTRACT_BIT(data, bit_pos) ((data & (1 << bit_pos)) >> bit_pos)
+
+struct hci_ev_tune_status {
+    char    sub_event;
+    int     station_freq;
+    char    serv_avble;
+    char    rssi;
+    char    stereo_prg;
+    char    rds_sync_status;
+    char    mute_mode;
+    char    sinr;
+    char    intf_det_th;
+} ;
+
+struct rds_blk_data {
+    char  rdsMsb;
+    char  rdsLsb;
+    char  blockStatus;
+} ;
+
+struct rds_grp_data {
+    struct rds_blk_data rdsBlk[4];
+} ;
+
+struct hci_ev_rds_rx_data {
+    char    num_rds_grps;
+    struct  rds_grp_data rds_grp_data[MAX_RAW_RDS_GRPS];
+} ;
+
+struct hci_ev_prg_service {
+    short   pi_prg_id;
+    char    pty_prg_type;
+    char    ta_prg_code_type;
+    char    ta_ann_code_flag;
+    char    ms_switch_code_flag;
+    char    dec_id_ctrl_code_flag;
+    char    ps_num;
+    char    prg_service_name[119];
+} ;
+
+struct hci_ev_radio_text {
+    short   pi_prg_id;
+    char    pty_prg_type;
+    char    ta_prg_code_type;
+    char    txt_ab_flag;
+    char    radio_txt[64];
+} ;
+
+struct hci_ev_af_list {
+    int   tune_freq;
+    short   pi_code;
+    char    af_size;
+    char    af_list[FM_AF_LIST_MAX_SIZE];
+} ;
+
+struct hci_ev_cmd_complete {
+    char    num_hci_cmd_pkts;
+    short   cmd_opcode;
+} ;
+
+struct hci_ev_cmd_status {
+    char    status;
+    char    num_hci_cmd_pkts;
+    short   status_opcode;
+} ;
+
+struct hci_ev_srch_st {
+    int    station_freq;
+    char    rds_cap;
+    char   pty;
+    short   status_opcode;
+} ;
+
+struct hci_ev_rel_freq {
+    char  rel_freq_msb;
+    char  rel_freq_lsb;
+
+} ;
+struct hci_ev_srch_list_compl {
+    char    num_stations_found;
+    struct hci_ev_rel_freq  rel_freq[20];
+} ;
+
+/* ----- HCI Event Response ----- */
+struct hci_fm_conf_rsp {
+    char    status;
+    struct hci_fm_recv_conf_req recv_conf_rsp;
+} ;
+
+struct hci_fm_get_trans_conf_rsp {
+    char    status;
+    struct hci_fm_trans_conf_req_struct trans_conf_rsp;
+} ;
+struct hci_fm_sig_threshold_rsp {
+    char    status;
+    char    sig_threshold;
+} ;
+
+struct hci_fm_station_rsp {
+    struct hci_ev_tune_status station_rsp;
+} ;
+
+struct hci_fm_prgm_srv_rsp {
+    char    status;
+    struct hci_ev_prg_service prg_srv;
+} ;
+
+struct hci_fm_radio_txt_rsp {
+    char    status;
+    struct hci_ev_radio_text rd_txt;
+} ;
+
+struct hci_fm_af_list_rsp {
+    char    status;
+    struct hci_ev_af_list rd_txt;
+} ;
+
+struct hci_fm_data_rd_rsp {
+    char    status;
+    char    ret_data_len;
+    char    data[DEFAULT_DATA_SIZE];
+} ;
+
+struct hci_fm_feature_list_rsp {
+    char    status;
+    char    feature_mask;
+} ;
+
+struct hci_fm_dbg_param_rsp {
+    char    status;
+    char    blend;
+    char    soft_mute;
+    char    inf_blend;
+    char    inf_soft_mute;
+    char    pilot_pil;
+    char    io_verc;
+    char    in_det_out;
+} ;
+
+#define CLKSPURID_INDEX0	0
+#define CLKSPURID_INDEX1	5
+#define CLKSPURID_INDEX2	10
+#define CLKSPURID_INDEX3	15
+#define CLKSPURID_INDEX4	20
+#define CLKSPURID_INDEX5	25
+
+#define MAX_SPUR_FREQ_LIMIT	30
+#define CKK_SPUR		0x3B
+#define SPUR_DATA_SIZE		0x4
+#define SPUR_ENTRIES_PER_ID	0x5
+
+#define COMPUTE_SPUR(val)         ((((val) - (76000)) / (50)))
+#define GET_FREQ(val, bit)        ((bit == 1) ? ((val) >> 8) : ((val) & 0xFF))
+#define GET_SPUR_ENTRY_LEVEL(val) ((val) / (5))
+
+struct hci_fm_spur_data {
+    int	  freq[MAX_SPUR_FREQ_LIMIT];
+    char  rmssi[MAX_SPUR_FREQ_LIMIT];
+    char  enable[MAX_SPUR_FREQ_LIMIT];
+} ;
+
+
+/* HCI dev events */
+#define RADIO_HCI_DEV_REG			1
+#define RADIO_HCI_DEV_WRITE			2
+
+#define hci_req_lock(d)		mutex_lock(&d->req_lock)
+#define hci_req_unlock(d)	mutex_unlock(&d->req_lock)
+
+/* FM RDS */
+#define RDS_PTYPE 2
+#define RDS_PID_LOWER 1
+#define RDS_PID_HIGHER 0
+#define RDS_OFFSET 5
+#define RDS_PS_LENGTH_OFFSET 7
+#define RDS_STRING 8
+#define RDS_PS_DATA_OFFSET 8
+#define RDS_CONFIG_OFFSET  3
+#define RDS_AF_JUMP_OFFSET 4
+#define PI_CODE_OFFSET 4
+#define AF_SIZE_OFFSET 6
+#define AF_LIST_OFFSET 7
+#define RT_A_B_FLAG_OFFSET 4
+/*FM states*/
+
+enum radio_state_t {
+    FM_OFF,
+    FM_RECV,
+    FM_TRANS,
+    FM_RESET,
+    FM_CALIB,
+    FM_TURNING_OFF,
+    FM_RECV_TURNING_ON,
+    FM_TRANS_TURNING_ON,
+    FM_MAX_NO_STATES,
+};
+
+enum emphasis_type {
+    FM_RX_EMP75 = 0x0,
+    FM_RX_EMP50 = 0x1
+};
+
+enum channel_space_type {
+    FM_RX_SPACE_200KHZ = 0x0,
+    FM_RX_SPACE_100KHZ = 0x1,
+    FM_RX_SPACE_50KHZ = 0x2
+};
+
+enum high_low_injection {
+    AUTO_HI_LO_INJECTION = 0x0,
+    LOW_SIDE_INJECTION = 0x1,
+    HIGH_SIDE_INJECTION = 0x2
+};
+
+enum fm_rds_type {
+    FM_RX_RDBS_SYSTEM = 0x0,
+    FM_RX_RDS_SYSTEM = 0x1
+};
+
+enum hlm_region_t {
+    HELIUM_REGION_US,
+    HELIUM_REGION_EU,
+    HELIUM_REGION_JAPAN,
+    HELIUM_REGION_JAPAN_WIDE,
+    HELIUM_REGION_OTHER
+};
+
+/* Search options */
+enum search_t {
+    SEEK,
+    SCAN,
+    SCAN_FOR_STRONG,
+    SCAN_FOR_WEAK,
+    RDS_SEEK_PTY,
+    RDS_SCAN_PTY,
+    RDS_SEEK_PI,
+    RDS_AF_JUMP,
+};
+
+enum spur_entry_levels {
+    ENTRY_0,
+    ENTRY_1,
+    ENTRY_2,
+    ENTRY_3,
+    ENTRY_4,
+    ENTRY_5,
+};
+
+/* Band limits */
+#define REGION_US_EU_BAND_LOW              87500
+#define REGION_US_EU_BAND_HIGH             108000
+#define REGION_JAPAN_STANDARD_BAND_LOW     76000
+#define REGION_JAPAN_STANDARD_BAND_HIGH    90000
+#define REGION_JAPAN_WIDE_BAND_LOW         90000
+#define REGION_JAPAN_WIDE_BAND_HIGH        108000
+
+#define SRCH_MODE       0x07
+#define SRCH_DIR        0x08 /* 0-up 1-down */
+#define SCAN_DWELL      0x70
+#define SRCH_ON	        0x80
+
+/* I/O Control */
+#define IOC_HRD_MUTE    0x03
+#define IOC_SFT_MUTE    0x01
+#define IOC_MON_STR     0x01
+#define IOC_SIG_BLND    0x01
+#define IOC_INTF_BLND   0x01
+#define IOC_ANTENNA     0x01
+
+/* RDS Control */
+#define RDS_ON	    0x01
+#define RDS_BUF_SZ  100
+
+/* constants */
+#define  RDS_BLOCKS_NUM	(4)
+#define BYTES_PER_BLOCK	(3)
+#define MAX_PS_LENGTH   (108)
+#define MAX_RT_LENGTH   (64)
+#define RDS_GRP_CNTR_LEN (36)
+#define RX_RT_DATA_LENGTH (63)
+/* Search direction */
+#define SRCH_DIR_UP      (0)
+#define SRCH_DIR_DOWN    (1)
+
+/*Search RDS stations*/
+#define SEARCH_RDS_STNS_MODE_OFFSET 4
+
+/*Search Station list */
+#define PARAMS_PER_STATION 0x08
+#define STN_NUM_OFFSET     0x01
+#define STN_FREQ_OFFSET    0x02
+#define KHZ_TO_MHZ         1000
+#define GET_MSB(x)((x >> 8) & 0xFF)
+#define GET_LSB(x)((x) & 0xFF)
+
+/* control options */
+#define CTRL_ON	    (1)
+#define CTRL_OFF    (0)
+
+/*Diagnostic commands*/
+
+#define RIVA_PEEK_OPCODE 0x0D
+#define RIVA_POKE_OPCODE 0x0C
+
+#define PEEK_DATA_OFSET 0x1
+#define RIVA_PEEK_PARAM     0x6
+#define RIVA_PEEK_LEN_OFSET  0x6
+#define SSBI_PEEK_LEN    0x01
+/*Calibration data*/
+#define PROCS_CALIB_MODE  1
+#define PROCS_CALIB_SIZE  23
+#define DC_CALIB_MODE     2
+#define DC_CALIB_SIZE     48
+#define RSB_CALIB_MODE    3
+#define RSB_CALIB_SIZE    4
+#define CALIB_DATA_OFSET  2
+#define CALIB_MODE_OFSET  1
+#define MAX_CALIB_SIZE 75
+
+/* Channel validity */
+#define INVALID_CHANNEL	    (0)
+#define VALID_CHANNEL       (1)
+
+struct hci_fm_set_cal_req_proc {
+    char    mode;
+    /*Max process calibration data size*/
+    char    data[PROCS_CALIB_SIZE];
+} ;
+
+struct hci_fm_set_cal_req_dc {
+    char    mode;
+    /*Max DC calibration data size*/
+    char    data[DC_CALIB_SIZE];
+} ;
+
+struct hci_cc_do_calibration_rsp {
+    char status;
+    char mode;
+    char data[MAX_CALIB_SIZE];
+} ;
+
+struct hci_fm_set_spur_table_req {
+    char mode;
+    char no_of_freqs_entries;
+    char spur_data[FM_SPUR_TBL_SIZE];
+} ;
+/* Low Power mode*/
+#define SIG_LEVEL_INTR  (1 << 0)
+#define RDS_SYNC_INTR   (1 << 1)
+#define AUDIO_CTRL_INTR (1 << 2)
+#define AF_JUMP_ENABLE  (1 << 4)
+
+int hci_def_data_read(struct hci_fm_def_data_rd_req *arg,
+       struct radio_hci_dev *hdev);
+int hci_def_data_write(struct hci_fm_def_data_wr_req *arg,
+       struct radio_hci_dev *hdev);
+int hci_fm_do_calibration(char *arg, struct radio_hci_dev *hdev);
+int hci_fm_do_calibration(char *arg, struct radio_hci_dev *hdev);
+
+static inline int is_valid_tone(int tone)
+{
+    if ((tone >= MIN_TX_TONE_VAL) &&
+        (tone <= MAX_TX_TONE_VAL))
+        return 1;
+    else
+        return 0;
+}
+
+static inline int is_valid_hard_mute(int hard_mute)
+{
+    if ((hard_mute >= MIN_HARD_MUTE_VAL) &&
+        (hard_mute <= MAX_HARD_MUTE_VAL))
+        return 1;
+    else
+        return 0;
+}
+
+static inline int is_valid_srch_mode(int srch_mode)
+{
+    if ((srch_mode >= MIN_SRCH_MODE) &&
+        (srch_mode <= MAX_SRCH_MODE))
+        return 1;
+    else
+        return 0;
+}
+
+static inline int is_valid_scan_dwell_prd(int scan_dwell_prd)
+{
+    if ((scan_dwell_prd >= MIN_SCAN_DWELL) &&
+        (scan_dwell_prd <= MAX_SCAN_DWELL))
+        return 1;
+    else
+        return 0;
+}
+
+static inline int is_valid_sig_th(int sig_th)
+{
+    if ((sig_th >= MIN_SIG_TH) &&
+        (sig_th <= MAX_SIG_TH))
+        return 1;
+    else
+        return 0;
+}
+
+static inline int is_valid_pty(int pty)
+{
+    if ((pty >= MIN_PTY) &&
+        (pty <= MAX_PTY))
+        return 1;
+    else
+        return 0;
+}
+
+static inline int is_valid_pi(int pi)
+{
+    if ((pi >= MIN_PI) &&
+        (pi <= MAX_PI))
+        return 1;
+    else
+        return 0;
+}
+
+static inline int is_valid_srch_station_cnt(int cnt)
+{
+    if ((cnt >= MIN_SRCH_STATIONS_CNT) &&
+        (cnt <= MAX_SRCH_STATIONS_CNT))
+        return 1;
+    else
+        return 0;
+}
+
+static inline int is_valid_chan_spacing(int spacing)
+{
+    if ((spacing >= MIN_CHAN_SPACING) &&
+        (spacing <= MAX_CHAN_SPACING))
+        return 1;
+    else
+        return 0;
+}
+
+static inline int is_valid_emphasis(int emphasis)
+{
+    if ((emphasis >= MIN_EMPHASIS) &&
+        (emphasis <= MAX_EMPHASIS))
+        return 1;
+    else
+        return 0;
+}
+
+static inline int is_valid_rds_std(int rds_std)
+{
+    if ((rds_std >= MIN_RDS_STD) &&
+        (rds_std <= MAX_RDS_STD))
+        return 1;
+    else
+        return 0;
+}
+
+static inline int is_valid_antenna(int antenna_type)
+{
+    if ((antenna_type >= MIN_ANTENNA_VAL) &&
+        (antenna_type <= MAX_ANTENNA_VAL))
+        return 1;
+    else
+        return 0;
+}
+
+static inline int is_valid_ps_repeat_cnt(int cnt)
+{
+    if ((cnt >= MIN_TX_PS_REPEAT_CNT) &&
+        (cnt <= MAX_TX_PS_REPEAT_CNT))
+        return 1;
+    else
+        return 0;
+}
+
+static inline int is_valid_soft_mute(int soft_mute)
+{
+    if ((soft_mute >= MIN_SOFT_MUTE) &&
+        (soft_mute <= MAX_SOFT_MUTE))
+        return 1;
+    else
+        return 0;
+}
+
+static inline int is_valid_peek_len(int len)
+{
+    if ((len >= MIN_PEEK_ACCESS_LEN) &&
+        (len <= MAX_PEEK_ACCESS_LEN))
+        return 1;
+    else
+        return 0;
+}
+
+static inline int is_valid_reset_cntr(int cntr)
+{
+    if ((cntr >= MIN_RESET_CNTR) &&
+        (cntr <= MAX_RESET_CNTR))
+        return 1;
+    else
+        return 0;
+}
+
+static inline int is_valid_hlsi(int hlsi)
+{
+    if ((hlsi >= MIN_HLSI) &&
+        (hlsi <= MAX_HLSI))
+        return 1;
+    else
+        return 0;
+}
+
+static inline int is_valid_notch_filter(int filter)
+{
+    if ((filter >= MIN_NOTCH_FILTER) &&
+        (filter <= MAX_NOTCH_FILTER))
+        return 1;
+    else
+        return 0;
+}
+
+static inline int is_valid_intf_det_low_th(int th)
+{
+    if ((th >= MIN_INTF_DET_OUT_LW_TH) &&
+        (th <= MAX_INTF_DET_OUT_LW_TH))
+        return 1;
+    else
+        return 0;
+}
+
+static inline int is_valid_intf_det_hgh_th(int th)
+{
+    if ((th >= MIN_INTF_DET_OUT_HG_TH) &&
+        (th <= MAX_INTF_DET_OUT_HG_TH))
+        return 1;
+    else
+        return 0;
+}
+
+static inline int is_valid_sinr_th(int th)
+{
+    if ((th >= MIN_SINR_TH) &&
+        (th <= MAX_SINR_TH))
+        return 1;
+    else
+        return 0;
+}
+
+static inline int is_valid_sinr_samples(int samples_cnt)
+{
+    if ((samples_cnt >= MIN_SINR_SAMPLES) &&
+        (samples_cnt <= MAX_SINR_SAMPLES))
+        return 1;
+    else
+        return 0;
+}
+
+static inline int is_valid_fm_state(int state)
+{
+    if ((state >= 0) && (state < FM_MAX_NO_STATES))
+        return 1;
+    else
+        return 0;
+}
+
+static inline int is_valid_blend_value(int val)
+{
+    if ((val >= MIN_BLEND_HI) && (val <= MAX_BLEND_HI))
+        return 1;
+    else
+        return 0;
+}
+
+struct helium_device {
+    int tune_req;
+    unsigned int mode;
+    short pi;
+    char pty;
+    char ps_repeatcount;
+    char prev_trans_rds;
+    char af_jump_bit;
+    struct hci_fm_mute_mode_req mute_mode;
+    struct hci_fm_stereo_mode_req stereo_mode;
+    struct hci_fm_station_rsp fm_st_rsp;
+    struct hci_fm_search_station_req srch_st;
+    struct hci_fm_search_rds_station_req srch_rds;
+    struct hci_fm_search_station_list_req srch_st_list;
+    struct hci_fm_recv_conf_req recv_conf;
+    struct hci_fm_trans_conf_req_struct trans_conf;
+    struct hci_fm_rds_grp_req rds_grp;
+    unsigned char g_search_mode;
+    unsigned char power_mode;
+    int search_on;
+    unsigned char spur_table_size;
+    unsigned char g_scan_time;
+    unsigned int g_antenna;
+    unsigned int g_rds_grp_proc_ps;
+    unsigned char event_mask;
+    enum hlm_region_t region;
+    struct hci_fm_dbg_param_rsp st_dbg_param;
+    struct hci_ev_srch_list_compl srch_st_result;
+};
+#endif /* __UAPI_RADIO_HCI_CORE_H */
diff --git a/helium/radio_helium_hal.c b/helium/radio_helium_hal.c
new file mode 100644
index 0000000..ce39b59
--- /dev/null
+++ b/helium/radio_helium_hal.c
@@ -0,0 +1,1067 @@
+/*
+Copyright (c) 2015, 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.
+*/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <utils/Log.h>
+#include "radio-helium-commands.h"
+#include "radio-helium.h"
+#include "fm_hci.h"
+#include <dlfcn.h>
+
+fm_vendor_callbacks_t *jni_cb;
+int hci_fm_get_signal_threshold();
+int hci_fm_enable_recv_req();
+struct helium_device *radio;
+static int oda_agt;
+static int grp_mask;
+static int rt_plus_carrier = -1;
+static int ert_carrier = -1;
+static unsigned char ert_buf[256];
+static unsigned char ert_len;
+static unsigned char c_byt_pair_index;
+static char utf_8_flag;
+static char rt_ert_flag;
+static char formatting_dir;
+
+#define LOG_TAG "radio_helium"
+static void radio_hci_req_complete(char result)
+{
+  ALOGD("%s:enetred %s", LOG_TAG, __func__);
+}
+
+static void radio_hci_status_complete(int result)
+{
+   ALOGD("%s:enetred %s", LOG_TAG, __func__);
+}
+
+static void hci_cc_fm_enable_rsp(char *ev_rsp)
+{
+    struct hci_fm_conf_rsp  *rsp;
+
+    if (ev_rsp == NULL) {
+        ALOGE("%s:%s, buffer is null\n", LOG_TAG, __func__);
+        return;
+    }
+    rsp = (struct hci_fm_conf_rsp *)ev_rsp;
+    jni_cb->thread_evt_cb(0);
+    radio_hci_req_complete(rsp->status);
+    jni_cb->enabled_cb();
+}
+
+static void hci_cc_conf_rsp(char *ev_rsp)
+{
+    struct hci_fm_conf_rsp  *rsp;
+
+    if (ev_rsp == NULL) {
+        ALOGE("%s:%s, buffer is null\n", LOG_TAG, __func__);
+        return;
+    }
+    rsp = (struct hci_fm_conf_rsp *)ev_rsp;
+    radio_hci_req_complete(rsp->status);
+    if (!rsp->status) {
+        radio->recv_conf = rsp->recv_conf_rsp;
+    }
+}
+
+static void hci_cc_fm_disable_rsp(char *ev_buff)
+{
+    char status;
+
+    if (ev_buff == NULL) {
+        ALOGE("%s:%s, buffer is null\n", LOG_TAG, __func__);
+        return;
+    }
+    status = (char) *ev_buff;
+    radio_hci_req_complete(status);
+    if (radio->mode == FM_TURNING_OFF) {
+        jni_cb->disabled_cb();
+        radio->mode = FM_OFF;
+    }
+}
+
+static void hci_cc_rsp(char *ev_buff)
+{
+    char status;
+
+    if (ev_buff == NULL) {
+        ALOGE("%s:%s, socket buffer is null\n", LOG_TAG, __func__);
+        return;
+    }
+    status = (char)*ev_buff;
+
+    radio_hci_req_complete(status);
+}
+
+static inline void hci_cmd_complete_event(char *buff)
+{
+    uint16_t opcode;
+    uint8_t *pbuf;
+
+    if (buff == NULL) {
+        ALOGE("%s:%s, buffer is null\n", LOG_TAG, __func__);
+        return;
+    }
+    ALOGE("%s:buff[1] = 0x%x buff[2] = 0x%x", LOG_TAG, buff[1], buff[2]);
+    opcode = ((buff[2] << 8) | buff[1]);
+    ALOGE("%s: Received HCI CMD COMPLETE EVENT for opcode: 0x%x", __func__, opcode);
+    pbuf = &buff[3];
+
+    switch (opcode) {
+    case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_ENABLE_RECV_REQ):
+            ALOGE("%s: Recvd. CC event for FM_ENABLE_RECV_REQ", __func__);
+            hci_cc_fm_enable_rsp(pbuf);
+            break;
+    case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_RECV_CONF_REQ):
+            hci_cc_conf_rsp(pbuf);
+            break;
+    case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_DISABLE_RECV_REQ):
+            hci_cc_fm_disable_rsp(pbuf);
+            break;
+
+    case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_RECV_CONF_REQ):
+    case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_MUTE_MODE_REQ):
+    case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_STEREO_MODE_REQ):
+    case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_ANTENNA):
+    case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_SIGNAL_THRESHOLD):
+    case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_CANCEL_SEARCH):
+    case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_GRP):
+    case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_RDS_GRP_PROCESS):
+    case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_EN_WAN_AVD_CTRL):
+    case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_EN_NOTCH_CTRL):
+    case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_CH_DET_THRESHOLD):
+    case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_BLND_TBL):
+    case hci_common_cmd_op_pack(HCI_OCF_FM_DEFAULT_DATA_WRITE):
+            hci_cc_rsp(pbuf);
+            break;
+    case hci_common_cmd_op_pack(HCI_OCF_FM_RESET):
+    case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_SSBI_POKE_REG):
+    case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_POKE_DATA):
+    case hci_diagnostic_cmd_op_pack(HCI_FM_SET_INTERNAL_TONE_GENRATOR):
+    case hci_common_cmd_op_pack(HCI_OCF_FM_SET_CALIBRATION):
+    case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_SET_EVENT_MASK):
+    case hci_common_cmd_op_pack(HCI_OCF_FM_SET_SPUR_TABLE):
+            hci_cc_rsp(pbuf);
+            break;
+/*    case hci_common_cmd_op_pack(HCI_OCF_FM_GET_SPUR_TABLE):
+            hci_cc_get_spur_tbl(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_SIGNAL_THRESHOLD):
+            hci_cc_sig_threshold_rsp(buff);
+            break;
+
+    case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_STATION_PARAM_REQ):
+            hci_cc_station_rsp(buff);
+            break;
+
+    case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_PROGRAM_SERVICE_REQ):
+            hci_cc_prg_srv_rsp(buff);
+            break;
+
+    case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_RADIO_TEXT_REQ):
+            hci_cc_rd_txt_rsp(buff);
+            break;
+
+    case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_AF_LIST_REQ):
+            hci_cc_af_list_rsp(buff);
+            break;
+
+    case hci_common_cmd_op_pack(HCI_OCF_FM_DEFAULT_DATA_READ):
+            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;
+
+    case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_STATION_DBG_PARAM):
+            hci_cc_dbg_param_rsp(buff);
+            break;
+    case hci_status_param_op_pack(HCI_OCF_FM_READ_GRP_COUNTERS):
+            hci_cc_rds_grp_cntrs_rsp(buff);
+            break;
+    case hci_common_cmd_op_pack(HCI_OCF_FM_DO_CALIBRATION):
+            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;
+    default:
+            ALOGE("opcode 0x%x", opcode);
+            break; */
+    }
+}
+
+static inline void hci_cmd_status_event(char *st_rsp)
+{
+    struct hci_ev_cmd_status *ev = (void *) st_rsp;
+    uint16_t opcode;
+
+    if (st_rsp == NULL) {
+        ALOGE("%s:%s, buffer is null\n", LOG_TAG, __func__);
+        return;
+    }
+    ALOGE("%s:st_rsp[2] = 0x%x st_rsp[3] = 0x%x", LOG_TAG, st_rsp[2], st_rsp[3]);
+    opcode = ((st_rsp[3] << 8) | st_rsp[2]);
+    ALOGE("%s: Received HCI CMD STATUS EVENT for opcode: 0x%x", __func__, opcode);
+
+    radio_hci_status_complete(ev->status);
+}
+
+static inline void hci_ev_tune_status(char *buff)
+{
+
+    memcpy(&radio->fm_st_rsp.station_rsp, &buff[0],
+                               sizeof(struct hci_ev_tune_status));
+    jni_cb->tune_cb(radio->fm_st_rsp.station_rsp.station_freq);
+
+    //    if (radio->fm_st_rsp.station_rsp.serv_avble)
+          // todo callback for threshould
+
+    if (radio->fm_st_rsp.station_rsp.stereo_prg)
+        jni_cb->stereo_status_cb(true);
+    else if (radio->fm_st_rsp.station_rsp.stereo_prg == 0)
+        jni_cb->stereo_status_cb(false);
+
+    if (radio->fm_st_rsp.station_rsp.rds_sync_status)
+        jni_cb->rds_avail_status_cb(true);
+    else
+        jni_cb->rds_avail_status_cb(false);
+}
+
+static inline void hci_ev_search_next(char *buff)
+{
+    jni_cb->scan_next_cb();
+}
+
+static inline void hci_ev_stereo_status(char *buff)
+{
+    char st_status;
+
+    if (buff == NULL) {
+        ALOGE("%s:%s, socket buffer is null\n", LOG_TAG,__func__);
+        return;
+    }
+    st_status =  buff[0];
+    if (st_status)
+        jni_cb->stereo_status_cb(true);
+    else
+        jni_cb->stereo_status_cb(false);
+}
+
+static void hci_ev_rds_lock_status(char *buff)
+{
+    char rds_status;
+
+    if (buff == NULL) {
+        ALOGE("%s:%s, socket buffer is null\n", LOG_TAG, __func__);
+        return;
+    }
+
+    rds_status = buff[0];
+
+    if (rds_status)
+        jni_cb->rds_avail_status_cb(true);
+    else
+        jni_cb->rds_avail_status_cb(false);
+}
+
+static inline void hci_ev_program_service(char *buff)
+{
+    int len;
+    char *data;
+
+    len = (buff[RDS_PS_LENGTH_OFFSET] * RDS_STRING) + RDS_OFFSET;
+    data = malloc(len);
+    if (!data) {
+        ALOGE("%s:Failed to allocate memory", LOG_TAG);
+        return;
+    }
+
+    data[0] = buff[RDS_PS_LENGTH_OFFSET];
+    data[1] = buff[RDS_PTYPE];
+    data[2] = buff[RDS_PID_LOWER];
+    data[3] = buff[RDS_PID_HIGHER];
+    data[4] = 0;
+
+    memcpy(data+RDS_OFFSET, &buff[RDS_PS_DATA_OFFSET], len-RDS_OFFSET);
+
+    ALOGE("SSK call ps-callback");
+    jni_cb->ps_update_cb(data);
+
+    free(data);
+}
+
+static inline void hci_ev_radio_text(char *buff)
+{
+    int len = 0;
+    char *data;
+
+    if (buff == NULL) {
+        ALOGE("%s:%s, buffer is null\n", LOG_TAG,__func__);
+        return;
+    }
+
+    while ((buff[len+RDS_OFFSET] != 0x0d) && (len < MAX_RT_LENGTH))
+           len++;
+    data = malloc(len+RDS_OFFSET);
+    if (!data) {
+        ALOGE("%s:Failed to allocate memory", LOG_TAG);
+        return;
+    }
+
+    data[0] = len;
+    data[1] = buff[RDS_PTYPE];
+    data[2] = buff[RDS_PID_LOWER];
+    data[3] = buff[RDS_PID_HIGHER];
+    data[4] = buff[RT_A_B_FLAG_OFFSET];
+
+    memcpy(data+RDS_OFFSET, &buff[RDS_OFFSET], len);
+    data[len+RDS_OFFSET] = 0x00;
+
+    jni_cb->rt_update_cb(data);
+    free(data);
+}
+
+static void hci_ev_af_list(char *buff)
+{
+    struct hci_ev_af_list ev;
+
+    if (buff == NULL) {
+        ALOGE("%s:%s, buffer is null\n", LOG_TAG, __func__);
+        return;
+    }
+    ev.tune_freq = *((int *) &buff[0]);
+    ev.pi_code = *((__le16 *) &buff[PI_CODE_OFFSET]);
+    ev.af_size = buff[AF_SIZE_OFFSET];
+    if (ev.af_size > AF_LIST_MAX) {
+        ALOGE("%s:AF list size received more than available size", LOG_TAG);
+        return;
+    }
+    memcpy(&ev.af_list[0], &buff[AF_LIST_OFFSET],
+                                        ev.af_size * sizeof(int));
+    jni_cb->af_list_update_cb(&ev);
+}
+
+static inline void hci_ev_search_compl(char *buff)
+{
+    if (buff == NULL) {
+        ALOGE("%s:%s,buffer is null\n", LOG_TAG, __func__);
+        return;
+    }
+    radio->search_on = 0;
+    jni_cb->seek_cmpl_cb(radio->fm_st_rsp.station_rsp.station_freq);
+}
+
+static inline void hci_ev_srch_st_list_compl(char *buff)
+{
+    struct hci_ev_srch_list_compl *ev ;
+    int cnt;
+    int stn_num;
+    int rel_freq;
+    int abs_freq;
+    int len;
+
+    if (buff == NULL) {
+        ALOGE("%s:%s, buffer is null\n", LOG_TAG,__func__);
+        return;
+    }
+    ev = malloc(sizeof(*ev));
+    if (!ev) {
+        ALOGE("%s:Memory allocation failed", LOG_TAG);
+        return ;
+    }
+
+    ev->num_stations_found = buff[STN_NUM_OFFSET];
+    len = ev->num_stations_found * PARAMS_PER_STATION + STN_FREQ_OFFSET;
+
+    for(cnt = STN_FREQ_OFFSET, stn_num = 0;
+           (cnt < len) && (stn_num < ev->num_stations_found)
+                      && (stn_num < SIZE_ARRAY(ev->rel_freq));
+            cnt += PARAMS_PER_STATION, stn_num++) {
+
+        abs_freq = *((int *)&buff[cnt]);
+        rel_freq = abs_freq - radio->recv_conf.band_low_limit;
+        rel_freq = (rel_freq * 20) / KHZ_TO_MHZ;
+
+        ev->rel_freq[stn_num].rel_freq_lsb = GET_LSB(rel_freq);
+        ev->rel_freq[stn_num].rel_freq_msb = GET_MSB(rel_freq);
+    }
+
+    len = ev->num_stations_found * 2 + sizeof(ev->num_stations_found);
+    jni_cb->srch_list_cb((char*)ev);
+    free(ev);
+}
+
+static void hci_ev_rt_plus(struct rds_grp_data rds_buf)
+{
+    char tag_type1, tag_type2;
+    char *data = NULL;
+    int len = 0;
+    unsigned short int agt;
+
+    agt = AGT(rds_buf.rdsBlk[1].rdsLsb);
+    /*right most 3 bits of Lsb of block 2
+     * and left most 3 bits of Msb of block 3
+     */
+    tag_type1 = (((agt & TAG1_MSB_MASK) << TAG1_MSB_OFFSET) |
+                 (rds_buf.rdsBlk[2].rdsMsb >> TAG1_LSB_OFFSET));
+
+    /*right most 1 bit of lsb of 3rd block
+     * and left most 5 bits of Msb of 4th block
+     */
+    tag_type2 = (((rds_buf.rdsBlk[2].rdsLsb & TAG2_MSB_MASK) << TAG2_MSB_OFFSET) |
+                 (rds_buf.rdsBlk[3].rdsMsb >> TAG2_LSB_OFFSET));
+
+    if (tag_type1 != DUMMY_CLASS)
+        len += RT_PLUS_LEN_1_TAG;
+    if (tag_type2 != DUMMY_CLASS)
+        len += RT_PLUS_LEN_1_TAG;
+
+    if (len != 0) {
+        len += 2;
+        data = malloc(len);
+    } else {
+        ALOGE("%s:Len is zero\n", LOG_TAG);
+        return ;
+    }
+    if (data != NULL) {
+        data[0] = len;
+        len = 1;
+        data[len++] = rt_ert_flag;
+        if (tag_type1 != DUMMY_CLASS) {
+            data[len++] = tag_type1;
+            /*start position of tag1
+             *right most 5 bits of msb of 3rd block
+             *and left most bit of lsb of 3rd block
+             */
+            data[len++] = (((rds_buf.rdsBlk[2].rdsMsb & TAG1_POS_MSB_MASK)
+                                            << TAG1_POS_MSB_OFFSET)|
+                            (rds_buf.rdsBlk[2].rdsLsb >> TAG1_POS_LSB_OFFSET));
+            /*length of tag1
+             *left most 6 bits of lsb of 3rd block
+             */
+            data[len++] = ((rds_buf.rdsBlk[2].rdsLsb >> TAG1_LEN_OFFSET) &
+                                                         TAG1_LEN_MASK) + 1;
+        }
+        if (tag_type2 != DUMMY_CLASS) {
+            data[len++] = tag_type2;
+            /*start position of tag2
+             *right most 3 bit of msb of 4th block
+             *and left most 3 bits of lsb of 4th block
+             */
+            data[len++] = (((rds_buf.rdsBlk[3].rdsMsb & TAG2_POS_MSB_MASK)
+                                                << TAG2_POS_MSB_OFFSET) |
+                           (rds_buf.rdsBlk[3].rdsLsb >> TAG2_POS_LSB_OFFSET));
+            /*length of tag2
+             *right most 5 bits of lsb of 4th block
+             */
+            data[len++] = (rds_buf.rdsBlk[3].rdsLsb & TAG2_LEN_MASK) + 1;
+        }
+       jni_cb->rt_plus_update_cb(data);
+        free(data);
+    } else {
+        ALOGE("%s:memory allocation failed\n", LOG_TAG);
+    }
+}
+
+static void hci_ev_ert()
+{
+    char *data = NULL;
+
+    if (ert_len <= 0)
+        return;
+    data = malloc(ert_len + 3);
+    if (data != NULL) {
+        data[0] = ert_len;
+        data[1] = utf_8_flag;
+        data[2] = formatting_dir;
+        memcpy((data + 3), ert_buf, ert_len);
+        jni_cb->ert_update_cb(data);
+        free(data);
+    }
+}
+
+static void hci_buff_ert(struct rds_grp_data *rds_buf)
+{
+    int i;
+    unsigned short int info_byte = 0;
+    unsigned short int byte_pair_index;
+
+    if (rds_buf == NULL) {
+        ALOGE("%s:%s, rds buffer is null\n", LOG_TAG, __func__);
+        return;
+    }
+    byte_pair_index = AGT(rds_buf->rdsBlk[1].rdsLsb);
+    if (byte_pair_index == 0) {
+        c_byt_pair_index = 0;
+        ert_len = 0;
+    }
+    if (c_byt_pair_index == byte_pair_index) {
+        c_byt_pair_index++;
+        for (i = 2; i <= 3; i++) {
+             info_byte = rds_buf->rdsBlk[i].rdsLsb;
+             info_byte |= (rds_buf->rdsBlk[i].rdsMsb << 8);
+             ert_buf[ert_len++] = rds_buf->rdsBlk[i].rdsMsb;
+             ert_buf[ert_len++] = rds_buf->rdsBlk[i].rdsLsb;
+             if ((utf_8_flag == 0) && (info_byte == CARRIAGE_RETURN)) {
+                 ert_len -= 2;
+                 break;
+             } else if ((utf_8_flag == 1) &&
+                        (rds_buf->rdsBlk[i].rdsMsb == CARRIAGE_RETURN)) {
+                 info_byte = CARRIAGE_RETURN;
+                 ert_len -= 2;
+                 break;
+             } else if ((utf_8_flag == 1) &&
+                        (rds_buf->rdsBlk[i].rdsLsb == CARRIAGE_RETURN)) {
+                 info_byte = CARRIAGE_RETURN;
+                 ert_len--;
+                 break;
+             }
+        }
+        if ((byte_pair_index == MAX_ERT_SEGMENT) ||
+            (info_byte == CARRIAGE_RETURN)) {
+            hci_ev_ert();
+            c_byt_pair_index = 0;
+            ert_len = 0;
+        }
+    } else {
+        ert_len = 0;
+        c_byt_pair_index = 0;
+    }
+}
+
+static void hci_ev_raw_rds_group_data(char *buff)
+{
+    unsigned char blocknum, index;
+    struct rds_grp_data temp;
+    unsigned int mask_bit;
+    unsigned short int aid, agt, gtc;
+    unsigned short int carrier;
+
+    index = RDSGRP_DATA_OFFSET;
+
+    if (buff == NULL) {
+        ALOGE("%s:%s, socket buffer is null\n", LOG_TAG, __func__);
+        return;
+    }
+
+    for (blocknum = 0; blocknum < RDS_BLOCKS_NUM; blocknum++) {
+         temp.rdsBlk[blocknum].rdsLsb = buff[index];
+         temp.rdsBlk[blocknum].rdsMsb = buff[index+1];
+         index = index + 2;
+    }
+
+    aid = AID(temp.rdsBlk[3].rdsLsb, temp.rdsBlk[3].rdsMsb);
+    gtc = GTC(temp.rdsBlk[1].rdsMsb);
+    agt = AGT(temp.rdsBlk[1].rdsLsb);
+
+    if (gtc == GRP_3A) {
+        switch (aid) {
+        case ERT_AID:
+            /* calculate the grp mask for RDS grp
+             * which will contain actual eRT text
+             *
+             * Bit Pos  0  1  2  3  4   5  6   7
+             * Grp Type 0A 0B 1A 1B 2A  2B 3A  3B
+             *
+             * similary for rest grps
+             */
+             mask_bit = (((agt >> 1) << 1) + (agt & 1));
+             oda_agt = (1 << mask_bit);
+             utf_8_flag = (temp.rdsBlk[2].rdsLsb & 1);
+             formatting_dir = EXTRACT_BIT(temp.rdsBlk[2].rdsLsb,
+                                               ERT_FORMAT_DIR_BIT);
+             if (ert_carrier != agt)
+                 jni_cb->oda_update_cb();
+             ert_carrier = agt;
+             break;
+        case RT_PLUS_AID:
+            /* calculate the grp mask for RDS grp
+             * which will contain actual eRT text
+             *
+             * Bit Pos  0  1  2  3  4   5  6   7
+             * Grp Type 0A 0B 1A 1B 2A  2B 3A  3B
+             *
+             * similary for rest grps
+             */
+             mask_bit = (((agt >> 1) << 1) + (agt & 1));
+             oda_agt =  (1 << mask_bit);
+             /*Extract 5th bit of MSB (b7b6b5b4b3b2b1b0)*/
+             rt_ert_flag = EXTRACT_BIT(temp.rdsBlk[2].rdsMsb,
+                                              RT_ERT_FLAG_BIT);
+             if (rt_plus_carrier != agt)
+                 jni_cb->oda_update_cb();
+             rt_plus_carrier = agt;
+             break;
+        default:
+             oda_agt = 0;
+             break;
+        }
+    } else {
+        carrier = gtc;
+        if ((carrier == rt_plus_carrier))
+             hci_ev_rt_plus(temp);
+        else if (carrier == ert_carrier)
+             hci_buff_ert(&temp);
+    }
+}
+
+void radio_hci_event_packet(char *evt_buf)
+{
+    char evt;
+
+    ALOGE("%s:%s: Received %d bytes of HCI EVENT PKT from Controller", LOG_TAG,
+                                      __func__, ((FM_EVT_HDR *)evt_buf)->evt_len);
+    evt = ((FM_EVT_HDR *)evt_buf)->evt_code;
+    ALOGE("%s:evt: %d", LOG_TAG, evt);
+
+    switch(evt) {
+    case HCI_EV_TUNE_STATUS:
+        hci_ev_tune_status(((FM_EVT_HDR *)evt_buf)->cmd_params);
+        break;
+    case HCI_EV_SEARCH_PROGRESS:
+    case HCI_EV_SEARCH_RDS_PROGRESS:
+    case HCI_EV_SEARCH_LIST_PROGRESS:
+        hci_ev_search_next(((FM_EVT_HDR *)evt_buf)->cmd_params);
+        break;
+    case HCI_EV_STEREO_STATUS:
+        hci_ev_stereo_status(((FM_EVT_HDR *)evt_buf)->cmd_params);
+        break;
+    case HCI_EV_RDS_LOCK_STATUS:
+        hci_ev_rds_lock_status(((FM_EVT_HDR *)evt_buf)->cmd_params);
+        break;
+/*    case HCI_EV_SERVICE_AVAILABLE:
+        hci_ev_service_available(hdev, skb);
+        break; */
+    case HCI_EV_RDS_RX_DATA:
+        hci_ev_raw_rds_group_data(((FM_EVT_HDR *)evt_buf)->cmd_params);
+        break;
+    case HCI_EV_PROGRAM_SERVICE:
+        hci_ev_program_service(((FM_EVT_HDR *)evt_buf)->cmd_params);
+        break;
+    case HCI_EV_RADIO_TEXT:
+        hci_ev_radio_text(((FM_EVT_HDR *)evt_buf)->cmd_params);
+        break;
+    case HCI_EV_FM_AF_LIST:
+        hci_ev_af_list(((FM_EVT_HDR *)evt_buf)->cmd_params);
+        break;
+    case HCI_EV_CMD_COMPLETE:
+        ALOGE("%s:%s: Received HCI_EV_CMD_COMPLETE", LOG_TAG, __func__);
+        hci_cmd_complete_event(((FM_EVT_HDR *)evt_buf)->cmd_params);
+        break;
+    case HCI_EV_CMD_STATUS:
+        hci_cmd_status_event(((FM_EVT_HDR *)evt_buf)->cmd_params);
+        break;
+    case HCI_EV_SEARCH_COMPLETE:
+    case HCI_EV_SEARCH_RDS_COMPLETE:
+        hci_ev_search_compl(((FM_EVT_HDR *)evt_buf)->cmd_params);
+        break;
+    case HCI_EV_SEARCH_LIST_COMPLETE:
+        hci_ev_srch_st_list_compl(((FM_EVT_HDR *)evt_buf)->cmd_params);
+        break;
+    default:
+        break;
+    }
+}
+
+/* 'evt_buf' contains the event received from Controller */
+int fm_evt_notify(char *evt_buf)
+{
+    ALOGI("%s: %s: Received event notification from FM-HCI thread. EVT CODE: %d ",
+                            LOG_TAG,  __func__, ((FM_EVT_HDR *)evt_buf)->evt_code);
+    radio_hci_event_packet(evt_buf);
+    return 0;
+}
+
+int helium_search_req(int on, int direct)
+{
+    int retval = 0;
+    enum search_t srch;
+    int saved_val;
+    int dir;
+
+    srch = radio->g_search_mode & SRCH_MODE;
+    saved_val = radio->search_on;
+    radio->search_on = on;
+    if (direct)
+        dir = SRCH_DIR_UP;
+    else
+        dir = SRCH_DIR_DOWN;
+
+    if (on) {
+        switch (srch) {
+        case SCAN_FOR_STRONG:
+        case SCAN_FOR_WEAK:
+            radio->srch_st_list.srch_list_dir = dir;
+            radio->srch_st_list.srch_list_mode = srch;
+            retval = helium_search_list(&radio->srch_st_list);
+            break;
+        case RDS_SEEK_PTY:
+        case RDS_SCAN_PTY:
+        case RDS_SEEK_PI:
+            srch = srch - SEARCH_RDS_STNS_MODE_OFFSET;
+            radio->srch_rds.srch_station.srch_mode = srch;
+            radio->srch_rds.srch_station.srch_dir = dir;
+            radio->srch_rds.srch_station.scan_time = radio->g_scan_time;
+            retval = helium_search_rds_stations(&radio->srch_rds);
+            break;
+        default:
+            radio->srch_st.srch_mode = srch;
+            radio->srch_st.scan_time = radio->g_scan_time;
+            radio->srch_st.srch_dir = dir;
+            retval = helium_search_stations(&radio->srch_st);
+            break;
+        }
+    } else {
+        retval = helium_cancel_search_req();
+    }
+
+    if (retval < 0)
+        radio->search_on = saved_val;
+    return retval;
+}
+
+int helium_recv_set_region(int req_region)
+{
+    int retval;
+    int saved_val;
+
+    saved_val = radio->region;
+    radio->region = req_region;
+
+    retval = hci_fm_set_recv_conf_req(&radio->recv_conf);
+    if (retval < 0)
+        radio->region = saved_val;
+    return retval;
+}
+
+int set_low_power_mode(int lp_mode)
+{
+    int rds_grps_proc = 0x00;
+    int retval = 0;
+
+    if (radio->power_mode != lp_mode) {
+       if (lp_mode) {
+           radio->event_mask = 0x00;
+           if (radio->af_jump_bit)
+               rds_grps_proc = 0x00 | AF_JUMP_ENABLE;
+           else
+               rds_grps_proc = 0x00;
+           retval = helium_rds_grp_process_req(rds_grps_proc);
+           if (retval < 0) {
+               ALOGE("%s:Disable RDS failed", LOG_TAG);
+               return retval;
+           }
+           retval = helium_set_event_mask_req(&radio->event_mask);
+       } else {
+           radio->event_mask = SIG_LEVEL_INTR | RDS_SYNC_INTR | AUDIO_CTRL_INTR;
+           retval = helium_set_event_mask_req(&radio->event_mask);
+           if (retval < 0) {
+               ALOGE("%s:Enable Async events failed", LOG_TAG);
+               return retval;
+           }
+           retval = helium_rds_grp_process_req(&radio->g_rds_grp_proc_ps);
+       }
+       radio->power_mode = lp_mode;
+    }
+    return retval;
+}
+
+
+/* Callback function to be registered with FM-HCI for event notification */
+static fm_hal_cb hal_cb = {
+    fm_evt_notify
+};
+
+int hal_init( fm_vendor_callbacks_t *p_cb)
+{
+    int ret = -1;
+
+     radio = malloc(sizeof(struct helium_device));
+     if (!radio) {
+         ALOGE("%s:Failed to allocate memory for device", LOG_TAG);
+         return ret;
+     }
+    /* Save the JNI callback functions */
+    jni_cb = p_cb;
+
+    /* Initialize the FM-HCI */
+    ALOGE("%s:%s: Initializing the event notification func with FM-HCI", LOG_TAG, __func__);
+    ret = fm_hci_init(&hal_cb);
+
+    ALOGE("%s:%s: Turning FM ON...", LOG_TAG, __func__);
+    fm_power(FM_RADIO_ENABLE);
+
+    ALOGE("%s:%s: Firmware download and HCI Initialization in-progress...", LOG_TAG, __func__);
+    /* TODO : Start the preload timer */
+    open_serial_port();
+    pthread_mutex_init(&fm_hal, NULL);
+    return 0;
+}
+
+/* Called by the JNI for performing the FM operations */
+static int set_fm_ctrl(int cmd, int val)
+{
+    int ret = 0;
+    int saved_val;
+    char temp_val = 0;
+    unsigned int rds_grps_proc = 0;
+    char *data;
+
+    ALOGE("%s:cmd: %x, val: %d",LOG_TAG, cmd, val);
+    switch (cmd) {
+    case HCI_FM_HELIUM_AUDIO_MUTE:
+        saved_val = radio->mute_mode.hard_mute;
+        radio->mute_mode.hard_mute = val;
+        ret = hci_fm_mute_mode_req(radio->mute_mode);
+        if (ret < 0) {
+            ALOGE("%s:Error while set FM hard mute %d", LOG_TAG, ret);
+            radio->mute_mode.hard_mute = saved_val;
+        }
+        break;
+    case HCI_FM_HELIUM_SRCHMODE:
+            radio->g_search_mode = val;
+        break;
+    case HCI_FM_HELIUM_SCANDWELL:
+            radio->g_scan_time = val;
+        break;
+    case HCI_FM_HELIUM_SRCHON:
+        helium_search_req(val, SRCH_DIR_UP);
+        break;
+    case HCI_FM_HELIUM_STATE:
+        switch (val) {
+        case FM_RECV:
+            ret = hci_fm_enable_recv_req();
+            break;
+        case FM_OFF:
+            radio->mode = FM_TURNING_OFF;
+            hci_fm_disable_recv_req();
+            break;
+        default:
+            break;
+        }
+        break;
+    case HCI_FM_HELIUM_REGION:
+        ret = helium_recv_set_region(val);
+        break;
+    case HCI_FM_HELIUM_SIGNAL_TH:
+        temp_val = val;
+        ret = helium_set_sig_threshold_req(temp_val);
+        if (ret < 0) {
+            ALOGE("%s:Error while setting signal threshold\n", LOG_TAG);
+            goto END;
+        }
+        break;
+    case HCI_FM_HELIUM_SRCH_PTY:
+         radio->srch_rds.srch_pty = val;
+         radio->srch_st_list.srch_pty = val;
+         break;
+    case HCI_FM_HELIUM_SRCH_PI:
+         radio->srch_rds.srch_pi = val;
+         break;
+    case HCI_FM_HELIUM_SRCH_CNT:
+         radio->srch_st_list.srch_list_max = val;
+         break;
+    case HCI_FM_HELIUM_SPACING:
+         saved_val = radio->recv_conf.ch_spacing;
+         radio->recv_conf.ch_spacing = val;
+         ret = hci_fm_set_recv_conf_req(&radio->recv_conf);
+         if (ret < 0) {
+             ALOGE("%s:Error in setting channel spacing", LOG_TAG);
+             radio->recv_conf.ch_spacing = saved_val;
+             goto END;
+        }
+        break;
+    case HCI_FM_HELIUM_EMPHASIS:
+         saved_val = radio->recv_conf.emphasis;
+         radio->recv_conf.emphasis = val;
+         ret = hci_fm_set_recv_conf_req(&radio->recv_conf);
+         if (ret < 0) {
+             ALOGE("%s:Error in setting emphasis", LOG_TAG);
+             radio->recv_conf.emphasis = saved_val;
+             goto END;
+         }
+         break;
+    case HCI_FM_HELIUM_RDS_STD:
+         saved_val = radio->recv_conf.rds_std;
+         radio->recv_conf.rds_std = val;
+         ret = hci_fm_set_recv_conf_req(&radio->recv_conf);
+         if (ret < 0) {
+             ALOGE("%s:Error in rds_std", LOG_TAG);
+             radio->recv_conf.rds_std = saved_val;
+             goto END;
+         }
+         break;
+    case HCI_FM_HELIUM_RDSON:
+         saved_val = radio->recv_conf.rds_std;
+         radio->recv_conf.rds_std = val;
+         ret = hci_fm_set_recv_conf_req(&radio->recv_conf);
+         if (ret < 0) {
+             ALOGE("%s:Error in rds_std", LOG_TAG);
+             radio->recv_conf.rds_std = saved_val;
+             goto END;
+         }
+         break;
+    case HCI_FM_HELIUM_RDSGROUP_MASK:
+         saved_val = radio->rds_grp.rds_grp_enable_mask;
+         grp_mask = (grp_mask | oda_agt | val);
+         radio->rds_grp.rds_grp_enable_mask = grp_mask;
+         radio->rds_grp.rds_buf_size = 1;
+         radio->rds_grp.en_rds_change_filter = 0;
+         ret = helium_rds_grp_mask_req(&radio->rds_grp);
+         if (ret < 0) {
+             ALOGE("%s:error in setting group mask\n", LOG_TAG);
+             radio->rds_grp.rds_grp_enable_mask = saved_val;
+             goto END;
+        }
+        break;
+    case HCI_FM_HELIUM_RDSGROUP_PROC:
+         saved_val = radio->g_rds_grp_proc_ps;
+         rds_grps_proc = radio->g_rds_grp_proc_ps | val;
+         radio->g_rds_grp_proc_ps = (rds_grps_proc >> RDS_CONFIG_OFFSET);
+         ret = helium_rds_grp_process_req(radio->g_rds_grp_proc_ps);
+         if (ret < 0) {
+             radio->g_rds_grp_proc_ps = saved_val;
+             goto END;
+         }
+         break;
+    case HCI_FM_HELIUM_RDSD_BUF:
+         radio->rds_grp.rds_buf_size = val;
+         break;
+    case HCI_FM_HELIUM_PSALL:
+         saved_val = radio->g_rds_grp_proc_ps;
+         rds_grps_proc = (val << RDS_CONFIG_OFFSET);
+         radio->g_rds_grp_proc_ps |= rds_grps_proc;
+         ret = helium_rds_grp_process_req(radio->g_rds_grp_proc_ps);
+         if (ret < 0) {
+             radio->g_rds_grp_proc_ps = saved_val;
+             goto END;
+        }
+        break;
+    case HCI_FM_HELIUM_AF_JUMP:
+        saved_val = radio->g_rds_grp_proc_ps;
+        radio->g_rds_grp_proc_ps &= ~(1 << RDS_AF_JUMP_OFFSET);
+        radio->af_jump_bit = val;
+        rds_grps_proc = 0x00;
+        rds_grps_proc = (val << RDS_AF_JUMP_OFFSET);
+        radio->g_rds_grp_proc_ps |= rds_grps_proc;
+        ret = helium_rds_grp_process_req(radio->g_rds_grp_proc_ps);
+        if (ret < 0) {
+            radio->g_rds_grp_proc_ps = saved_val;
+            goto END;
+        }
+        break;
+    case HCI_FM_HELIUM_LP_MODE:
+         set_low_power_mode(val);
+         break;
+    case HCI_FM_HELIUM_ANTENNA:
+        temp_val = val;
+        ret = helium_set_antenna_req(temp_val);
+        if (ret < 0) {
+            ALOGE("%s:Set Antenna failed retval = %x", LOG_TAG, ret);
+            goto END;
+        }
+        radio->g_antenna =  val;
+        break;
+    case HCI_FM_HELIUM_SOFT_MUTE:
+         saved_val = radio->mute_mode.soft_mute;
+         radio->mute_mode.soft_mute = val;
+         ret = helium_set_fm_mute_mode_req(&radio->mute_mode);
+         if (ret < 0) {
+             ALOGE("%s:Error while setting FM soft mute %d", LOG_TAG, ret);
+             radio->mute_mode.soft_mute = saved_val;
+             goto END;
+         }
+         break;
+    case HCI_FM_HELIUM_FREQ:
+        hci_fm_tune_station_req(val);
+        break;
+    case HCI_FM_HELIUM_SEEK:
+        helium_search_req(1, val);
+        break;
+    case HCI_FM_HELIUM_UPPER_BAND:
+        radio->recv_conf.band_high_limit = val;
+        break;
+    case HCI_FM_HELIUM_LOWER_BAND:
+        radio->recv_conf.band_low_limit = val;
+        break;
+    case HCI_FM_HELIUM_AUDIO_MODE:
+        radio->stereo_mode.stereo_mode = ~val;
+        hci_set_fm_stereo_mode_req(&radio->stereo_mode);
+        break;
+    default:
+        ALOGE("%s:%s: Not a valid FM CMD!!", LOG_TAG, __func__);
+        ret = 0;
+        break;
+    }
+END:
+    if (ret < 0)
+        ALOGE("%s:%s: %d cmd failed", LOG_TAG, __func__, cmd);
+    return ret;
+}
+
+static void get_fm_ctrl(int cmd, int val)
+{
+    int ret = 0;
+
+    switch(cmd) {
+    case HCI_FM_HELIUM_FREQ:
+        val = radio->fm_st_rsp.station_rsp.station_freq;
+        break;
+    case HCI_FM_HELIUM_UPPER_BAND:
+        val = radio->recv_conf.band_high_limit;
+        break;
+    case HCI_FM_HELIUM_LOWER_BAND:
+        val = radio->recv_conf.band_low_limit;
+        break;
+    default:
+        break;
+    }
+    if (ret < 0)
+        ALOGE("%s:%s: %d cmd failed", LOG_TAG, __func__, cmd);
+    return ret;
+}
+
+const fm_interface_t FM_HELIUM_LIB_INTERFACE = {
+    hal_init,
+    set_fm_ctrl,
+    get_fm_ctrl
+};
diff --git a/helium/radio_helium_hal_cmds.c b/helium/radio_helium_hal_cmds.c
new file mode 100644
index 0000000..8e69e4b
--- /dev/null
+++ b/helium/radio_helium_hal_cmds.c
@@ -0,0 +1,256 @@
+/*
+Copyright (c) 2015, 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.
+*/
+
+#include <stdio.h>
+#include <utils/Log.h>
+#include "radio-helium-commands.h"
+#include "radio-helium.h"
+#include "fm_hci.h"
+#include <dlfcn.h>
+#define LOG_TAG "radio_helium"
+
+static int send_fm_cmd_pkt(uint16_t opcode,  uint32_t len, void *param)
+{
+    int p_len = 4 + len;
+    int ret = 0;
+
+//    pthread_mutex_lock(&fm_hal);
+    FM_HDR *hdr = (FM_HDR *) malloc(p_len);
+    if (!hdr) {
+        ALOGE("%s:hdr allocation failed", LOG_TAG);
+        return -1;
+    }
+
+    ALOGE("%s:%s: Sizeof FM_HDR: %d", LOG_TAG, __func__, sizeof(FM_HDR));
+    ALOGE("%s:opcode: %x", LOG_TAG, opcode);
+
+    hdr->protocol_byte = 0x11;
+    hdr->opcode = opcode;
+    hdr->plen = len;
+    if (len)
+        memcpy(hdr->cmd_params, (uint8_t *)param, len);
+    ALOGE("%s:calling transmit", __func__);
+    transmit(hdr);
+    ALOGE("%s:transmit success",__func__);
+    return 0;
+}
+
+int hci_fm_get_signal_threshold()
+{
+
+    FM_HDR *hdr = (FM_HDR *) malloc(sizeof(FM_HDR));
+    hdr->protocol_byte = FM_CMD;
+    hdr->opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ, HCI_OCF_FM_GET_SIGNAL_THRESHOLD);
+    hdr->plen   = 0;
+    transmit(hdr);
+    return 0;
+}
+
+int hci_fm_enable_recv_req()
+{
+    uint16_t opcode = 0;
+
+    opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+                                  HCI_OCF_FM_ENABLE_RECV_REQ);
+    return send_fm_cmd_pkt(opcode, 0, NULL);
+}
+
+int hci_fm_disable_recv_req()
+{
+  uint16_t opcode = 0;
+
+  opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+                                 HCI_OCF_FM_DISABLE_RECV_REQ);
+  return send_fm_cmd_pkt(opcode, 0, NULL);
+}
+
+int  hci_fm_mute_mode_req(struct hci_fm_mute_mode_req *mute)
+{
+    uint16_t opcode = 0;
+    int len = 0;
+    opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+                               HCI_OCF_FM_SET_MUTE_MODE_REQ);
+    len = sizeof(struct hci_fm_mute_mode_req);
+    return send_fm_cmd_pkt(opcode, len, mute);
+}
+
+int helium_search_list(struct hci_fm_search_station_list_req *s_list)
+{
+   uint16_t opcode = 0;
+
+   if (s_list == NULL) {
+       ALOGE("%s:%s, search list param is null\n", LOG_TAG, __func__);
+       return -1;
+   }
+   opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+                HCI_OCF_FM_SEARCH_STATIONS_LIST);
+   return send_fm_cmd_pkt(opcode, sizeof((*s_list)), s_list);
+}
+
+int helium_search_rds_stations(struct hci_fm_search_rds_station_req *rds_srch)
+{
+   uint16_t opcode = 0;
+
+   if (rds_srch == NULL) {
+       ALOGE("%s:%s, rds stations param is null\n", LOG_TAG, __func__);
+       return -1;
+   }
+   opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+                HCI_OCF_FM_SEARCH_RDS_STATIONS);
+   return send_fm_cmd_pkt(opcode, sizeof((*rds_srch)), rds_srch);
+}
+
+int helium_search_stations(struct hci_fm_search_station_req *srch)
+{
+   uint16_t opcode = 0;
+
+   if (srch == NULL) {
+       ALOGE("%s:%s, search station param is null\n", LOG_TAG, __func__);
+       return -1;
+   }
+   opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+                HCI_OCF_FM_SEARCH_STATIONS);
+   return send_fm_cmd_pkt(opcode, sizeof((*srch)), srch);
+}
+
+int helium_cancel_search_req()
+{
+   uint16_t opcode = 0;
+
+   opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+                HCI_OCF_FM_CANCEL_SEARCH);
+   return send_fm_cmd_pkt(opcode, 0, NULL);
+}
+
+int hci_fm_set_recv_conf_req (struct hci_fm_recv_conf_req *conf)
+{
+    uint16_t opcode = 0;
+
+    if (conf == NULL) {
+        ALOGE("%s:%s, recv conf is null\n", LOG_TAG, __func__);
+        return -1;
+    }
+    opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+                              HCI_OCF_FM_SET_RECV_CONF_REQ);
+    return send_fm_cmd_pkt(opcode, sizeof((*conf)), conf);
+}
+
+int helium_set_sig_threshold_req(char th)
+{
+    uint16_t opcode = 0;
+
+    if (th == NULL) {
+        ALOGE("%s:Threshold value NULL", LOG_TAG);
+        return -1;
+    }
+    opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+                               HCI_OCF_FM_SET_SIGNAL_THRESHOLD);
+    return send_fm_cmd_pkt(opcode, sizeof(th), th);
+}
+
+int helium_rds_grp_mask_req(struct hci_fm_rds_grp_req *rds_grp_msk)
+{
+    uint16_t opcode = 0;
+
+    if (rds_grp_msk == NULL) {
+        ALOGE("%s:%s, grp mask param is null\n", LOG_TAG, __func__);
+        return -EINVAL;
+    }
+    opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+                                    HCI_OCF_FM_RDS_GRP);
+    return send_fm_cmd_pkt(opcode, sizeof(*rds_grp_msk), rds_grp_msk);
+}
+
+int helium_rds_grp_process_req(int rds_grp)
+{
+    uint16_t opcode = 0;
+
+    opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+                              HCI_OCF_FM_RDS_GRP_PROCESS);
+    return send_fm_cmd_pkt(opcode, sizeof(rds_grp), &rds_grp);
+}
+
+int helium_set_event_mask_req(char e_mask)
+{
+    uint16_t opcode = 0;
+
+    opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+                          HCI_OCF_FM_SET_EVENT_MASK);
+    return send_fm_cmd_pkt(opcode, sizeof(e_mask), &e_mask);
+}
+
+int helium_set_antenna_req(char ant)
+{
+    uint16_t opcode = 0;
+
+    opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+                                   HCI_OCF_FM_SET_ANTENNA);
+    return send_fm_cmd_pkt(opcode, sizeof(ant), &ant);
+}
+
+int helium_set_fm_mute_mode_req(struct hci_fm_mute_mode_req *mute)
+{
+    uint16_t opcode = 0;
+
+    if (mute == NULL) {
+        ALOGE("%s:%s, mute mode is null\n", LOG_TAG, __func__);
+        return -1;
+    }
+    opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+                               HCI_OCF_FM_SET_MUTE_MODE_REQ);
+    return send_fm_cmd_pkt(opcode, sizeof((*mute)), mute);
+}
+
+int hci_fm_tune_station_req(int param)
+{
+    uint16_t opcode = 0;
+    int tune_freq = param;
+
+    ALOGE("%s:tune_freq: %d", LOG_TAG, tune_freq);
+    opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
+                                  HCI_OCF_FM_TUNE_STATION_REQ);
+    return send_fm_cmd_pkt(opcode, sizeof(tune_freq), &tune_freq);
+}
+
+int hci_set_fm_stereo_mode_req(struct hci_fm_stereo_mode_req *param)
+{
+    uint16_t opcode = 0;
+    struct hci_fm_stereo_mode_req *stereo_mode_req =
+                           (struct hci_fm_stereo_mode_req *) param;
+
+    if (stereo_mode_req == NULL) {
+        ALOGE("%s:%s, stere mode req is null\n", LOG_TAG, __func__);
+        return -1;
+    }
+    opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+                             HCI_OCF_FM_SET_STEREO_MODE_REQ);
+    return send_fm_cmd_pkt(opcode, sizeof((*stereo_mode_req)),
+                                              stereo_mode_req);
+}
+
diff --git a/jni/Android.mk b/jni/Android.mk
index 5bc46d3..b554b40 100644
--- a/jni/Android.mk
+++ b/jni/Android.mk
@@ -10,7 +10,9 @@ ConfigFmThs.cpp \
 FmIoctlsInterface.cpp \
 FmPerformanceParams.cpp
 
+LOCAL_LDLIBS += -ldl
 LOCAL_SHARED_LIBRARIES := \
+        libandroid_runtime \
         libnativehelper \
         libcutils
 
diff --git a/jni/FmConst.h b/jni/FmConst.h
index 00e6f82..8c8d6f4 100644
--- a/jni/FmConst.h
+++ b/jni/FmConst.h
@@ -145,5 +145,13 @@ enum FM_V4L2_PRV_CONTROLS
     V4L2_CID_PRV_IRIS_READ_DEFAULT = V4L2_CTRL_CLASS_USER + 0x928,
     V4L2_CID_PRV_IRIS_WRITE_DEFAULT,
     V4L2_CID_PRV_SET_CALIBRATION = V4L2_CTRL_CLASS_USER + 0x92A,
+    HCI_FM_HELIUM_SET_SPURTABLE = 0x0098092D,
+    HCI_FM_HELIUM_GET_SPUR_TBL  = 0x0098092E,
+    V4L2_CID_PRV_IRIS_FREQ,
+    V4L2_CID_PRV_IRIS_SEEK,
+    V4L2_CID_PRV_IRIS_UPPER_BAND,
+    V4L2_CID_PRV_IRIS_LOWER_BAND,
+    V4L2_CID_PRV_IRIS_AUDIO_MODE,
 };
+
 #endif
diff --git a/jni/android_hardware_fm.cpp b/jni/android_hardware_fm.cpp
index 9eea048..8663bfe 100644
--- a/jni/android_hardware_fm.cpp
+++ b/jni/android_hardware_fm.cpp
@@ -30,20 +30,32 @@
 
 #include "jni.h"
 #include "JNIHelp.h"
-#include "android_runtime/AndroidRuntime.h"
 #include "utils/Log.h"
 #include "utils/misc.h"
 #include "FmIoctlsInterface.h"
 #include "ConfigFmThs.h"
 #include <cutils/properties.h>
 #include <fcntl.h>
+#include <math.h>
 #include <sys/ioctl.h>
 #include <linux/videodev2.h>
-#include <math.h>
+#include <assert.h>
+#include <dlfcn.h>
+#include "android_runtime/Log.h"
+#include "android_runtime/AndroidRuntime.h"
 
 #define RADIO "/dev/radio0"
 #define FM_JNI_SUCCESS 0L
 #define FM_JNI_FAILURE -1L
+
+static JNIEnv *g_jEnv = NULL;
+static JavaVM *g_jVM = NULL;
+
+namespace android {
+char *FM_LIBRARY_NAME = "fm_helium.so";
+char *FM_LIBRARY_SYMBOL_NAME = "FM_HELIUM_LIB_INTERFACE";
+void *lib_handle;
+
 #define SEARCH_DOWN 0
 #define SEARCH_UP 1
 #define HIGH_BAND 2
@@ -74,9 +86,296 @@ enum search_dir_t {
     SCAN_UP,
     SCAN_DN
 };
+typedef void (*enb_result_cb)();
+typedef void (*tune_rsp_cb)(int Freq);
+typedef void (*seek_rsp_cb)(int Freq);
+typedef void (*scan_rsp_cb)();
+typedef void (*srch_list_rsp_cb)(uint16_t *scan_tbl);
+typedef void (*stereo_mode_cb)(bool status);
+typedef void (*rds_avl_sts_cb)(bool status);
+typedef void (*af_list_cb)(uint16_t *af_list);
+typedef void (*rt_cb)(char *rt);
+typedef void (*ps_cb)(char *ps);
+typedef void (*oda_cb)();
+typedef void (*rt_plus_cb)(char *rt_plus);
+typedef void (*ert_cb)(char *ert);
+typedef void (*disable_cb)();
+typedef void (*callback_thread_event)(unsigned int evt);
+
+
+static JNIEnv *mCallbackEnv = NULL;
+static jobject mCallbacksObj = NULL;
+static jfieldID sCallbacksField;
+
+jclass javaClassRef;
+static jmethodID method_psInfoCallback;
+static jmethodID method_rtCallback;
+static jmethodID method_ertCallback;
+static jmethodID method_aflistCallback;
+static jmethodID method_rtplusCallback;
+
+jmethodID method_enableCallback;
+jmethodID method_tuneCallback;
+jmethodID method_seekCmplCallback;
+jmethodID method_scanNxtCallback;
+jmethodID method_srchListCallback;
+jmethodID method_stereostsCallback;
+jmethodID method_rdsAvlStsCallback;
+jmethodID method_disableCallback;
+
+static bool checkCallbackThread() {
+   JNIEnv* env = AndroidRuntime::getJNIEnv();
+   ALOGE("Callback env check fail: env: %p, callback: %p", env, mCallbackEnv);
+   if (mCallbackEnv != env || mCallbackEnv == NULL)
+   {
+       ALOGE("Callback env check fail: env: %p, callback: %p", env, mCallbackEnv);
+       return false;
+   }
+    return true;
+}
 
+void fm_enabled_cb() {
+    ALOGE("Entered %s", __func__);
+    if (mCallbackEnv != NULL) {
+        ALOGE("javaObjectRef creating");
+        jobject javaObjectRef =  mCallbackEnv->NewObject(javaClassRef, method_enableCallback);
+        mCallbacksObj = javaObjectRef;
+        ALOGE("javaObjectRef = %p mCallbackobject =%p \n",javaObjectRef,mCallbacksObj);
+    }
+    ALOGE("exit  %s", __func__);
+}
+
+void fm_tune_cb(int Freq)
+{
+    ALOGE("TUNE:Freq:%d", Freq);
+    mCallbackEnv->CallVoidMethod(mCallbacksObj, method_tuneCallback, (jint) Freq);
+}
+
+void fm_seek_cmpl_cb(int Freq)
+{
+    ALOGE("SEEK_CMPL: Freq: %d", Freq);
+    mCallbackEnv->CallVoidMethod(mCallbacksObj, method_seekCmplCallback, (jint) Freq);
+}
+
+void fm_scan_next_cb()
+{
+    ALOGE("SCAN_NEXT");
+    mCallbackEnv->CallVoidMethod(mCallbacksObj, method_scanNxtCallback);
+}
+
+void fm_srch_list_cb(uint16_t *scan_tbl)
+{
+    ALOGE("SRCH_LIST");
+    //mCallbackEnv->CallVoidMethod(javaObjectRef, method_srchListCallback);
+}
+
+void fm_stereo_status_cb(bool stereo)
+{
+    ALOGE("STEREO: %d", stereo);
+    mCallbackEnv->CallVoidMethod(mCallbacksObj, method_stereostsCallback, (jboolean) stereo);
+}
+
+void fm_rds_avail_status_cb(bool rds_avl)
+{
+    ALOGE("fm_rds_avail_status_cb: %d", rds_avl);
+    mCallbackEnv->CallVoidMethod(mCallbacksObj, method_rdsAvlStsCallback, (jboolean) rds_avl);
+}
+
+void fm_af_list_update_cb(uint16_t *af_list)
+{
+    ALOGE("AF_LIST");
+    jbyteArray af_buffer = NULL;
+
+    if (!checkCallbackThread()) {
+        ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
+        return;
+    }
+
+    af_buffer = mCallbackEnv->NewByteArray(STD_BUF_SIZE);
+    if (af_buffer == NULL) {
+        ALOGE(" af list allocate failed :");
+        return;
+    }
+
+    mCallbackEnv->SetByteArrayRegion(af_buffer, 0, STD_BUF_SIZE,(jbyte *)af_list);
+    mCallbackEnv->CallVoidMethod(mCallbacksObj, method_aflistCallback,af_buffer);
+    mCallbackEnv->DeleteLocalRef(af_buffer);
+}
+
+void fm_rt_update_cb(char *rt)
+{
+    ALOGE("RT_EVT: " );
+    jbyteArray rt_buff = NULL;
+    int i,len;
+
+    if (!checkCallbackThread()) {
+        ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
+        return;
+    }
+
+    len  = (int)(rt[0] & 0x0F);
+    len = len+5;
+
+    ALOGE(" rt data len=%d :",len);
+    rt_buff = mCallbackEnv->NewByteArray(len);
+    if (rt_buff == NULL) {
+        ALOGE(" ps data allocate failed :");
+        return;
+    }
+
+    mCallbackEnv->SetByteArrayRegion(rt_buff, 0, len,(jbyte *)rt);
+    jbyte* bytes= mCallbackEnv->GetByteArrayElements(rt_buff,0);
+
+    mCallbackEnv->CallVoidMethod(mCallbacksObj, method_rtCallback,rt_buff);
+    mCallbackEnv->DeleteLocalRef(rt_buff);
+}
+
+void fm_ps_update_cb(char *ps)
+{
+    jbyteArray ps_data = NULL;
+    int i,len;
+    int numPs;
+    if (!checkCallbackThread()) {
+        ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
+        return;
+    }
+
+    numPs  = (int)(ps[0] & 0x0F);
+    len = (numPs *8)+5;
+
+    ALOGE(" ps data len=%d :",len);
+    ps_data = mCallbackEnv->NewByteArray(len);
+    if(ps_data == NULL) {
+       ALOGE(" ps data allocate failed :");
+       return;
+    }
+
+    mCallbackEnv->SetByteArrayRegion(ps_data, 0, len,(jbyte *)ps);
+    jbyte* bytes= mCallbackEnv->GetByteArrayElements(ps_data,0);
+    mCallbackEnv->CallVoidMethod(mCallbacksObj, method_psInfoCallback,ps_data);
+    mCallbackEnv->DeleteLocalRef(ps_data);
+}
+
+void fm_oda_update_cb()
+{
+    ALOGE("ODA_EVT");
+}
+
+void fm_rt_plus_update_cb(char *rt_plus)
+{
+    jbyteArray RtPlus = NULL;
+    ALOGE("RT_PLUS");
+    int len;
+
+    len =  (int)(rt_plus[0] & 0x0F);
+    ALOGE(" rt plus len=%d :",len);
+    RtPlus = mCallbackEnv->NewByteArray(len);
+    if (RtPlus == NULL) {
+        ALOGE(" rt plus data allocate failed :");
+        return;
+    }
+    mCallbackEnv->SetByteArrayRegion(RtPlus, 0, len,(jbyte *)rt_plus);
+    mCallbackEnv->CallVoidMethod(mCallbacksObj, method_rtplusCallback,RtPlus);
+    mCallbackEnv->DeleteLocalRef(RtPlus);
+}
+
+void fm_ert_update_cb(char *ert)
+{
+    ALOGE("ERT_EVT");
+    jbyteArray ert_buff = NULL;
+    int i,len;
+
+    if (!checkCallbackThread()) {
+        ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
+        return;
+    }
+
+    len = (int)(ert[0] & 0x0F);
+    len = len+3;
+
+    ALOGE(" ert data len=%d :",len);
+    ert_buff = mCallbackEnv->NewByteArray(len);
+    if (ert_buff == NULL) {
+        ALOGE(" ps data allocate failed :");
+        return;
+    }
+
+    mCallbackEnv->SetByteArrayRegion(ert_buff, 0, len,(jbyte *)ert);
+    jbyte* bytes= mCallbackEnv->GetByteArrayElements(ert_buff,0);
+    mCallbackEnv->CallVoidMethod(mCallbacksObj, method_ertCallback,ert_buff);
+    mCallbackEnv->DeleteLocalRef(ert_buff);
+}
+
+void fm_disabled_cb()
+{
+   ALOGE("DISABLE");
+   mCallbackEnv->CallVoidMethod(mCallbacksObj, method_disableCallback);
+}
 
-using namespace android;
+static void fm_thread_evt_cb(unsigned int event) {
+    JavaVM* vm = AndroidRuntime::getJavaVM();
+    if (event  == 0) {
+        JavaVMAttachArgs args;
+        char name[] = "FM Service Callback Thread";
+        args.version = JNI_VERSION_1_6;
+        args.name = name;
+        args.group = NULL;
+       vm->AttachCurrentThread(&mCallbackEnv, &args);
+        ALOGE("satish: Callback thread attached: %p", mCallbackEnv);
+    } else if (event == 1) {
+        if (!checkCallbackThread()) {
+            ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
+            return;
+        }
+        vm->DetachCurrentThread();
+    }
+}
+typedef struct {
+   size_t  size;
+
+   enb_result_cb  enabled_cb;
+   tune_rsp_cb tune_cb;
+   seek_rsp_cb  seek_cmpl_cb;
+   scan_rsp_cb  scan_next_cb;
+   srch_list_rsp_cb  srch_list_cb;
+   stereo_mode_cb  stereo_status_cb;
+   rds_avl_sts_cb  rds_avail_status_cb;
+   af_list_cb  af_list_update_cb;
+   rt_cb  rt_update_cb;
+   ps_cb  ps_update_cb;
+   oda_cb  oda_update_cb;
+   rt_plus_cb  rt_plus_update_cb;
+   ert_cb  ert_update_cb;
+   disable_cb  disabled_cb;
+   callback_thread_event thread_evt_cb;
+} fm_vendor_callbacks_t;
+
+typedef struct {
+    int (*hal_init)(fm_vendor_callbacks_t *p_cb);
+
+    int (*set_fm_ctrl)(int ioctl, int val);
+    int (*get_fm_ctrl) (int ioctl, int val);
+} fm_interface_t;
+
+fm_interface_t *vendor_interface;
+static   fm_vendor_callbacks_t fm_callbacks = {
+    sizeof(fm_callbacks),
+    fm_enabled_cb,
+    fm_tune_cb,
+    fm_seek_cmpl_cb,
+    fm_scan_next_cb,
+    fm_srch_list_cb,
+    fm_stereo_status_cb,
+    fm_rds_avail_status_cb,
+    fm_af_list_update_cb,
+    fm_rt_update_cb,
+    fm_ps_update_cb,
+    fm_oda_update_cb,
+    fm_rt_plus_update_cb,
+    fm_ert_update_cb,
+    fm_disabled_cb,
+    fm_thread_evt_cb
+};
 
 /* native interface */
 static jint android_hardware_fmradio_FmReceiverJNI_acquireFdNative
@@ -178,7 +477,8 @@ static jint android_hardware_fmradio_FmReceiverJNI_getFreqNative
     int err;
     long freq;
 
-    if (fd >= 0) {
+    err = vendor_interface->get_fm_ctrl(V4L2_CID_PRV_IRIS_FREQ, freq);
+/*    if (fd >= 0) {
         err = FmIoctlsInterface :: get_cur_freq(fd, freq);
         if(err < 0) {
            err = FM_JNI_FAILURE;
@@ -190,7 +490,7 @@ static jint android_hardware_fmradio_FmReceiverJNI_getFreqNative
         ALOGE("%s: get freq failed because fd is negative, fd: %d\n",
               LOG_TAG, fd);
         err = FM_JNI_FAILURE;
-    }
+    } */
     return err;
 }
 
@@ -200,7 +500,8 @@ static jint android_hardware_fmradio_FmReceiverJNI_setFreqNative
 {
     int err;
 
-    if ((fd >= 0) && (freq > 0)) {
+    err = vendor_interface->set_fm_ctrl(V4L2_CID_PRV_IRIS_FREQ, freq);
+/*    if ((fd >= 0) && (freq > 0)) {
         err = FmIoctlsInterface :: set_freq(fd, freq);
         if (err < 0) {
             ALOGE("%s: set freq failed, freq: %d\n", LOG_TAG, freq);
@@ -212,7 +513,7 @@ static jint android_hardware_fmradio_FmReceiverJNI_setFreqNative
         ALOGE("%s: set freq failed because either fd/freq is negative,\
               fd: %d, freq: %d\n", LOG_TAG, fd, freq);
         err = FM_JNI_FAILURE;
-    }
+    } */
     return err;
 }
 
@@ -223,7 +524,7 @@ static jint android_hardware_fmradio_FmReceiverJNI_setControlNative
     int err;
     ALOGE("id(%x) value: %x\n", id, value);
 
-    if ((fd >= 0) && (id >= 0)) {
+/*    if ((fd >= 0) && (id >= 0)) {
         err = FmIoctlsInterface :: set_control(fd, id, value);
         if (err < 0) {
             ALOGE("%s: set control failed, id: %d\n", LOG_TAG, id);
@@ -235,7 +536,8 @@ static jint android_hardware_fmradio_FmReceiverJNI_setControlNative
         ALOGE("%s: set control failed because either fd/id is negavtive,\
                fd: %d, id: %d\n", LOG_TAG, fd, id);
         err = FM_JNI_FAILURE;
-    }
+    } */
+    err = vendor_interface->set_fm_ctrl(id, value);
 
     return err;
 }
@@ -271,7 +573,14 @@ static jint android_hardware_fmradio_FmReceiverJNI_getControlNative
 
     ALOGE("id(%x)\n", id);
 
-    if ((fd >= 0) && (id >= 0)) {
+    err = vendor_interface->get_fm_ctrl(id, val);
+    if (err < 0) {
+        ALOGE("%s: get control failed, id: %d\n", LOG_TAG, id);
+        err = FM_JNI_FAILURE;
+    } else {
+        err = val;
+    }
+/*    if ((fd >= 0) && (id >= 0)) {
         err = FmIoctlsInterface :: get_control(fd, id, val);
         if (err < 0) {
             ALOGE("%s: get control failed, id: %d\n", LOG_TAG, id);
@@ -283,7 +592,7 @@ static jint android_hardware_fmradio_FmReceiverJNI_getControlNative
         ALOGE("%s: get control failed because either fd/id is negavtive,\
                fd: %d, id: %d\n", LOG_TAG, fd, id);
         err = FM_JNI_FAILURE;
-    }
+    } */
 
     return err;
 }
@@ -294,7 +603,14 @@ static jint android_hardware_fmradio_FmReceiverJNI_startSearchNative
 {
     int err;
 
-    if ((fd >= 0) && (dir >= 0)) {
+    err = vendor_interface->set_fm_ctrl(V4L2_CID_PRV_IRIS_SEEK, dir);
+    if (err < 0) {
+        ALOGE("%s: search failed, dir: %d\n", LOG_TAG, dir);
+        err = FM_JNI_FAILURE;
+    } else {
+        err = FM_JNI_SUCCESS;
+    }
+/*    if ((fd >= 0) && (dir >= 0)) {
         ALOGD("startSearchNative: Issuing the VIDIOC_S_HW_FREQ_SEEK");
         err = FmIoctlsInterface :: start_search(fd, dir);
         if (err < 0) {
@@ -307,7 +623,7 @@ static jint android_hardware_fmradio_FmReceiverJNI_startSearchNative
         ALOGE("%s: search failed because either fd/dir is negative,\
                fd: %d, dir: %d\n", LOG_TAG, fd, dir);
         err = FM_JNI_FAILURE;
-    }
+    } */
 
     return err;
 }
@@ -318,7 +634,14 @@ static jint android_hardware_fmradio_FmReceiverJNI_cancelSearchNative
 {
     int err;
 
-    if (fd >= 0) {
+    err = vendor_interface->set_fm_ctrl(V4L2_CID_PRV_SRCHON, 0);
+    if (err < 0) {
+        ALOGE("%s: cancel search failed\n", LOG_TAG);
+        err = FM_JNI_FAILURE;
+    } else {
+        err = FM_JNI_SUCCESS;
+    }
+/*    if (fd >= 0) {
         err = FmIoctlsInterface :: set_control(fd, V4L2_CID_PRV_SRCHON, 0);
         if (err < 0) {
             ALOGE("%s: cancel search failed\n", LOG_TAG);
@@ -330,7 +653,7 @@ static jint android_hardware_fmradio_FmReceiverJNI_cancelSearchNative
         ALOGE("%s: cancel search failed because fd is negative, fd: %d\n",
                LOG_TAG, fd);
         err = FM_JNI_FAILURE;
-    }
+    } */
 
     return err;
 }
@@ -365,7 +688,20 @@ static jint android_hardware_fmradio_FmReceiverJNI_setBandNative
 {
     int err;
 
-    if ((fd >= 0) && (low >= 0) && (high >= 0)) {
+    err = vendor_interface->set_fm_ctrl(V4L2_CID_PRV_IRIS_UPPER_BAND, high);
+    if (err < 0) {
+        ALOGE("%s: set band failed, high: %d\n", LOG_TAG, high);
+        err = FM_JNI_FAILURE;
+        return err;
+    }
+    err = vendor_interface->set_fm_ctrl(V4L2_CID_PRV_IRIS_LOWER_BAND, low);
+    if (err < 0) {
+        ALOGE("%s: set band failed, low: %d\n", LOG_TAG, low);
+        err = FM_JNI_FAILURE;
+    } else {
+        err = FM_JNI_SUCCESS;
+    }
+/*    if ((fd >= 0) && (low >= 0) && (high >= 0)) {
         err = FmIoctlsInterface :: set_band(fd, low, high);
         if (err < 0) {
             ALOGE("%s: set band failed, low: %d, high: %d\n",
@@ -378,7 +714,7 @@ static jint android_hardware_fmradio_FmReceiverJNI_setBandNative
         ALOGE("%s: set band failed because either fd/band is negative,\
                fd: %d, low: %d, high: %d\n", LOG_TAG, fd, low, high);
         err = FM_JNI_FAILURE;
-    }
+    } */
 
     return err;
 }
@@ -390,7 +726,14 @@ static jint android_hardware_fmradio_FmReceiverJNI_getLowerBandNative
     int err;
     ULINT freq;
 
-    if (fd >= 0) {
+    err = vendor_interface->get_fm_ctrl(V4L2_CID_PRV_IRIS_LOWER_BAND, freq);
+    if (err < 0) {
+        ALOGE("%s: get lower band failed\n", LOG_TAG);
+        err = FM_JNI_FAILURE;
+    } else {
+        err = freq;
+    }
+/*    if (fd >= 0) {
         err = FmIoctlsInterface :: get_lowerband_limit(fd, freq);
         if (err < 0) {
             ALOGE("%s: get lower band failed\n", LOG_TAG);
@@ -402,7 +745,7 @@ static jint android_hardware_fmradio_FmReceiverJNI_getLowerBandNative
         ALOGE("%s: get lower band failed because fd is negative,\
                fd: %d\n", LOG_TAG, fd);
         err = FM_JNI_FAILURE;
-    }
+    } */
 
     return err;
 }
@@ -414,7 +757,14 @@ static jint android_hardware_fmradio_FmReceiverJNI_getUpperBandNative
     int err;
     ULINT freq;
 
-    if (fd >= 0) {
+    err = vendor_interface->get_fm_ctrl(V4L2_CID_PRV_IRIS_UPPER_BAND, freq);
+    if (err < 0) {
+        ALOGE("%s: get upper band failed\n", LOG_TAG);
+        err = FM_JNI_FAILURE;
+    } else {
+        err = freq;
+    }
+/*    if (fd >= 0) {
         err = FmIoctlsInterface :: get_upperband_limit(fd, freq);
         if (err < 0) {
             ALOGE("%s: get lower band failed\n", LOG_TAG);
@@ -426,7 +776,7 @@ static jint android_hardware_fmradio_FmReceiverJNI_getUpperBandNative
         ALOGE("%s: get lower band failed because fd is negative,\
                fd: %d\n", LOG_TAG, fd);
         err = FM_JNI_FAILURE;
-    }
+    } */
 
     return err;
 }
@@ -437,7 +787,14 @@ static jint android_hardware_fmradio_FmReceiverJNI_setMonoStereoNative
 
     int err;
 
-    if (fd >= 0) {
+    err = vendor_interface->get_fm_ctrl(V4L2_CID_PRV_IRIS_AUDIO_MODE, val);
+    if (err < 0) {
+        ALOGE("%s: set audio mode failed\n", LOG_TAG);
+        err = FM_JNI_FAILURE;
+    } else {
+        err = FM_JNI_SUCCESS;
+    }
+/*    if (fd >= 0) {
         err = FmIoctlsInterface :: set_audio_mode(fd, (enum AUDIO_MODE)val);
         if (err < 0) {
             err = FM_JNI_FAILURE;
@@ -446,7 +803,7 @@ static jint android_hardware_fmradio_FmReceiverJNI_setMonoStereoNative
         }
     } else {
         err = FM_JNI_FAILURE;
-    }
+    } */
 
     return err;
 }
@@ -927,11 +1284,83 @@ static jint android_hardware_fmradio_FmReceiverJNI_setSpurDataNative
     return FM_JNI_SUCCESS;
 }
 
+static void classInitNative(JNIEnv* env, jclass clazz) {
+
+    ALOGE("ClassInit native called \n");
+    jclass dataClass = env->FindClass("qcom/fmradio/FmReceiverJNI");
+    javaClassRef = (jclass) env->NewGlobalRef(dataClass);
+    lib_handle = dlopen(FM_LIBRARY_NAME, RTLD_NOW);
+    if (!lib_handle) {
+        ALOGE("%s unable to open %s: %s", __func__, FM_LIBRARY_NAME, dlerror());
+        goto error;
+    }
+    ALOGE("Opened %s shared object library successfully", FM_LIBRARY_NAME);
+
+    ALOGI("Obtaining handle: '%s' to the shared object library...", FM_LIBRARY_SYMBOL_NAME);
+    vendor_interface = (fm_interface_t *)dlsym(lib_handle, FM_LIBRARY_SYMBOL_NAME);
+    if (!vendor_interface) {
+        ALOGE("%s unable to find symbol %s in %s: %s", __func__, FM_LIBRARY_SYMBOL_NAME, FM_LIBRARY_NAME, dlerror());
+        goto error;
+    }
+
+    method_psInfoCallback = env->GetMethodID(javaClassRef, "PsInfoCallback", "([B)V");
+    method_rtCallback = env->GetMethodID(javaClassRef, "RtCallback", "([B)V");
+    method_ertCallback = env->GetMethodID(javaClassRef, "ErtCallback", "([B)V");
+    method_rtplusCallback = env->GetMethodID(javaClassRef, "RtPlusCallback", "([B)V");
+    method_aflistCallback = env->GetMethodID(javaClassRef, "AflistCallback", "([B)V");
+    ALOGI("method_psInfoCallback: '%p' env =%p...", method_psInfoCallback, env);
+    method_enableCallback = env->GetMethodID(javaClassRef, "enableCallback", "()V");
+    method_tuneCallback = env->GetMethodID(javaClassRef, "tuneCallback", "(I)V");
+    method_seekCmplCallback = env->GetMethodID(javaClassRef, "seekCmplCallback", "(I)V");
+    method_scanNxtCallback = env->GetMethodID(javaClassRef, "scanNxtCallback", "()V");
+    //method_srchListCallback = env->GetMethodID(javaClassRef, "srchListCallback", "([B)V");
+    method_stereostsCallback = env->GetMethodID(javaClassRef, "stereostsCallback", "(Z)V");
+    method_rdsAvlStsCallback = env->GetMethodID(javaClassRef, "rdsAvlStsCallback", "(Z)V");
+    method_disableCallback = env->GetMethodID(javaClassRef, "disableCallback", "()V");
+
+    return;
+error:
+    vendor_interface = NULL;
+    if (lib_handle)
+        dlclose(lib_handle);
+    lib_handle = NULL;
+}
+
+static void initNative(JNIEnv *env, jobject object) {
+
+    int status;
+    ALOGE("Init native called \n");
+
+    if (vendor_interface) {
+        ALOGE("Initializing the FM HAL module & registering the JNI callback functions...");
+        status = vendor_interface->hal_init(&fm_callbacks);
+        if (status) {
+            ALOGE("%s unable to initialize vendor library: %d", __func__, status);
+            return;
+        }
+        ALOGE("***** FM HAL Initialization complete *****\n");
+    }
+    ALOGE("object =%p, env = %p\n",object,env);
+    mCallbacksObj = env->NewGlobalRef(object);
+    ALOGE("mCallbackobject =%p, \n",mCallbacksObj);
+
+
+}
+static void cleanupNative(JNIEnv *env, jobject object) {
+
+    if (mCallbacksObj != NULL) {
+        env->DeleteGlobalRef(mCallbacksObj);
+        mCallbacksObj = NULL;
+    }
+}
 /*
  * JNI registration.
  */
 static JNINativeMethod gMethods[] = {
         /* name, signature, funcPtr */
+        { "classInitNative", "()V", (void*)classInitNative},
+        { "initNative", "()V", (void*)initNative},
+        {"cleanupNative", "()V", (void *) cleanupNative},
         { "acquireFdNative", "(Ljava/lang/String;)I",
             (void*)android_hardware_fmradio_FmReceiverJNI_acquireFdNative},
         { "closeFdNative", "(I)I",
@@ -996,21 +1425,24 @@ int register_android_hardware_fm_fmradio(JNIEnv* env)
 {
         return jniRegisterNativeMethods(env, "qcom/fmradio/FmReceiverJNI", gMethods, NELEM(gMethods));
 }
+} // end namespace
+
 
 jint JNI_OnLoad(JavaVM *jvm, void *reserved)
 {
-  JNIEnv *e;
-  int status;
-   ALOGE("FM : loading QCOMM FM-JNI\n");
-  
-   if(jvm->GetEnv((void **)&e, JNI_VERSION_1_6)) {
-       ALOGE("JNI version mismatch error");
-      return JNI_ERR;
-   }
+    JNIEnv *e;
+    int status;
+    g_jVM = jvm;
+
+    ALOGE("FM : Loading QCOMM FM-JNI");
+    if (jvm->GetEnv((void **)&e, JNI_VERSION_1_6)) {
+        ALOGE("JNI version mismatch error");
+        return JNI_ERR;
+    }
 
-   if ((status = register_android_hardware_fm_fmradio(e)) < 0) {
-       ALOGE("jni adapter service registration failure, status: %d", status);
-      return JNI_ERR;
-   }
-   return JNI_VERSION_1_6;
+    if ((status = android::register_android_hardware_fm_fmradio(e)) < 0) {
+        ALOGE("jni adapter service registration failure, status: %d", status);
+        return JNI_ERR;
+    }
+    return JNI_VERSION_1_6;
 }
diff --git a/qcom/fmradio/FmReceiver.java b/qcom/fmradio/FmReceiver.java
index 732c0b2..a52a233 100644
--- a/qcom/fmradio/FmReceiver.java
+++ b/qcom/fmradio/FmReceiver.java
@@ -30,7 +30,8 @@ package qcom.fmradio;
 
 import android.util.Log;
 import android.os.SystemProperties;
-
+import java.util.Arrays;
+import java.lang.Runnable;
 /**
  * This class contains all interfaces and types needed to
  * Control the FM receiver.
@@ -271,7 +272,9 @@ public class FmReceiver extends FmTransceiver
    private static final int TAVARUA_BUF_AF_LIST=5;
    private static final int TAVARUA_BUF_MAX=6;
 
-   private FmRxEvCallbacksAdaptor mCallback;
+   public static FmRxEvCallbacksAdaptor mCallback;
+   static FmRxEvCallbacks callback;
+   static FmReceiverJNI mFmReceiverJNI;
   /**
     *  Internal Constants for Signal thresholds
     *
@@ -323,8 +326,12 @@ public class FmReceiver extends FmTransceiver
       mControl = new FmRxControls();
       mRxEvents = new FmRxEventListner();
 
+      Log.e(TAG, "FmReceiver constructor");
       //registerClient(callback);
       mCallback = callback;
+     if (mCallback == null)
+         Log.e(TAG, "mCallback is NULL");
+      mFmReceiverJNI = new FmReceiverJNI(mCallback);
    }
 
 
@@ -454,7 +461,7 @@ public class FmReceiver extends FmTransceiver
 
       if( status == true ) {
          /* Do Receiver Specific Enable Stuff here.*/
-         status = registerClient(mCallback);
+        // status = registerClient(mCallback);
          mRdsData = new FmRxRdsData(sFd);
       }
       else {
@@ -1398,16 +1405,20 @@ public class FmReceiver extends FmTransceiver
       int piLower = 0;
       int piHigher = 0;
 
-      FmReceiverJNI.getBufferNative(sFd, buff, 3);
+     // FmReceiverJNI.getBufferNative(sFd, buff, 3);
+      buff = FmReceiverJNI.getPsBuffer(buff);
+
       /* byte is signed ;(
       *  knock down signed bits
       */
       piLower = buff[3] & 0xFF;
       piHigher = buff[2] & 0xFF;
       int pi = ((piHigher << 8) | piLower);
+      Log.d (TAG, "PI= " + pi);
       mRdsData.setPrgmId (pi);
       mRdsData.setPrgmType ( (int)( buff[1] & 0x1F));
       int numOfPs = (int)(buff[0] & 0x0F);
+      Log.d (TAG, "numofpsI= " + numOfPs);
       try
       {
 
@@ -1448,7 +1459,8 @@ public class FmReceiver extends FmTransceiver
       int piLower = 0;
       int piHigher = 0;
 
-      FmReceiverJNI.getBufferNative(sFd, buff, 2);
+     // FmReceiverJNI.getBufferNative(sFd, buff, 2);
+      buff = FmReceiverJNI.getPsBuffer(buff);
       String rdsStr = new String(buff);
       /* byte is signed ;(
       *  knock down signed bit
@@ -1478,7 +1490,9 @@ public class FmReceiver extends FmTransceiver
       int i, j = 2;
       byte tag_code, tag_len, tag_start_pos;
 
-      bytes_read = FmReceiverJNI.getBufferNative(sFd, rt_plus, BUF_RTPLUS);
+//      bytes_read = FmReceiverJNI.getBufferNative(sFd, rt_plus, BUF_RTPLUS);
+      rt_plus = FmReceiverJNI.getPsBuffer(rt_plus);
+      bytes_read = rt_plus[0];
       if (bytes_read > 0) {
           if (rt_plus[RT_OR_ERT_IND] == 0)
               rt = mRdsData.getRadioText();
@@ -1514,7 +1528,9 @@ public class FmReceiver extends FmTransceiver
       String encoding_type = "UCS-2";
       int bytes_read;
 
-      bytes_read = FmReceiverJNI.getBufferNative(sFd, raw_ert, BUF_ERT);
+  //    bytes_read = FmReceiverJNI.getBufferNative(sFd, raw_ert, BUF_ERT);
+     raw_ert = FmReceiverJNI.getPsBuffer(raw_ert);
+      bytes_read = raw_ert[0];
       if (bytes_read > 0) {
           ert_text = new byte[raw_ert[LEN_IND]];
           for(i = 3; (i - 3) < raw_ert[LEN_IND]; i++) {
@@ -1581,7 +1597,8 @@ public class FmReceiver extends FmTransceiver
       int lowerBand, i;
       int tunedFreq, PI, size_AFLIST;
 
-      FmReceiverJNI.getBufferNative(sFd, buff, TAVARUA_BUF_AF_LIST);
+    // FmReceiverJNI.getBufferNative(sFd, buff, TAVARUA_BUF_AF_LIST);
+      buff = FmReceiverJNI.getPsBuffer(buff);
 
       if (IsSmdTransportLayer() || IsRomeChip()) {
           Log.d(TAG, "SMD transport layer or Rome chip");
diff --git a/qcom/fmradio/FmReceiverJNI.java b/qcom/fmradio/FmReceiverJNI.java
index c6ca964..8a2be0f 100644
--- a/qcom/fmradio/FmReceiverJNI.java
+++ b/qcom/fmradio/FmReceiverJNI.java
@@ -27,6 +27,10 @@
  */
 
 package qcom.fmradio;
+import android.util.Log;
+import java.util.Arrays;
+import java.lang.Runnable;
+import qcom.fmradio.FmReceiver;
 
 class FmReceiverJNI {
     /**
@@ -44,8 +48,175 @@ class FmReceiverJNI {
      * @return The file descriptor of the device
      *
      */
-    static native int acquireFdNative(String path);
+      private static final String TAG = "FmReceiverJNI";
+
+    static {
+        Log.e(TAG, "classinit native called");
+        classInitNative();
+    }
+    static native void classInitNative();
+    static native void initNative();
+    static native void cleanupNative();
+
+    final private FmRxEvCallbacks mCallback;
+    static private final int STD_BUF_SIZE = 256;
+    static private byte[] mRdsBuffer = new byte[STD_BUF_SIZE];
+
+    public static  byte[]  getPsBuffer(byte[] buff) {
+        Log.e(TAG, "getPsBuffer enter");
+        buff = Arrays.copyOf(mRdsBuffer, mRdsBuffer.length);
+        Log.e(TAG, "getPsBuffer exit");
+        return buff;
+    }
+
+    public void AflistCallback(byte[] aflist) {
+        Log.e(TAG, "AflistCallback enter " );
+        if (aflist == null) {
+            Log.e(TAG, "aflist null return  ");
+            return;
+        }
+        mRdsBuffer = Arrays.copyOf(aflist, aflist.length);
+        FmReceiver.mCallback.FmRxEvRdsAfInfo();
+        Log.e(TAG, "AflistCallback exit " );
+    }
+
+    public void RtPlusCallback(byte[] rtplus) {
+        Log.e(TAG, "RtPlusCallback enter " );
+        if (rtplus == null) {
+            Log.e(TAG, "psInfo null return  ");
+            return;
+        }
+        mRdsBuffer = Arrays.copyOf(rtplus, rtplus.length);
+        FmReceiver.mCallback.FmRxEvRTPlus();
+        Log.e(TAG, "RtPlusCallback exit " );
+    }
+
+    public void RtCallback(byte[] rt) {
+        Log.e(TAG, "RtCallback enter " );
+        if (rt == null) {
+            Log.e(TAG, "psInfo null return  ");
+            return;
+        }
+        mRdsBuffer = Arrays.copyOf(rt, rt.length);
+        FmReceiver.mCallback.FmRxEvRdsRtInfo();
+        Log.e(TAG, "RtCallback exit " );
+    }
+
+    public void ErtCallback(byte[] ert) {
+        Log.e(TAG, "ErtCallback enter " );
+        if (ert == null) {
+            Log.e(TAG, "ERT null return  ");
+            return;
+        }
+        mRdsBuffer = Arrays.copyOf(ert, ert.length);
+        FmReceiver.mCallback.FmRxEvERTInfo();
+        Log.e(TAG, "RtCallback exit " );
+    }
+
+    public void PsInfoCallback(byte[] psInfo) {
+        Log.e(TAG, "PsInfoCallback enter " );
+        if (psInfo == null) {
+            Log.e(TAG, "psInfo null return  ");
+            return;
+        }
+        Log.e(TAG, "length =  " +psInfo.length);
+        mRdsBuffer = Arrays.copyOf(psInfo, psInfo.length);
+        FmReceiver.mCallback.FmRxEvRdsPsInfo();
+        Log.e(TAG, "PsInfoCallback exit");
+    }
+
+    public void enableCallback() {
+        Log.e(TAG, "enableCallback enter");
+        FmTransceiver.setFMPowerState(FmTransceiver.FMState_Rx_Turned_On);
+        Log.v(TAG, "RxEvtList: CURRENT-STATE : FMRxStarting ---> NEW-STATE : FMRxOn");
+        FmReceiver.mCallback.FmRxEvEnableReceiver();
+        Log.e(TAG, "enableCallback exit");
+    }
 
+    public void tuneCallback(int freq) {
+        int state;
+
+        Log.e(TAG, "tuneCallback enter");
+        state = FmReceiver.getSearchState();
+        switch(state) {
+        case FmTransceiver.subSrchLevel_SrchAbort:
+            Log.v(TAG, "Current state is SRCH_ABORTED");
+            Log.v(TAG, "Aborting on-going search command...");
+            /* intentional fall through */
+        case FmTransceiver.subSrchLevel_SeekInPrg :
+            Log.v(TAG, "Current state is " + state);
+            FmReceiver.setSearchState(FmTransceiver.subSrchLevel_SrchComplete);
+            Log.v(TAG, "RxEvtList: CURRENT-STATE : Search ---> NEW-STATE : FMRxOn");
+            FmReceiver.mCallback.FmRxEvSearchComplete(freq);
+            break;
+        default:
+            if (freq > 0)
+                FmReceiver.mCallback.FmRxEvRadioTuneStatus(freq);
+            else
+                Log.e(TAG, "get frequency command failed");
+            break;
+        }
+        Log.e(TAG, "tuneCallback exit");
+    }
+
+    public void seekCmplCallback(int freq) {
+        int state;
+
+        Log.e(TAG, "seekCmplCallback enter");
+        state = FmReceiver.getSearchState();
+        switch(state) {
+        case FmTransceiver.subSrchLevel_ScanInProg:
+            Log.v(TAG, "Current state is " + state);
+            FmReceiver.setSearchState(FmTransceiver.subSrchLevel_SrchComplete);
+            Log.v(TAG, "RxEvtList: CURRENT-STATE : Search ---> NEW-STATE :FMRxOn");
+            FmReceiver.mCallback.FmRxEvSearchComplete(freq);
+            break;
+        case FmTransceiver.subSrchLevel_SrchAbort:
+            Log.v(TAG, "Current state is SRCH_ABORTED");
+            Log.v(TAG, "Aborting on-going search command...");
+            FmReceiver.setSearchState(FmTransceiver.subSrchLevel_SrchComplete);
+            Log.v(TAG, "RxEvtList: CURRENT-STATE : Search ---> NEW-STATE : FMRxOn");
+            FmReceiver.mCallback.FmRxEvSearchComplete(freq);
+            break;
+        }
+        Log.e(TAG, "seekCmplCallback exit");
+    }
+
+    public void scanNxtCallback() {
+        Log.e(TAG, "scanNxtCallback enter");
+        FmReceiver.mCallback.FmRxEvSearchInProgress();
+        Log.e(TAG, "scanNxtCallback exit");
+    }
+
+    public void stereostsCallback(boolean stereo) {
+        Log.e(TAG, "stereostsCallback enter");
+        FmReceiver.mCallback.FmRxEvStereoStatus (stereo);
+        Log.e(TAG, "stereostsCallback exit");
+    }
+
+    public void rdsAvlStsCallback(boolean rdsAvl) {
+        Log.e(TAG, "rdsAvlStsCallback enter");
+        FmReceiver.mCallback.FmRxEvRdsLockStatus(rdsAvl);
+        Log.e(TAG, "rdsAvlStsCallback exit");
+    }
+
+    public void disableCallback() {
+        Log.e(TAG, "disableCallback enter");
+        FmTransceiver.setFMPowerState(FmTransceiver.FMState_Turned_Off);
+        Log.v(TAG, "RxEvtList: CURRENT-STATE : FMTurningOff ---> NEW-STATE : FMOff");
+        FmReceiver.mCallback.FmRxEvDisableReceiver();
+        Log.e(TAG, "disableCallback exit");
+    }
+
+    public FmReceiverJNI(FmRxEvCallbacks callback) {
+        mCallback = callback;
+        if (mCallback == null)
+            Log.e(TAG, "mCallback is null in JNI");
+        Log.e(TAG, "satish init native called");
+        initNative();
+    }
+
+    static native int acquireFdNative(String path);
 
     /**
      * native method:
diff --git a/qcom/fmradio/FmTransceiver.java b/qcom/fmradio/FmTransceiver.java
index b39fd7a..a567152 100644
--- a/qcom/fmradio/FmTransceiver.java
+++ b/qcom/fmradio/FmTransceiver.java
@@ -405,9 +405,9 @@ public class FmTransceiver
       boolean status;
       int ret;
       //Acquire the deviceon Enable
-      if( !acquire("/dev/radio0")){
-         return false;
-      }
+//      if( !acquire("/dev/radio0")){
+//         return false;
+//      }
       if (new File("/etc/fm/SpurTableFile.txt").isFile()) {
           Log.d(TAG, "Send Spur roation table");
           FmConfig.fmSpurConfig(sFd);
-- 
GitLab