Revert "FM: Remove Ioctl base code"

This reverts commit 5156eb1ae2b6a385ccfee8a1ddadf5811dce8f82.

Change-Id: I68fb8a81cadde7a49d83f9189d592e88d1b35ba8
diff --git a/fm_hci/fm_hci.c b/fm_hci/fm_hci.c
new file mode 100644
index 0000000..ff932b9
--- /dev/null
+++ b/fm_hci/fm_hci.c
@@ -0,0 +1,808 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "fm_hci_helium"
+
+#include <assert.h>
+#include <utils/Log.h>
+
+#include "bt_hci_bdroid.h"
+#include "bt_vendor_lib.h"
+#include "userial.h"
+#include "fm_hci.h"
+#include "wcnss_hci.h"
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <cutils/sockets.h>
+#include <pthread.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <cutils/properties.h>
+#include <signal.h>
+
+static int fm_hal_fd =0;
+
+#define FM_VND_SERVICE_START "wc_transport.start_fmhci"
+#define WAIT_TIMEOUT 200000 /* 200*1000us */
+
+static void fm_hci_exit(void *arg);
+static int power(struct fm_hci_t *hci, fm_power_state_t state);
+
+static void event_notification(struct fm_hci_t *hci, uint16_t event)
+{
+    pthread_mutex_lock(&hci->event_lock);
+    ALOGI("%s: Notifying worker thread with event: %d", __func__, event);
+    ready_events |= event;
+    pthread_cond_broadcast(&hci->event_cond);
+    pthread_mutex_unlock(&hci->event_lock);
+}
+
+static void rx_thread_exit_handler(int sig)
+{
+    ALOGD("%s: sig = 0x%x", __func__, sig);
+    if (sig == SIGUSR1) {
+    ALOGE("Got the signal.. exiting");
+    pthread_exit(NULL);
+    }
+}
+
+static int vendor_init(struct fm_hci_t *hci)
+{
+    void *dlhandle = hci->dlhandle = NULL;
+    unsigned char bdaddr[] = {0xaa, 0xbb, 0xcc, 0x11, 0x22, 0x33};
+
+    dlhandle = dlopen("libbt-vendor.so", RTLD_NOW);
+    if (!dlhandle) {
+        ALOGE("!!! Failed to load libbt-vendor.so !!!");
+        goto err;
+    }
+
+    hci->vendor = (bt_vendor_interface_t *) dlsym(dlhandle, "BLUETOOTH_VENDOR_LIB_INTERFACE");
+    if (!hci->vendor) {
+        ALOGE("!!! Failed to get bt vendor interface !!!");
+        goto err;
+    }
+
+    ALOGI("FM-HCI: Registering the WCNSS HAL library by passing CBs and BD addr.");
+    if (hci->vendor->init(&fm_vendor_callbacks, bdaddr) !=
+                FM_HC_STATUS_SUCCESS) {
+        ALOGE("FM vendor interface init failed");
+        goto err;
+    }
+
+    return FM_HC_STATUS_SUCCESS;
+
+err:
+    return FM_HC_STATUS_FAIL;
+}
+
+static void vendor_close(struct fm_hci_t *hci)
+{
+    void *dlhandle = hci->dlhandle;
+
+    if (hci->vendor)
+        hci->vendor->cleanup();
+    if (dlhandle) {
+        dlclose(dlhandle);
+        dlhandle = NULL;
+    }
+    hci->vendor = NULL;
+}
+
+/* De-queues the FM CMD from the struct transmit_queue_t */
+static void dequeue_fm_tx_cmd(struct fm_hci_t *hci)
+{
+    struct transmit_queue_t *temp;
+    uint16_t count = 0, len = 0;
+
+    ALOGD("%s", __func__);
+    while (1) {
+        pthread_mutex_lock(&hci->tx_q_lock);
+        temp = hci->first;
+        if (!temp) {
+            ALOGI("No FM CMD available in the Queue\n");
+            pthread_mutex_unlock(&hci->tx_q_lock);
+            return;
+        } else {
+            hci->first = temp->next;
+        }
+        pthread_mutex_unlock(&hci->tx_q_lock);
+
+        pthread_mutex_lock(&hci->credit_lock);
+wait_for_cmd_credits:
+        while (hci->command_credits == 0) {
+              pthread_cond_wait(&hci->cmd_credits_cond, &hci->credit_lock);
+        }
+
+        /* Check if we really got the command credits */
+        if (hci->command_credits) {
+
+            len = sizeof(struct fm_command_header_t) + temp->hdr->len;
+again:
+            /* Use socket 'fd' to send the command down to WCNSS Filter */
+            count = write(hci->fd, (uint8_t *)temp->hdr + count, len);
+
+            if (count < len) {
+                len -= count;
+                goto again;
+            }
+            count = 0;
+
+            /* Decrement cmd credits by '1' after sending the cmd*/
+            hci->command_credits--;
+            if (temp->hdr)
+                free(temp->hdr);
+            free(temp);
+        } else {
+            if (!lib_running) {
+                pthread_mutex_unlock(&hci->credit_lock);
+                break;
+            }
+            goto wait_for_cmd_credits;
+        }
+        pthread_mutex_unlock(&hci->credit_lock);
+    }
+}
+
+static int read_fm_event(struct fm_hci_t *hci, struct fm_event_header_t *pbuf, int len)
+{
+    fd_set readFds;
+    sigset_t sigmask, emptymask;
+    int n = 0, ret = -1, evt_len = -1,status=0;
+    volatile int fd = hci->fd;
+    struct sigaction action;
+
+    sigemptyset(&sigmask);
+    sigaddset(&sigmask, SIGUSR1);
+    if (sigprocmask(SIG_BLOCK, &sigmask, NULL) == -1) {
+    ALOGE("failed to sigprocmask");
+    }
+    memset(&action, 0, sizeof(struct sigaction));
+    sigemptyset(&action.sa_mask);
+    action.sa_flags = 0;
+    action.sa_handler = rx_thread_exit_handler;
+
+    sigemptyset(&emptymask);
+
+    if (sigaction(SIGUSR1, &action, NULL) < 0) {
+    ALOGE("%s:sigaction failed", __func__);
+    }
+
+    while (lib_running)
+    {
+        FD_ZERO(&readFds);
+        FD_SET(fd, &readFds);
+
+        ALOGV("%s: Waiting for events from WCNSS FILTER...\n", __func__);
+
+        /* Wait for event/data from WCNSS Filter */
+        n = pselect(fd+1, &readFds, NULL, NULL, NULL, &emptymask);
+        if (n > 0)
+        {
+            /* Check if event is available or not */
+            if (FD_ISSET(fd, &readFds)) {
+                ret = read(fd, (uint8_t *)pbuf, (size_t)(sizeof(struct fm_event_header_t) + MAX_FM_EVT_PARAMS));
+                if (0 == ret) {
+                    ALOGV("%s: read() returned '0' bytes\n", __func__);
+                    break;
+                }
+                else {
+                    ALOGV("%s: read() returned %d bytes of FM event/data\n", __func__, ret);
+                    while (ret > 0) {
+                        pthread_mutex_lock(&hci->credit_lock);
+                        if (pbuf->evt_code == FM_CMD_COMPLETE) {
+                            hci->command_credits = pbuf->params[0];
+                            pthread_cond_signal(&hci->cmd_credits_cond);
+                        } else if (pbuf->evt_code == FM_CMD_STATUS) {
+                            hci->command_credits = pbuf->params[1];
+                            pthread_cond_signal(&hci->cmd_credits_cond);
+                        } else if (pbuf->evt_code == FM_HW_ERR_EVENT) {
+                              ALOGI("%s: FM H/w Err Event Recvd. Event Code: 0x%2x", __func__, pbuf->evt_code);
+                         /*  remove until support added */
+                              //hci->vendor->ssr_cleanup(0x22);
+                              status  = power(hci, FM_RADIO_DISABLE);
+                              if (status < 0) {
+                                 ALOGE("power off fm radio failed during SSR ");
+                              }
+                        } else {
+                            ALOGE("%s: Not CS/CC Event: Recvd. Event Code: 0x%2x", __func__, pbuf->evt_code);
+                        }
+                        pthread_mutex_unlock(&hci->credit_lock);
+
+                        evt_len = pbuf->evt_len;
+
+                        /* Notify 'hci_tx_thread' about availability of event or data */
+                        ALOGI("%s: \nNotifying 'hci_tx_thread' availability of FM event or data...\n", __func__);
+                        event_notification(hci, HC_EVENT_RX);
+
+                        if (hci->cb && hci->cb->process_event)
+                            hci->cb->process_event((uint8_t *)pbuf);
+                        else
+                            ALOGE("%s: ASSERT $$$$$$ Callback function NULL $$$$$", __func__);
+
+                        ret = ret - (evt_len + 3);
+                        ALOGD("%s: Length of available bytes @ HCI Layer: %d", __func__, ret);
+                        if (ret > 0) {
+                            ALOGE("%s: Remaining bytes of event/data: %d", __func__, ret);
+                            pbuf = (struct fm_event_header_t *)&pbuf->params[evt_len];
+                        }
+                    }
+                } //end of processing the event
+
+            } else
+                ALOGV("%s: No data available, though select returned!!!\n", __func__);
+        }
+        else if (n < 0) {
+           ALOGE("%s: select() failed with return value: %d", __func__, ret);
+           lib_running =0;
+        }
+        else if (n == 0)
+            ALOGE("%s: select() timeout!!!", __func__);
+    }
+
+    return ret;
+}
+
+static void *hci_read_thread(void *arg)
+{
+    int length = 0;
+    struct fm_hci_t *hci = (struct fm_hci_t *)arg;
+
+    struct fm_event_header_t *evt_buf = (struct fm_event_header_t *) malloc(sizeof(struct fm_event_header_t) + MAX_FM_EVT_PARAMS);
+
+    if (!evt_buf) {
+        ALOGE("%s: Memory allocation failed for evt_buf", __func__);
+        goto cleanup;
+    }
+
+    length = read_fm_event(hci, evt_buf, sizeof(struct fm_event_header_t) + MAX_FM_EVT_PARAMS);
+    ALOGD("length=%d\n",length);
+    if(length <=0) {
+       lib_running =0;
+    }
+    goto exit;
+
+cleanup:
+    lib_running = 0;
+    hci = NULL;
+
+exit:
+    ALOGV("%s: Leaving hci_read_thread()", __func__);
+    if (evt_buf)
+        free(evt_buf);
+    pthread_exit(NULL);
+    return arg;
+}
+
+int connect_to_local_fmsocket(char* name) {
+       socklen_t len; int sk = -1;
+
+       ALOGE("%s: ACCEPT ", __func__);
+       sk  = socket(AF_LOCAL, SOCK_STREAM, 0);
+       if (sk < 0) {
+           ALOGE("Socket creation failure");
+           return -1;
+       }
+
+        if(socket_local_client_connect(sk, name,
+            ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM) < 0)
+        {
+             ALOGE("failed to connect (%s)", strerror(errno));
+             close(sk);
+             sk = -1;
+        } else {
+             ALOGE("%s: Connection succeeded\n", __func__);
+        }
+        return sk;
+}
+
+/*
+ * Reads the FM-CMDs from the struct transmit_queue_t and sends it down to WCNSS Filter
+ * Reads events sent by the WCNSS Filter and copies onto RX_Q
+ */
+static void* hci_tx_thread(void *arg)
+{
+    uint16_t events;
+    struct fm_hci_t *hci = (struct fm_hci_t *)arg;
+
+    while (lib_running) {
+        pthread_mutex_lock(&hci->event_lock);
+        if (!(ready_events & HC_EVENT_TX))
+            pthread_cond_wait(&hci->event_cond, &hci->event_lock);
+        ALOGE("%s: ready_events= %d", __func__, ready_events);
+        events = ready_events;
+        if (ready_events & HC_EVENT_TX)
+            ready_events &= (~HC_EVENT_TX);
+        if (ready_events & HC_EVENT_RX)
+            ready_events &= (~HC_EVENT_RX);
+        pthread_mutex_unlock(&hci->event_lock);
+
+        if (events & HC_EVENT_TX) {
+            dequeue_fm_tx_cmd(hci);
+        }
+        if (events & HC_EVENT_RX) {
+             ALOGI("\n##### FM-HCI Task : EVENT_RX available #####\n");
+        }
+        if (events & HC_EVENT_EXIT) {
+            ALOGE("GOT HC_EVENT_EXIT.. exiting");
+            break;
+        }
+    }
+
+    ALOGV("%s: ##### Exiting hci_tx_thread Worker thread!!! #####", __func__);
+    return NULL;
+}
+
+void stop_fmhal_service() {
+       char value[PROPERTY_VALUE_MAX] = {'\0'};
+       ALOGI("%s: Entry ", __func__);
+       property_get(FM_VND_SERVICE_START, value, "false");
+       if (strcmp(value, "false") == 0) {
+           ALOGI("%s: fmhal service  has been stopped already", __func__);
+//         return;
+       }
+       close(fm_hal_fd);
+       fm_hal_fd = -1;
+       property_set(FM_VND_SERVICE_START, "false");
+       property_set("wc_transport.fm_service_status", "0");
+       ALOGI("%s: Exit ", __func__);
+}
+
+void start_fmhal_service() {
+       ALOGI("%s: Entry ", __func__);
+       int i, init_success = 0;
+       char value[PROPERTY_VALUE_MAX] = {'\0'};
+
+       property_get(FM_VND_SERVICE_START, value, false);
+
+       if (strcmp(value, "true") == 0) {
+           ALOGI("%s: hci_filter has been started already", __func__);
+           return;
+       }
+  //     property_set("wc_transport.fm_service_status", "0");
+       usleep(100 * 1000);	// 100 msecs
+       property_set(FM_VND_SERVICE_START, "true");
+       ALOGI("%s: %s set to true ", __func__, FM_VND_SERVICE_START );
+       for(i=0; i<45; i++) {
+          property_get("wc_transport.fm_service_status", value, "0");
+          if (strcmp(value, "1") == 0) {
+               ALOGI("%s: wc_transport.fm_service_status set to %s", __func__,value);
+               init_success = 1;
+               break;
+           } else {
+               usleep(WAIT_TIMEOUT);
+           }
+        }
+        ALOGI("start_fmhal_service status:%d after %f seconds \n", init_success, 0.2*i);
+
+        ALOGI("%s: Exit ", __func__);
+}
+
+static int start_tx_thread(struct fm_hci_t *hci)
+{
+    struct sched_param param;
+    int policy, result;
+
+    ALOGI("FM-HCI: Creating the FM-HCI TASK...");
+    if (pthread_create(&hci->tx_thread, NULL, hci_tx_thread, hci) != 0)
+    {
+        ALOGE("pthread_create failed!");
+        lib_running = 0;
+        return FM_HC_STATUS_FAIL;
+    }
+
+    if(pthread_getschedparam(hci->tx_thread, &policy, &param)==0)
+    {
+        policy = SCHED_NORMAL;
+#if (BTHC_LINUX_BASE_POLICY!=SCHED_NORMAL)
+        param.sched_priority = BTHC_MAIN_THREAD_PRIORITY;
+#endif
+        result = pthread_setschedparam(hci->tx_thread, policy, &param);
+        if (result != 0)
+        {
+            ALOGW("libbt-hci init: pthread_setschedparam failed (%d)", \
+                  result);
+        }
+    } else
+        ALOGI("FM-HCI: Failed to get the Scheduling parameters!!!");
+
+    return FM_HC_STATUS_SUCCESS;
+}
+
+static void stop_tx_thread(struct fm_hci_t *hci)
+{
+    int ret;
+
+    ALOGV("%s++", __func__);
+    if ((ret = pthread_kill(hci->tx_thread, SIGUSR1))
+            == FM_HC_STATUS_SUCCESS) {
+        ALOGE("%s:pthread_join", __func__);
+         if ((ret = pthread_join(hci->tx_thread, NULL)) != FM_HC_STATUS_SUCCESS)
+             ALOGE("Error joining tx thread, error = %d (%s)",
+                     ret, strerror(ret));
+    } else {
+        ALOGE("Error killing tx thread, error = %d (%s)",
+                ret, strerror(ret));
+    }
+}
+
+static void *hci_mon_thread(void *arg)
+{
+    struct fm_hci_t *hci = (struct fm_hci_t *)arg;
+    uint16_t events;
+    ALOGV("%s", __func__);
+
+    while (lib_running) {
+        pthread_mutex_lock(&hci->event_lock);
+        if (!(ready_events & HC_EVENT_EXIT))
+            pthread_cond_wait(&hci->event_cond, &hci->event_lock);
+        events = ready_events;
+        if (ready_events & HC_EVENT_EXIT)
+            ready_events &= (~HC_EVENT_EXIT);
+        pthread_mutex_unlock(&hci->event_lock);
+
+        ALOGD("events = 0x%x", events);
+        if (events & HC_EVENT_EXIT) {
+            ALOGD("Got Exit event.. Exiting HCI");
+            fm_hci_exit(hci);
+            break;
+        }
+    }
+    ALOGV("%s--", __func__);
+    return NULL;
+}
+
+static int start_mon_thread(struct fm_hci_t *hci)
+{
+    int ret = FM_HC_STATUS_SUCCESS;
+    ALOGD("%s", __func__);
+    if ((ret = pthread_create(&hci->mon_thread, NULL,
+                    hci_mon_thread, hci)) !=0) {
+        ALOGE("pthread_create failed! status = %d (%s)",
+                ret, strerror(ret));
+        lib_running = 0;
+    }
+    return ret;
+}
+
+static void stop_mon_thread(struct fm_hci_t *hci)
+{
+    int ret;
+    ALOGV("%s++", __func__);
+    if ((ret = pthread_kill(hci->mon_thread, SIGUSR1))
+            == FM_HC_STATUS_SUCCESS) {
+        ALOGE("%s:pthread_join", __func__);
+        if ((ret = pthread_join(hci->mon_thread, NULL)) != FM_HC_STATUS_SUCCESS)
+            ALOGE("Error joining mon thread, error = %d (%s)",
+                    ret, strerror(ret));
+    } else {
+        ALOGE("Error killing mon thread, error = %d (%s)",
+                ret, strerror(ret));
+    }
+}
+
+static int start_rx_thread(struct fm_hci_t *hci)
+{
+    int ret = FM_HC_STATUS_SUCCESS;
+    ALOGV("%s++", __func__);
+
+    ALOGD("%s: Starting the userial read thread....", __func__);
+    if ((ret = pthread_create(&hci->rx_thread, NULL, \
+                       hci_read_thread, hci)) != 0) {
+        ALOGE("pthread_create failed! status = %d (%s)",
+                ret, strerror(ret));
+        lib_running = 0;
+    }
+    return ret;
+}
+
+static void stop_rx_thread(struct fm_hci_t *hci)
+{
+    int ret;
+    ALOGV("%s++", __func__);
+    if ((ret = pthread_kill(hci->rx_thread, SIGUSR1))
+            == FM_HC_STATUS_SUCCESS) {
+        ALOGE("%s:pthread_join", __func__);
+        if ((ret = pthread_join(hci->rx_thread, NULL)) != FM_HC_STATUS_SUCCESS)
+            ALOGE("Error joining rx thread, error = %d (%s)",
+                    ret, strerror(ret));
+    } else {
+        ALOGE("Error killing rx thread, error = %d (%s)",
+                ret, strerror(ret));
+    }
+}
+
+static int power(struct fm_hci_t *hci, fm_power_state_t state)
+{
+        int i,opcode,ret;
+        int init_success = 0;
+        char value[PROPERTY_VALUE_MAX] = {'\0'};
+        if (fm_hal_fd)
+        {
+            if (state)
+                opcode = 2;
+            else {
+                opcode = 1;
+            }
+            ALOGI("%s:opcode: %x", LOG_TAG, opcode);
+            ret = write(fm_hal_fd,&opcode, 1);
+            if (ret < 0) {
+                ALOGE("failed to write fm hal socket");
+            } else {
+                ret = FM_HC_STATUS_SUCCESS;
+            }
+        } else {
+            ALOGE("Connect to socket failed ..");
+            ret = -1;
+        }
+        if (state == FM_RADIO_DISABLE) {
+            for (i=0; i<10; i++) {
+                property_get("wc_transport.fm_power_status", value, "0");
+                if (strcmp(value, "0") == 0) {
+                    init_success = 1;
+                    break;
+                } else {
+                    usleep(WAIT_TIMEOUT);
+                }
+            }
+            ALOGI("fm power OFF status:%d after %f seconds \n", init_success, 0.2*i);
+            stop_fmhal_service();
+        }
+        if (state == FM_RADIO_ENABLE) {
+            for (i=0; i<10; i++) {
+                property_get("wc_transport.fm_power_status", value, "0");
+                if (strcmp(value, "1") == 0) {
+                    init_success = 1;
+                    break;
+                } else {
+                    usleep(WAIT_TIMEOUT);
+                }
+            }
+            ALOGI("fm power ON status:%d after %f seconds \n", init_success, 0.2*i);
+        }
+        return ret;
+}
+
+#define CH_MAX 3
+static int serial_port_init(struct fm_hci_t *hci)
+{
+    int i, ret;
+    int fd_array[CH_MAX];
+
+    for (int i = 0; i < CH_MAX; i++)
+        fd_array[i] = -1;
+
+    ALOGI("%s: Opening the TTy Serial port...", __func__);
+    ret = hci->vendor->op(BT_VND_OP_FM_USERIAL_OPEN, &fd_array);
+
+    if (fd_array[0] == -1) {
+        ALOGE("%s unable to open TTY serial port", __func__);
+        goto err;
+    }
+    hci->fd = fd_array[0];
+
+    return FM_HC_STATUS_SUCCESS;
+
+err:
+    return FM_HC_STATUS_FAIL;
+}
+
+static void serial_port_close(struct fm_hci_t *hci)
+{
+    //TODO: what if hci/fm_vnd_if is null.. need to take lock and check
+    ALOGI("%s: Closing the TTy Serial port!!!", __func__);
+    hci->vendor->op(BT_VND_OP_FM_USERIAL_CLOSE, NULL);
+    hci->fd = -1;
+}
+
+static int enqueue_fm_tx_cmd(struct fm_hci_t *hci, struct fm_command_header_t *pbuf)
+{
+    struct transmit_queue_t *element =  (struct transmit_queue_t *) malloc(sizeof(struct transmit_queue_t));
+
+    if (!element) {
+        ALOGI("Failed to allocate memory for element!!\n");
+        return FM_HC_STATUS_NOMEM;
+    }
+    element->hdr = pbuf;
+    element->next = NULL;
+
+    pthread_mutex_lock(&hci->tx_q_lock);
+
+    if (!hci->first) {
+        hci->last = hci->first = element;
+    } else {
+        hci->last->next = element;
+        hci->last = element;
+    }
+    ALOGI("%s: FM-CMD ENQUEUED SUCCESSFULLY", __func__);
+
+    pthread_mutex_unlock(&hci->tx_q_lock);
+
+    return FM_HC_STATUS_SUCCESS;
+}
+
+int fm_hci_transmit(void *hci, struct fm_command_header_t *buf)
+{
+    int status = FM_HC_STATUS_FAIL;
+
+    if (!hci || !buf) {
+        ALOGE("NULL input arguments");
+        return FM_HC_STATUS_NULL_POINTER;
+    }
+
+    if ((status = enqueue_fm_tx_cmd((struct fm_hci_t *)hci, buf))
+            == FM_HC_STATUS_SUCCESS)
+        event_notification(hci, HC_EVENT_TX);
+
+    return status;
+}
+
+void fm_hci_close(void *arg) {
+
+    ALOGV("%s  close fm userial ", __func__);
+
+    struct fm_hci_t *hci = (struct fm_hci_t *)arg;
+    if (!hci) {
+        ALOGE("NULL arguments");
+        return;
+    }
+    event_notification(hci, HC_EVENT_EXIT);
+    pthread_mutex_lock(&hci->event_lock);
+again:
+    pthread_cond_wait(&hci->event_cond, &hci->event_lock);
+    if (!(ready_events & HC_EVENT_EXIT_DONE))
+        goto again;
+    pthread_mutex_unlock(&hci->event_lock);
+}
+
+int fm_hci_init(fm_hci_hal_t *hci_hal)
+{
+    int ret = FM_HC_STATUS_FAIL;
+    struct fm_hci_t *hci = NULL;
+    ALOGV("++%s", __func__);
+
+    if (!hci_hal || !hci_hal->hal) {
+        ALOGE("NULL input argument");
+        return FM_HC_STATUS_NULL_POINTER;
+    }
+
+    hci = malloc(sizeof(struct fm_hci_t));
+    if (!hci) {
+        ALOGE("Failed to malloc hci context");
+        return FM_HC_STATUS_NOMEM;
+    }
+    memset(hci, 0, sizeof(struct fm_hci_t));
+
+    pthread_mutex_init(&hci->tx_q_lock, NULL);
+    pthread_mutex_init(&hci->credit_lock, NULL);
+    pthread_mutex_init(&hci->event_lock, NULL);
+
+    pthread_cond_init(&hci->event_cond, NULL);
+    pthread_cond_init(&hci->cmd_credits_cond, NULL);
+
+    start_fmhal_service();
+    fm_hal_fd = connect_to_local_fmsocket("fmhal_sock");
+    if (fm_hal_fd == -1) {
+        ALOGI("FM hal service socket connect failed..");
+        goto err_socket;
+    }
+    ALOGI("fm_hal_fd = %d", fm_hal_fd);
+
+    lib_running = 1;
+    ready_events = 0;
+    hci->command_credits = 1;
+    hci->fd = -1;
+
+    ret = vendor_init(hci);
+    if (ret)
+        goto err_vendor;
+    ret = power(hci, FM_RADIO_ENABLE);
+    if (ret)
+        goto err_power;
+    ret = serial_port_init(hci);
+    if (ret)
+        goto err_serial;
+    ret = start_mon_thread(hci);
+    if (ret)
+        goto err_thread_mon;
+    ret = start_tx_thread(hci);
+    if (ret)
+        goto err_thread_tx;
+    ret = start_rx_thread(hci);
+    if (ret)
+        goto err_thread_rx;
+
+    hci->cb = hci_hal->cb;
+    hci->private_data = hci_hal->hal;
+    hci_hal->hci = hci;
+    ALOGD("--%s success", __func__);
+    return FM_HC_STATUS_SUCCESS;
+
+err_thread_rx:
+    stop_rx_thread(hci);
+err_thread_tx:
+    stop_tx_thread(hci);
+err_thread_mon:
+    stop_mon_thread(hci);
+err_serial:
+    serial_port_close(hci);
+err_power:
+    power(hci, FM_RADIO_DISABLE);
+err_vendor:
+    vendor_close(hci);
+err_socket:
+    stop_fmhal_service();
+
+    pthread_mutex_destroy(&hci->tx_q_lock);
+    pthread_mutex_destroy(&hci->credit_lock);
+    pthread_mutex_destroy(&hci->event_lock);
+    pthread_cond_destroy(&hci->event_cond);
+    pthread_cond_destroy(&hci->cmd_credits_cond);
+
+    lib_running = 0;
+    ready_events = 0;
+    hci->command_credits = 0;
+    free(hci);
+
+    ALOGE("--%s fail", __func__);
+    return ret;
+}
+
+static void fm_hci_exit(void *arg)
+{
+    struct fm_hci_t *hci = (struct fm_hci_t *)arg;
+    ALOGE("%s", __func__);
+
+    lib_running = 0;
+    ready_events = HC_EVENT_EXIT;
+    hci->command_credits = 0;
+    serial_port_close(hci);
+    power(hci, FM_RADIO_DISABLE);//need to address this
+    vendor_close(hci);
+    pthread_cond_broadcast(&hci->event_cond);
+    pthread_cond_broadcast(&hci->cmd_credits_cond);
+    event_notification(hci, HC_EVENT_EXIT_DONE);
+    stop_rx_thread(hci);
+    stop_tx_thread(hci);
+    ALOGD("Tx, Rx Threads join done");
+    pthread_mutex_destroy(&hci->tx_q_lock);
+    pthread_mutex_destroy(&hci->credit_lock);
+    pthread_mutex_destroy(&hci->event_lock);
+    pthread_cond_destroy(&hci->event_cond);
+    pthread_cond_destroy(&hci->cmd_credits_cond);
+
+    free(hci);
+    hci = NULL;
+}
+
diff --git a/fm_hci/fm_hci.cpp b/fm_hci/fm_hci.cpp
index c08b884..550b8dd 100644
--- a/fm_hci/fm_hci.cpp
+++ b/fm_hci/fm_hci.cpp
@@ -60,7 +60,6 @@
 using ::android::hardware::Return;
 using ::android::hardware::Void;
 using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_death_recipient;
 
 static struct fm_hci_t hci;
 
@@ -82,31 +81,6 @@
 static bool hci_initialize();
 static void hci_transmit(struct fm_command_header_t *hdr);
 static void hci_close();
-#define HCI_EV_HW_ERR_EVENT             0x1A
-
-void hal_service_died() {
-    struct fm_event_header_t *temp = (struct fm_event_header_t *)
-                       malloc(sizeof(struct fm_event_header_t));
-    if (temp != nullptr) {
-        temp->evt_code = HCI_EV_HW_ERR_EVENT;
-        temp->evt_len = 0;
-        ALOGI("%s: evt_code:  0x%x", __func__, temp->evt_code);
-        enqueue_fm_rx_event(temp);
-    } else {
-        ALOGE("%s: Memory Allocation failed for event buffer ",__func__);
-    }
-}
-
-class FmHciDeathRecipient : public hidl_death_recipient {
-    public:
-       virtual void serviceDied(uint64_t /*cookie*/,
-           const android::wp<::android::hidl::base::V1_0::IBase>& /*who*/) {
-       ALOGE("Fm HAL service died!");
-       hal_service_died();
-   }
-};
-
-android::sp<FmHciDeathRecipient> fmHciDeathRecipient = new FmHciDeathRecipient();
 
 /*******************************************************************************
 **
@@ -511,7 +485,6 @@
     int ret;
     ALOGI("++%s: is_hci_initialize: %d", __func__, is_hci_initialize);
 
-    hci.on_mtx.lock();
     while (is_hci_initialize) {
         ret = start_tx_thread();
         if (ret)
@@ -534,7 +507,6 @@
     }
 
     hci.on_cond.notify_all();
-    hci.on_mtx.unlock();
     ALOGI("--%s: is_hci_initialize: %d", __func__, is_hci_initialize);
 
 }
@@ -602,6 +574,8 @@
     ALOGI("%s: acquiring mutex", __func__);
     std::lock_guard<std::recursive_mutex> lk(mtx);
 
+    fmHci = IFmHci::getService();
+
     if (fmHci != nullptr) {
         hci.state = FM_RADIO_ENABLING;
         android::sp<IFmHciCallbacks> callbacks = new FmHciCallbacks();
@@ -666,10 +640,6 @@
     std::lock_guard<std::recursive_mutex> lk(mtx);
 
     if (fmHci != nullptr) {
-        auto death_unlink = fmHci->unlinkToDeath(fmHciDeathRecipient);
-        if (!death_unlink.isOk()) {
-            ALOGE( "%s: Error unlinking death recipient from the Fm HAL", __func__);
-        }
         auto hidl_daemon_status = fmHci->close();
         if(!hidl_daemon_status.isOk()) {
             ALOGE("%s: HIDL daemon is dead", __func__);
@@ -730,10 +700,10 @@
 
     if (hci_initialize()) {
         //wait for iniialization complete
-        Lock lk(hci.on_mtx);
+        ALOGD("--%s waiting for iniialization complete hci state: %d ",
+                __func__, hci.state);
         if(hci.state == FM_RADIO_ENABLING){
-            ALOGD("--%s waiting for iniialization complete hci state: %d ",
-                    __func__, hci.state);
+            Lock lk(hci.on_mtx);
             std::cv_status status = std::cv_status::no_timeout;
             auto now = std::chrono::system_clock::now();
             status =
@@ -744,7 +714,6 @@
                  kill(getpid(), SIGKILL);
              }
         }
-        hci.on_mtx.unlock();
     }
 
     if (hci.state == FM_RADIO_ENABLED) {
diff --git a/fm_hci/wcnss_hci.h b/fm_hci/wcnss_hci.h
new file mode 100644
index 0000000..95fa9c1
--- /dev/null
+++ b/fm_hci/wcnss_hci.h
@@ -0,0 +1,70 @@
+/*
+ * 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 __WCNSS_HCI__
+#define __WCNSS_HCI__
+static void vendor_fwcfg_cb(bt_vendor_op_result_t result) {
+}
+
+static void vendor_scocfg_cb(bt_vendor_op_result_t result) {
+}
+
+static void vendor_lpm_vnd_cb(bt_vendor_op_result_t result) {
+}
+
+static void sco_audiostate_cb(bt_vendor_op_result_t result) {
+}
+
+static void* vendor_alloc(int size) {
+    return NULL;
+}
+
+static void vendor_dealloc(void *p_buf) {
+}
+
+static uint8_t vendor_xmit_cb(uint16_t opcode, void *p_buf, tINT_CMD_CBACK p_cback) {
+    return 0;
+}
+
+static void vendor_epilog_cb(bt_vendor_op_result_t result) {
+}
+
+
+static const bt_vendor_callbacks_t fm_vendor_callbacks = {
+  sizeof(fm_vendor_callbacks),
+   vendor_fwcfg_cb,
+   vendor_scocfg_cb,
+   vendor_lpm_vnd_cb,
+   sco_audiostate_cb,
+   vendor_alloc,
+   vendor_dealloc,
+   vendor_xmit_cb,
+   vendor_epilog_cb
+};
+#endif
diff --git a/fmapp2/Android.bp b/fmapp2/Android.bp
index a2ef6ab..eeeab5f 100755
--- a/fmapp2/Android.bp
+++ b/fmapp2/Android.bp
@@ -3,7 +3,7 @@
 android_app {
     name: "FM2",
 
-    srcs: ["src/com/caf/fmradio/CommaSeparatedFreqFileReader.java"] + ["src/com/caf/fmradio/FMAdapterApp.java"] + ["src/com/caf/fmradio/FMMediaButtonIntentReceiver.java"] + ["src/com/caf/fmradio/FMRadio.java"] + ["src/com/caf/fmradio/FMRadioService.java"] + ["src/com/caf/fmradio/FmSharedPreferences.java"] + ["src/com/caf/fmradio/FMStats.java"] + ["src/com/caf/fmradio/FmTags.java"] + ["src/com/caf/fmradio/GetNextFreqInterface.java"] + ["src/com/caf/fmradio/HorizontalNumberPicker.java"] + ["src/com/caf/fmradio/PresetList.java"] + ["src/com/caf/fmradio/PresetStation.java"] + ["src/com/caf/fmradio/Settings.java"] + ["src/com/caf/fmradio/StationListActivity.java"] + ["src/com/caf/fmradio/IFMRadioService.aidl"] + ["src/com/caf/fmradio/IFMRadioServiceCallbacks.aidl"] + ["src/com/caf/fmradio/IFMTransmitterServiceCallbacks.aidl"] + ["src/com/caf/hc_utils/**/*.java"],
+    srcs: ["src/com/caf/fmradio/CommaSeparatedFreqFileReader.java"] + ["src/com/caf/fmradio/FMAdapterApp.java"] + ["src/com/caf/fmradio/FMMediaButtonIntentReceiver.java"] + ["src/com/caf/fmradio/FMRadio.java"] + ["src/com/caf/fmradio/FMRadioService.java"] + ["src/com/caf/fmradio/FmSharedPreferences.java"] + ["src/com/caf/fmradio/FMStats.java"] + ["src/com/caf/fmradio/FmTags.java"] + ["src/com/caf/fmradio/GetNextFreqInterface.java"] + ["src/com/caf/fmradio/HorizontalNumberPicker.java"] + ["src/com/caf/fmradio/PresetList.java"] + ["src/com/caf/fmradio/PresetStation.java"] + ["src/com/caf/fmradio/Settings.java"] + ["src/com/caf/fmradio/StationListActivity.java"] + ["src/com/caf/fmradio/IFMRadioService.aidl"] + ["src/com/caf/fmradio/IFMRadioServiceCallbacks.aidl"] + ["src/com/caf/hc_utils/**/*.java"],
     certificate: "platform",
     jni_libs: ["libqcomfm_jni"],
     libs: ["qcom.fmradio"],
diff --git a/fmapp2/src/com/caf/fmradio/FMRadioService.java b/fmapp2/src/com/caf/fmradio/FMRadioService.java
index 7b99141..1c7c700 100644
--- a/fmapp2/src/com/caf/fmradio/FMRadioService.java
+++ b/fmapp2/src/com/caf/fmradio/FMRadioService.java
@@ -851,7 +851,9 @@
           setLowPowerMode(false);
           if(false == mPlaybackInProgress) {
               startFM();
-              enableSlimbus(ENABLE_SLIMBUS_DATA_PORT);
+              if (mReceiver.isCherokeeChip() && (mPref.getBoolean("SLIMBUS_SEQ", true))) {
+                  enableSlimbus(ENABLE_SLIMBUS_DATA_PORT);
+              }
           }
       }
    }
@@ -1607,9 +1609,10 @@
                       //intentional fall through.
                   case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
                       Log.v(LOGTAG, "AudioFocus: received AUDIOFOCUS_LOSS_TRANSIENT");
-
-                      enableSlimbus(DISABLE_SLIMBUS_DATA_PORT);
-
+                      if (mReceiver != null && mReceiver.isCherokeeChip() &&
+                                            (mPref.getBoolean("SLIMBUS_SEQ", true))) {
+                          enableSlimbus(DISABLE_SLIMBUS_DATA_PORT);
+                      }
                       if (true == mPlaybackInProgress) {
                           stopFM();
                       }
@@ -1631,8 +1634,10 @@
 
                       if(false == mPlaybackInProgress) {
                           startFM();
-                          enableSlimbus(ENABLE_SLIMBUS_DATA_PORT);
-
+                          if (mReceiver != null && mReceiver.isCherokeeChip() &&
+                                (mPref.getBoolean("SLIMBUS_SEQ", true))) {
+                              enableSlimbus(ENABLE_SLIMBUS_DATA_PORT);
+                          }
                       } else {
                           /* This case usually happens, when FM volume is lowered down and Playback
                            * In Progress on AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK recived. Need
@@ -1943,6 +1948,11 @@
       {
          return(mService.get().getProgramID());
       }
+      public int[] getSearchList()
+      {
+         return(mService.get().getSearchList());
+      }
+
       public boolean setLowPowerMode(boolean enable)
       {
          return(mService.get().setLowPowerMode(enable));
@@ -2187,6 +2197,86 @@
        return status;
    }
 
+   private boolean fmTurnOnSequence () {
+       boolean bStatus = false;
+       // This sets up the FM radio device
+       FmConfig config = FmSharedPreferences.getFMConfiguration();
+
+       Log.d(LOGTAG, "fmOn: RadioBand   :"+ config.getRadioBand());
+       Log.d(LOGTAG, "fmOn: Emphasis    :"+ config.getEmphasis());
+       Log.d(LOGTAG, "fmOn: ChSpacing   :"+ config.getChSpacing());
+       Log.d(LOGTAG, "fmOn: RdsStd      :"+ config.getRdsStd());
+       Log.d(LOGTAG, "fmOn: LowerLimit  :"+ config.getLowerLimit());
+       Log.d(LOGTAG, "fmOn: UpperLimit  :"+ config.getUpperLimit());
+
+       mEventReceived = false;
+       bStatus = mReceiver.enable(FmSharedPreferences.getFMConfiguration(), this);
+
+       if (mReceiver.isCherokeeChip()) {
+           bStatus = waitForEvent();
+       }
+
+       Log.d(LOGTAG, "mReceiver.enable done, Status :" +  bStatus);
+
+         if (bStatus == true)
+         {
+            /* Put the hardware into normal mode */
+            bStatus = setLowPowerMode(false);
+            Log.d(LOGTAG, "setLowPowerMode done, Status :" +  bStatus);
+
+
+            AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+            if( (audioManager != null) &&(false == mPlaybackInProgress) )
+            {
+               Log.d(LOGTAG, "mAudioManager.setFmRadioOn = true \n" );
+               //audioManager.setParameters("FMRadioOn="+mAudioDevice);
+               int state =  getCallState();
+               if ( TelephonyManager.CALL_STATE_IDLE != getCallState() )
+               {
+                 fmActionOnCallState(state);
+               } else {
+                   startFM(); // enable FM Audio only when Call is IDLE
+               }
+               Log.d(LOGTAG, "mAudioManager.setFmRadioOn done \n" );
+            }
+            if (mReceiver != null) {
+                bStatus = mReceiver.registerRdsGroupProcessing(FmReceiver.FM_RX_RDS_GRP_RT_EBL|
+                                                           FmReceiver.FM_RX_RDS_GRP_PS_EBL|
+                                                           FmReceiver.FM_RX_RDS_GRP_AF_EBL|
+                                                           FmReceiver.FM_RX_RDS_GRP_PS_SIMPLE_EBL|
+                                                           FmReceiver.FM_RX_RDS_GRP_ECC_EBL|
+                                                           FmReceiver.FM_RX_RDS_GRP_PTYN_EBL|
+                                                           FmReceiver.FM_RX_RDS_GRP_RT_PLUS_EBL);
+                Log.d(LOGTAG, "registerRdsGroupProcessing done, Status :" +  bStatus);
+            }
+            bStatus = enableAutoAF(FmSharedPreferences.getAutoAFSwitch());
+            Log.d(LOGTAG, "enableAutoAF done, Status :" +  bStatus);
+
+            /* There is no internal Antenna*/
+            bStatus = mReceiver.setInternalAntenna(false);
+            Log.d(LOGTAG, "setInternalAntenna done, Status :" +  bStatus);
+
+            /* Read back to verify the internal Antenna mode*/
+            readInternalAntennaAvailable();
+
+            startNotification();
+            bStatus = true;
+         }
+         else
+         {
+            if ((mReceiver.getFMState() != mReceiver.subPwrLevel_FMRx_Starting) &&
+                            (mReceiver.getFMState() != mReceiver.FMState_Rx_Turned_On)) {
+                mReceiver = null; // as enable failed no need to disable
+                              // failure of enable can be because handle
+                              // already open which gets effected if
+                              // we disable
+                stop();
+            }
+         }
+
+         return bStatus;
+   }
+
    private boolean enableSlimbus(int flag) {
        Log.d(LOGTAG, "enableSlimbus");
        boolean bStatus = false;
@@ -2205,7 +2295,7 @@
    *                                                                                 .
    * @return true if fm Enable api was invoked successfully, false if the api failed.
    */
-   private boolean fmTurnOnSequence() {
+   private boolean fmTurnOnSequenceCherokee () {
        boolean bStatus = false;
        AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        if ((audioManager != null) & (false == mPlaybackInProgress)) {
@@ -2311,9 +2401,15 @@
          }
          else
          {
-             enableSlimbus(ENABLE_SLIMBUS_DATA_PORT);
-             bStatus = fmTurnOnSequence();
-                /* reset SSR flag */
+           if (mReceiver.isCherokeeChip()) {
+               if (mPref.getBoolean("SLIMBUS_SEQ", true)) {
+                   enableSlimbus(ENABLE_SLIMBUS_DATA_PORT);
+               }
+               bStatus = fmTurnOnSequenceCherokee();
+           } else {
+               bStatus = fmTurnOnSequence();
+           }
+           /* reset SSR flag */
            mIsSSRInProgressFromActivity = false;
          }
       }
@@ -2386,6 +2482,23 @@
    private boolean fmOffImpl() {
       boolean bStatus=false;
 
+      // This will disable the FM radio device
+      synchronized(mReceiverLock) {
+         if (mReceiver != null)
+         {
+            bStatus = mReceiver.disable(this);
+            mReceiver = null;
+         }
+      }
+      fmOperationsOff();
+      stop();
+
+      return(bStatus);
+   }
+
+   private boolean fmOffImplCherokee() {
+      boolean bStatus=false;
+
       fmOperationsOff();
       stop();
       try {
@@ -2421,7 +2534,11 @@
    private boolean fmOff() {
        boolean ret = false;
        if (mReceiver != null) {
-           ret = fmOffImpl();
+           if (mReceiver.isCherokeeChip()) {
+               ret = fmOffImplCherokee();
+           } else {
+              ret = fmOffImpl();
+           }
        }
        mWakeLock.release();
        return ret;
@@ -2505,7 +2622,9 @@
            return;
 
        mSpeakerPhoneOn = speakerOn;
-       enableSlimbus(DISABLE_SLIMBUS_DATA_PORT);
+       if (mReceiver.isCherokeeChip() && (mPref.getBoolean("SLIMBUS_SEQ", true))) {
+           enableSlimbus(DISABLE_SLIMBUS_DATA_PORT);
+       }
 
        if (speakerOn == false) {
            mAudioDevice = AudioDeviceInfo.TYPE_WIRED_HEADPHONES;
@@ -2519,7 +2638,9 @@
        String keyValPairs = new String("fm_routing="+mAudioDeviceType);
        Log.d(LOGTAG, "keyValPairs = "+keyValPairs);
        audioManager.setParameters(keyValPairs);
-       enableSlimbus(ENABLE_SLIMBUS_DATA_PORT);
+       if (mReceiver.isCherokeeChip() && (mPref.getBoolean("SLIMBUS_SEQ", true))) {
+          enableSlimbus(ENABLE_SLIMBUS_DATA_PORT);
+       }
    }
   /*
    *  ReConfigure the FM Setup parameters
@@ -2915,6 +3036,24 @@
       return pi;
    }
 
+
+   /* Retrieves the station list from the SearchStationlist.
+    *
+    * @return Array of integers that represents the station frequencies.
+    * Note: 1. This is a synchronous call that should typically called when
+    *           Callback onSearchListComplete.
+    */
+   public int[] getSearchList()
+   {
+      int[] frequencyList = null;
+      if (mReceiver != null)
+      {
+         Log.d(LOGTAG, "getSearchList: ");
+         frequencyList = mReceiver.getStationList();
+      }
+      return frequencyList;
+   }
+
    /* Set the FM Power Mode on the FM hardware SoC.
     * Typically used when UI/Activity is in the background, so the Host is interrupted less often.
     *
@@ -3108,9 +3247,11 @@
       {
          Log.d(LOGTAG, "FmRxEvEnableReceiver");
          if (mReceiver != null) {
-             synchronized(mEventWaitLock) {
-                 mEventReceived = true;
-                 mEventWaitLock.notify();
+             if (mReceiver.isCherokeeChip()) {
+                 synchronized(mEventWaitLock) {
+                     mEventReceived = true;
+                     mEventWaitLock.notify();
+                 }
              }
          }
       }
@@ -3119,9 +3260,11 @@
          Log.d(LOGTAG, "FmRxEvDisableReceiver");
          mFMOn = false;
          FmSharedPreferences.clearTags();
-         synchronized (mEventWaitLock) {
-             mEventReceived = true;
-             mEventWaitLock.notify();
+         if (mReceiver != null && mReceiver.isCherokeeChip()) {
+             synchronized (mEventWaitLock) {
+                 mEventReceived = true;
+                 mEventWaitLock.notify();
+             }
          }
       }
       public void FmRxEvRadioReset()
@@ -3357,9 +3500,11 @@
           if (mCallbacks != null) {
               try {
                   mCallbacks.getStationParamCb(val, status);
-                  synchronized(mEventWaitLock) {
-                      mEventReceived = true;
-                      mEventWaitLock.notify();
+                  if (mReceiver != null && mReceiver.isCherokeeChip()) {
+                      synchronized(mEventWaitLock) {
+                          mEventReceived = true;
+                          mEventWaitLock.notify();
+                      }
                   }
               } catch (RemoteException e) {
                   e.printStackTrace();
@@ -3568,18 +3713,21 @@
       public void FmRxEvEnableSlimbus(int status)
       {
          Log.e(LOGTAG, "FmRxEvEnableSlimbus status = " + status);
-         synchronized(mEventWaitLock) {
-             mEventReceived = true;
-             mEventWaitLock.notify();
+         if (mReceiver != null && mReceiver.isCherokeeChip()) {
+             synchronized(mEventWaitLock) {
+                 mEventReceived = true;
+                 mEventWaitLock.notify();
+             }
          }
-
       }
       public void FmRxEvEnableSoftMute(int status)
       {
          Log.e(LOGTAG, "FmRxEvEnableSoftMute status = " + status);
-         synchronized(mEventWaitLock) {
-             mEventReceived = true;
-             mEventWaitLock.notify();
+         if (mReceiver != null && mReceiver.isCherokeeChip()) {
+             synchronized(mEventWaitLock) {
+                 mEventReceived = true;
+                 mEventWaitLock.notify();
+             }
          }
       }
    };
@@ -3865,7 +4013,18 @@
    }
 
    private void requestFocusImpl() {
-      Log.d(LOGTAG, "++requestFocusImpl mPlaybackInProgress: " +
+      if( (false == mPlaybackInProgress) &&
+          (true  == mStoppedOnFocusLoss) && isFmOn()) {
+           // adding code for audio focus gain.
+           AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+           audioManager.requestAudioFocus(mGainFocusReq);
+           startFM();
+           mStoppedOnFocusLoss = false;
+       }
+   }
+
+   private void requestFocusImplCherokee() {
+      Log.d(LOGTAG, "++requestFocusImplCherokee mPlaybackInProgress: " +
                     mPlaybackInProgress + " mStoppedOnFocusLoss: " +
                     mStoppedOnFocusLoss + " isFmOn: " + isFmOn());
       if( (false == mPlaybackInProgress) &&
@@ -3875,7 +4034,9 @@
            audioManager.requestAudioFocus(mGainFocusReq);
            if(false == mPlaybackInProgress) {
                startFM();
-               enableSlimbus(ENABLE_SLIMBUS_DATA_PORT);
+               if (mReceiver.isCherokeeChip() && (mPref.getBoolean("SLIMBUS_SEQ", true))) {
+                  enableSlimbus(ENABLE_SLIMBUS_DATA_PORT);
+               }
            }
            mStoppedOnFocusLoss = false;
        }
@@ -3883,10 +4044,15 @@
 
    private void requestFocus() {
        Log.d(LOGTAG, "++requestFocus");
-       requestFocusImpl();
+       if (mReceiver.isCherokeeChip() && (mPref.getBoolean("SLIMBUS_SEQ", true))) {
+           requestFocusImplCherokee();
+       } else {
+           requestFocusImpl();
+       }
        Log.d(LOGTAG, "--requestFocus");
    }
 
+
    public void onAudioFocusChange(int focusChange) {
            mDelayedStopHandler.obtainMessage(FOCUSCHANGE, focusChange, 0).sendToTarget();
    }
diff --git a/fmapp2/src/com/caf/fmradio/FMStats.java b/fmapp2/src/com/caf/fmradio/FMStats.java
index 063326d..71a4a38 100644
--- a/fmapp2/src/com/caf/fmradio/FMStats.java
+++ b/fmapp2/src/com/caf/fmradio/FMStats.java
@@ -3018,11 +3018,15 @@
         case SEARCH_TEST:
               try {
                   Log.e(LOGTAG, "start scanning\n");
-                  Log.d(LOGTAG,"Scanning with 0 scan time");
-                  if (mReceiver != null)
-                      mIsSearching = mReceiver.searchStations(FmReceiver.FM_RX_SRCH_MODE_SCAN,
-                              SCAN_DWELL_PERIOD, FmReceiver.FM_RX_SEARCHDIR_UP);
-              } catch (Exception e) {
+                  if(isTransportLayerSMD() || isCherokeeChip()) {
+                      Log.d(LOGTAG,"Scanning with 0 scan time");
+                      if (mReceiver != null)
+                          mIsSearching = mReceiver.searchStations(FmReceiver.FM_RX_SRCH_MODE_SCAN,
+                                  SCAN_DWELL_PERIOD, FmReceiver.FM_RX_SEARCHDIR_UP);
+                  } else {
+                      mIsSearching = mService.scan(0);
+                  }
+              }catch (RemoteException e) {
                   e.printStackTrace();
               }
 
@@ -3219,12 +3223,16 @@
         boolean isCherokeeChip = isCherokeeChip();
         if((null != mService)) {
             try {
-                lastCmdSent = CMD_STNPARAM_RSSI;
-                ret = mService.getRssi();
-                if (ret != 0) {
-                    Log.e(LOGTAG, "getrssi cmd failed: ret = " + ret);
-                    lastCmdSent = 0;
-                    return null;
+                if (isCherokeeChip) {
+                    lastCmdSent = CMD_STNPARAM_RSSI;
+                    ret = mService.getRssi();
+                     if (ret != 0) {
+                         Log.e(LOGTAG, "getrssi cmd failed: ret = " + ret);
+                         lastCmdSent = 0;
+                         return null;
+                     }
+                } else {
+                    nRssi = mService.getRssi();
                 }
                 Log.e(LOGTAG, "Got response of mService.getRssi");
                 if (nRssi != Integer.MAX_VALUE) {
diff --git a/fmapp2/src/com/caf/fmradio/IFMRadioService.aidl b/fmapp2/src/com/caf/fmradio/IFMRadioService.aidl
index 70d906e..9766093 100644
--- a/fmapp2/src/com/caf/fmradio/IFMRadioService.aidl
+++ b/fmapp2/src/com/caf/fmradio/IFMRadioService.aidl
@@ -25,6 +25,7 @@
     boolean scan(int pty);
     boolean seekPI(int piCode);
     boolean searchStrongStationList(int numStations);
+    int[]   getSearchList();
     boolean cancelSearch();
     String getProgramService();
     String getRadioText();
diff --git a/fmapp2/src/com/caf/fmradio/IFMTransmitterServiceCallbacks.aidl b/fmapp2/src/com/caf/fmradio/IFMTransmitterServiceCallbacks.aidl
deleted file mode 100644
index 641785d..0000000
--- a/fmapp2/src/com/caf/fmradio/IFMTransmitterServiceCallbacks.aidl
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2009,2012-2013 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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.
- */
-
-package com.caf.fmradio;
-
-interface IFMTransmitterServiceCallbacks
-{
-  void onEnabled(boolean bStatus);
-  void onDisabled();
-  void onRadioReset();
-  void onTuneStatusChanged(int frequency);
-  void onRadioTextChanged();
-  void onSearchListComplete(boolean bStatus);
-  void onReconfigured();
-  void onMetaDataChanged(String str);
-  void onPSInfoSent(String str);
-}
diff --git a/helium/radio-helium.h b/helium/radio-helium.h
index d3dae68..eb6ea9b 100644
--- a/helium/radio-helium.h
+++ b/helium/radio-helium.h
@@ -134,7 +134,6 @@
 #define FM_AFJUMP_CONFG_MODE 0x42
 #define FM_SRCH_CNFG_LEN    0x08
 #define FM_AFJUMP_CNFG_LEN  0x06
-#define STD_BUF_SIZE  256
 
 /* HCI timeouts */
 #define RADIO_HCI_TIMEOUT   (10000) /* 10 seconds */
@@ -514,10 +513,6 @@
 #define HCI_EV_RADIO_TEXT_PLUS_TAG      0x19
 #define HCI_EV_HW_ERR_EVENT             0x1A
 
-/*HCI event opcode for fm driver RDS support*/
-#define HCI_EV_DRIVER_RDS_EVENT         0x1B
-#define HCI_EV_E_RADIO_TEXT             0x1C
-
 #define HCI_REQ_DONE      0
 #define HCI_REQ_PEND      1
 #define HCI_REQ_CANCELED  2
diff --git a/helium/radio_helium_hal.c b/helium/radio_helium_hal.c
index e258bff..79e69f5 100644
--- a/helium/radio_helium_hal.c
+++ b/helium/radio_helium_hal.c
@@ -862,50 +862,6 @@
     }
 }
 
-static void hci_ev_driver_rds_event(uint8_t buff[])
-{
-    uint8_t rds_type;
-    char *rds_data = NULL;
-    rds_type = buff[0];
-
-    ALOGD("%s:%s:rds type = 0x%x", LOG_TAG, __func__, rds_type);
-    rds_data = malloc(STD_BUF_SIZE);
-    if (rds_data == NULL) {
-        ALOGE("%s:memory allocation failed\n", LOG_TAG);
-        return;
-    } else {
-        memcpy(rds_data, &buff[1],STD_BUF_SIZE);
-    }
-
-    switch (rds_type) {
-        case HCI_EV_RADIO_TEXT:
-            hal->jni_cb->rt_update_cb(rds_data);
-            break;
-
-        case HCI_EV_PROGRAM_SERVICE:
-            hal->jni_cb->ps_update_cb(rds_data);
-            break;
-
-        case HCI_EV_FM_AF_LIST:
-            hal->jni_cb->af_list_update_cb((uint16_t *)&rds_data);
-            break;
-
-        case HCI_EV_RADIO_TEXT_PLUS_TAG:
-            hal->jni_cb->rt_plus_update_cb(rds_data);
-            break;
-
-        case HCI_EV_E_RADIO_TEXT:
-            hal->jni_cb->ert_update_cb(rds_data);
-            break;
-
-        default:
-            ALOGD("%s: Unknown RDS event", __func__);
-            break;
-        }
-
-    free(rds_data);
-}
-
 static void hci_ev_ert()
 {
     char *data = NULL;
@@ -1119,9 +1075,6 @@
     case HCI_EV_EXT_COUNTRY_CODE:
         hci_ev_ext_country_code(((struct fm_event_header_t *)evt_buf)->params);
         break;
-    case HCI_EV_DRIVER_RDS_EVENT:
-        hci_ev_driver_rds_event(((struct fm_event_header_t *)evt_buf)->params);
-        break;
     case HCI_EV_HW_ERR_EVENT:
         hci_ev_hw_error();
         break;
diff --git a/jni/Android.bp b/jni/Android.bp
index 1d6e8e0..29da75c 100755
--- a/jni/Android.bp
+++ b/jni/Android.bp
@@ -4,6 +4,10 @@
     system_ext_specific: true,
     srcs: [
         "android_hardware_fm.cpp",
+        "ConfFileParser.cpp",
+        "ConfigFmThs.cpp",
+        "FmIoctlsInterface.cpp",
+        "FmPerformanceParams.cpp",
     ],
 
     host_ldlibs: ["-ldl"],
diff --git a/jni/ConfFileParser.cpp b/jni/ConfFileParser.cpp
new file mode 100644
index 0000000..d270690
--- /dev/null
+++ b/jni/ConfFileParser.cpp
@@ -0,0 +1,930 @@
+/*
+ * Copyright (c) 2014, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 "ConfFileParser.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <math.h>
+#include <utils/Log.h>
+
+//declaration of functions only specific to this file
+static char parse_line
+(
+  group_table *key_file,
+  const char *line,
+  char **cur_grp
+);
+
+static char parse_load_frm_fhandler
+(
+  group_table *key_file,
+  FILE *fp
+);
+
+static char line_is_grp
+(
+  group_table *key_file,
+  const char *str,
+  char **cur_grp
+);
+
+static void free_grp_list
+(
+  group *a
+);
+
+static void free_key_list
+(
+  key_value_pair_list *a
+);
+
+static char line_is_key_value_pair
+(
+  group_table *key_file,
+  const char *str,
+  const char *cur_grp
+);
+
+static char line_is_comment
+(
+  const char *str
+);
+
+static char grp_exist
+(
+  const group_table *key_file,
+  const char *new_grp
+);
+
+static char add_grp
+(
+  group_table *key_file,
+  const char *new_grp
+);
+
+static group *alloc_group
+(
+  void
+);
+
+static key_value_pair_list *alloc_key_value_pair
+(
+  void
+);
+
+static char add_key_value_pair
+(
+  group_table *key_file,
+  const char *cur_grp,
+  const char *key,
+  const char *val
+);
+
+
+//Definitions
+void free_strs
+(
+  char **str_array
+)
+{
+  char **str_array_cpy = str_array;
+  if(str_array != NULL) {
+     while(*str_array != NULL) {
+           free(*str_array);
+           str_array++;
+     }
+  }
+  free(str_array_cpy);
+}
+//ToDo: Come up with code hashing
+//function
+unsigned int get_hash_code
+(
+  const char *str
+)
+{
+
+  unsigned len = strlen(str);
+  unsigned int i;
+  unsigned int hash_code = 0;
+
+  for(i = 0; len > 0; len--, i++) {
+      hash_code += (int)((str[i] * pow(2, len))) % INT_MAX;
+      hash_code %= INT_MAX;
+  }
+  return hash_code;
+}
+
+static key_value_pair_list *alloc_key_value_pair
+(
+  void
+)
+{
+  key_value_pair_list *key_list = NULL;
+
+  key_list = (key_value_pair_list *)malloc(
+                                       sizeof(key_value_pair_list));
+  if(key_list != NULL) {
+     key_list->key = NULL;
+     key_list->next = NULL;
+     key_list->value = NULL;
+  }
+  return key_list;
+}
+
+static group * alloc_group
+(
+  void
+)
+{
+  group *grp = NULL;
+  unsigned int i;
+
+  grp = (group *)malloc(sizeof(group));
+  if(grp != NULL) {
+     grp->grp_name = NULL;
+     grp->grp_next = NULL;
+     grp->num_of_keys = 0;
+     grp->keys_hash_size = MAX_UNIQ_KEYS;
+     grp->list = (key_value_pair_list **)malloc
+                    (sizeof(key_value_pair_list *) * grp->keys_hash_size);
+     if(grp->list == NULL) {
+        ALOGE("Could not alloc group\n");
+        free(grp);
+        grp = NULL;
+     }else {
+        for(i = 0; i < grp->keys_hash_size; i++) {
+            grp->list[i] = NULL;
+        }
+     }
+  }
+  return grp;
+}
+
+group_table *get_key_file
+(
+)
+{
+  group_table *t = NULL;
+  unsigned int i;
+
+  t = (group_table *)malloc(sizeof(group_table));
+  if (t != NULL) {
+      t->grps_hash_size = MAX_UNIQ_GRPS;
+      t->num_of_grps = 0;
+      t->grps_hash = (group **)malloc(sizeof(group *)
+                                       * t->grps_hash_size);
+      if (t->grps_hash == NULL) {
+          free(t);
+          return NULL;
+      }
+      for(i = 0; i < t->grps_hash_size; i++) {
+          t->grps_hash[i] = NULL;
+      }
+  }
+  return t;
+}
+
+void free_key_file(
+  group_table *key_file
+)
+{
+  unsigned int i;
+
+  if(key_file != NULL) {
+     if(key_file->grps_hash != NULL) {
+        for(i = 0; i < key_file->grps_hash_size; i++) {
+            free_grp_list(key_file->grps_hash[i]);
+        }
+     }
+     free(key_file->grps_hash);
+     free(key_file);
+  }
+}
+
+static void free_grp_list
+(
+  group *a
+)
+{
+  group *next;
+  unsigned int i;
+
+  while(a != NULL) {
+       next = a->grp_next;
+       if(a->list != NULL) {
+          for(i = 0; i < a->keys_hash_size; i++) {
+              free_key_list(a->list[i]);
+          }
+       }
+       free(a->grp_name);
+       free(a->list);
+       free(a);
+       a = next;
+  }
+}
+
+static void free_key_list
+(
+  key_value_pair_list *a
+)
+{
+  key_value_pair_list *next;
+
+  while(a != NULL) {
+       next = a->next;
+       free(a->key);
+       free(a->value);
+       free(a);
+       a = next;
+  }
+}
+//return all the groups
+//present in the file
+char **get_grps
+(
+  const group_table *key_file
+)
+{
+  char **grps = NULL;
+  unsigned int i = 0;
+  unsigned int j = 0;
+  unsigned int grp_len;
+  group *grp_list;
+
+  if((key_file == NULL)
+     || (key_file->grps_hash == NULL)
+     || (key_file->grps_hash_size == 0)
+     || (key_file->num_of_grps == 0)) {
+     return grps;
+  }
+  grps = (char **)calloc((key_file->num_of_grps + 1),
+                           sizeof(char *));
+  if(grps == NULL) {
+     return grps;
+  }
+  for(i = 0; i < key_file->grps_hash_size; i++) {
+      grp_list = key_file->grps_hash[i];
+      while(grp_list != NULL) {
+            grp_len = strlen(grp_list->grp_name);
+            grps[j] = (char *)malloc(sizeof(char) *
+                                     (grp_len + 1));
+            if(grps[j] == NULL) {
+               free_strs(grps);
+               grps = NULL;
+               return grps;
+            }
+            memcpy(grps[j], grp_list->grp_name,
+                   (grp_len + 1));
+            grp_list = grp_list->grp_next;
+            j++;
+      }
+  }
+  grps[j] = NULL;
+  return grps;
+}
+
+//returns the list of keys
+//associated with group name
+char **get_keys
+(
+  const group_table *key_file,
+  const char *grp_name
+)
+{
+  unsigned int grp_hash_code;
+  unsigned int grp_index;
+  unsigned int num_of_keys;
+  unsigned int i;
+  unsigned int j = 0;
+  unsigned int key_len;
+  group *grp;
+  key_value_pair_list *key_val_list;
+  char **keys = NULL;
+
+  if((key_file == NULL) || (grp_name == NULL)
+     || (key_file->num_of_grps == 0) ||
+     (key_file->grps_hash_size == 0) ||
+     (key_file->grps_hash == NULL) ||
+     (!strcmp(grp_name, ""))) {
+      return keys;
+  }
+  grp_hash_code = get_hash_code(grp_name);
+  grp_index = (grp_hash_code % key_file->grps_hash_size);
+  grp = key_file->grps_hash[grp_index];
+  while(grp != NULL) {
+        if(!strcmp(grp_name, grp->grp_name)) {
+            if((grp->num_of_keys == 0)
+               || (grp->keys_hash_size == 0)
+               || (grp->list == 0)) {
+               return keys;
+            }
+            keys = (char **)calloc((grp->num_of_keys + 1),
+                                   sizeof(char *));
+            if(keys == NULL) {
+                return keys;
+            }
+            for(i = 0; i < grp->keys_hash_size; i++) {
+                key_val_list = grp->list[i];
+                while(key_val_list != NULL) {
+                     key_len = strlen(key_val_list->key);
+                     keys[j] = (char *)malloc(sizeof(char) *
+                                              (key_len + 1));
+                     if(keys[j] == NULL) {
+                         free_strs(keys);
+                         keys = NULL;
+                         return keys;
+                     }
+                     memcpy(keys[j], key_val_list->key,
+                            (key_len + 1));
+                     j++;
+                     key_val_list = key_val_list->next;
+                }
+            }
+            keys[j] = NULL;
+            return keys;
+        }
+        grp = grp->grp_next;
+  }
+  return keys;
+}
+
+char *get_value
+(
+   const group_table *key_file,
+   const char *grp_name,
+   const char *key
+)
+{
+   unsigned int grp_hash_code;
+   unsigned int key_hash_code;
+   unsigned int grp_index;
+   unsigned int key_index;
+   unsigned val_len;
+   char *val = NULL;
+   group *grp;
+   key_value_pair_list *list;
+
+   if((key_file == NULL) || (grp_name == NULL)
+      || (key == NULL) || (key_file->grps_hash == NULL)
+      || (key_file->grps_hash_size == 0) || !strcmp(grp_name, "")
+      ||(!strcmp(key, ""))) {
+       return NULL;
+   }
+   grp_hash_code = get_hash_code(grp_name);
+   key_hash_code = get_hash_code(key);
+   grp_index = (grp_hash_code % key_file->grps_hash_size);
+   grp = key_file->grps_hash[grp_index];
+   while(grp != NULL) {
+         if(!strcmp(grp_name, grp->grp_name) && grp->keys_hash_size
+            && grp->list) {
+            key_index = (key_hash_code % grp->keys_hash_size);
+            list = grp->list[key_index];
+            while((list != NULL) && (strcmp(list->key, key))) {
+                   list = list->next;
+            }
+            if(list != NULL) {
+                val_len = strlen(list->value);
+                val = (char *)malloc(sizeof(char) * (val_len + 1));
+                if(val != NULL) {
+                   memcpy(val, list->value, val_len);
+                   val[val_len] = '\0';
+                }
+            }
+            return val;
+         }
+         grp = grp->grp_next;
+   }
+   return val;
+}
+//open the file,
+//read, parse and load
+//returns PARSE_SUCCESS if successfully
+//loaded else PARSE_FAILED
+char parse_load_file
+(
+  group_table *key_file,
+  const char *file
+)
+{
+  FILE *fp;
+  char ret = FALSE;
+
+  if((file == NULL) || !strcmp(file, "")) {
+     ALOGE("File name is null or empty \n");
+     return ret;
+  }
+
+  fp = fopen(file, "r");
+  if(fp == NULL) {
+     ALOGE("could not open file for read\n");
+     return ret;
+  }
+
+  ret = parse_load_frm_fhandler(key_file, fp);
+  fclose(fp);
+
+  return ret;
+}
+
+//Read block of data from file handler
+//extract each line, check kind of line(comment,
+//group, key value pair)
+static char parse_load_frm_fhandler
+(
+  group_table *key_file,
+  FILE *fp
+)
+{
+  char buf[MAX_LINE_LEN];
+  char ret = TRUE;
+  char *line = NULL;
+  void *new_line;
+  char *cur_grp = NULL;
+  unsigned line_len = 0;
+  unsigned line_allocated = 0;
+  unsigned int bytes_read = 0;
+  unsigned int i;
+  bool has_carriage_rtn = false;
+
+  while((bytes_read = fread(buf, 1, MAX_LINE_LEN, fp))) {
+        for(i = 0; i < bytes_read; i++) {
+            if(line_len == line_allocated) {
+                line_allocated += 25;
+                new_line = realloc(line, line_allocated);
+                if(new_line == NULL) {
+                   ret = FALSE;
+                   ALOGE("memory allocation failed for line\n");
+                   break;
+                }
+                line = (char *)new_line;
+            }
+            if((buf[i] == '\n')) {
+                has_carriage_rtn = false;
+                line[line_len] = '\0';
+                ret = parse_line(key_file, line, &cur_grp);
+                line_len = 0;
+                if(ret == FALSE) {
+                   ALOGE("could not parse the line, line not proper\n");
+                   break;
+                }
+            }else if(buf[i] == '\r') {
+                ALOGE("File has carriage return\n");
+                has_carriage_rtn = true;
+            }else if(has_carriage_rtn) {
+                ALOGE("File format is not proper, no line character\
+                        after carraige return\n");
+                ret = FALSE;
+                break;
+            }else {
+                line[line_len] = buf[i];
+                line_len++;
+            }
+        }
+        if (!ret) {
+            break;
+        }
+  }
+  free(line);
+  free(cur_grp);
+
+  return ret;
+}
+
+//checks whether a line is
+//comment or grp or key pair value
+//and accordingly adds to list
+static char parse_line
+(
+  group_table *key_file,
+  const char *line,
+  char **cur_grp
+)
+{
+  const char *line_begin;
+  char *grp_name;
+  unsigned int len;
+
+  if((line == NULL) || (key_file == NULL)) {
+      ALOGE("key file or line is null\n");
+      return FALSE;
+  }
+
+  for(line_begin = line; isspace(*line_begin);
+          line_begin++);
+
+  if(line_is_comment(line_begin)) {
+      ALOGE("line is comment\n");
+      return TRUE;
+  }else if(line_is_grp(key_file, line_begin, cur_grp)) {
+      ALOGE("line is grp\n");
+      return TRUE;
+  }else if(line_is_key_value_pair(key_file, line_begin, *cur_grp)) {
+      ALOGE("line is key value pair\n");
+      return TRUE;
+  }else {
+     ALOGE("line is neither comment, grp nor key value pair\n");
+     return FALSE;
+  }
+}
+
+static char line_is_comment
+(
+  const char *str
+)
+{
+  if(str == NULL) {
+      return FALSE;
+  }else if(((*str) == '#') || ((*str) == '\0')
+       || ((*str) == '\n')) {
+      return TRUE;
+  }else {
+      ALOGE("line is not comment\n");
+      return FALSE;
+  }
+}
+
+//return true if a group
+//name already exist
+//else false
+static char grp_exist
+(
+  const group_table *key_file,
+  const char *new_grp
+)
+{
+  unsigned hash_code;
+  unsigned int index;
+  group *grp;
+
+  if((key_file == NULL) || (new_grp == NULL)
+     || (!key_file->grps_hash_size)) {
+     return FALSE;
+  }else {
+    hash_code = get_hash_code(new_grp);
+    index = hash_code % key_file->grps_hash_size;
+    grp = key_file->grps_hash[index];
+    while(grp != NULL) {
+          if (!strcmp(grp->grp_name, new_grp))
+              return TRUE;
+          grp = grp->grp_next;
+    }
+    return FALSE;
+  }
+}
+
+//Add a group to group
+//table if it does not exist
+static char add_grp
+(
+  group_table *key_file,
+  const char *new_grp
+)
+{
+  unsigned int hash_code;
+  unsigned int index;
+  unsigned int grp_name_len;
+  group *grp;
+
+  if(!grp_exist(key_file, new_grp)) {
+      if((key_file == NULL) || (new_grp == NULL)
+         || !key_file->grps_hash_size) {
+         return FALSE;
+      }
+      hash_code = get_hash_code(new_grp);
+      ALOGE("group hash code is: %u\n", hash_code);
+      index = hash_code % key_file->grps_hash_size;
+      ALOGE("group index is: %u\n", index);
+      grp = alloc_group();
+      if(grp == NULL) {
+         return FALSE;
+      }
+      grp_name_len = strlen(new_grp);
+      grp->grp_name = (char *)malloc(
+                                  sizeof(char) * (grp_name_len + 1));
+      if(grp->grp_name == NULL) {
+         ALOGE("could not alloc memory for group name\n");
+         ALOGE("Add group failed\n");
+         free_grp_list(grp);
+         return FALSE;
+      }else {
+         memcpy(grp->grp_name, new_grp, (grp_name_len + 1));
+      }
+      grp->grp_next = key_file->grps_hash[index];
+      key_file->grps_hash[index] = grp;
+      key_file->num_of_grps++;
+      return TRUE;
+  }else {
+     return FALSE;
+  }
+}
+
+//checks validity of a group
+//a valid group is
+//inside [] group name must be
+//alphanumeric
+//Example: [grpName]
+static char line_is_grp
+(
+  group_table *key_file,
+  const char *str,
+  char **cur_grp
+)
+{
+  const char *g_start;
+  const char *g_end;
+  char *new_grp;
+  unsigned int grp_len;
+
+  if ((str == NULL) || (key_file == NULL)) {
+      ALOGE("str is null or key file is null\n");
+      return FALSE;
+  }
+  //checks start mark char ']'
+  if(((*str) != '[')) {
+      ALOGE("start mark is not '['\n");
+      return FALSE;
+  }else {
+      str++;
+      g_start = str;
+  }
+  //checks the end char '['
+  while((*str != '\0') && ((*str) != ']')) {
+        str++;
+  }
+  //if end mark group not found
+  if ((*str) != ']') {
+       ALOGE("grp end mark is not '['\n");
+       return FALSE;
+  }else {
+       g_end = (str - 1);
+  }
+
+  str++;
+  //if end mark found checks the rest chars as well
+  //rest chars should be space
+  while(((*str) == ' ') || ((*str) == '\t')) {
+        str++;
+  }
+  if(*str) {
+     ALOGE("after ']' there are some character\n");
+     return FALSE;
+  }
+
+  str = g_start;
+  while((*g_start != '\0') && (g_start != g_end)
+         && isalnum(*g_start)) {
+        g_start++;
+  }
+  if((g_start == g_end) && isalnum(*g_start)) {
+      //look up if already exist
+      //return false else insert the grp in grp table
+      grp_len = (g_end - str + 1);
+      new_grp = (char *)malloc(sizeof(char) * (grp_len + 1));
+      if (new_grp == NULL) {
+          ALOGE("could not alloc memory for new group\n");
+          return FALSE;
+      }
+      memcpy(new_grp, str, grp_len);
+      new_grp[grp_len] = '\0';
+
+      if(add_grp(key_file, new_grp)) {
+          free(*cur_grp);
+         *cur_grp = new_grp;
+         return TRUE;
+      }else {
+         ALOGE("could not add group to group table\n");
+         return FALSE;
+      }
+  }else {
+      return FALSE;
+  }
+}
+
+static char key_exist
+(
+  const group_table *key_file,
+  const char *cur_grp,
+  const char *key
+)
+{
+  unsigned int grp_hash_code;
+  unsigned int key_hash_code;
+  unsigned int grp_index;
+  unsigned int key_index;
+  group *grp = NULL;
+  key_value_pair_list *list = NULL;
+
+  if((key_file != NULL) && (cur_grp != NULL)
+      && (key != NULL) && ((key_file->grps_hash != NULL))
+      && (strcmp(key, ""))) {
+     grp_hash_code = get_hash_code(cur_grp);
+     grp_index = (grp_hash_code % key_file->grps_hash_size);
+     grp = key_file->grps_hash[grp_index];
+     key_hash_code = get_hash_code(key);
+     while((grp != NULL)) {
+           if(!strcmp(cur_grp, grp->grp_name)) {
+              key_index = (key_hash_code % grp->keys_hash_size);
+              if(grp->list)
+                 list = grp->list[key_index];
+              while((list != NULL) && strcmp(key, list->key)) {
+                    list = list->next;
+              }
+              if(list != NULL){
+                  return TRUE;
+              }else{
+                  return FALSE;
+              }
+           }
+           grp = grp->grp_next;
+     }
+     if(!grp) {
+        return TRUE;
+     }else {
+        return FALSE;
+     }
+  }else {
+     return FALSE;
+  }
+}
+
+//checks validity of key
+//a valid key must start in
+//a seperate line and key must
+//be alphanumeric and before '='
+//there must not be any space
+//Example: key=value
+static char line_is_key_value_pair
+(
+  group_table *key_file,
+  const char *str,
+  const char *cur_grp
+)
+{
+  const char *equal_start;
+  char *key = NULL;
+  char *val = NULL;
+  unsigned key_len;
+  unsigned val_len;
+
+  if((str == NULL) || (cur_grp == NULL) ||
+     !strcmp(cur_grp, "") || (key_file == NULL)) {
+     ALOGE("line is null or cur group or key file is null or empty\n");
+     return FALSE;
+  }
+  equal_start = strchr(str, '=');
+  key_len = (equal_start - str);
+  if((equal_start == NULL) || (equal_start == str)) {
+     ALOGE("line does not have '=' character or no key\n");
+     return FALSE;
+  }
+  while((str != equal_start) && isalnum(*str))
+        str++;
+  if((str == equal_start)) {
+      key = (char *)malloc(sizeof(char) * (key_len + 1));
+      if(key == NULL) {
+         ALOGE("could not alloc memory for new key\n");
+         return FALSE;
+      }
+      equal_start++;
+      val_len = strlen(equal_start);
+      val = (char *)malloc(sizeof(char) * (val_len + 1));
+      if(val == NULL) {
+         ALOGE("could not alloc memory for value\n");
+         if(key){
+             free(key);
+             key = NULL;
+         }
+         return FALSE;
+      }
+      memcpy(key, (str - key_len), key_len);
+      memcpy(val, equal_start, val_len);
+      key[key_len] = '\0';
+      val[val_len] = '\0';
+      ALOGE("Grp: %s, key: %s, value: %s\n", cur_grp, key, val);
+      return add_key_value_pair(key_file,
+                                 cur_grp, key, val);
+  }else {
+     ALOGE("key name doesnot have alpha numeric char\n");
+     return FALSE;
+  }
+}
+
+static char add_key_value_pair
+(
+  group_table *key_file,
+  const char *cur_grp,
+  const char *key,
+  const char *val
+)
+{
+  unsigned int grp_hash_code;
+  unsigned int key_hash_code;
+  unsigned int grp_index;
+  unsigned int key_index;
+  unsigned key_len = 0;
+  unsigned val_len = 0;
+  group *grp = NULL;
+  key_value_pair_list *list = NULL;
+
+  if((key_file != NULL) && (cur_grp != NULL)
+      && (key != NULL) && ((key_file->grps_hash != NULL))
+      && (strcmp(key, ""))) {
+     grp_hash_code = get_hash_code(cur_grp);
+     ALOGE("grp hash code is %u\n", grp_hash_code);
+     grp_index = (grp_hash_code % key_file->grps_hash_size);
+     ALOGE("grp index is %u\n", grp_index);
+     grp = key_file->grps_hash[grp_index];
+     key_hash_code = get_hash_code(key);
+     while((grp != NULL)) {
+           if(!strcmp(cur_grp, grp->grp_name)) {
+              key_index = (key_hash_code % grp->keys_hash_size);
+              if(grp->list) {
+                 list = grp->list[key_index];
+              }else {
+                 ALOGE("group list is null\n");
+                 goto err;
+              }
+              while((list != NULL) && strcmp(key, list->key)) {
+                    list = list->next;
+              }
+              if(list != NULL) {
+                  ALOGE("group already contains the key\n");
+                  goto err;
+              }else{
+                  list = alloc_key_value_pair();
+                  if(list == NULL) {
+                     ALOGE("add key value failed as could not alloc memory for key\
+                            val pair\n");
+                     goto err;
+                  }
+                  if(key) {
+                      key_len = strlen(key);
+                  }
+                  list->key = (char *)malloc(sizeof(char) *
+                                              (key_len + 1));
+                  if(list->key == NULL) {
+                     ALOGE("could not alloc memory for key\n");
+                     free(list);
+                     goto err;
+                  }
+                  if(val) {
+                      val_len = strlen(val);
+                  }
+                  list->value = (char *)malloc(sizeof(char) *
+                                                (val_len + 1));
+                  if(!list->value) {
+                      free(list->key);
+                      free(list);
+                      goto err;
+                  }
+                  memcpy(list->key, key, key_len);
+                  memcpy(list->value, val, val_len);
+                  if (key) free((char*)key);
+                  if (val) free((char*)val);
+                  list->key[key_len] = '\0';
+                  list->value[val_len] = '\0';
+                  list->next = grp->list[key_index];
+                  grp->list[key_index] = list;
+                  grp->num_of_keys++;
+                  return TRUE;
+              }
+           }
+           grp = grp->grp_next;
+     }
+     ALOGE("group does not exist\n");
+     goto err;
+  }
+err:
+     if (key) free((char*)key);
+     if (val) free((char*)val);
+     return FALSE;
+}
diff --git a/jni/ConfFileParser.h b/jni/ConfFileParser.h
new file mode 100644
index 0000000..33b86ce
--- /dev/null
+++ b/jni/ConfFileParser.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2014, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 __CONF_FILE_PARSER_H__
+#define __CONF_FILE_PARSER_H__
+
+#define MAX_LINE_LEN 512
+#define MAX_UNIQ_KEYS 5
+#define MAX_UNIQ_GRPS 10
+#define TRUE 1
+#define FALSE 0
+
+struct key_value_pair_list
+{
+   char *key;
+   char *value;
+   key_value_pair_list *next;
+};
+
+struct group
+{
+    char *grp_name;
+    unsigned int num_of_keys;
+    unsigned int keys_hash_size;
+    key_value_pair_list **list;
+    group *grp_next;
+};
+
+struct group_table
+{
+    unsigned int grps_hash_size;
+    unsigned int num_of_grps;
+    group **grps_hash;
+};
+
+enum CONF_PARSE_ERRO_CODE
+{
+  PARSE_SUCCESS,
+  INVALID_FILE_NAME,
+  FILE_OPEN_FAILED,
+  FILE_NOT_PROPER,
+  MEMORY_ALLOC_FAILED,
+  PARSE_FAILED,
+};
+
+unsigned int get_hash_code(const char *str);
+group_table *get_key_file();
+void free_strs(char **str_array);
+void free_key_file(group_table *key_file);
+char parse_load_file(group_table *key_file, const char *file);
+char **get_grps(const group_table *key_file);
+char **get_keys(const group_table *key_file, const char *grp);
+char *get_value(const group_table *key_file, const char *grp,
+                 const char *key);
+
+#endif //__CONF_FILE_PARSER_H__
diff --git a/jni/ConfigFmThs.cpp b/jni/ConfigFmThs.cpp
new file mode 100644
index 0000000..3845dfd
--- /dev/null
+++ b/jni/ConfigFmThs.cpp
@@ -0,0 +1,528 @@
+/*
+ * Copyright (c) 2014, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 <cstdlib>
+#include <cstring>
+#include "ConfigFmThs.h"
+#include "FmPerformanceParams.h"
+#include <utils/Log.h>
+
+static int compare_name
+(
+   const void *name1, const void *name2
+)
+{
+    char *first = (char *)name1;
+    struct NAME_MAP *second = (struct NAME_MAP *)name2;
+
+    return(strcmp(first, second->name));
+}
+
+ConfigFmThs :: ConfigFmThs
+(
+)
+{
+    keyfile = NULL;
+}
+
+ConfigFmThs :: ~ConfigFmThs
+(
+)
+{
+   free_key_file(keyfile);
+}
+
+void ConfigFmThs :: set_af_ths
+(
+   UINT fd
+)
+{
+    signed char ret = FM_SUCCESS;
+    char **keys;
+    char **keys_cpy;
+    char *key_value;
+    int value;
+    FmPerformanceParams perf_params;
+    struct NAME_MAP *found;
+
+    if(keyfile != NULL) {
+       keys_cpy = keys = get_keys(keyfile, GRPS_MAP[0].name);
+       if(keys != NULL) {
+          while(*keys != NULL) {
+              ALOGE("key found is: %s\n", *keys);
+              found = (NAME_MAP *)bsearch(*keys, AF_PARAMS_MAP,
+                          MAX_AF_PARAMS, sizeof(NAME_MAP), compare_name);
+              if(found != NULL) {
+                 key_value = get_value(keyfile,
+                                     GRPS_MAP[0].name, found->name);
+                 if((key_value != NULL) && strcmp(key_value, "")) {
+                    value = atoi(key_value);
+                    switch(found->num) {
+                    case AF_RMSSI_TH:
+                         if((value >= AF_RMSSI_TH_MIN)
+                             && (value <= AF_RMSSI_TH_MAX)) {
+                             ALOGE("Set af rmssi th: %d\n", value);
+                             ret = perf_params.SetAfRmssiTh(fd, value);
+                             if(ret == FM_FAILURE) {
+                                ALOGE("Error in setting Af Rmssi th\n");
+                                break;
+                             }
+                             unsigned short th;
+                             ret = perf_params.GetAfRmssiTh(fd, th);
+                             if(ret == FM_SUCCESS) {
+                                ALOGE("Read af rmssith: %hd\n", th);
+                             }else {
+                                ALOGE("Error in reading Af Rmssi th\n");
+                             }
+                         }
+                         break;
+                    case AF_RMSSI_SAMPLES:
+                         if((value >= AF_RMSSI_SAMPLES_MIN)
+                             && (value <= AF_RMSSI_SAMPLES_MAX)) {
+                             ALOGE("Set af rmssi samples cnt: %d\n", value);
+                             ret = perf_params.SetAfRmssiSamplesCnt(fd, value);
+                             if(ret == FM_FAILURE) {
+                                ALOGE("Error in setting af rmssi samples\n");
+                                break;
+                             }
+                             unsigned char cnt;
+                             ret = perf_params.GetAfRmssiSamplesCnt(fd, cnt);
+                             if(ret == FM_SUCCESS) {
+                                ALOGE("Read af rmssi samples cnt: %hhd\n", cnt);
+                             }else {
+                                 ALOGE("Error in reading rmssi samples\n");
+                             }
+                         }
+                         break;
+                    case GOOD_CH_RMSSI_TH:
+                         if((value >= GOOD_CH_RMSSI_TH_MIN)
+                             && (value <= GOOD_CH_RMSSI_TH_MAX)) {
+                             ALOGE("Set Good channle rmssi th: %d\n", value);
+                             ret = perf_params.SetGoodChannelRmssiTh(fd, value);
+                             if(ret == FM_FAILURE) {
+                                ALOGE("Error in setting Good channle rmssi th\n");
+                                break;
+                             }
+                             signed char th;
+                             ret = perf_params.GetGoodChannelRmssiTh(fd, th);
+                             if(ret == FM_SUCCESS) {
+                                ALOGE("Read good channel rmssi th: %d\n", th);
+                             }else {
+                                ALOGE("Error in reading Good channle rmssi th\n");
+                             }
+                         }
+                         break;
+                   }
+                 }else {
+                   ALOGE("key_val for key: %s is empty\n",
+                             *keys);
+                 }
+                 free(key_value);
+              }
+              keys++;
+          }
+       }else {
+          ALOGE("No of keys found is zero\n");
+       }
+       free_strs(keys_cpy);
+    }else {
+       ALOGE("key file is null\n");
+    }
+}
+
+void ConfigFmThs :: set_srch_ths
+(
+    UINT fd
+)
+{
+    signed char ret = FM_SUCCESS;
+    char **keys = NULL;
+    char **keys_cpy = NULL;
+    char *key_value = NULL;
+    int value;
+    FmPerformanceParams perf_params;
+    struct NAME_MAP *found = NULL;
+
+    if(keyfile != NULL) {
+       keys_cpy = keys = get_keys(keyfile, GRPS_MAP[2].name);
+       if(keys != NULL) {
+          while(*keys != NULL) {
+              found = (NAME_MAP *)bsearch(*keys, SEACH_PARAMS_MAP,
+                           MAX_SRCH_PARAMS, sizeof(NAME_MAP), compare_name);
+              if(found != NULL) {
+                 key_value = get_value(keyfile, GRPS_MAP[2].name, found->name);
+                 ALOGE("found srch ths: %s: %s\n", found->name, key_value);
+                 if((key_value != NULL) && strcmp(key_value, "")) {
+                    value = atoi(key_value);
+                    switch(found->num) {
+                    case SINR_FIRST_STAGE:
+                         if((value >= SINR_FIRST_STAGE_MIN)
+                             && (value <= SINR_FIRST_STAGE_MAX)) {
+                             ALOGE("Set sinr first stage: %d\n", value);
+                             ret = perf_params.SetSinrFirstStage(fd, value);
+                             if(ret == FM_FAILURE) {
+                                ALOGE("Error in setting sinr first stage\n");
+                                break;
+                             }
+                             signed char th;
+                             ret = perf_params.GetSinrFirstStage(fd, th);
+                             if(ret == FM_SUCCESS) {
+                                ALOGE("Read sinr first stage: %d\n", th);
+                             }else {
+                                ALOGE("Error in reading sinr first stage\n");
+                             }
+                         }
+                         break;
+                    case RMSSI_FIRST_STAGE:
+                         if((value >= RMSSI_FIRST_STAGE_MIN)
+                             && (value <= RMSSI_FIRST_STAGE_MAX)) {
+                             ALOGE("Set rmssi first stage: %d\n", value);
+                             ret = perf_params.SetRmssiFirstStage(fd, value);
+                             if(ret == FM_FAILURE) {
+                                ALOGE("Error in setting rmssi first stage\n");
+                                break;
+                             }
+                             signed char th;
+                             ret = perf_params.GetRmssiFirstStage(fd, th);
+                             if(ret == FM_SUCCESS) {
+                                ALOGE("Read rmssi first stage: %d\n", th);
+                             }else {
+                                ALOGE("Error in reading rmssi first stage\n");
+                             }
+                         }
+                         break;
+                    case INTF_LOW_TH:
+                         if((value >= INTF_LOW_TH_MIN)
+                             && (value <= INTF_LOW_TH_MAX)) {
+                            ALOGE("Set intf low th: %d\n", value);
+                            ret = perf_params.SetIntfLowTh(fd, value);
+                            if(ret == FM_FAILURE) {
+                                ALOGE("Error in setting intf low th\n");
+                                break;
+                            }
+                            unsigned char th;
+                            ret = perf_params.GetIntfLowTh(fd, th);
+                            if(ret == FM_SUCCESS) {
+                               ALOGE("Read intf low th: %u\n", th);
+                            }else {
+                               ALOGE("Error in reading intf low th\n");
+                            }
+                         }
+                         break;
+                    case INTF_HIGH_TH:
+                         if((value >= INTF_HIGH_TH_MIN)
+                             && (value <= INTF_HIGH_TH_MAX)) {
+                            ALOGE("Set intf high th: %d\n", value);
+                            ret = perf_params.SetIntfHighTh(fd, value);
+                            if(ret == FM_FAILURE) {
+                                ALOGE("Error in setting intf high th\n");
+                                break;
+                            }
+                            unsigned char th;
+                            ret = perf_params.GetIntfHighTh(fd, th);
+                            if(ret == FM_SUCCESS) {
+                               ALOGE("Read intf high th: %u\n", th);
+                            }else {
+                               ALOGE("Error in reading intf high th\n");
+                            }
+                         }
+                         break;
+                    case CF0_TH:
+                         ALOGE("Set cf0 th: %d\n", value);
+                         ret = perf_params.SetCf0Th12(fd, value);
+                         if(ret == FM_FAILURE) {
+                            ALOGE("Error in setting cf0 th\n");
+                            break;
+                         }
+                         int th;
+                         ret = perf_params.GetCf0Th12(fd, th);
+                         if(ret == FM_SUCCESS) {
+                            ALOGE("Read CF012 th: %d\n", th);
+                         }else {
+                            ALOGE("Error in reading cf0 th\n");
+                         }
+                         break;
+                    case SRCH_ALGO_TYPE:
+                         if((value >= SRCH_ALGO_TYPE_MIN)
+                             && (value <= SRCH_ALGO_TYPE_MAX)) {
+                             ALOGE("Set search algo type: %d\n", value);
+                             ret = perf_params.SetSrchAlgoType(fd, value);
+                             if(ret == FM_FAILURE) {
+                                ALOGE("Error in setting search algo type\n");
+                                break;
+                             }
+                             unsigned char algo;
+                             ret = perf_params.GetSrchAlgoType(fd, algo);
+                             if(ret == FM_SUCCESS) {
+                                ALOGE("Read algo type: %u\n", algo);
+                             }else {
+                                ALOGE("Error in reading search algo type\n");
+                             }
+                         }
+                         break;
+                    case SINR_SAMPLES:
+                         if((value >= SINR_SAMPLES_CNT_MIN)
+                             && (value <= SINR_SAMPLES_CNT_MAX)) {
+                             ALOGE("Set sinr samples count: %d\n", value);
+                             ret = perf_params.SetSinrSamplesCnt(fd, value);
+                             if(ret == FM_FAILURE) {
+                                ALOGE("Error in setting sinr samples count\n");
+                                break;
+                             }
+                             unsigned char cnt;
+                             ret = perf_params.GetSinrSamplesCnt(fd, cnt);
+                             if(ret == FM_SUCCESS) {
+                                ALOGE("Read sinr samples cnt: %u\n", cnt);
+                             }else {
+                                ALOGE("Error in reading sinr samples count\n");
+                             }
+                         }
+                         break;
+                    case SINR:
+                         if((value >= SINR_FINAL_STAGE_MIN)
+                             && (value <= SINR_FINAL_STAGE_MAX)) {
+                             ALOGE("Set final stage sinr: %d\n", value);
+                             ret = perf_params.SetSinrFinalStage(fd, value);
+                             if(ret == FM_FAILURE) {
+                                ALOGE("Error in setting final stage sinr\n");
+                                break;
+                             }
+                             signed char th;
+                             ret = perf_params.GetSinrFinalStage(fd, th);
+                             if(ret == FM_SUCCESS) {
+                                ALOGE("Read final stage sinr: %d\n", th);
+                             }else {
+                                ALOGE("Error in reading final stage sinr\n");
+                             }
+                         }
+                         break;
+                    }
+                 }else {
+                    ALOGE("key_value for key: %s is empty\n",
+                                  *keys);
+                 }
+                 free(key_value);
+              }
+              keys++;
+          }
+       }else {
+          ALOGE("No of keys found is zero\n");
+       }
+       free_strs(keys_cpy);
+    }else {
+       ALOGE("key file is null\n");
+    }
+}
+
+void ConfigFmThs :: set_hybrd_list
+(
+    UINT fd
+)
+{
+    signed char ret = FM_SUCCESS;
+    char **keys = NULL;
+    char **keys_cpy = NULL;
+    char *key_value = NULL;
+    char *freqs = NULL;
+    unsigned int *freqs_array = NULL;
+    signed char *sinrs_array = NULL;
+    char *sinrs = NULL;
+    int value;
+    unsigned int freq_cnt = 0;
+    unsigned int sinr_cnt = 0;
+    FmPerformanceParams perf_params;
+    struct NAME_MAP *found;
+
+    ALOGE("Inside hybrid srch list\n");
+    if(keyfile != NULL) {
+       keys_cpy = keys = get_keys(keyfile, GRPS_MAP[1].name);
+       if(keys != NULL) {
+          while(*keys != NULL) {
+              found = (NAME_MAP *)bsearch(*keys, HYBRD_SRCH_MAP,
+                           MAX_HYBRID_SRCH_PARAMS, sizeof(NAME_MAP), compare_name);
+              if(found != NULL) {
+                 key_value = get_value(keyfile, GRPS_MAP[1].name, found->name);
+                 if((key_value != NULL) && strcmp(key_value, "")) {
+                     switch(found->num) {
+                     case FREQ_LIST:
+                          freqs = key_value;
+                          break;
+                     case SINR_LIST:
+                          sinrs = key_value;
+                          break;
+                     default:
+                          free(key_value);
+                          break;
+                     }
+                 }
+              }
+              keys++;
+          }
+          free_strs(keys_cpy);
+       }else {
+          ALOGE("No of keys found is zero\n");
+       }
+    }else {
+       ALOGE("key file is null\n");
+    }
+
+    freq_cnt = extract_comma_sep_freqs(freqs, &freqs_array, ",");
+    sinr_cnt = extract_comma_sep_sinrs(sinrs, &sinrs_array, ",");
+
+    if((freq_cnt == sinr_cnt) && (sinr_cnt > 0)) {
+       perf_params.SetHybridSrchList(fd, freqs_array, sinrs_array, freq_cnt);
+    }
+
+    free(freqs);
+    free(sinrs);
+    free(freqs_array);
+    free(sinrs_array);
+}
+
+unsigned int ConfigFmThs :: extract_comma_sep_freqs
+(
+    char *freqs,
+    unsigned int **freqs_arr,
+    const char *str
+)
+{
+    char *next_freq;
+    char *saveptr = NULL;
+    unsigned int freq;
+    unsigned int *freqs_new_arr;
+    unsigned int size = 0;
+    unsigned int len = 0;
+
+    next_freq = strtok_r(freqs, str, &saveptr);
+    while(next_freq != NULL) {
+          freq = atoi(next_freq);
+          ALOGD("HYBRID_SRCH freq: %u\n", freq);
+          if(size == len) {
+             size <<= 1;
+             if(size == 0)
+                size = 1;
+             freqs_new_arr = (unsigned int *)realloc(*freqs_arr,
+                                              size * sizeof(unsigned int));
+             if(freqs_new_arr == NULL) {
+                free(*freqs_arr);
+                *freqs_arr = NULL;
+                break;
+             }
+             *freqs_arr = freqs_new_arr;
+          }
+          (*freqs_arr)[len] = freq;
+          len++;
+          next_freq = strtok_r(NULL, str, &saveptr);
+    }
+    return len;
+}
+
+unsigned int ConfigFmThs :: extract_comma_sep_sinrs
+(
+    char *sinrs,
+    signed char **sinrs_arr,
+    const char *str
+)
+{
+    char *next_sinr;
+    char *saveptr = NULL;
+    signed char *sinrs_new_arr;
+    unsigned int size = 0;
+    unsigned int len = 0;
+    signed char sinr;
+
+    next_sinr = strtok_r(sinrs, str, &saveptr);
+    while(next_sinr != NULL) {
+          sinr = atoi(next_sinr);
+          ALOGD("HYBRID_SRCH sinr: %d\n", sinr);
+          if(size == len) {
+             size <<= 1;
+             if(size == 0)
+                size = 1;
+             sinrs_new_arr = (signed char *)realloc(*sinrs_arr,
+                                               size * sizeof(signed char));
+             if(sinrs_new_arr == NULL) {
+                free(*sinrs_arr);
+                *sinrs_arr = NULL;
+                break;
+             }
+             *sinrs_arr = sinrs_new_arr;
+          }
+          (*sinrs_arr)[len] = sinr;
+          len++;
+          next_sinr = strtok_r(NULL, str, &saveptr);
+    }
+    return len;
+}
+
+void  ConfigFmThs :: SetRxSearchAfThs
+(
+    const char *file, UINT fd
+)
+{
+    int index;
+    struct NAME_MAP *found;
+    char **grps = NULL;
+    char **grps_cpy = NULL;
+
+    keyfile = get_key_file();
+
+    ALOGE("file name is: %s\n", file);
+    if(!parse_load_file(keyfile, file)) {
+       ALOGE("Error in loading threshold file\n");
+    }else {
+       grps_cpy = grps = get_grps(keyfile);
+       if(grps != NULL) {
+          while(*grps != NULL) {
+              ALOGE("Search grp: %s\n", *grps);
+              found = (NAME_MAP *)bsearch(*grps, GRPS_MAP, MAX_GRPS,
+                             sizeof(NAME_MAP), compare_name);
+              if(found != NULL) {
+                 ALOGE("Found group: %s\n", found->name);
+                 switch(found->num) {
+                 case AF_THS:
+                      set_af_ths(fd);
+                      break;
+                 case SRCH_THS:
+                      set_srch_ths(fd);
+                      break;
+                 case HYBRD_SRCH_LIST:
+                      set_hybrd_list(fd);
+                      break;
+                 }
+              }
+              grps++;
+          }
+       }else {
+          ALOGE("No of groups found is zero\n");
+       }
+       free_strs(grps_cpy);
+    }
+    free_key_file(keyfile);
+    keyfile = NULL;
+}
diff --git a/jni/ConfigFmThs.h b/jni/ConfigFmThs.h
new file mode 100644
index 0000000..0a791f7
--- /dev/null
+++ b/jni/ConfigFmThs.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2014, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 __CONFIG_FM_THS_H__
+#define __CONFIG_FM_THS_H__
+
+#include <cstring>
+#include "FmConst.h"
+#include "ConfFileParser.h"
+
+#define MAX_GRPS 3
+#define MAX_SRCH_PARAMS 8
+#define MAX_AF_PARAMS 3
+
+#define SINR_SAMPLES_CNT_MIN 0
+#define SINR_SAMPLES_CNT_MAX 255
+#define SINR_FIRST_STAGE_MIN -128
+#define SINR_FIRST_STAGE_MAX 127
+#define RMSSI_FIRST_STAGE_MIN -128
+#define RMSSI_FIRST_STAGE_MAX 127
+#define INTF_LOW_TH_MIN 0
+#define INTF_LOW_TH_MAX  255
+#define INTF_HIGH_TH_MIN 0
+#define INTF_HIGH_TH_MAX 255
+#define SRCH_ALGO_TYPE_MIN 0
+#define SRCH_ALGO_TYPE_MAX 1
+#define SINR_FINAL_STAGE_MIN -128
+#define SINR_FINAL_STAGE_MAX 127
+
+#define AF_RMSSI_TH_MIN 0
+#define AF_RMSSI_TH_MAX 65535
+#define AF_RMSSI_SAMPLES_MIN 0
+#define AF_RMSSI_SAMPLES_MAX 255
+#define GOOD_CH_RMSSI_TH_MIN -128
+#define GOOD_CH_RMSSI_TH_MAX 127
+
+const unsigned char MAX_HYBRID_SRCH_PARAMS = 2;
+
+struct NAME_MAP
+{
+   const char name[50];
+   const int num;
+};
+
+enum PERFORMANCE_GRPS
+{
+    AF_THS,
+    SRCH_THS,
+    HYBRD_SRCH_LIST,
+};
+
+enum PERFORMANCE_SRCH_PARAMS
+{
+    SRCH_ALGO_TYPE,
+    CF0_TH,
+    SINR_FIRST_STAGE,
+    SINR,
+    RMSSI_FIRST_STAGE,
+    INTF_LOW_TH,
+    INTF_HIGH_TH,
+    SINR_SAMPLES,
+};
+
+enum PERFORMANCE_AF_PARAMS
+{
+    AF_RMSSI_TH,
+    AF_RMSSI_SAMPLES,
+    GOOD_CH_RMSSI_TH,
+};
+
+enum HYBRID_SRCH_PARAMS
+{
+    FREQ_LIST,
+    SINR_LIST,
+};
+
+//Keep this list in sorted order (ascending order in terms of "name")
+//Don't change the name of GRPS, if changed please also change accordingly
+//file: fm_srch_af_th.conf
+static struct NAME_MAP GRPS_MAP[] =
+{
+   {"AFTHRESHOLDS", AF_THS},
+   {"HYBRIDSEARCHLIST", HYBRD_SRCH_LIST},
+   {"SEARCHTHRESHOLDS", SRCH_THS},
+};
+
+//Keep this list in sorted order (ascending order in terms of "name")
+//Don't change the name of SEARCH thresholds,
+//if changed please also change accordingly
+//file: fm_srch_af_th.conf
+static struct NAME_MAP SEACH_PARAMS_MAP[] =
+{
+   {"Cf0Th12", CF0_TH},
+   {"IntfHighTh", INTF_HIGH_TH},
+   {"IntfLowTh", INTF_LOW_TH},
+   {"RmssiFirstStage", RMSSI_FIRST_STAGE},
+   {"SearchAlgoType", SRCH_ALGO_TYPE},
+   {"Sinr", SINR},
+   {"SinrFirstStage", SINR_FIRST_STAGE},
+   {"SinrSamplesCnt", SINR_SAMPLES},
+};
+
+//Keep this list in sorted order (ascending order in terms of "name")
+//Don't change the name of SEARCH thresholds,
+//if changed please also change accordingly
+//file: fm_srch_af_th.conf
+static struct NAME_MAP AF_PARAMS_MAP[] =
+{
+   {"AfRmssiSamplesCnt", AF_RMSSI_SAMPLES},
+   {"AfRmssiTh", AF_RMSSI_TH},
+   {"GoodChRmssiTh", GOOD_CH_RMSSI_TH},
+};
+
+static struct NAME_MAP HYBRD_SRCH_MAP[] =
+{
+   {"Freqs", FREQ_LIST},
+   {"Sinrs", SINR_LIST},
+};
+
+class ConfigFmThs {
+   private:
+          group_table *keyfile;
+          void set_srch_ths(UINT fd);
+          void set_af_ths(UINT fd);
+          unsigned int extract_comma_sep_freqs(char *freqs, unsigned int **freqs_arr, const char *str);
+          unsigned int extract_comma_sep_sinrs(char *sinrs, signed char **sinrs_arr, const char *str);
+          void set_hybrd_list(UINT fd);
+   public:
+          ConfigFmThs();
+          ~ConfigFmThs();
+          void SetRxSearchAfThs(const char *file, UINT fd);
+};
+
+#endif //__CONFIG_FM_THS_H__
diff --git a/jni/FmConst.h b/jni/FmConst.h
new file mode 100644
index 0000000..e37160f
--- /dev/null
+++ b/jni/FmConst.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2014, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 __FM_CONST_H__
+#define __FM_CONST_H__
+
+
+typedef  unsigned int UINT;
+typedef  unsigned long ULINT;
+
+//return related
+const int IOCTL_SUCC = 0;
+const int FM_SUCCESS = 0;
+const int FM_FAILURE = -1;
+const int PROP_SET_SUCC = 0;
+
+#define TUNE_MULT  16
+const UINT CAL_DATA_SIZE = 23;
+#define STD_BUF_SIZE  256
+
+const char *const FM_PERFORMANCE_PARAMS = "/etc/fm/fm_srch_af_th.conf";
+const char *const CALIB_DATA_NAME = "/data/misc/fm/Riva_fm_cal";
+
+#define V4L2_CTRL_CLASS_USER  0x00980000
+#define V4L2_CID_BASE  (V4L2_CTRL_CLASS_USER | 0x900)
+#define V4L2_CID_AUDIO_MUTE   (V4L2_CID_BASE + 9)
+const UINT SEARCH_DWELL_TIME = 2;
+const UINT SEEK_DWELL_TIME = 0;
+
+enum FM_AUDIO_PATH
+{
+    AUDIO_DIGITAL_PATH,
+    AUDIO_ANALOG_PATH,
+};
+
+enum FM_DEVICE
+{
+    FM_DEV_NONE,
+    FM_RX,
+    FM_TX,
+};
+
+enum BUFF_INDEXES
+{
+    STATION_LIST_IND,
+    EVENT_IND,
+    RT_IND,
+    PS_IND,
+    AF_LIST_IND = PS_IND + 2,
+    RT_PLUS_IND = 11,
+    ERT_IND,
+};
+
+enum SEARCH_MODE
+{
+    SEEK_MODE,
+    SCAN_MODE,
+};
+
+enum SEARCH_DIR
+{
+    SEARCH_DOWN,
+    SEARCH_UP,
+};
+
+enum AUDIO_MODE
+{
+    MONO,
+    STEREO,
+};
+
+//V4L2 CONTROLS FOR FM DRIVER
+enum FM_V4L2_PRV_CONTROLS
+{
+    V4L2_CID_PRV_BASE = 0x8000000,
+    V4L2_CID_PRV_SRCHMODE,
+    V4L2_CID_PRV_SCANDWELL,
+    V4L2_CID_PRV_SRCHON,
+    V4L2_CID_PRV_STATE,
+    V4L2_CID_PRV_TRANSMIT_MODE,
+    V4L2_CID_PRV_RDSGROUP_MASK,
+    V4L2_CID_PRV_REGION,
+    V4L2_CID_PRV_SIGNAL_TH,
+    V4L2_CID_PRV_SRCH_PTY,
+    V4L2_CID_PRV_SRCH_PI,
+    V4L2_CID_PRV_SRCH_CNT,
+    V4L2_CID_PRV_EMPHASIS,
+    V4L2_CID_PRV_RDS_STD,
+    V4L2_CID_PRV_CHAN_SPACING,
+    V4L2_CID_PRV_RDSON,
+    V4L2_CID_PRV_RDSGROUP_PROC,
+    V4L2_CID_PRV_LP_MODE,
+    V4L2_CID_PRV_INTDET = V4L2_CID_PRV_BASE + 25,
+    V4L2_CID_PRV_AF_JUMP = V4L2_CID_PRV_BASE + 27,
+    V4L2_CID_PRV_SOFT_MUTE = V4L2_CID_PRV_BASE + 30,
+    V4L2_CID_PRV_AUDIO_PATH = V4L2_CID_PRV_BASE + 41,
+    V4L2_CID_PRV_SINR = V4L2_CID_PRV_BASE + 44,
+    V4L2_CID_PRV_ON_CHANNEL_THRESHOLD = V4L2_CID_PRV_BASE + 0x2D,
+    V4L2_CID_PRV_OFF_CHANNEL_THRESHOLD,
+    V4L2_CID_PRV_SINR_THRESHOLD,
+    V4L2_CID_PRV_SINR_SAMPLES,
+    V4L2_CID_PRV_SPUR_FREQ,
+    V4L2_CID_PRV_SPUR_FREQ_RMSSI,
+    V4L2_CID_PRV_SPUR_SELECTION,
+    V4L2_CID_PRV_AF_RMSSI_TH = V4L2_CID_PRV_BASE + 0x36,
+    V4L2_CID_PRV_AF_RMSSI_SAMPLES,
+    V4L2_CID_PRV_GOOD_CH_RMSSI_TH,
+    V4L2_CID_PRV_SRCHALGOTYPE,
+    V4L2_CID_PRV_CF0TH12,
+    V4L2_CID_PRV_SINRFIRSTSTAGE,
+    V4L2_CID_PRV_RMSSIFIRSTSTAGE,
+    V4L2_CID_PRV_SOFT_MUTE_TH,
+    V4L2_CID_PRV_IRIS_RDSGRP_RT,
+    V4L2_CID_PRV_IRIS_RDSGRP_PS_SIMPLE,
+    V4L2_CID_PRV_IRIS_RDSGRP_AFLIST,
+    V4L2_CID_PRV_IRIS_RDSGRP_ERT,
+    V4L2_CID_PRV_IRIS_RDSGRP_RT_PLUS,
+    V4L2_CID_PRV_IRIS_RDSGRP_3A,
+
+    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,
+    V4L2_CID_PRV_IRIS_RMSSI,
+
+    V4L2_CID_PRV_ENABLE_SLIMBUS = 0x00980940,
+};
+
+#endif
diff --git a/jni/FmIoctlsInterface.cpp b/jni/FmIoctlsInterface.cpp
new file mode 100644
index 0000000..640a90f
--- /dev/null
+++ b/jni/FmIoctlsInterface.cpp
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2014, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 "FmIoctlsInterface.h"
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <fcntl.h>
+#include <utils/Log.h>
+#include <cutils/properties.h>
+#include <sys/ioctl.h>
+#include <linux/videodev2.h>
+#include <math.h>
+
+char const * const FmIoctlsInterface::LOGTAG = "FmIoctlsInterface";
+
+int  FmIoctlsInterface :: get_cur_freq
+(
+    UINT fd, long &freq
+)
+{
+    int ret;
+    struct v4l2_frequency channel;
+
+    channel.type = V4L2_TUNER_RADIO;
+    ret = ioctl(fd, VIDIOC_G_FREQUENCY, &channel);
+
+    if(ret < IOCTL_SUCC) {
+        return FM_FAILURE;
+    }else {
+        freq = (channel.frequency / TUNE_MULT);
+        return FM_SUCCESS;
+    }
+}
+
+int  FmIoctlsInterface :: set_freq
+(
+    UINT fd, ULINT freq
+)
+{
+    int ret;
+    struct v4l2_frequency channel;
+
+    channel.type = V4L2_TUNER_RADIO;
+    channel.frequency = (freq * TUNE_MULT);
+
+    ret = ioctl(fd, VIDIOC_S_FREQUENCY, &channel);
+    if(ret < IOCTL_SUCC) {
+        return FM_FAILURE;
+    }else {
+        return FM_SUCCESS;
+    }
+}
+
+int FmIoctlsInterface :: set_control
+(
+    UINT fd, UINT id, int val
+)
+{
+    int ret;
+    struct v4l2_control control;
+
+    control.value = val;
+    control.id = id;
+
+    for(int i = 0; i < 3; i++) {
+        ret = ioctl(fd, VIDIOC_S_CTRL, &control);
+        if(ret < IOCTL_SUCC) {
+           ret = FM_FAILURE;
+        }else {
+           ret = FM_SUCCESS;
+           break;
+        }
+    }
+    return ret;
+}
+
+int  FmIoctlsInterface :: set_calibration
+(
+    UINT fd
+)
+{
+    int ret;
+    FILE *cal_fp;
+    struct v4l2_ext_control ext_ctl;
+    struct v4l2_ext_controls v4l2_ctls;
+    char cal_data[CAL_DATA_SIZE] = {0};
+
+    memset(&v4l2_ctls, 0, sizeof(v4l2_ctls));
+    memset(&ext_ctl, 0, sizeof(ext_ctl));
+
+    cal_fp = fopen(CALIB_DATA_NAME, "r");
+    if(cal_fp != NULL) {
+       if(fread(&cal_data[0], 1, CAL_DATA_SIZE, cal_fp)
+           < CAL_DATA_SIZE) {
+           fclose(cal_fp);
+           ALOGE("%s: calibration file read failed\n", LOGTAG);
+           return FM_FAILURE;
+       }
+       fclose(cal_fp);
+       ext_ctl.id = V4L2_CID_PRV_SET_CALIBRATION;
+       ext_ctl.string = cal_data;
+       ext_ctl.size = CAL_DATA_SIZE;
+       v4l2_ctls.ctrl_class = V4L2_CTRL_CLASS_USER;
+       v4l2_ctls.count = 1;
+       v4l2_ctls.controls = &ext_ctl;
+       ret = ioctl(fd, VIDIOC_S_EXT_CTRLS, &v4l2_ctls);
+       if(ret < IOCTL_SUCC) {
+           ALOGE("%s: ioctl call failed\n", LOGTAG);
+           return FM_FAILURE;
+       }else {
+           return FM_SUCCESS;
+       }
+    }else {
+        return FM_SUCCESS;
+    }
+}
+
+int  FmIoctlsInterface :: get_control
+(
+    UINT fd, UINT id, long &val
+)
+{
+    int ret;
+    struct v4l2_control control;
+
+    control.id = id;
+    ret = ioctl(fd, VIDIOC_G_CTRL, &control);
+    if(ret < IOCTL_SUCC) {
+        return FM_FAILURE;
+    }else {
+        val = control.value;
+        return FM_SUCCESS;
+    }
+}
+
+int  FmIoctlsInterface :: start_search
+(
+    UINT fd, UINT dir
+)
+{
+    int ret;
+    struct v4l2_hw_freq_seek hw_seek;
+
+    hw_seek.seek_upward = dir;
+    hw_seek.type = V4L2_TUNER_RADIO;
+
+    ret = ioctl(fd, VIDIOC_S_HW_FREQ_SEEK, &hw_seek);
+    if(ret < IOCTL_SUCC) {
+        return FM_FAILURE;
+    }else {
+        return FM_SUCCESS;
+    }
+}
+
+int  FmIoctlsInterface :: set_band
+(
+    UINT fd, ULINT low, ULINT high
+)
+{
+    int ret;
+    struct v4l2_tuner tuner;
+
+    tuner.index = 0;
+    tuner.signal = 0;
+    tuner.rangelow = (low * TUNE_MULT);
+    tuner.rangehigh = (high * TUNE_MULT);
+
+    ret = ioctl(fd, VIDIOC_S_TUNER, &tuner);
+    ret = set_control(fd, V4L2_CID_PRV_REGION, 0);
+    if(ret < IOCTL_SUCC) {
+        return FM_FAILURE;
+    }else {
+        return FM_SUCCESS;
+    }
+}
+
+int FmIoctlsInterface :: get_rmssi
+(
+    UINT fd, long &rmssi
+)
+{
+    struct v4l2_tuner tuner;
+    int ret;
+
+    tuner.index = 0;
+    tuner.signal = 0;
+    ret = ioctl(fd, VIDIOC_G_TUNER, &tuner);
+    if(ret < IOCTL_SUCC) {
+        ret = FM_FAILURE;
+    }else {
+        rmssi = tuner.signal;
+        ret = FM_SUCCESS;
+    }
+    return ret;
+}
+
+int FmIoctlsInterface :: get_upperband_limit
+(
+    UINT fd, ULINT &freq
+)
+{
+    int ret;
+    struct v4l2_tuner tuner;
+
+    tuner.index = 0;
+    ret = ioctl(fd, VIDIOC_G_TUNER, &tuner);
+    if(ret < IOCTL_SUCC) {
+        return FM_FAILURE;
+    }else {
+        freq = (tuner.rangehigh / TUNE_MULT);
+        return FM_SUCCESS;
+    }
+}
+
+int FmIoctlsInterface :: get_lowerband_limit
+(
+    UINT fd, ULINT &freq
+)
+{
+    int ret;
+    struct v4l2_tuner tuner;
+
+    tuner.index = 0;
+    ret = ioctl(fd, VIDIOC_G_TUNER, &tuner);
+    if(ret < IOCTL_SUCC) {
+        return FM_FAILURE;
+    }else {
+        freq = (tuner.rangelow / TUNE_MULT);
+        return FM_SUCCESS;
+    }
+}
+
+int FmIoctlsInterface :: set_audio_mode
+(
+    UINT fd, enum AUDIO_MODE mode
+)
+{
+    int ret;
+    struct v4l2_tuner tuner;
+
+    tuner.index = 0;
+    ret = ioctl(fd, VIDIOC_G_TUNER, &tuner);
+    if(ret < IOCTL_SUCC) {
+        return FM_FAILURE;
+    }else {
+        tuner.audmode = mode;
+        ret = ioctl(fd, VIDIOC_S_TUNER, &tuner);
+        if(ret < IOCTL_SUCC) {
+            return FM_FAILURE;
+        }else {
+            return FM_SUCCESS;
+        }
+    }
+}
+
+int FmIoctlsInterface :: get_buffer
+(
+     UINT fd, char *buff, UINT len, UINT index
+)
+{
+    int ret;
+    struct v4l2_buffer v4l2_buf;
+
+    if((len < STD_BUF_SIZE) || (buff == NULL)) {
+        return FM_FAILURE;
+    }else {
+        memset(&v4l2_buf, 0, sizeof(v4l2_buf));
+        v4l2_buf.index = index;
+        v4l2_buf.type = V4L2_BUF_TYPE_PRIVATE;
+        v4l2_buf.length = STD_BUF_SIZE;
+        v4l2_buf.m.userptr = (ULINT)buff;
+        ret = ioctl(fd, VIDIOC_DQBUF, &v4l2_buf);
+        if(ret < IOCTL_SUCC) {
+            return FM_FAILURE;
+        }else {
+            return v4l2_buf.bytesused;
+        }
+    }
+}
+
+int FmIoctlsInterface :: set_ext_control
+(
+    UINT fd,
+    struct v4l2_ext_controls *v4l2_ctls
+)
+{
+    int ret;
+
+    ret = ioctl(fd, VIDIOC_S_EXT_CTRLS, v4l2_ctls);
+
+    if(ret < IOCTL_SUCC) {
+       return FM_FAILURE;
+    }else {
+       return FM_SUCCESS;
+    }
+}
+
diff --git a/jni/FmIoctlsInterface.h b/jni/FmIoctlsInterface.h
new file mode 100644
index 0000000..eda28ee
--- /dev/null
+++ b/jni/FmIoctlsInterface.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 __FM_IOCTL_INTERFACE_H__
+#define __FM_IOCTL_INTERFACE_H__
+
+#include "FmConst.h"
+
+#include <linux/videodev2.h>
+
+class FmIoctlsInterface
+{
+    private:
+        static char const * const LOGTAG;
+    public:
+        static int start_fm_patch_dl(UINT fd);
+        static int close_fm_patch_dl(void);
+        static int get_cur_freq(UINT fd, long &freq);
+        static int set_freq(UINT fd, ULINT freq);
+        static int set_control(UINT fd, UINT id, int val);
+        static int set_calibration(UINT fd);
+        static int get_control(UINT fd, UINT id, long &val);
+        static int start_search(UINT fd, UINT dir);
+        static int set_band(UINT fd, ULINT low, ULINT high);
+        static int get_upperband_limit(UINT fd, ULINT &freq);
+        static int get_lowerband_limit(UINT fd, ULINT &freq);
+        static int set_audio_mode(UINT fd, enum AUDIO_MODE mode);
+        static int get_buffer(UINT fd, char *buff, UINT len, UINT index);
+        static int get_rmssi(UINT fd, long &rmssi);
+        static int set_ext_control(UINT fd, struct v4l2_ext_controls *v4l2_ctls);
+};
+
+//char const *FmIoctlsInterface::LOGTAG = "FmIoctlsInterface";
+
+#endif //__FM_IOCTL_INTERFACE_H__
diff --git a/jni/FmPerformanceParams.cpp b/jni/FmPerformanceParams.cpp
new file mode 100644
index 0000000..bdd0a43
--- /dev/null
+++ b/jni/FmPerformanceParams.cpp
@@ -0,0 +1,422 @@
+/*
+ * Copyright (c) 2014, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 "FmPerformanceParams.h"
+#include "FmIoctlsInterface.h"
+
+#include <cstdio>
+#include <linux/videodev2.h>
+#include <utils/Log.h>
+
+signed char FmPerformanceParams :: SetAfRmssiTh
+(
+   UINT fd, unsigned short th
+)
+{
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::set_control(fd,
+                V4L2_CID_PRV_AF_RMSSI_TH, th);
+
+   return ret;
+}
+
+signed char FmPerformanceParams :: SetAfRmssiSamplesCnt
+(
+   UINT fd, unsigned char cnt
+)
+{
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::set_control(fd,
+                V4L2_CID_PRV_AF_RMSSI_SAMPLES, cnt);
+
+   return ret;
+}
+
+signed char FmPerformanceParams :: SetGoodChannelRmssiTh
+(
+   UINT fd, signed char th
+)
+{
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::set_control(fd,
+                V4L2_CID_PRV_GOOD_CH_RMSSI_TH, th);
+
+   return ret;
+}
+
+signed char FmPerformanceParams :: SetSrchAlgoType
+(
+   UINT fd, unsigned char algo
+)
+{
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::set_control(fd,
+                V4L2_CID_PRV_SRCHALGOTYPE, algo);
+
+   return ret;
+}
+
+signed char FmPerformanceParams :: SetSinrFirstStage
+(
+   UINT fd, signed char th
+)
+{
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::set_control(fd,
+                V4L2_CID_PRV_SINRFIRSTSTAGE, th);
+
+   return ret;
+}
+
+signed char FmPerformanceParams :: SetRmssiFirstStage
+(
+   UINT fd, signed char th
+)
+{
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::set_control(fd,
+                V4L2_CID_PRV_RMSSIFIRSTSTAGE, th);
+
+   return ret;
+}
+
+signed char FmPerformanceParams :: SetCf0Th12
+(
+   UINT fd, int th
+)
+{
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::set_control(fd,
+                V4L2_CID_PRV_CF0TH12, th);
+   return ret;
+}
+
+signed char FmPerformanceParams :: SetSinrSamplesCnt
+(
+   UINT fd, unsigned char cnt
+)
+{
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::set_control(fd,
+                V4L2_CID_PRV_SINR_SAMPLES, cnt);
+
+   return ret;
+}
+
+signed char FmPerformanceParams :: SetIntfLowTh
+(
+   UINT fd, unsigned char th
+)
+{
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::set_control(fd,
+                V4L2_CID_PRV_ON_CHANNEL_THRESHOLD, th);
+
+   return ret;
+}
+
+signed char FmPerformanceParams :: SetIntfHighTh
+(
+   UINT fd, unsigned char th
+)
+{
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::set_control(fd,
+                V4L2_CID_PRV_OFF_CHANNEL_THRESHOLD, th);
+   return ret;
+}
+
+signed char FmPerformanceParams :: SetSinrFinalStage
+(
+   UINT fd, signed char th
+)
+{
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::set_control(fd,
+                V4L2_CID_PRV_SINR_THRESHOLD, th);
+
+   return ret;
+}
+
+signed char FmPerformanceParams :: GetAfRmssiTh
+(
+   UINT fd, unsigned short &th
+)
+{
+   long int af_rmssi_th;
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::get_control(fd,
+                V4L2_CID_PRV_AF_RMSSI_TH, af_rmssi_th);
+   if(ret == FM_SUCCESS) {
+      th = af_rmssi_th;
+   }
+   return ret;
+}
+
+signed char FmPerformanceParams :: GetAfRmssiSamplesCnt
+(
+   UINT fd, unsigned char &cnt
+)
+{
+   long int af_samples_cnt;
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::get_control(fd,
+                V4L2_CID_PRV_AF_RMSSI_SAMPLES, af_samples_cnt);
+   if(ret == FM_SUCCESS) {
+      cnt = af_samples_cnt;
+   }
+   return ret;
+}
+
+signed char FmPerformanceParams :: GetGoodChannelRmssiTh
+(
+   UINT fd, signed char &th
+)
+{
+   long int gd_chan_rmssi_th;
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::get_control(fd,
+                V4L2_CID_PRV_GOOD_CH_RMSSI_TH, gd_chan_rmssi_th);
+   if(ret == FM_SUCCESS) {
+      th = gd_chan_rmssi_th;
+   }
+   return ret;
+}
+
+signed char FmPerformanceParams :: GetSrchAlgoType
+(
+   UINT fd, unsigned char &algo
+)
+{
+   long int srch_algo_type;
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::get_control(fd,
+                V4L2_CID_PRV_SRCHALGOTYPE, srch_algo_type);
+   if(ret == FM_SUCCESS) {
+      algo = srch_algo_type;
+   }
+   return ret;
+}
+
+signed char FmPerformanceParams :: GetSinrFirstStage
+(
+   UINT fd, signed char &th
+)
+{
+   long int sinr_first_stage;
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::get_control(fd,
+                V4L2_CID_PRV_SINRFIRSTSTAGE, sinr_first_stage);
+   if(ret == FM_SUCCESS) {
+      th = sinr_first_stage;
+   }
+   return ret;
+}
+
+signed char FmPerformanceParams :: GetRmssiFirstStage
+(
+   UINT fd, signed char &th
+)
+{
+   long int rmssi_first_stage;
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::get_control(fd,
+                V4L2_CID_PRV_RMSSIFIRSTSTAGE, rmssi_first_stage);
+   if(ret == FM_SUCCESS) {
+      th = rmssi_first_stage;
+   }
+   return ret;
+}
+
+signed char FmPerformanceParams :: GetCf0Th12
+(
+   UINT fd, int &th
+)
+{
+   long int cf0th12;
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::get_control(fd,
+                V4L2_CID_PRV_CF0TH12, cf0th12);
+   if(ret == FM_SUCCESS) {
+      th = cf0th12;
+   }
+   return ret;
+}
+
+signed char FmPerformanceParams :: GetSinrSamplesCnt
+(
+   UINT fd, unsigned char &cnt
+)
+{
+   long int sinr_samples_cnt;
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::get_control(fd,
+                V4L2_CID_PRV_SINR_SAMPLES, sinr_samples_cnt);
+   if(ret == FM_SUCCESS) {
+      cnt = sinr_samples_cnt;
+   }
+   return ret;
+}
+
+signed char FmPerformanceParams :: GetIntfLowTh
+(
+   UINT fd, unsigned char &th
+)
+{
+   long int intf_low_th;
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::get_control(fd,
+               V4L2_CID_PRV_ON_CHANNEL_THRESHOLD, intf_low_th);
+   if(ret == FM_SUCCESS) {
+      th = intf_low_th;
+   }
+   return ret;
+}
+
+signed char FmPerformanceParams :: GetIntfHighTh
+(
+   UINT fd, unsigned char &th
+)
+{
+   long int intf_high_th;
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::get_control(fd,
+               V4L2_CID_PRV_OFF_CHANNEL_THRESHOLD, intf_high_th);
+   if(ret == FM_SUCCESS) {
+      th = intf_high_th;
+   }
+   return ret;
+}
+
+signed char FmPerformanceParams :: GetIntfDet
+(
+   UINT fd, unsigned char &th
+)
+{
+   long int int_det;
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::get_control(fd,
+               V4L2_CID_PRV_INTDET, int_det);
+   if(ret == FM_SUCCESS) {
+      th = int_det;
+   }
+   return ret;
+}
+signed char FmPerformanceParams :: GetSinrFinalStage
+(
+   UINT fd, signed char &th
+)
+{
+   signed char ret = FM_FAILURE;
+   long int sinr;
+
+   ret = FmIoctlsInterface::get_control(fd,
+                V4L2_CID_PRV_SINR_THRESHOLD, sinr);
+
+   if(ret == FM_SUCCESS) {
+      th = sinr;
+   }
+   return ret;
+}
+
+signed char FmPerformanceParams :: SetHybridSrchList
+(
+   UINT fd,
+   unsigned int *freqs,
+   signed char *sinrs,
+   unsigned int n
+)
+{
+   struct v4l2_ext_control ext_ctl;
+   struct v4l2_ext_controls v4l2_ctls;
+   unsigned int freq;
+   signed char sinr;
+   unsigned int size = 0;
+   char *data = NULL;
+   signed char ret = FM_FAILURE;
+
+   if(n <= 0) {
+      return ret;
+   }
+   data = new char[(n * 3 + 3)];
+
+   if(data != NULL) {
+      data[size++] = 0x40;
+      data[size++] = ((n * 3) + 1);
+      data[size++] = n;
+      while((size < (n * 3 + 2)) && (freqs != NULL)
+            && (sinrs != NULL)) {
+            freq = (*freqs - 76000) / 50;
+            data[size++] = (freq & 0xff);
+            data[size++] = ((freq >> 8) & 0xff);
+            data[size++] = *sinrs;
+            freqs++;
+            sinrs++;
+      }
+      if(size == (n * 3 + 3)) {
+         ext_ctl.id = V4L2_CID_PRV_IRIS_WRITE_DEFAULT;
+         ext_ctl.string = data;
+         ext_ctl.size = size;
+         v4l2_ctls.ctrl_class = V4L2_CTRL_CLASS_USER;
+         v4l2_ctls.count = 1;
+         v4l2_ctls.controls  = &ext_ctl;
+         ret =  FmIoctlsInterface::set_ext_control(fd, &v4l2_ctls);
+         if(ret == FM_SUCCESS) {
+            ALOGE("hybrid srch list sent successfully\n");
+         }else {
+            ALOGE("hybrid srch list setting failed\n");
+         }
+      }
+   }
+
+   delete []data;
+
+   return ret;
+}
diff --git a/jni/FmPerformanceParams.h b/jni/FmPerformanceParams.h
new file mode 100644
index 0000000..fd9ee52
--- /dev/null
+++ b/jni/FmPerformanceParams.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2014, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 __FM_PERFORMANCE_PARAMS_H__
+#define __FM_PERFORMANCE_PARAMS_H__
+
+#include "FmConst.h"
+
+class FmPerformanceParams
+{
+      private:
+      public:
+          signed char SetAfRmssiTh(UINT fd, unsigned short th);
+          signed char SetAfRmssiSamplesCnt(UINT fd, unsigned char cnt);
+          signed char SetGoodChannelRmssiTh(UINT fd, signed char th);
+          signed char SetSrchAlgoType(UINT fd, unsigned char algo);
+          signed char SetSinrFirstStage(UINT fd, signed char th);
+          signed char SetRmssiFirstStage(UINT fd, signed char th);
+          signed char SetCf0Th12(UINT fd, int th);
+          signed char SetSinrSamplesCnt(UINT fd, unsigned char cnt);
+          signed char SetIntfLowTh(UINT fd, unsigned char th);
+          signed char SetIntfHighTh(UINT fd, unsigned char th);
+          signed char SetSinrFinalStage(UINT fd, signed char th);
+          signed char SetHybridSrchList(UINT fd, unsigned int *freqs, signed char *sinrs, unsigned int n);
+
+          signed char GetAfRmssiTh(UINT fd, unsigned short &th);
+          signed char GetAfRmssiSamplesCnt(UINT fd, unsigned char &cnt);
+          signed char GetGoodChannelRmssiTh(UINT fd, signed char &th);
+          signed char GetSrchAlgoType(UINT fd, unsigned char &algo);
+          signed char GetSinrFirstStage(UINT fd, signed char &th);
+          signed char GetRmssiFirstStage(UINT fd, signed char &th);
+          signed char GetCf0Th12(UINT fd, int &th);
+          signed char GetSinrSamplesCnt(UINT fd, unsigned char &cnt);
+          signed char GetIntfLowTh(UINT fd, unsigned char &th);
+          signed char GetIntfHighTh(UINT fd, unsigned char &th);
+          signed char GetIntfDet(UINT fd, unsigned char &th);
+          signed char GetSinrFinalStage(UINT fd, signed char &th);
+};
+
+#endif //__FM_PERFORMANCE_PARAMS_H__
diff --git a/jni/android_hardware_fm.cpp b/jni/android_hardware_fm.cpp
index 76490ee..622d4e9 100644
--- a/jni/android_hardware_fm.cpp
+++ b/jni/android_hardware_fm.cpp
@@ -32,6 +32,8 @@
 #include <nativehelper/JNIHelp.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>
@@ -45,9 +47,7 @@
 #include <vector>
 #include "radio-helium.h"
 
-typedef  unsigned int UINT;
-typedef  unsigned long ULINT;
-#define STD_BUF_SIZE  256
+#define RADIO "/dev/radio0"
 #define FM_JNI_SUCCESS 0L
 #define FM_JNI_FAILURE -1L
 #define SEARCH_DOWN 0
@@ -74,68 +74,6 @@
 #define MASK_PTY                   (0x0000001F)
 #define MASK_TXREPCOUNT            (0x0000000F)
 
-enum FM_V4L2_PRV_CONTROLS
-{
-    V4L2_CID_PRV_BASE = 0x8000000,
-    V4L2_CID_PRV_SRCHMODE,
-    V4L2_CID_PRV_SCANDWELL,
-    V4L2_CID_PRV_SRCHON,
-    V4L2_CID_PRV_STATE,
-    V4L2_CID_PRV_TRANSMIT_MODE,
-    V4L2_CID_PRV_RDSGROUP_MASK,
-    V4L2_CID_PRV_REGION,
-    V4L2_CID_PRV_SIGNAL_TH,
-    V4L2_CID_PRV_SRCH_PTY,
-    V4L2_CID_PRV_SRCH_PI,
-    V4L2_CID_PRV_SRCH_CNT,
-    V4L2_CID_PRV_EMPHASIS,
-    V4L2_CID_PRV_RDS_STD,
-    V4L2_CID_PRV_CHAN_SPACING,
-    V4L2_CID_PRV_RDSON,
-    V4L2_CID_PRV_RDSGROUP_PROC,
-    V4L2_CID_PRV_LP_MODE,
-    V4L2_CID_PRV_INTDET = V4L2_CID_PRV_BASE + 25,
-    V4L2_CID_PRV_AF_JUMP = V4L2_CID_PRV_BASE + 27,
-    V4L2_CID_PRV_SOFT_MUTE = V4L2_CID_PRV_BASE + 30,
-    V4L2_CID_PRV_AUDIO_PATH = V4L2_CID_PRV_BASE + 41,
-    V4L2_CID_PRV_SINR = V4L2_CID_PRV_BASE + 44,
-    V4L2_CID_PRV_ON_CHANNEL_THRESHOLD = V4L2_CID_PRV_BASE + 0x2D,
-    V4L2_CID_PRV_OFF_CHANNEL_THRESHOLD,
-    V4L2_CID_PRV_SINR_THRESHOLD,
-    V4L2_CID_PRV_SINR_SAMPLES,
-    V4L2_CID_PRV_SPUR_FREQ,
-    V4L2_CID_PRV_SPUR_FREQ_RMSSI,
-    V4L2_CID_PRV_SPUR_SELECTION,
-    V4L2_CID_PRV_AF_RMSSI_TH = V4L2_CID_PRV_BASE + 0x36,
-    V4L2_CID_PRV_AF_RMSSI_SAMPLES,
-    V4L2_CID_PRV_GOOD_CH_RMSSI_TH,
-    V4L2_CID_PRV_SRCHALGOTYPE,
-    V4L2_CID_PRV_CF0TH12,
-    V4L2_CID_PRV_SINRFIRSTSTAGE,
-    V4L2_CID_PRV_RMSSIFIRSTSTAGE,
-    V4L2_CID_PRV_SOFT_MUTE_TH,
-    V4L2_CID_PRV_IRIS_RDSGRP_RT,
-    V4L2_CID_PRV_IRIS_RDSGRP_PS_SIMPLE,
-    V4L2_CID_PRV_IRIS_RDSGRP_AFLIST,
-    V4L2_CID_PRV_IRIS_RDSGRP_ERT,
-    V4L2_CID_PRV_IRIS_RDSGRP_RT_PLUS,
-    V4L2_CID_PRV_IRIS_RDSGRP_3A,
-
-    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,
-    V4L2_CID_PRV_IRIS_RMSSI,
-
-    V4L2_CID_PRV_ENABLE_SLIMBUS = 0x00980940,
-};
-
 enum search_dir_t {
     SEEK_UP,
     SEEK_DN,
@@ -648,6 +586,13 @@
 };
 /* native interface */
 
+static bool is_soc_pronto() {
+    if(strcmp(soc_name, "pronto") == 0)
+        return true;
+    else
+        return false;
+}
+
 static void get_property(int ptype, char *value)
 {
     std::vector<vendor_property_t> vPropList;
@@ -660,6 +605,83 @@
     }
 }
 
+static jint android_hardware_fmradio_FmReceiverJNI_acquireFdNative
+        (JNIEnv* env, jobject thiz, jstring path)
+{
+    int fd;
+    int i,err;
+    char value[PROPERTY_VALUE_MAX] = {'\0'};
+    int init_success = 0;
+    jboolean isCopy;
+    v4l2_capability cap;
+    const char* radio_path = env->GetStringUTFChars(path, &isCopy);
+
+    if(radio_path == NULL){
+        return FM_JNI_FAILURE;
+    }
+    fd = open(radio_path, O_RDONLY, O_NONBLOCK);
+    if(isCopy == JNI_TRUE){
+        env->ReleaseStringUTFChars(path, radio_path);
+    }
+    if(fd < 0){
+        return FM_JNI_FAILURE;
+    }
+    //Read the driver verions
+    err = ioctl(fd, VIDIOC_QUERYCAP, &cap);
+
+    ALOGD("VIDIOC_QUERYCAP returns :%d: version: %d \n", err , cap.version );
+
+    if (is_soc_pronto())
+    {
+       /*Set the mode for soc downloader*/
+       if (bt_configstore_intf != NULL) {
+           bt_configstore_intf->set_vendor_property(FM_PROP_HW_MODE, "normal");
+
+          /* Need to clear the hw.fm.init firstly */
+          bt_configstore_intf->set_vendor_property(FM_PROP_HW_INIT, "0");
+          bt_configstore_intf->set_vendor_property(FM_PROP_CTL_START, "fm_dl");
+
+          sched_yield();
+          for(i=0; i<45; i++) {
+              get_property(FM_PROP_HW_INIT, value);
+              if (strcmp(value, "1") == 0) {
+                  init_success = 1;
+                  break;
+              } else {
+                  usleep(WAIT_TIMEOUT);
+              }
+          }
+          ALOGE("init_success:%d after %f seconds \n", init_success, 0.2*i);
+          if(!init_success) {
+             bt_configstore_intf->set_vendor_property(FM_PROP_CTL_STOP,"fm_dl");
+             // close the fd(power down)
+             close(fd);
+             return FM_JNI_FAILURE;
+          }
+       }
+    }
+    return fd;
+}
+
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_closeFdNative
+    (JNIEnv * env, jobject thiz, jint fd)
+{
+    if (is_soc_pronto() && bt_configstore_intf != NULL)
+    {
+        bt_configstore_intf->set_vendor_property(FM_PROP_CTL_STOP,"fm_dl");
+    }
+    close(fd);
+    return FM_JNI_SUCCESS;
+}
+
+static bool is_soc_cherokee() {
+    if(strcmp(soc_name, "cherokee") == 0)
+        return true;
+    else
+        return false;
+}
+
 /********************************************************************
  * Current JNI
  *******************************************************************/
@@ -670,13 +692,31 @@
 {
     int err;
     long freq;
-
-    err = vendor_interface->get_fm_ctrl(V4L2_CID_PRV_IRIS_FREQ, (int *)&freq);
-    if (err == FM_JNI_SUCCESS) {
-        err = freq;
-    } else {
-        err = FM_JNI_FAILURE;
-        ALOGE("%s: get freq failed\n", LOG_TAG);
+    if (is_soc_cherokee())
+    {
+        err = vendor_interface->get_fm_ctrl(V4L2_CID_PRV_IRIS_FREQ, (int *)&freq);
+        if (err == FM_JNI_SUCCESS) {
+            err = freq;
+        } else {
+            err = FM_JNI_FAILURE;
+            ALOGE("%s: get freq failed\n", LOG_TAG);
+        }
+    }
+    else
+    {
+        if (fd >= 0) {
+            err = FmIoctlsInterface :: get_cur_freq(fd, freq);
+            if(err < 0) {
+               err = FM_JNI_FAILURE;
+               ALOGE("%s: get freq failed\n", LOG_TAG);
+            } else {
+               err = freq;
+            }
+        } else {
+            ALOGE("%s: get freq failed because fd is negative, fd: %d\n",
+                  LOG_TAG, fd);
+            err = FM_JNI_FAILURE;
+        }
     }
     return err;
 }
@@ -686,9 +726,26 @@
     (JNIEnv * env, jobject thiz, jint fd, jint freq)
 {
     int err;
-
-    err = vendor_interface->set_fm_ctrl(V4L2_CID_PRV_IRIS_FREQ, freq);
-
+    if (is_soc_cherokee())
+    {
+        err = vendor_interface->set_fm_ctrl(V4L2_CID_PRV_IRIS_FREQ, freq);
+    }
+    else
+    {
+        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);
+                err = FM_JNI_FAILURE;
+            } else {
+                err = FM_JNI_SUCCESS;
+            }
+        } else {
+            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;
 }
 
@@ -698,9 +755,26 @@
 {
     int err;
     ALOGE("id(%x) value: %x\n", id, value);
-
-    err = vendor_interface->set_fm_ctrl(id, value);
-
+    if (is_soc_cherokee())
+    {
+        err = vendor_interface->set_fm_ctrl(id, value);
+    }
+    else
+    {
+        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);
+                err = FM_JNI_FAILURE;
+            } else {
+                err = FM_JNI_SUCCESS;
+            }
+        } else {
+            ALOGE("%s: set control failed because either fd/id is negavtive,\
+                   fd: %d, id: %d\n", LOG_TAG, fd, id);
+            err = FM_JNI_FAILURE;
+        }
+    }
     return err;
 }
 
@@ -712,13 +786,33 @@
     long val;
 
     ALOGE("id(%x)\n", id);
-    err = vendor_interface->get_fm_ctrl(id, (int *)&val);
-    if (err < 0) {
-        ALOGE("%s: get control failed, id: %d\n", LOG_TAG, id);
-        err = FM_JNI_FAILURE;
-    } else {
-        err = val;
+    if (is_soc_cherokee())
+    {
+        err = vendor_interface->get_fm_ctrl(id, (int *)&val);
+        if (err < 0) {
+            ALOGE("%s: get control failed, id: %d\n", LOG_TAG, id);
+            err = FM_JNI_FAILURE;
+        } else {
+            err = val;
+        }
     }
+    else
+    {
+        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);
+                err = FM_JNI_FAILURE;
+            } else {
+                err = val;
+            }
+        } else {
+            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;
 }
 
@@ -727,15 +821,33 @@
     (JNIEnv * env, jobject thiz, jint fd, jint dir)
 {
     int err;
-
-    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 (is_soc_cherokee())
+    {
+        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;
+        }
     }
-
+    else
+    {
+        if ((fd >= 0) && (dir >= 0)) {
+            ALOGD("startSearchNative: Issuing the VIDIOC_S_HW_FREQ_SEEK");
+            err = FmIoctlsInterface :: start_search(fd, dir);
+            if (err < 0) {
+                ALOGE("%s: search failed, dir: %d\n", LOG_TAG, dir);
+                err = FM_JNI_FAILURE;
+            } else {
+                err = FM_JNI_SUCCESS;
+            }
+        } else {
+            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;
 }
 
@@ -745,14 +857,32 @@
 {
     int err;
 
-    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 (is_soc_cherokee())
+    {
+        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;
+        }
     }
-
+    else
+    {
+        if (fd >= 0) {
+            err = FmIoctlsInterface :: set_control(fd, 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;
+            }
+        } else {
+            ALOGE("%s: cancel search failed because fd is negative, fd: %d\n",
+                   LOG_TAG, fd);
+            err = FM_JNI_FAILURE;
+        }
+    }
     return err;
 }
 
@@ -763,14 +893,32 @@
     int err;
     long rmssi;
 
-    err = vendor_interface->get_fm_ctrl(V4L2_CID_PRV_IRIS_RMSSI, (int *)&rmssi);
-    if (err < 0) {
-        ALOGE("%s: Get Rssi failed", LOG_TAG);
-        err = FM_JNI_FAILURE;
-    } else {
-        err = FM_JNI_SUCCESS;
+    if (is_soc_cherokee())
+    {
+        err = vendor_interface->get_fm_ctrl(V4L2_CID_PRV_IRIS_RMSSI, (int *)&rmssi);
+        if (err < 0) {
+            ALOGE("%s: Get Rssi failed", LOG_TAG);
+            err = FM_JNI_FAILURE;
+        } else {
+            err = FM_JNI_SUCCESS;
+        }
     }
-
+    else
+    {
+        if (fd >= 0) {
+            err = FmIoctlsInterface :: get_rmssi(fd, rmssi);
+            if (err < 0) {
+                ALOGE("%s: get rmssi failed\n", LOG_TAG);
+                err = FM_JNI_FAILURE;
+            } else {
+                err = rmssi;
+            }
+        } else {
+            ALOGE("%s: get rmssi failed because fd is negative, fd: %d\n",
+                   LOG_TAG, fd);
+            err = FM_JNI_FAILURE;
+        }
+    }
     return err;
 }
 
@@ -779,21 +927,39 @@
     (JNIEnv * env, jobject thiz, jint fd, jint low, jint high)
 {
     int err;
-
-    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;
+    if (is_soc_cherokee())
+    {
+        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;
+        }
     }
-    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;
+    else
+    {
+        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",
+                       LOG_TAG, low, high);
+                err = FM_JNI_FAILURE;
+            } else {
+                err = FM_JNI_SUCCESS;
+            }
+        } else {
+            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;
 }
 
@@ -803,7 +969,8 @@
 {
     int err;
     ULINT freq;
-
+if (is_soc_cherokee())
+{
     err = vendor_interface->get_fm_ctrl(V4L2_CID_PRV_IRIS_LOWER_BAND, (int *)&freq);
     if (err < 0) {
         ALOGE("%s: get lower band failed\n", LOG_TAG);
@@ -811,7 +978,24 @@
     } else {
         err = freq;
     }
-
+    return err;
+}
+else
+{
+    if (fd >= 0) {
+        err = FmIoctlsInterface :: get_lowerband_limit(fd, freq);
+        if (err < 0) {
+            ALOGE("%s: get lower band failed\n", LOG_TAG);
+            err = FM_JNI_FAILURE;
+        } else {
+            err = freq;
+        }
+    } else {
+        ALOGE("%s: get lower band failed because fd is negative,\
+               fd: %d\n", LOG_TAG, fd);
+        err = FM_JNI_FAILURE;
+    }
+}
     return err;
 }
 
@@ -821,7 +1005,8 @@
 {
     int err;
     ULINT freq;
-
+if (is_soc_cherokee())
+{
     err = vendor_interface->get_fm_ctrl(V4L2_CID_PRV_IRIS_UPPER_BAND, (int *)&freq);
     if (err < 0) {
         ALOGE("%s: get upper band failed\n", LOG_TAG);
@@ -829,7 +1014,24 @@
     } else {
         err = freq;
     }
-
+    return err;
+}
+else
+{
+    if (fd >= 0) {
+        err = FmIoctlsInterface :: get_upperband_limit(fd, freq);
+        if (err < 0) {
+            ALOGE("%s: get lower band failed\n", LOG_TAG);
+            err = FM_JNI_FAILURE;
+        } else {
+            err = freq;
+        }
+    } else {
+        ALOGE("%s: get lower band failed because fd is negative,\
+               fd: %d\n", LOG_TAG, fd);
+        err = FM_JNI_FAILURE;
+    }
+}
     return err;
 }
 
@@ -838,7 +1040,8 @@
 {
 
     int err;
-
+if (is_soc_cherokee())
+{
     err = vendor_interface->set_fm_ctrl(V4L2_CID_PRV_IRIS_AUDIO_MODE, val);
     if (err < 0) {
         ALOGE("%s: set audio mode failed\n", LOG_TAG);
@@ -846,6 +1049,51 @@
     } else {
         err = FM_JNI_SUCCESS;
     }
+    return err;
+}
+else
+{
+    if (fd >= 0) {
+        err = FmIoctlsInterface :: set_audio_mode(fd, (enum AUDIO_MODE)val);
+        if (err < 0) {
+            err = FM_JNI_FAILURE;
+        } else {
+            err = FM_JNI_SUCCESS;
+        }
+    } else {
+        err = FM_JNI_FAILURE;
+    }
+}
+    return err;
+}
+
+
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_getBufferNative
+ (JNIEnv * env, jobject thiz, jint fd, jbyteArray buff, jint index)
+{
+    int err;
+    jboolean isCopy;
+    jbyte *byte_buffer = NULL;
+
+    if ((fd >= 0) && (index >= 0)) {
+        ALOGE("index: %d\n", index);
+        byte_buffer = env->GetByteArrayElements(buff, &isCopy);
+        err = FmIoctlsInterface :: get_buffer(fd,
+                                               (char *)byte_buffer,
+                                               STD_BUF_SIZE,
+                                               index);
+        if (err < 0) {
+            err = FM_JNI_FAILURE;
+        }
+        if (buff != NULL) {
+            ALOGE("Free the buffer\n");
+            env->ReleaseByteArrayElements(buff, byte_buffer, 0);
+            byte_buffer =  NULL;
+        }
+    } else {
+        err = FM_JNI_FAILURE;
+    }
 
     return err;
 }
@@ -862,28 +1110,81 @@
 static jint android_hardware_fmradio_FmReceiverJNI_configureSpurTable
     (JNIEnv * env, jobject thiz, jint fd)
 {
+    int err;
+
     ALOGD("->android_hardware_fmradio_FmReceiverJNI_configureSpurTable\n");
 
-    return FM_JNI_SUCCESS;
+    if (fd >= 0) {
+        err = FmIoctlsInterface :: set_control(fd,
+                                                V4L2_CID_PRIVATE_UPDATE_SPUR_TABLE,
+                                                0);
+        if (err < 0) {
+            err = FM_JNI_FAILURE;
+        } else {
+            err = FM_JNI_SUCCESS;
+        }
+    } else {
+        err = FM_JNI_FAILURE;
+    }
+
+    return err;
 }
 
 static jint android_hardware_fmradio_FmReceiverJNI_setPSRepeatCountNative
     (JNIEnv * env, jobject thiz, jint fd, jint repCount)
 {
+    int masked_ps_repeat_cnt;
+    int err;
 
     ALOGE("->android_hardware_fmradio_FmReceiverJNI_setPSRepeatCountNative\n");
 
-    return FM_JNI_SUCCESS;
+    if (fd >= 0) {
+        masked_ps_repeat_cnt = repCount & MASK_TXREPCOUNT;
+        err = FmIoctlsInterface :: set_control(fd,
+                                                V4L2_CID_PRIVATE_TAVARUA_TX_SETPSREPEATCOUNT,
+                                                masked_ps_repeat_cnt);
+        if (err < 0) {
+            err = FM_JNI_FAILURE;
+        } else {
+            err = FM_JNI_SUCCESS;
+        }
+    } else {
+        err = FM_JNI_FAILURE;
+    }
 
+    return err;
 }
 
 static jint android_hardware_fmradio_FmReceiverJNI_setTxPowerLevelNative
     (JNIEnv * env, jobject thiz, jint fd, jint powLevel)
 {
+    int err;
 
     ALOGE("->android_hardware_fmradio_FmReceiverJNI_setTxPowerLevelNative\n");
 
-    return FM_JNI_SUCCESS;
+    if (fd >= 0) {
+        err = FmIoctlsInterface :: set_control(fd,
+                                                V4L2_CID_TUNE_POWER_LEVEL,
+                                                powLevel);
+        if (err < 0) {
+            err = FM_JNI_FAILURE;
+        } else {
+            err = FM_JNI_SUCCESS;
+        }
+    } else {
+        err = FM_JNI_FAILURE;
+    }
+
+    return err;
+}
+
+static void android_hardware_fmradio_FmReceiverJNI_configurePerformanceParams
+    (JNIEnv * env, jobject thiz, jint fd)
+{
+
+     ConfigFmThs thsObj;
+
+     thsObj.SetRxSearchAfThs(FM_PERFORMANCE_PARAMS, fd);
 }
 
 /* native interface */
@@ -891,7 +1192,37 @@
  (JNIEnv * env, jobject thiz, jint fd, jshortArray buff, jint count)
 {
     ALOGE("entered JNI's setSpurDataNative\n");
+    int err, i = 0;
+    struct v4l2_ext_control ext_ctl;
+    struct v4l2_ext_controls v4l2_ctls;
+    uint8_t *data;
+    short *spur_data = env->GetShortArrayElements(buff, NULL);
+    if (spur_data == NULL) {
+        ALOGE("Spur data is NULL\n");
+        return FM_JNI_FAILURE;
+    }
+    data = (uint8_t *) malloc(count);
+    if (data == NULL) {
+        ALOGE("Allocation failed for data\n");
+        return FM_JNI_FAILURE;
+    }
+    for(i = 0; i < count; i++)
+        data[i] = (uint8_t) spur_data[i];
 
+    ext_ctl.id = V4L2_CID_PRIVATE_IRIS_SET_SPURTABLE;
+    ext_ctl.string = (char*)data;
+    ext_ctl.size = count;
+    v4l2_ctls.ctrl_class = V4L2_CTRL_CLASS_USER;
+    v4l2_ctls.count   = 1;
+    v4l2_ctls.controls  = &ext_ctl;
+
+    err = ioctl(fd, VIDIOC_S_EXT_CTRLS, &v4l2_ctls );
+    if (err < 0){
+        ALOGE("Set ioctl failed\n");
+        free(data);
+        return FM_JNI_FAILURE;
+    }
+    free(data);
     return FM_JNI_SUCCESS;
 }
 
@@ -900,8 +1231,9 @@
 {
     ALOGD("%s: val = %d\n", __func__, val);
     int err = JNI_ERR;
+if (is_soc_cherokee()) {
     err = vendor_interface->set_fm_ctrl(V4L2_CID_PRV_ENABLE_SLIMBUS, val);
-
+}
     return err;
 }
 
@@ -945,8 +1277,9 @@
 {
     ALOGD("%s: val = %d\n", __func__, val);
     int err = JNI_ERR;
+if (is_soc_cherokee()) {
     err = vendor_interface->set_fm_ctrl(V4L2_CID_PRV_SOFT_MUTE, val);
-
+}
     return err;
 }
 
@@ -1026,6 +1359,7 @@
 }
 
 static void initNative(JNIEnv *env, jobject object) {
+if (is_soc_cherokee()) {
     int status;
     ALOGI("Init native called \n");
 
@@ -1040,12 +1374,15 @@
     }
     mCallbacksObj = env->NewGlobalRef(object);
 }
+}
 
 static void cleanupNative(JNIEnv *env, jobject object) {
 
-    if (mCallbacksObj != NULL) {
-        env->DeleteGlobalRef(mCallbacksObj);
-        mCallbacksObj = NULL;
+    if (is_soc_cherokee()) {
+        if (mCallbacksObj != NULL) {
+            env->DeleteGlobalRef(mCallbacksObj);
+            mCallbacksObj = NULL;
+        }
     }
 }
 /*
@@ -1056,6 +1393,10 @@
         { "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",
+            (void*)android_hardware_fmradio_FmReceiverJNI_closeFdNative},
         { "getFreqNative", "(I)I",
             (void*)android_hardware_fmradio_FmReceiverJNI_getFreqNative},
         { "setFreqNative", "(II)I",
@@ -1076,6 +1417,8 @@
             (void*)android_hardware_fmradio_FmReceiverJNI_getLowerBandNative},
         { "getUpperBandNative", "(I)I",
             (void*)android_hardware_fmradio_FmReceiverJNI_getUpperBandNative},
+        { "getBufferNative", "(I[BI)I",
+            (void*)android_hardware_fmradio_FmReceiverJNI_getBufferNative},
         { "setMonoStereoNative", "(II)I",
             (void*)android_hardware_fmradio_FmReceiverJNI_setMonoStereoNative},
         { "getRawRdsNative", "(I[BI)I",
@@ -1088,6 +1431,8 @@
             (void*)android_hardware_fmradio_FmReceiverJNI_configureSpurTable},
         { "setSpurDataNative", "(I[SI)I",
             (void*)android_hardware_fmradio_FmReceiverJNI_setSpurDataNative},
+        { "configurePerformanceParams", "(I)V",
+             (void*)android_hardware_fmradio_FmReceiverJNI_configurePerformanceParams},
         { "enableSlimbus", "(II)I",
              (void*)android_hardware_fmradio_FmReceiverJNI_enableSlimbusNative},
         { "enableSoftMute", "(II)I",
diff --git a/qcom/fmradio/FmReceiver.java b/qcom/fmradio/FmReceiver.java
index 48e4d11..b7c1613 100644
--- a/qcom/fmradio/FmReceiver.java
+++ b/qcom/fmradio/FmReceiver.java
@@ -366,6 +366,14 @@
            return false;
    }
 
+   public static boolean isCherokeeChip() {
+       String chip = FmReceiverJNI.getSocNameNative();
+       if (chip.equals("cherokee"))
+           return true;
+       else
+           return false;
+   }
+
    public PhoneStateListener  mDataConnectionStateListener = new PhoneStateListener(){
         public void onDataConnectionStateChanged(int state, int networkType) {
               Log.d (TAG, "state: " + Integer.toString(state) +  " networkType: " + Integer.toString(networkType));
@@ -445,6 +453,7 @@
    public FmReceiver(){
       mControl = new FmRxControls();
       mRdsData = new FmRxRdsData (sFd);
+      mRxEvents = new FmRxEventListner();
    }
 
    /**
@@ -459,11 +468,79 @@
    public FmReceiver(String devicePath,
                      FmRxEvCallbacksAdaptor callback) throws InstantiationException {
       mControl = new FmRxControls();
+      mRxEvents = new FmRxEventListner();
 
       Log.e(TAG, "FmReceiver constructor");
       //registerClient(callback);
       mCallback = callback;
-      mFmReceiverJNI = new FmReceiverJNI(mCallback);
+      if (isCherokeeChip()) {
+          mFmReceiverJNI = new FmReceiverJNI(mCallback);
+      }
+   }
+
+
+   /*==============================================================
+   FUNCTION:  registerClient
+   ==============================================================*/
+   /**
+   *    Registers a callback for FM receiver event
+   *           notifications.
+   *    <p>
+   *    This is a synchronous command used to register for event
+   *    notifications from the FM receiver driver. Since the FM
+   *    driver performs some tasks asynchronously, this function
+   *    allows the client to receive information asynchronously.
+   *    <p>
+   *    When calling this function, the client must pass a callback
+   *    function which will be used to deliver asynchronous events.
+   *    The argument callback must be a non-NULL value.  If a NULL
+   *    value is passed to this function, the registration will
+   *    fail.
+   *    <p>
+   *    The client can choose which events will be sent from the
+   *    receiver driver by simply implementing functions for events
+   *    it wishes to receive.
+   *    <p>
+   *    @param callback the callbacks to handle the events
+   *                               events from the FM receiver.
+   *    @return true if Callback registered, false if Callback
+   *            registration failed.
+   *    <p>
+   *    @see #acquire
+   *    @see #unregisterClient
+   *
+   */
+   public boolean registerClient(FmRxEvCallbacks callback){
+      boolean status;
+      status = super.registerClient(callback);
+      /* Do Receiver Specific Stuff here.*/
+
+      return status;
+   }
+
+   /*==============================================================
+   FUNCTION:  unregisterClient
+   ==============================================================*/
+   /**
+   *    UnRegisters a client's event notification callback.
+   *
+   *    This is a synchronous command used to unregister a client's
+   *    event callback.
+   *    <p>
+   *    @return true Always returns true.
+   *    <p>
+   *    @see #acquire
+   *    @see #release
+   *    @see #registerClient
+   *
+   */
+   public boolean unregisterClient () {
+      boolean status;
+
+      status = super.unregisterClient();
+
+      /* Do Receiver Specific Stuff here.*/
+      return status;
    }
 
    /*==============================================================
@@ -531,6 +608,10 @@
       status = super.enable(configSettings, FmTransceiver.FM_RX);
 
       if (status == true ) {
+          if (!isCherokeeChip()) {
+              /* Do Receiver Specific Enable Stuff here.*/
+              status = registerClient(mCallback);
+          }
           mRdsData = new FmRxRdsData(sFd);
           registerDataConnectionStateListener(app_context);
           app_context.registerReceiver(mReceiver, mIntentFilter);
@@ -591,6 +672,10 @@
       setFMPowerState(FMState_Turned_Off);
       Log.v(TAG, "reset: NEW-STATE : FMState_Turned_Off");
 
+      status = unregisterClient();
+
+      release("/dev/radio0");
+
       return status;
    }
 
@@ -1491,7 +1576,11 @@
       int piLower = 0;
       int piHigher = 0;
 
-      buff = FmReceiverJNI.getPsBuffer(buff);
+      if(isCherokeeChip()) {
+          buff = FmReceiverJNI.getPsBuffer(buff);
+      }
+      else
+          FmReceiverJNI.getBufferNative(sFd, buff, 3);
 
       /* byte is signed ;(
       *  knock down signed bits
@@ -1544,8 +1633,12 @@
       int piLower = 0;
       int piHigher = 0;
 
-      buff = FmReceiverJNI.getPsBuffer(buff);
-
+      if (isCherokeeChip()) {
+          buff = FmReceiverJNI.getPsBuffer(buff);
+      }
+      else {
+          FmReceiverJNI.getBufferNative(sFd, buff, 2);
+      }
       String rdsStr = new String(buff);
       /* byte is signed ;(
       *  knock down signed bit
@@ -1574,8 +1667,13 @@
       int rt_len;
       int i, j = 2;
       byte tag_code, tag_len, tag_start_pos;
-      rt_plus = FmReceiverJNI.getPsBuffer(rt_plus);
-
+      if (isCherokeeChip()) {
+          rt_plus = FmReceiverJNI.getPsBuffer(rt_plus);
+      }
+      else
+      {
+          bytes_read = FmReceiverJNI.getBufferNative(sFd, rt_plus, BUF_RTPLUS);
+      }
       bytes_read = rt_plus[0];
       if (bytes_read > 0) {
           if (rt_plus[RT_OR_ERT_IND] == 0)
@@ -1612,8 +1710,14 @@
       String encoding_type = "UCS-2";
       int bytes_read;
 
-      raw_ert = FmReceiverJNI.getPsBuffer(raw_ert);
-
+      if(isCherokeeChip())
+      {
+         raw_ert = FmReceiverJNI.getPsBuffer(raw_ert);
+      }
+      else
+      {
+         bytes_read = FmReceiverJNI.getBufferNative(sFd, raw_ert, BUF_ERT);
+      }
       bytes_read = raw_ert[0];
       if (bytes_read > 0) {
           ert_text = new byte[raw_ert[LEN_IND]];
@@ -1680,29 +1784,58 @@
       int  [] AfList = new int [50];
       int lowerBand, i;
       int tunedFreq, PI, size_AFLIST;
+      if (isCherokeeChip()) {
+          buff = FmReceiverJNI.getPsBuffer(buff);
+      }
+      else
+      {
+          FmReceiverJNI.getBufferNative(sFd, buff, TAVARUA_BUF_AF_LIST);
+      }
+      if (isSmdTransportLayer() || isRomeChip() || isCherokeeChip()) {
+          Log.d(TAG, "SMD transport layer or Rome chip");
 
-      buff = FmReceiverJNI.getPsBuffer(buff);
+          tunedFreq = (buff[0] & 0xFF) |
+                      ((buff[1] & 0xFF) << 8) |
+                      ((buff[2] & 0xFF) << 16) |
+                      ((buff[3] & 0xFF) << 24) ;
+          Log.d(TAG, "tunedFreq = " +tunedFreq);
 
-      tunedFreq = (buff[0] & 0xFF) |
-                  ((buff[1] & 0xFF) << 8) |
-                  ((buff[2] & 0xFF) << 16) |
-                  ((buff[3] & 0xFF) << 24) ;
-      Log.d(TAG, "tunedFreq = " +tunedFreq);
-       PI = (buff[4] & 0xFF) |
-           ((buff[5] & 0xFF) << 8);
-      Log.d(TAG, "PI: " + PI);
-       size_AFLIST = buff[6] & 0xFF;
-      Log.d(TAG, "size_AFLIST : " +size_AFLIST);
+          PI = (buff[4] & 0xFF) |
+               ((buff[5] & 0xFF) << 8);
+          Log.d(TAG, "PI: " + PI);
 
-      for (i = 0;i < size_AFLIST;i++) {
-            AfList[i] = (buff[6 + i * 4 + 1] & 0xFF) |
-                       ((buff[6 + i * 4 + 2] & 0xFF) << 8) |
-                       ((buff[6 + i * 4 + 3] & 0xFF) << 16) |
-                       ((buff[6 + i * 4 + 4] & 0xFF) << 24) ;
-            Log.d(TAG, "AF: " + AfList[i]);
+          size_AFLIST = buff[6] & 0xFF;
+          Log.d(TAG, "size_AFLIST : " +size_AFLIST);
+
+          for (i = 0;i < size_AFLIST;i++) {
+                AfList[i] = (buff[6 + i * 4 + 1] & 0xFF) |
+                           ((buff[6 + i * 4 + 2] & 0xFF) << 8) |
+                           ((buff[6 + i * 4 + 3] & 0xFF) << 16) |
+                           ((buff[6 + i * 4 + 4] & 0xFF) << 24) ;
+                Log.d(TAG, "AF: " + AfList[i]);
+          }
+      } else {
+
+          if ((buff[4] <= 0) || (buff[4] > 25))
+              return null;
+
+          lowerBand = FmReceiverJNI.getLowerBandNative(sFd);
+          Log.d (TAG, "Low band " + lowerBand);
+
+          Log.d (TAG, "AF_buff 0: " + (buff[0] & 0xff));
+          Log.d (TAG, "AF_buff 1: " + (buff[1] & 0xff));
+          Log.d (TAG, "AF_buff 2: " + (buff[2] & 0xff));
+          Log.d (TAG, "AF_buff 3: " + (buff[3] & 0xff));
+          Log.d (TAG, "AF_buff 4: " + (buff[4] & 0xff));
+
+          for (i=0; i<buff[4]; i++) {
+               AfList[i] = ((buff[i+4] & 0xFF) * 1000) + lowerBand;
+               Log.d (TAG, "AF : " + AfList[i]);
+          }
       }
 
       return AfList;
+
    }
 
    /*==============================================================
@@ -2271,6 +2404,39 @@
    }
 
    /*==============================================================
+   FUNCTION:  getStationList
+   ==============================================================*/
+   /**
+   *    Returns a frequency List of the searched stations.
+   *
+   *    <p>
+   *    This method retreives the results of the {@link
+   *    #searchStationList}. This method should be called when the
+   *    FmRxEvSearchListComplete is invoked.
+   *
+   *    <p>
+   *    @return      An array of integers that corresponds to the
+   *                    frequency of the searched Stations
+   *    @see #searchStationList
+   */
+   public int[] getStationList ()
+   {
+      int state = getFMState();
+      /* Check current state of FM device */
+      if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
+          Log.d(TAG, "getStationList: Device currently busy in executing another command.");
+          return null;
+      }
+      int[] stnList = new int [100];
+
+      stnList = mControl.stationList (sFd);
+
+      return stnList;
+
+   }
+
+
+   /*==============================================================
    FUNCTION:  getRssi
    ==============================================================*/
    /**
@@ -2763,6 +2929,38 @@
        return retval;
    }
 
+   public static void getSpurTableData()
+   {
+     int freq;
+     byte no_of_spurs;
+     int rotation_value;
+     byte lsbOfLen;
+     byte filterCoe;
+     byte isEnbale;
+     byte [] buff = new byte[STD_BUF_SIZE];
+     int i = 0;
+     FmReceiverJNI.getBufferNative(sFd, buff, 13);
+
+     freq = buff[0] & 0xFF;
+     freq |= ((buff[1] & 0xFF) << 8);
+     freq |= ((buff[2] & 0xFF) << 16);
+     Log.d (TAG, "freq = " +freq);
+     no_of_spurs =  buff[3];
+     Log.d (TAG, "no_of_spurs = " + no_of_spurs);
+     for(i = 0; i < FmConfig.no_Of_Spurs_For_Entry; i++) {
+         rotation_value =  buff[(i * 4) + 4] & 0xFF;
+         rotation_value |= ((buff[(i * 4) + 5] & 0xFF) << 8);
+         rotation_value |= ((buff[(i * 4) + 6] & 0x0F) << 12);
+         Log.d (TAG, "rotation_value = " +rotation_value);
+         lsbOfLen = (byte) (((buff[(i * 4) + 6] & 0xF0) >> 4) & 0x01);
+         Log.d (TAG, "lsbOfLen = "+lsbOfLen);
+         filterCoe = (byte) (((buff[(i * 4) + 6] & 0xF0) >> 5) & 0x03);
+         Log.d (TAG, "filterCoe = " +filterCoe);
+         isEnbale = (byte) (((buff[(i * 4) + 6] & 0xF0) >> 7) & 0x01);
+         Log.d (TAG, "spur level: " +buff[(i * 4) + 7]);
+     }
+     return;
+   }
    public void FMcontrolLowPassFilter(int state, int net_type, int enable) {
        int RatConf = getFmWanWlanCoexProp(WAN_RATCONF);
        Log.v (TAG, "FMcontrolLowPassFilter " + RatConf);
diff --git a/qcom/fmradio/FmReceiverJNI.java b/qcom/fmradio/FmReceiverJNI.java
index 298ed07..86a7df7 100644
--- a/qcom/fmradio/FmReceiverJNI.java
+++ b/qcom/fmradio/FmReceiverJNI.java
@@ -319,6 +319,8 @@
         Log.d(TAG, "FmReceiverJNI constructor called");
     }
 
+    static native int acquireFdNative(String path);
+
     /**
      * native method:
      * @param fd
@@ -338,6 +340,15 @@
     static native int cancelSearchNative(int fd);
 
     /**
+     * native method: release control of device
+     * @param fd file descriptor of device
+     * @return May return
+     *             {@link #FM_JNI_SUCCESS}
+     *             {@link #FM_JNI_FAILURE}
+     */
+    static native int closeFdNative(int fd);
+
+    /**
      * native method: get frequency
      * @param fd file descriptor of device
      * @return Returns frequency in int form
@@ -383,6 +394,16 @@
     static native int startSearchNative (int fd, int dir);
 
     /**
+     * native method: get buffer
+     * @param fd file descriptor of device
+     * @param buff[] buffer
+     * @param index index of the buffer to be retrieved
+     * @return {@link #FM_JNI_SUCCESS}
+     *         {@link #FM_JNI_FAILURE}
+     */
+    static native int getBufferNative (int fd, byte  buff[], int index);
+
+    /**
      * native method: get RSSI value of the
      *                received signal
      * @param fd file descriptor of device
@@ -468,6 +489,7 @@
      *         {@link #FM_JNI_FAILURE}
      */
     static native int setSpurDataNative(int fd, short  buff[], int len);
+    static native void configurePerformanceParams(int fd);
     static native int enableSlimbus(int fd, int val);
     static native int enableSoftMute(int fd, int val);
     static native String getSocNameNative();
diff --git a/qcom/fmradio/FmRxControls.java b/qcom/fmradio/FmRxControls.java
index 1891ece..c67b7e4 100644
--- a/qcom/fmradio/FmRxControls.java
+++ b/qcom/fmradio/FmRxControls.java
@@ -123,11 +123,12 @@
          Log.d(TAG,"setControlNative faile" + V4L2_CID_PRIVATE_TAVARUA_STATE);
          return re;
       }
-      boolean ret = enableSoftMute(fd,ENABLE_SOFT_MUTE);
-      if(false == ret) {
-          Log.d(TAG,"enableSoftMute failed");
+      if (FmReceiver.isCherokeeChip()) {
+          boolean ret = enableSoftMute(fd,ENABLE_SOFT_MUTE);
+          if(false == ret) {
+              Log.d(TAG,"enableSoftMute failed");
+          }
       }
-
       setAudioPath(fd, false);
       return re;
    }
@@ -438,6 +439,69 @@
 
    }
 
+   /* Read search list from buffer */
+   public int[] stationList (int fd)
+   {
+         int freq = 0;
+         int i=0, j = 0;
+         int station_num = 0;
+         float real_freq = 0;
+         int [] stationList;
+         byte [] sList = new byte[100];
+         int tmpFreqByte1=0;
+         int tmpFreqByte2=0;
+         float lowBand, highBand;
+
+
+         lowBand  = (float) (FmReceiverJNI.getLowerBandNative(fd) / 1000.00);
+         highBand = (float) (FmReceiverJNI.getUpperBandNative(fd) / 1000.00);
+
+         Log.d(TAG, "lowBand: " + lowBand);
+         Log.d(TAG, "highBand: " + highBand);
+
+         FmReceiverJNI.getBufferNative(fd, sList, 0);
+
+         if ((int)sList[0] >0) {
+            station_num = (int)sList[0];
+         }
+         stationList = new int[station_num+1];
+         Log.d(TAG, "station_num: " + station_num);
+
+         for (i=0;i<station_num;i++) {
+            freq = 0;
+            Log.d(TAG, " Byte1 = " + sList[i*2+1]);
+            Log.d(TAG, " Byte2 = " + sList[i*2+2]);
+            tmpFreqByte1 = sList[i*2+1] & 0xFF;
+            tmpFreqByte2 = sList[i*2+2] & 0xFF;
+            Log.d(TAG, " tmpFreqByte1 = " + tmpFreqByte1);
+            Log.d(TAG, " tmpFreqByte2 = " + tmpFreqByte2);
+            freq = (tmpFreqByte1 & 0x03) << 8;
+            freq |= tmpFreqByte2;
+            Log.d(TAG, " freq: " + freq);
+            real_freq  = (float)(freq * 50) + (lowBand * FREQ_MUL);//tuner.rangelow * FREQ_MUL;
+            Log.d(TAG, " real_freq: " + real_freq);
+            if ( (real_freq < (lowBand * FREQ_MUL)) || (real_freq > (highBand * FREQ_MUL)) ) {
+               Log.e(TAG, "Frequency out of band limits");
+            }
+            else {
+               stationList[j] = (int)(real_freq);
+               Log.d(TAG, " stationList: " + stationList[j]);
+               j++;
+            }
+         }
+
+        try {
+          // mark end of list
+           stationList[station_num] = 0;
+        }
+        catch (ArrayIndexOutOfBoundsException e) {
+           Log.d(TAG, "ArrayIndexOutOfBoundsException !!");
+        }
+
+        return stationList;
+
+   }
+
 
    /* configure various search parameters and start search */
    public int searchStations (int fd, int mode, int dwell,
diff --git a/qcom/fmradio/FmRxEventListner.java b/qcom/fmradio/FmRxEventListner.java
new file mode 100644
index 0000000..c178f17
--- /dev/null
+++ b/qcom/fmradio/FmRxEventListner.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2009,2012-2014, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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.
+ */
+
+package qcom.fmradio;
+import qcom.fmradio.FmReceiver;
+import qcom.fmradio.FmTransceiver;
+import java.util.Arrays;
+import android.util.Log;
+
+
+class FmRxEventListner {
+
+    private final int EVENT_LISTEN = 1;
+
+    private final int STD_BUF_SIZE = 256;
+
+    private enum FmRxEvents {
+      READY_EVENT,
+      TUNE_EVENT,
+      SEEK_COMPLETE_EVENT,
+      SCAN_NEXT_EVENT,
+      RAW_RDS_EVENT,
+      RT_EVENT,
+      PS_EVENT,
+      ERROR_EVENT,
+      BELOW_TH_EVENT,
+      ABOVE_TH_EVENT,
+      STEREO_EVENT,
+      MONO_EVENT,
+      RDS_AVAL_EVENT,
+      RDS_NOT_AVAL_EVENT,
+      TAVARUA_EVT_NEW_SRCH_LIST,
+      TAVARUA_EVT_NEW_AF_LIST
+    }
+
+    private Thread mThread;
+    private static final String TAG = "FMRadio";
+
+    public void startListner (final int fd, final FmRxEvCallbacks cb) {
+        /* start a thread and listen for messages */
+        mThread = new Thread(){
+            public void run(){
+                byte [] buff = new byte[STD_BUF_SIZE];
+                Log.d(TAG, "Starting listener " + fd);
+
+                while ((!Thread.currentThread().isInterrupted())) {
+
+                    try {
+                        int index = 0;
+                        int state = 0;
+                        Arrays.fill(buff, (byte)0x00);
+                        int freq = 0;
+                        int eventCount = FmReceiverJNI.getBufferNative (fd, buff, EVENT_LISTEN);
+
+                        if (eventCount >= 0)
+                            Log.d(TAG, "Received event. Count: " + eventCount);
+
+                        for (  index = 0; index < eventCount; index++ ) {
+                            Log.d(TAG, "Received <" +buff[index]+ ">" );
+
+                            switch(buff[index]){
+                            case 0:
+                                Log.d(TAG, "Got READY_EVENT");
+                                if(FmTransceiver.getFMPowerState() == FmTransceiver.subPwrLevel_FMRx_Starting) {
+                                    /*Set the state as FMRxOn */
+                                    FmTransceiver.setFMPowerState(FmTransceiver.FMState_Rx_Turned_On);
+                                    Log.v(TAG, "RxEvtList: CURRENT-STATE : FMRxStarting ---> NEW-STATE : FMRxOn");
+                                    cb.FmRxEvEnableReceiver();
+                                    FmReceiverJNI.configurePerformanceParams(fd);
+                                }
+                                else if (FmTransceiver.getFMPowerState() == FmTransceiver.subPwrLevel_FMTurning_Off) {
+                                    /*Set the state as FMOff */
+                                    FmTransceiver.setFMPowerState(FmTransceiver.FMState_Turned_Off);
+                                    Log.v(TAG, "RxEvtList: CURRENT-STATE : FMTurningOff ---> NEW-STATE : FMOff");
+                                    FmTransceiver.release("/dev/radio0");
+                                    cb.FmRxEvDisableReceiver();
+                                    Thread.currentThread().interrupt();
+                                }
+                                break;
+                            case 1:
+                                Log.d(TAG, "Got TUNE_EVENT");
+                                freq = FmReceiverJNI.getFreqNative(fd);
+                                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");
+                                        cb.FmRxEvSearchComplete(freq);
+                                        break;
+                                   default:
+                                        if (freq > 0)
+                                            cb.FmRxEvRadioTuneStatus(freq);
+                                        else
+                                            Log.e(TAG, "get frequency command failed");
+                                        break;
+                                }
+                                break;
+                            case 2:
+                                Log.d(TAG, "Got SEEK_COMPLETE_EVENT");
+                                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");
+                                      cb.FmRxEvSearchComplete(FmReceiverJNI.getFreqNative(fd));
+                                      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");
+                                      cb.FmRxEvSearchComplete(FmReceiverJNI.getFreqNative(fd));
+                                      break;
+                                }
+                                break;
+                            case 3:
+                                Log.d(TAG, "Got SCAN_NEXT_EVENT");
+                                cb.FmRxEvSearchInProgress();
+                                break;
+                            case 4:
+                                Log.d(TAG, "Got RAW_RDS_EVENT");
+                                cb.FmRxEvRdsGroupData();
+                                break;
+                            case 5:
+                                Log.d(TAG, "Got RT_EVENT");
+                                cb.FmRxEvRdsRtInfo();
+                                break;
+                            case 6:
+                                Log.d(TAG, "Got PS_EVENT");
+                                cb.FmRxEvRdsPsInfo();
+                                break;
+                            case 7:
+                                Log.d(TAG, "Got ERROR_EVENT");
+                                break;
+                            case 8:
+                                Log.d(TAG, "Got BELOW_TH_EVENT");
+                                cb.FmRxEvServiceAvailable (false);
+                                break;
+                            case 9:
+                                Log.d(TAG, "Got ABOVE_TH_EVENT");
+                                cb.FmRxEvServiceAvailable(true);
+                                break;
+                            case 10:
+                                Log.d(TAG, "Got STEREO_EVENT");
+                                cb.FmRxEvStereoStatus (true);
+                                break;
+                            case 11:
+                                Log.d(TAG, "Got MONO_EVENT");
+                                cb.FmRxEvStereoStatus (false);
+                                break;
+                            case 12:
+                                Log.d(TAG, "Got RDS_AVAL_EVENT");
+                                cb.FmRxEvRdsLockStatus (true);
+                                break;
+                            case 13:
+                                Log.d(TAG, "Got RDS_NOT_AVAL_EVENT");
+                                cb.FmRxEvRdsLockStatus (false);
+                                break;
+                            case 14:
+                                Log.d(TAG, "Got NEW_SRCH_LIST");
+                                state = FmReceiver.getSearchState();
+                                switch(state) {
+                                   case FmTransceiver.subSrchLevel_SrchListInProg:
+                                      Log.v(TAG, "FmRxEventListener: Current state is AUTO_PRESET_INPROGRESS");
+                                      FmReceiver.setSearchState(FmTransceiver.subSrchLevel_SrchComplete);
+                                      Log.v(TAG, "RxEvtList: CURRENT-STATE : Search ---> NEW-STATE : FMRxOn");
+                                      cb.FmRxEvSearchListComplete ();
+                                      break;
+                                   case FmTransceiver.subSrchLevel_SrchAbort:
+                                      Log.v(TAG, "Current state is SRCH_ABORTED");
+                                      Log.v(TAG, "Aborting on-going SearchList command...");
+                                      FmReceiver.setSearchState(FmTransceiver.subSrchLevel_SrchComplete);
+                                      Log.v(TAG, "RxEvtList: CURRENT-STATE : Search ---> NEW-STATE : FMRxOn");
+                                      cb.FmRxEvSearchCancelled();
+                                      break;
+                                }
+                                break;
+                            case 15:
+                                Log.d(TAG, "Got NEW_AF_LIST");
+                                cb.FmRxEvRdsAfInfo();
+                                break;
+                            case 18:
+                                Log.d(TAG, "Got RADIO_DISABLED");
+                                if (FmTransceiver.getFMPowerState() == FmTransceiver.subPwrLevel_FMTurning_Off) {
+                                    FmTransceiver.release("/dev/radio0");
+                                    /*Set the state as FMOff */
+                                    FmTransceiver.setFMPowerState(FmTransceiver.FMState_Turned_Off);
+                                    cb.FmRxEvDisableReceiver();
+                                    Log.v(TAG, "RxEvtList: CURRENT-STATE : FMTurningOff ---> NEW-STATE : FMOff");
+                                    Thread.currentThread().interrupt();
+                                } else {
+                                    Log.d(TAG, "Unexpected RADIO_DISABLED recvd");
+                                    FmTransceiver.release("/dev/radio0");
+                                    cb.FmRxEvRadioReset();
+                                    FmTransceiver.setFMPowerState(FmTransceiver.FMState_Turned_Off);
+                                    Log.v(TAG, "RxEvtList: CURRENT-STATE : FMRxOn ---> NEW-STATE : FMOff");
+                                    Thread.currentThread().interrupt();
+                                }
+                                break;
+                            case 19:
+                                FmTransceiver.setRDSGrpMask(0);
+                                break;
+                            case 20:
+                                Log.d(TAG, "got RT plus event");
+                                cb.FmRxEvRTPlus();
+                                break;
+                            case 21:
+                                Log.d(TAG, "got eRT event");
+                                cb.FmRxEvERTInfo();
+                                break;
+                            case 22:
+                                Log.d(TAG, "got IRIS_EVT_SPUR_TBL event");
+                                FmReceiver.getSpurTableData();
+                                break;
+                            default:
+                                Log.d(TAG, "Unknown event");
+                                break;
+                            }
+                        }//end of for
+                    } catch ( Exception ex ) {
+                        Log.d( TAG,  "RunningThread InterruptedException");
+                        ex.printStackTrace();
+                        Thread.currentThread().interrupt();
+                    }
+                }
+            }
+        };
+        mThread.start();
+    }
+
+    public void stopListener(){
+        //mThread.stop();
+        //Thread stop is deprecate API
+        //Interrupt the thread and check for the thread status
+        // and return from the run() method to stop the thread
+        //properly
+        Log.d( TAG,  "stopping the Listener\n");
+        if( mThread != null ) {
+         mThread.interrupt();
+        }
+    }
+
+}
diff --git a/qcom/fmradio/FmTransceiver.java b/qcom/fmradio/FmTransceiver.java
index eee89d4..589a2dc 100644
--- a/qcom/fmradio/FmTransceiver.java
+++ b/qcom/fmradio/FmTransceiver.java
@@ -139,14 +139,168 @@
    private static final int V4L2_CID_PRIVATE_TAVARUA_SET_NOTCH_FILTER = V4L2_CID_PRIVATE_BASE + 40;
 
    private final String TAG = "FmTransceiver";
+   private final String V4L2_DEVICE = "/dev/radio0";
 
    protected static int sFd;
    protected FmRxControls mControl;
    protected int mPowerMode;
+   protected FmRxEventListner mRxEvents;
    protected FmRxRdsData mRdsData;
+
    public static final int ERROR = -1;
 
    /*==============================================================
+   FUNCTION:  acquire
+   ==============================================================*/
+   /**
+   *    Allows access to the V4L2 FM device.
+   *
+   *    This synchronous call allows a client to use the V4L2 FM
+   *    device. This must be the first call issued by the client
+   *    before any receiver interfaces can be used.
+   *
+   *    This call also powers up the FM Module.
+   *
+   *    @param device String that is path to radio device
+   *
+   *    @return true if V4L2 FM device acquired, false if V4L2 FM
+   *            device could not be acquired, possibly acquired by
+   *            other client
+   *    @see   #release
+   *
+   */
+   protected boolean acquire(String device){
+      boolean bStatus = true;
+      if (sFd <= 0) { // if previous open fails fd will be -ve.
+         sFd = FmReceiverJNI.acquireFdNative(V4L2_DEVICE);
+
+         if (sFd > 0) {
+            Log.d(TAG, "Opened "+ sFd);
+            bStatus = true;
+         }
+         else {
+            Log.d(TAG, "Fail to Open "+ sFd);
+	    bStatus = false;
+         }
+      }
+      else {
+         Log.d(TAG, "Already Opened:" + sFd);
+         /*This should be case
+          * Where User try to opne the device
+          * secondtime.
+          * Case where Tx and Rx try to
+          * acquire the device
+          */
+         bStatus = false;
+       }
+      return (bStatus);
+   }
+
+   /*==============================================================
+   FUNCTION:  release
+   ==============================================================*/
+   /**
+   *    Releases access to the V4L2 FM device.
+   *    <p>
+   *    This synchronous call allows a client to release control of
+   *    V4L2 FM device.  This function should be called when the FM
+   *    device is no longer needed. This should be the last call
+   *    issued by the FM client. Once called, the client must call
+   *    #acquire to re-aquire the V4L2 device control before the
+   *    FM device can be used again.
+   *    <p>
+   *    Before the client can release control of the FM receiver
+   *    interface, it must disable the FM receiver, if the client
+   *    enabled it, and unregister any registered callback.  If the
+   *    client has ownership of the receiver, it will automatically
+   *    be returned to the system.
+   *    <p>
+   *    This call also powers down the FM Module.
+   *    <p>
+   *    @param device String that is path to radio device
+   *    @return true if V4L2 FM device released, false if V4L2 FM
+   *            device could not be released
+   *    @see   #acquire
+   */
+   static boolean release(String device) {
+      if (sFd!=0)
+      {
+         FmReceiverJNI.closeFdNative(sFd);
+         sFd = 0;
+         Log.d("FmTransceiver", "Turned off: " + sFd);
+      } else
+      {
+         Log.d("FmTransceiver", "Error turning off");
+      }
+      return true;
+   }
+
+   /*==============================================================
+   FUNCTION:  registerClient
+   ==============================================================*/
+   /**
+   *    Registers a callback for FM receiver event notifications.
+   *    <p>
+   *    This is a synchronous call used to register for event
+   *    notifications from the FM receiver driver. Since the FM
+   *    driver performs some tasks asynchronously, this function
+   *    allows the client to receive information asynchronously.
+   *    <p>
+   *    When calling this function, the client must pass a callback
+   *    function which will be used to deliver asynchronous events.
+   *    The argument callback must be a non-NULL value.  If a NULL
+   *    value is passed to this function, the registration will
+   *    fail.
+   *    <p>
+   *    The client can choose which events will be sent from the
+   *    receiver driver by simply implementing functions for events
+   *    it wishes to receive.
+   *    <p>
+   *
+   *    @param callback the callback to handle the events events
+   *                    from the FM receiver.
+   *    @return true if Callback registered, false if Callback
+   *            registration failed.
+   *
+   *    @see #acquire
+   *    @see #unregisterClient
+   *
+   */
+   public boolean registerClient(FmRxEvCallbacks callback){
+      boolean bReturnStatus = false;
+      if (callback!=null)
+      {
+         mRxEvents.startListner(sFd, callback);
+         bReturnStatus = true;
+      } else
+      {
+         Log.d(TAG, "Null, do nothing");
+      }
+      return bReturnStatus;
+   }
+
+   /*==============================================================
+   FUNCTION:  unregisterClient
+   ==============================================================*/
+   /**
+   *    Unregisters a client's event notification callback.
+   *    <p>
+   *    This is a synchronous call used to unregister a client's
+   *    event callback.
+   *    <p>
+   *    @return true always.
+   *
+   *    @see  #acquire
+   *    @see  #release
+   *    @see  #registerClient
+   *
+   */
+   public boolean unregisterClient () {
+      mRxEvents.stopListener();
+      return true;
+   }
+
+   /*==============================================================
    FUNCTION:  enable
    ==============================================================*/
    /**
@@ -183,6 +337,12 @@
       boolean status;
       int ret;
 
+      if (!FmReceiver.isCherokeeChip()) {
+          //Acquire the deviceon Enable
+          if (!acquire("/dev/radio0")) {
+              return false;
+          }
+      }
       if (new File("/etc/fm/SpurTableFile.txt").isFile()) {
           Log.d(TAG, "Send Spur roation table");
           FmConfig.fmSpurConfig(sFd);
@@ -193,6 +353,7 @@
       ret = mControl.fmOn(sFd, device);
       if (ret < 0) {
           Log.d(TAG, "turning on failed");
+          FmReceiverJNI.closeFdNative(sFd);
           sFd = 0;
           return false;
       }
@@ -201,6 +362,7 @@
       status = FmConfig.fmConfigure (sFd, configSettings);
       if (!status) {
           Log.d(TAG, "fmConfigure failed");
+          FmReceiverJNI.closeFdNative(sFd);
           sFd = 0;
       }
       return status;