FM: Migrate FM Framework code base to new git

Change-Id: I4769b2381fc62d75e67c428071c320b8f63cce0e
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..1fb20d5
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,15 @@
+ifeq ($(call is-vendor-board-platform,QCOM),true)
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_JNI_SHARED_LIBRARIES := libqcomfm_jni
+
+LOCAL_MODULE:= qcom.fmradio
+
+include $(BUILD_JAVA_LIBRARY)
+
+include $(LOCAL_PATH)/jni/Android.mk
+endif # is-vendor-board-platform
diff --git a/jni/Android.mk b/jni/Android.mk
new file mode 100644
index 0000000..594332f
--- /dev/null
+++ b/jni/Android.mk
@@ -0,0 +1,25 @@
+ifeq ($(call is-vendor-board-platform,QCOM),true)
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+android_hardware_fm.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+        libnativehelper \
+        libcutils
+
+LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+
+LOCAL_CFLAGS += -include bionic/libc/kernel/arch-arm/asm/posix_types.h
+LOCAL_CFLAGS += -include bionic/libc/kernel/arch-arm/asm/byteorder.h
+LOCAL_CFLAGS += -include bionic/libc/kernel/common/linux/types.h
+LOCAL_CFLAGS += -include bionic/libc/kernel/common/linux/posix_types.h
+LOCAL_CFLAGS += -include bionic/libc/kernel/common/linux/socket.h
+
+LOCAL_MODULE := libqcomfm_jni
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
+endif # is-vendor-board-platform
diff --git a/jni/android_hardware_fm.cpp b/jni/android_hardware_fm.cpp
new file mode 100644
index 0000000..7068b83
--- /dev/null
+++ b/jni/android_hardware_fm.cpp
@@ -0,0 +1,818 @@
+/*
+ * Copyright (c) 2009-2012, 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.
+ */
+
+#define LOG_TAG "fmradio"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "utils/Log.h"
+#include "utils/misc.h"
+#include <cutils/properties.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <media/tavarua.h>
+#include <linux/videodev2.h>
+#include <math.h>
+
+#define RADIO "/dev/radio0"
+#define FM_JNI_SUCCESS 0L
+#define FM_JNI_FAILURE -1L
+#define SEARCH_DOWN 0
+#define SEARCH_UP 1
+#define TUNE_MULT 16000
+#define HIGH_BAND 2
+#define LOW_BAND  1
+#define CAL_DATA_SIZE 23
+#define V4L2_CTRL_CLASS_USER 0x00980000
+#define V4L2_CID_PRIVATE_IRIS_SET_CALIBRATION           (V4L2_CTRL_CLASS_USER + 0x92A)
+#define V4L2_CID_PRIVATE_TAVARUA_ON_CHANNEL_THRESHOLD   (V4L2_CTRL_CLASS_USER + 0x92B)
+#define V4L2_CID_PRIVATE_TAVARUA_OFF_CHANNEL_THRESHOLD  (V4L2_CTRL_CLASS_USER + 0x92C)
+#define TX_RT_LENGTH       63
+#define WAIT_TIMEOUT 200000 /* 200*1000us */
+#define TX_RT_DELIMITER    0x0d
+#define PS_LEN    9
+#define STD_BUF_SIZE 256
+enum search_dir_t {
+    SEEK_UP,
+    SEEK_DN,
+    SCAN_UP,
+    SCAN_DN
+};
+
+
+using namespace android;
+
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_acquireFdNative
+        (JNIEnv* env, jobject thiz, jstring path)
+{
+    int fd;
+    int i, retval=0, err;
+    char value[PROPERTY_VALUE_MAX] = {'\0'};
+    char versionStr[40] = {'\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( err >= 0 ) {
+       ALOGD("Driver Version(Same as ChipId): %x \n",  cap.version );
+       /*Conver the integer to string */
+       sprintf(versionStr, "%d", cap.version );
+       property_set("hw.fm.version", versionStr);
+    } else {
+       return FM_JNI_FAILURE;
+    }
+    /*Set the mode for soc downloader*/
+    property_set("hw.fm.mode", "normal");
+    /* Need to clear the hw.fm.init firstly */
+    property_set("hw.fm.init", "0");
+    property_set("ctl.start", "fm_dl");
+    sched_yield();
+    for(i=0; i<45; i++) {
+        property_get("hw.fm.init", value, NULL);
+        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) {
+        property_set("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)
+{
+    int i = 0;
+    int cleanup_success = 0;
+    char value = 0, retval =0;
+
+    property_set("ctl.stop", "fm_dl");
+    close(fd);
+    return FM_JNI_SUCCESS;
+}
+
+/********************************************************************
+ * Current JNI
+ *******************************************************************/
+
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_getFreqNative
+    (JNIEnv * env, jobject thiz, jint fd)
+{
+    int err;
+    struct v4l2_frequency freq;
+    freq.type = V4L2_TUNER_RADIO;
+    err = ioctl(fd, VIDIOC_G_FREQUENCY, &freq);
+    if(err < 0){
+      return FM_JNI_FAILURE;
+    }
+    return ((freq.frequency*1000)/TUNE_MULT);
+}
+
+/*native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_setFreqNative
+    (JNIEnv * env, jobject thiz, jint fd, jint freq)
+{
+    int err;
+    double tune;
+    struct v4l2_frequency freq_struct;
+    freq_struct.type = V4L2_TUNER_RADIO;
+    freq_struct.frequency = (freq*TUNE_MULT/1000);
+    err = ioctl(fd, VIDIOC_S_FREQUENCY, &freq_struct);
+    if(err < 0){
+            return FM_JNI_FAILURE;
+    }
+    return FM_JNI_SUCCESS;
+}
+
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_setControlNative
+    (JNIEnv * env, jobject thiz, jint fd, jint id, jint value)
+{
+    struct v4l2_control control;
+    int i;
+    int err;
+    ALOGE("id(%x) value: %x\n", id, value);
+    control.value = value;
+
+    control.id = id;
+    for(i=0;i<3;i++) {
+        err = ioctl(fd,VIDIOC_S_CTRL,&control);
+        if(err >= 0){
+            return FM_JNI_SUCCESS;
+        }
+    }
+    ALOGE("setControl native returned with err %d", err);
+    return FM_JNI_FAILURE;
+}
+
+static jint android_hardware_fmradio_FmReceiverJNI_SetCalibrationNative
+     (JNIEnv * env, jobject thiz, jint fd, jbyteArray buff)
+{
+
+    struct v4l2_ext_control ext_ctl;
+    char tmp[CAL_DATA_SIZE] = {0x00};
+    int err;
+    FILE* cal_file;
+
+    cal_file = fopen("/data/app/Riva_fm_cal", "r" );
+    if(cal_file != NULL) {
+        ext_ctl.id = V4L2_CID_PRIVATE_IRIS_SET_CALIBRATION;
+        if (fread(&tmp[0],1,CAL_DATA_SIZE,cal_file) < CAL_DATA_SIZE)
+        {
+            ALOGE("File read failed");
+            return FM_JNI_FAILURE;
+        }
+        ext_ctl.string = tmp;
+        ext_ctl.size = CAL_DATA_SIZE;
+        struct v4l2_ext_controls v4l2_ctls;
+
+        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){
+            return FM_JNI_SUCCESS;
+        }
+    }else {
+        return FM_JNI_SUCCESS;
+    }
+  return FM_JNI_SUCCESS;
+}
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_getControlNative
+    (JNIEnv * env, jobject thiz, jint fd, jint id)
+{
+    struct v4l2_control control;
+    int err;
+    ALOGE("id(%x)\n", id);
+
+    control.id = id;
+    err = ioctl(fd,VIDIOC_G_CTRL,&control);
+    if(err < 0){
+        return FM_JNI_FAILURE;
+    }
+    return control.value;
+}
+
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_startSearchNative
+    (JNIEnv * env, jobject thiz, jint fd, jint dir)
+{
+    ALOGE("startSearchNative: Issuing the VIDIOC_S_HW_FREQ_SEEK");
+    struct v4l2_hw_freq_seek hw_seek;
+    int err;
+    hw_seek.seek_upward = dir;
+    hw_seek.type = V4L2_TUNER_RADIO;
+    err = ioctl(fd,VIDIOC_S_HW_FREQ_SEEK,&hw_seek);
+    if(err < 0){
+        ALOGE("startSearchNative: ioctl failed!!! with error %d\n", err);
+        return FM_JNI_FAILURE;
+    } else
+        ALOGE("startSearchNative: ioctl succedded!!!");
+    return FM_JNI_SUCCESS;
+}
+
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_cancelSearchNative
+    (JNIEnv * env, jobject thiz, jint fd)
+{
+    struct v4l2_control control;
+    int err;
+    control.id=V4L2_CID_PRIVATE_TAVARUA_SRCHON;
+    control.value=0;
+    err = ioctl(fd,VIDIOC_S_CTRL,&control);
+    if(err < 0){
+        return FM_JNI_FAILURE;
+    }
+    return FM_JNI_SUCCESS;
+}
+
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_getRSSINative
+    (JNIEnv * env, jobject thiz, jint fd)
+{
+    struct v4l2_tuner tuner;
+    int err;
+
+    tuner.index = 0;
+    tuner.signal = 0;
+    err = ioctl(fd, VIDIOC_G_TUNER, &tuner);
+    if(err < 0){
+        return FM_JNI_FAILURE;
+    }
+    return tuner.signal;
+}
+
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_setBandNative
+    (JNIEnv * env, jobject thiz, jint fd, jint low, jint high)
+{
+    struct v4l2_tuner tuner;
+    int err;
+
+    tuner.index = 0;
+    tuner.signal = 0;
+    tuner.rangelow = low * (TUNE_MULT/1000);
+    tuner.rangehigh = high * (TUNE_MULT/1000);
+    err = ioctl(fd, VIDIOC_S_TUNER, &tuner);
+    if(err < 0){
+        return FM_JNI_FAILURE;
+    }
+    return FM_JNI_SUCCESS;
+}
+
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_getLowerBandNative
+    (JNIEnv * env, jobject thiz, jint fd)
+{
+    struct v4l2_tuner tuner;
+    int err;
+    tuner.index = 0;
+
+    err = ioctl(fd, VIDIOC_G_TUNER, &tuner);
+    if(err < 0){
+        ALOGE("low_band value: <%x> \n", tuner.rangelow);
+        return FM_JNI_FAILURE;
+    }
+    return ((tuner.rangelow * 1000)/ TUNE_MULT);
+}
+
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_getUpperBandNative
+    (JNIEnv * env, jobject thiz, jint fd)
+{
+    struct v4l2_tuner tuner;
+    int err;
+    tuner.index = 0;
+
+    err = ioctl(fd, VIDIOC_G_TUNER, &tuner);
+    if(err < 0){
+        ALOGE("high_band value: <%x> \n", tuner.rangehigh);
+        return FM_JNI_FAILURE;
+    }
+    return ((tuner.rangehigh * 1000) / TUNE_MULT);
+}
+
+static jint android_hardware_fmradio_FmReceiverJNI_setMonoStereoNative
+    (JNIEnv * env, jobject thiz, jint fd, jint val)
+{
+
+    struct v4l2_tuner tuner;
+    int err;
+
+    tuner.index = 0;
+    err = ioctl(fd, VIDIOC_G_TUNER, &tuner);
+
+    if(err < 0)
+        return FM_JNI_FAILURE;
+
+    tuner.audmode = val;
+    err = ioctl(fd, VIDIOC_S_TUNER, &tuner);
+
+    if(err < 0)
+        return FM_JNI_FAILURE;
+
+    return FM_JNI_SUCCESS;
+
+}
+
+
+
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_getBufferNative
+ (JNIEnv * env, jobject thiz, jint fd, jbooleanArray buff, jint index)
+{
+    int err;
+    jboolean isCopy;
+    struct v4l2_requestbuffers reqbuf;
+    struct v4l2_buffer v4l2_buf;
+    memset(&reqbuf, 0, sizeof (reqbuf));
+    enum v4l2_buf_type type = V4L2_BUF_TYPE_PRIVATE;
+    reqbuf.type = V4L2_BUF_TYPE_PRIVATE;
+    reqbuf.memory = V4L2_MEMORY_USERPTR;
+    jboolean *bool_buffer = env->GetBooleanArrayElements(buff,&isCopy);
+    memset(&v4l2_buf, 0, sizeof (v4l2_buf));
+    v4l2_buf.index = index;
+    v4l2_buf.type = type;
+    v4l2_buf.length = STD_BUF_SIZE;
+    v4l2_buf.m.userptr = (unsigned long)bool_buffer;
+    err = ioctl(fd,VIDIOC_DQBUF,&v4l2_buf);
+    if(err < 0){
+        /* free up the memory in failure case*/
+        env->ReleaseBooleanArrayElements(buff, bool_buffer, 0);
+        return FM_JNI_FAILURE;
+    }
+
+    /* Always copy buffer and free up the memory */
+    env->ReleaseBooleanArrayElements(buff, bool_buffer, 0);
+
+    return v4l2_buf.bytesused;
+}
+
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_getRawRdsNative
+ (JNIEnv * env, jobject thiz, jint fd, jbooleanArray buff, jint count)
+{
+
+    return (read (fd, buff, count));
+
+}
+
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_setNotchFilterNative(JNIEnv * env, jobject thiz,jint fd, jint id, jboolean aValue)
+{
+    char value[PROPERTY_VALUE_MAX] = {'\0'};
+    int init_success = 0,i;
+    char notch[20] = {0x00};
+    struct v4l2_control control;
+    int err;
+    /*Enable/Disable the WAN avoidance*/
+    property_set("hw.fm.init", "0");
+    if (aValue)
+       property_set("hw.fm.mode", "wa_enable");
+    else
+       property_set("hw.fm.mode", "wa_disable");
+
+    property_set("ctl.start", "fm_dl");
+    sched_yield();
+    for(i=0; i<10; i++) {
+       property_get("hw.fm.init", value, NULL);
+       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);
+
+    property_get("notch.value", notch, NULL);
+    ALOGE("Notch = %s",notch);
+    if (!strncmp("HIGH",notch,strlen("HIGH")))
+        control.value = HIGH_BAND;
+    else if(!strncmp("LOW",notch,strlen("LOW")))
+        control.value = LOW_BAND;
+    else
+        control.value = 0;
+
+    ALOGE("Notch value : %d", control.value);
+    control.id = id;
+    err = ioctl(fd, VIDIOC_S_CTRL,&control );
+    if(err < 0){
+          return FM_JNI_FAILURE;
+    }
+    return FM_JNI_SUCCESS;
+}
+
+
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_setAnalogModeNative(JNIEnv * env, jobject thiz, jboolean aValue)
+{
+    int i=0;
+    char value[PROPERTY_VALUE_MAX] = {'\0'};
+    char firmwareVersion[80];
+
+    /*Enable/Disable Analog Mode FM*/
+    property_set("hw.fm.init", "0");
+    if (aValue) {
+        property_set("hw.fm.isAnalog", "true");
+    } else {
+        property_set("hw.fm.isAnalog", "false");
+    }
+    property_set("hw.fm.mode","config_dac");
+    property_set("ctl.start", "fm_dl");
+    sched_yield();
+    for(i=0; i<10; i++) {
+       property_get("hw.fm.init", value, NULL);
+       if (strcmp(value, "1") == 0) {
+          return 1;
+       } else {
+          usleep(WAIT_TIMEOUT);
+       }
+    }
+
+    return 0;
+}
+
+
+
+
+/*
+ * Interfaces added for Tx
+*/
+
+/*native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_setPTYNative
+    (JNIEnv * env, jobject thiz, jint fd, jint pty)
+{
+    ALOGE("->android_hardware_fmradio_FmReceiverJNI_setPTYNative\n");
+    struct v4l2_control control;
+
+    control.id = V4L2_CID_RDS_TX_PTY;
+    control.value = pty & MASK_PTY;
+
+    int err;
+    err = ioctl(fd, VIDIOC_S_CTRL,&control );
+    if(err < 0){
+            return FM_JNI_FAILURE;
+    }
+    return FM_JNI_SUCCESS;
+}
+
+static jint android_hardware_fmradio_FmReceiverJNI_setPINative
+    (JNIEnv * env, jobject thiz, jint fd, jint pi)
+{
+    ALOGE("->android_hardware_fmradio_FmReceiverJNI_setPINative\n");
+
+    struct v4l2_control control;
+
+    control.id = V4L2_CID_RDS_TX_PI;
+    control.value = pi & MASK_PI;
+
+    int err;
+    err = ioctl(fd, VIDIOC_S_CTRL,&control );
+    if(err < 0){
+		ALOGE("->pty native failed");
+            return FM_JNI_FAILURE;
+    }
+
+    return FM_JNI_SUCCESS;
+}
+
+static jint android_hardware_fmradio_FmReceiverJNI_startRTNative
+    (JNIEnv * env, jobject thiz, jint fd, jstring radio_text, jint count )
+{
+    ALOGD("->android_hardware_fmradio_FmReceiverJNI_startRTNative\n");
+
+    struct v4l2_ext_control ext_ctl;
+    struct v4l2_ext_controls v4l2_ctls;
+
+    int err = 0;
+    jboolean isCopy = false;
+    char* rt_string1 = NULL;
+    char* rt_string = (char*)env->GetStringUTFChars(radio_text, &isCopy);
+    if(rt_string == NULL ){
+        ALOGE("RT string is not valid \n");
+        return FM_JNI_FAILURE;
+    }
+
+    rt_string1 = (char*) malloc(TX_RT_LENGTH + 1);
+    if (rt_string1 == NULL) {
+       ALOGE("out of memory \n");
+       env->ReleaseStringUTFChars(radio_text, rt_string);
+       return FM_JNI_FAILURE;
+    }
+    memset (rt_string1, 0, TX_RT_LENGTH + 1);
+    memcpy(rt_string1, rt_string, count);
+
+    if(count < TX_RT_LENGTH)
+       rt_string1[count] = TX_RT_DELIMITER;
+
+    ext_ctl.id     = V4L2_CID_RDS_TX_RADIO_TEXT;
+    ext_ctl.string = rt_string1;
+    ext_ctl.size   = strlen(rt_string1) + 1;
+
+    /* form the ctrls data struct */
+    v4l2_ctls.ctrl_class = V4L2_CTRL_CLASS_FM_TX,
+    v4l2_ctls.count      = 1,
+    v4l2_ctls.controls   = &ext_ctl;
+
+
+    err = ioctl(fd, VIDIOC_S_EXT_CTRLS, &v4l2_ctls );
+    env->ReleaseStringUTFChars(radio_text, rt_string);
+    if (rt_string1 != NULL) {
+        free(rt_string1);
+        rt_string1 = NULL;
+    }
+    if(err < 0){
+        ALOGE("VIDIOC_S_EXT_CTRLS for start RT returned : %d\n", err);
+        return FM_JNI_FAILURE;
+    }
+
+    ALOGD("->android_hardware_fmradio_FmReceiverJNI_startRTNative is SUCCESS\n");
+    return FM_JNI_SUCCESS;
+}
+
+static jint android_hardware_fmradio_FmReceiverJNI_stopRTNative
+    (JNIEnv * env, jobject thiz, jint fd )
+{
+    ALOGE("->android_hardware_fmradio_FmReceiverJNI_stopRTNative\n");
+    int err;
+    struct v4l2_control control;
+    control.id = V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_RT;
+
+    err = ioctl(fd, VIDIOC_S_CTRL , &control);
+    if(err < 0){
+            return FM_JNI_FAILURE;
+    }
+    ALOGE("->android_hardware_fmradio_FmReceiverJNI_stopRTNative is SUCCESS\n");
+    return FM_JNI_SUCCESS;
+}
+
+static jint android_hardware_fmradio_FmReceiverJNI_startPSNative
+    (JNIEnv * env, jobject thiz, jint fd, jstring buff, jint count )
+{
+    ALOGD("->android_hardware_fmradio_FmReceiverJNI_startPSNative\n");
+
+    struct v4l2_ext_control ext_ctl;
+    struct v4l2_ext_controls v4l2_ctls;
+    int l;
+    int err = 0;
+    jboolean isCopy = false;
+    char *ps_copy = NULL;
+    const char *ps_string = NULL;
+
+    ps_string = env->GetStringUTFChars(buff, &isCopy);
+    if (ps_string != NULL) {
+        l = strlen(ps_string);
+        if ((l > 0) && ((l + 1) == PS_LEN)) {
+             ps_copy = (char *)malloc(sizeof(char) * PS_LEN);
+             if (ps_copy != NULL) {
+                 memset(ps_copy, '\0', PS_LEN);
+                 memcpy(ps_copy, ps_string, (PS_LEN - 1));
+             } else {
+                 env->ReleaseStringUTFChars(buff, ps_string);
+                 return FM_JNI_FAILURE;
+             }
+        } else {
+             env->ReleaseStringUTFChars(buff, ps_string);
+             return FM_JNI_FAILURE;
+        }
+    } else {
+        return FM_JNI_FAILURE;
+    }
+
+    env->ReleaseStringUTFChars(buff, ps_string);
+
+    ext_ctl.id     = V4L2_CID_RDS_TX_PS_NAME;
+    ext_ctl.string = ps_copy;
+    ext_ctl.size   = PS_LEN;
+
+    /* form the ctrls data struct */
+    v4l2_ctls.ctrl_class = V4L2_CTRL_CLASS_FM_TX,
+    v4l2_ctls.count      = 1,
+    v4l2_ctls.controls   = &ext_ctl;
+
+    err = ioctl(fd, VIDIOC_S_EXT_CTRLS, &v4l2_ctls);
+    if (err < 0) {
+        ALOGE("VIDIOC_S_EXT_CTRLS for Start PS returned : %d\n", err);
+        free(ps_copy);
+        return FM_JNI_FAILURE;
+    }
+
+    ALOGD("->android_hardware_fmradio_FmReceiverJNI_startPSNative is SUCCESS\n");
+    free(ps_copy);
+
+    return FM_JNI_SUCCESS;
+}
+
+static jint android_hardware_fmradio_FmReceiverJNI_stopPSNative
+    (JNIEnv * env, jobject thiz, jint fd)
+{
+    ALOGE("->android_hardware_fmradio_FmReceiverJNI_stopPSNative\n");
+    struct v4l2_control control;
+    control.id = V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_PS_NAME;
+
+    int err;
+    err = ioctl(fd, VIDIOC_S_CTRL , &control);
+    if(err < 0){
+            return FM_JNI_FAILURE;
+    }
+    ALOGE("->android_hardware_fmradio_FmReceiverJNI_stopPSNative is SUCCESS\n");
+    return FM_JNI_SUCCESS;
+}
+
+static jint android_hardware_fmradio_FmReceiverJNI_configureSpurTable
+    (JNIEnv * env, jobject thiz, jint fd)
+{
+    ALOGD("->android_hardware_fmradio_FmReceiverJNI_configureSpurTable\n");
+    int retval = 0;
+    struct v4l2_control control;
+
+    control.id = V4L2_CID_PRIVATE_UPDATE_SPUR_TABLE;
+    retval = ioctl(fd, VIDIOC_S_CTRL, &control);
+    if (retval < 0) {
+            ALOGE("configureSpurTable: Failed to Write the SPUR Table\n");
+            return FM_JNI_FAILURE;
+    } else
+            ALOGD("configureSpurTable: SPUR Table Configuration successful\n");
+
+    return FM_JNI_SUCCESS;
+}
+
+static jint android_hardware_fmradio_FmReceiverJNI_setPSRepeatCountNative
+    (JNIEnv * env, jobject thiz, jint fd, jint repCount)
+{
+    ALOGE("->android_hardware_fmradio_FmReceiverJNI_setPSRepeatCountNative\n");
+
+    struct v4l2_control control;
+
+    control.id = V4L2_CID_PRIVATE_TAVARUA_TX_SETPSREPEATCOUNT;
+    control.value = repCount & MASK_TXREPCOUNT;
+
+    int err;
+    err = ioctl(fd, VIDIOC_S_CTRL,&control );
+    if(err < 0){
+            return FM_JNI_FAILURE;
+    }
+
+    ALOGE("->android_hardware_fmradio_FmReceiverJNI_setPSRepeatCountNative is SUCCESS\n");
+    return FM_JNI_SUCCESS;
+}
+
+static jint android_hardware_fmradio_FmReceiverJNI_setTxPowerLevelNative
+    (JNIEnv * env, jobject thiz, jint fd, jint powLevel)
+{
+    ALOGE("->android_hardware_fmradio_FmReceiverJNI_setTxPowerLevelNative\n");
+
+    struct v4l2_control control;
+
+    control.id = V4L2_CID_TUNE_POWER_LEVEL;
+    control.value = powLevel;
+
+    int err;
+    err = ioctl(fd, VIDIOC_S_CTRL,&control );
+    if(err < 0){
+            return FM_JNI_FAILURE;
+    }
+
+    ALOGE("->android_hardware_fmradio_FmReceiverJNI_setTxPowerLevelNative is SUCCESS\n");
+    return FM_JNI_SUCCESS;
+}
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gMethods[] = {
+        /* name, signature, funcPtr */
+        { "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",
+            (void*)android_hardware_fmradio_FmReceiverJNI_setFreqNative},
+        { "getControlNative", "(II)I",
+            (void*)android_hardware_fmradio_FmReceiverJNI_getControlNative},
+        { "setControlNative", "(III)I",
+            (void*)android_hardware_fmradio_FmReceiverJNI_setControlNative},
+        { "startSearchNative", "(II)I",
+            (void*)android_hardware_fmradio_FmReceiverJNI_startSearchNative},
+        { "cancelSearchNative", "(I)I",
+            (void*)android_hardware_fmradio_FmReceiverJNI_cancelSearchNative},
+        { "getRSSINative", "(I)I",
+            (void*)android_hardware_fmradio_FmReceiverJNI_getRSSINative},
+        { "setBandNative", "(III)I",
+            (void*)android_hardware_fmradio_FmReceiverJNI_setBandNative},
+        { "getLowerBandNative", "(I)I",
+            (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",
+            (void*)android_hardware_fmradio_FmReceiverJNI_getRawRdsNative},
+       { "setNotchFilterNative", "(IIZ)I",
+            (void*)android_hardware_fmradio_FmReceiverJNI_setNotchFilterNative},
+        { "startRTNative", "(ILjava/lang/String;I)I",
+            (void*)android_hardware_fmradio_FmReceiverJNI_startRTNative},
+        { "stopRTNative", "(I)I",
+            (void*)android_hardware_fmradio_FmReceiverJNI_stopRTNative},
+        { "startPSNative", "(ILjava/lang/String;I)I",
+            (void*)android_hardware_fmradio_FmReceiverJNI_startPSNative},
+        { "stopPSNative", "(I)I",
+            (void*)android_hardware_fmradio_FmReceiverJNI_stopPSNative},
+        { "setPTYNative", "(II)I",
+            (void*)android_hardware_fmradio_FmReceiverJNI_setPTYNative},
+        { "setPINative", "(II)I",
+            (void*)android_hardware_fmradio_FmReceiverJNI_setPINative},
+        { "setPSRepeatCountNative", "(II)I",
+            (void*)android_hardware_fmradio_FmReceiverJNI_setPSRepeatCountNative},
+        { "setTxPowerLevelNative", "(II)I",
+            (void*)android_hardware_fmradio_FmReceiverJNI_setTxPowerLevelNative},
+       { "setAnalogModeNative", "(Z)I",
+            (void*)android_hardware_fmradio_FmReceiverJNI_setAnalogModeNative},
+        { "SetCalibrationNative", "(I)I",
+            (void*)android_hardware_fmradio_FmReceiverJNI_SetCalibrationNative},
+        { "configureSpurTable", "(I)I",
+            (void*)android_hardware_fmradio_FmReceiverJNI_configureSpurTable},
+
+};
+
+int register_android_hardware_fm_fmradio(JNIEnv* env)
+{
+        return jniRegisterNativeMethods(env, "qcom/fmradio/FmReceiverJNI", gMethods, NELEM(gMethods));
+}
+
+jint JNI_OnLoad(JavaVM *jvm, void *reserved)
+{
+  JNIEnv *e;
+  int status;
+   ALOGE("FM : loading QCOMM FM-JNI\n");
+  
+   if(jvm->GetEnv((void **)&e, JNI_VERSION_1_6)) {
+       ALOGE("JNI version mismatch error");
+      return JNI_ERR;
+   }
+
+   if ((status = register_android_hardware_fm_fmradio(e)) < 0) {
+       ALOGE("jni adapter service registration failure, status: %d", status);
+      return JNI_ERR;
+   }
+   return JNI_VERSION_1_6;
+}
diff --git a/qcom/fmradio/FmConfig.java b/qcom/fmradio/FmConfig.java
new file mode 100644
index 0000000..3044cc2
--- /dev/null
+++ b/qcom/fmradio/FmConfig.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2009-2011, 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 android.util.Log;
+import android.os.SystemProperties;
+
+
+/**
+ *
+ * Class to be used when changing radio settings
+ * @hide
+ */
+public class FmConfig {
+
+    /* V4l2 Controls */
+     private static final int V4L2_CID_PRIVATE_BASE                   = 0x8000000;
+     private static final int V4L2_CID_PRIVATE_TAVARUA_REGION         = V4L2_CID_PRIVATE_BASE + 7;
+     private static final int V4L2_CID_PRIVATE_TAVARUA_EMPHASIS       = V4L2_CID_PRIVATE_BASE + 12;
+     private static final int V4L2_CID_PRIVATE_TAVARUA_RDS_STD        = V4L2_CID_PRIVATE_BASE + 13;
+     private static final int V4L2_CID_PRIVATE_TAVARUA_SPACING        = V4L2_CID_PRIVATE_BASE + 14;
+     private static final int V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM = V4L2_CID_PRIVATE_BASE + 0x2B;
+
+     private static final String TAG = "FmConfig";
+
+
+
+    private int mRadioBand;
+    /**
+     * FM pre-emphasis/de-emphasis
+     *
+     * Possible Values:
+     *
+     * FmTransceiver.FM_DE_EMP75,
+     * FmTransceiver.FM_DE_EMP50
+     */
+    private int mEmphasis;
+    /**
+     * Channel spacing
+     *
+     * Possible Values:
+     *
+     * FmTransceiver.FM_CHSPACE_200_KHZ,
+     * FmTransceiver.FM_CHSPACE_100_KHZ,
+     * FmTransceiver.FM_CHSPACE_50_KHZ
+     */
+    private int mChSpacing;
+    /**
+     * RDS standard type
+     *
+     * Possible Values:
+     *
+     * FmTransceiver.FM_RDS_STD_RBDS,
+     * FmTransceiver.FM_RDS_STD_RDS,
+     * FmTransceiver.FM_RDS_STD_NONE
+     */
+    private int mRdsStd;
+
+    /**
+     * FM Frequency Band Lower Limit in KHz
+     */
+    private int mBandLowerLimit;
+    /**
+     * FM Frequency Band Upper Limit in KHz
+     */
+    private int mBandUpperLimit;
+
+    public int getRadioBand(){
+        return mRadioBand;
+    }
+
+    public void setRadioBand (int band){
+        mRadioBand = band;
+    }
+
+    public int getEmphasis(){
+        return mEmphasis;
+    }
+
+    public void setEmphasis (int emp){
+        mEmphasis = emp;
+    }
+
+    public int getChSpacing (){
+        return mChSpacing;
+    }
+
+    public void setChSpacing(int spacing) {
+        mChSpacing = spacing;
+    }
+
+    public int getRdsStd () {
+        return mRdsStd;
+    }
+
+    public void setRdsStd (int rdsStandard) {
+        mRdsStd = rdsStandard;
+    }
+
+    public int getLowerLimit(){
+        return mBandLowerLimit;
+    }
+
+    public void setLowerLimit(int lowLimit){
+        mBandLowerLimit = lowLimit;
+    }
+
+    public int getUpperLimit(){
+        return mBandUpperLimit;
+    }
+
+    public void setUpperLimit(int upLimit){
+        mBandUpperLimit = upLimit;
+    }
+
+    /*
+     * fmConfigure()
+     * This method call v4l2 private controls to set regional settings for the
+     * FM core
+     */
+    protected static boolean fmConfigure (final int fd, final FmConfig configSettings) {
+
+        int re;
+
+        Log.v (TAG, "In fmConfigure");
+	re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_EMPHASIS, configSettings.getEmphasis());
+        re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_RDS_STD, configSettings.getRdsStd() );
+        re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SPACING, configSettings.getChSpacing() );
+
+        boolean fmSrchAlg = SystemProperties.getBoolean("persist.fm.new.srch.algorithm",false);
+        if (fmSrchAlg) {
+          Log.v (TAG, "fmConfigure() : FM Srch Alg : NEW ");
+          re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM, 1);
+        }
+        else {
+          Log.v (TAG, "fmConfigure() : FM Srch Alg : OLD ");
+          re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM, 0);
+        }
+        if (re < 0)
+          return false;
+
+        re = FmReceiverJNI.setBandNative (fd, configSettings.getLowerLimit(), configSettings.getUpperLimit());
+        if (re < 0)
+          return false;
+
+        re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_REGION, configSettings.mRadioBand);
+        /* setControlNative for V4L2_CID_PRIVATE_TAVARUA_REGION triggers the config change*/
+        if (re < 0)
+          return false;
+
+        return true;
+    }
+
+}
diff --git a/qcom/fmradio/FmReceiver.java b/qcom/fmradio/FmReceiver.java
new file mode 100644
index 0000000..969656b
--- /dev/null
+++ b/qcom/fmradio/FmReceiver.java
@@ -0,0 +1,2342 @@
+/*
+ * Copyright (c) 2009,2012, 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 android.util.Log;
+
+/**
+ * This class contains all interfaces and types needed to
+ * Control the FM receiver.
+ *    @hide
+ */
+public class FmReceiver extends FmTransceiver
+{
+
+   public static int mSearchState = 0;
+
+   static final int STD_BUF_SIZE = 256;
+   static final int GRP_3A = 64;
+   private static final String TAG = "FMRadio";
+
+   /**
+   * Search (seek/scan/searchlist) by decrementing the frequency
+   *
+   * @see #FM_RX_SEARCHDIR_UP
+   * @see #searchStations(int, int, int)
+   * @see #searchStations(int, int, int, int, int)
+   * @see #searchStationList
+   */
+   public static final int FM_RX_SEARCHDIR_DOWN=0;
+   /**
+   * Search (seek/scan/searchlist) by inrementing the frequency
+   *
+   * @see #FM_RX_SEARCHDIR_DOWN
+   * @see #searchStations(int, int, int)
+   * @see #searchStations(int, int, int, int, int)
+   * @see #searchStationList
+   */
+   public static final int FM_RX_SEARCHDIR_UP=1;
+
+   /**
+   * Scan dwell (Preview) duration = 0 seconds
+   *
+   * @see #searchStations(int, int, int)
+   * @see #searchStations(int, int, int, int, int)
+   */
+   public static final int FM_RX_DWELL_PERIOD_0S=0;
+  /**
+   * Scan dwell (Preview) duration = 1 second
+   *
+   * @see #searchStations(int, int, int)
+   * @see #searchStations(int, int, int, int, int)
+   */
+   public static final int FM_RX_DWELL_PERIOD_1S=1;
+   /**
+   * Scan dwell (Preview) duration = 2 seconds
+   *
+   * @see #searchStations(int, int, int)
+   * @see #searchStations(int, int, int, int, int)
+   */
+   public static final int FM_RX_DWELL_PERIOD_2S=2;
+   /**
+   * Scan dwell (Preview) duration = 3 seconds
+   *
+   * @see #searchStations(int, int, int)
+   * @see #searchStations(int, int, int, int, int)
+   */
+   public static final int FM_RX_DWELL_PERIOD_3S=3;
+   /**
+   * Scan dwell (Preview) duration = 4 seconds
+   *
+   * @see #searchStations(int, int, int)
+   * @see #searchStations(int, int, int, int, int)
+   */
+   public static final int FM_RX_DWELL_PERIOD_4S=4;
+   /**
+    * Scan dwell (Preview) duration = 5 seconds
+    *
+    * @see #searchStations(int, int, int)
+    * @see #searchStations(int, int, int, int, int)
+    */
+   public static final int FM_RX_DWELL_PERIOD_5S=5;
+   /**
+    * Scan dwell (Preview) duration = 6 seconds
+    *
+    * @see #searchStations(int, int, int)
+    * @see #searchStations(int, int, int, int, int)
+    */
+   public static final int FM_RX_DWELL_PERIOD_6S=6;
+   /**
+    * Scan dwell (Preview) duration = 7 second
+    *
+    * @see #searchStations(int, int, int)
+    * @see #searchStations(int, int, int, int, int)
+    */
+   public static final int FM_RX_DWELL_PERIOD_7S=7;
+
+
+   /**
+   * Basic Seek Mode Option
+   *
+   * @see #searchStations(int, int, int)
+   */
+   public static final int FM_RX_SRCH_MODE_SEEK        =0;
+   /**
+   * Basic Scan Mode Option
+   *
+   * @see #searchStations(int, int, int)
+   */
+   public static final int FM_RX_SRCH_MODE_SCAN        =1;
+
+   /**
+   * Search list mode Options to search for Strong stations
+   *
+   * @see #searchStationList
+   */
+   public static final int FM_RX_SRCHLIST_MODE_STRONG  =2;
+   /**
+   * Search list mode Options to search for Weak stations
+   *
+   * @see #searchStationList
+   */
+   public static final int FM_RX_SRCHLIST_MODE_WEAK    =3;
+
+   /**
+   * Seek by Program Type
+   *
+   * @see #searchStations(int, int, int, int, int)
+   */
+   public static final int FM_RX_SRCHRDS_MODE_SEEK_PTY =4;
+   /**
+   * Scan by Program Type
+   *
+   * @see #searchStations(int, int, int, int, int)
+   */
+   public static final int FM_RX_SRCHRDS_MODE_SCAN_PTY =5;
+   /**
+   * Seek by Program identification
+   *
+   * @see #searchStations(int, int, int, int, int)
+   */
+   public static final int FM_RX_SRCHRDS_MODE_SEEK_PI  =6;
+   /**
+   * Seek Alternate Frequency for the same station
+   *
+   * @see #searchStations(int, int, int, int, int)
+   */
+   public static final int FM_RX_SRCHRDS_MODE_SEEK_AF  =7;
+   /**
+   * Search list mode Options to search for Strongest stations
+   *
+   * @see #searchStations(int, int, int, int, int)
+   */
+   public static final int FM_RX_SRCHLIST_MODE_STRONGEST  =8;
+   /**
+   * Search list mode Options to search for Weakest stations
+   *
+   * @see #searchStations(int, int, int, int, int)
+   */
+   public static final int FM_RX_SRCHLIST_MODE_WEAKEST  =9;
+
+   /**
+   * Maximum number of stations the SearchStationList can
+   * support
+   *
+   * @see #searchStationList
+   */
+   public static final int FM_RX_SRCHLIST_MAX_STATIONS =12;
+
+   /**
+    *  Argument option for setMuteMode to unmute FM
+    *
+    *  @see #setMuteMode
+    */
+   public static final int FM_RX_UNMUTE     =0;
+   /**
+    *  Argument option for setMuteMode to Mute FM
+    *
+    *  @see #setMuteMode
+    */
+   public static final int FM_RX_MUTE       =1;
+
+   /**
+    *  Argument option for setStereoMode to set FM to Stereo
+    *  Mode.
+    *
+    *  @see #setStereoMode
+    */
+   public static final int FM_RX_AUDIO_MODE_STEREO    =0;
+   /**
+    *  Argument option for setStereoMode to set FM to "Force
+    *  Mono" Mode.
+    *
+    *  @see #setStereoMode
+    */
+   public static final int FM_RX_AUDIO_MODE_MONO      =1;
+
+   /**
+    *  Signal Strength
+    *
+    *  @see #setSignalThreshold
+    *  @see #getSignalThreshold
+    */
+   public static final int FM_RX_SIGNAL_STRENGTH_VERY_WEAK  =0;
+   public static final int FM_RX_SIGNAL_STRENGTH_WEAK       =1;
+   public static final int FM_RX_SIGNAL_STRENGTH_STRONG     =2;
+   public static final int FM_RX_SIGNAL_STRENGTH_VERY_STRONG=3;
+
+   /**
+    * Power settings
+    *
+    * @see #setPowerMode
+    * @see #getPowerMode
+    */
+   public static final int FM_RX_NORMAL_POWER_MODE   =0;
+   public static final int FM_RX_LOW_POWER_MODE      =1;
+
+
+
+   /**
+    * RDS Processing Options
+    *
+    * @see #registerRdsGroupProcessing
+    * @see #getPSInfo
+    * @see #getRTInfo
+    * @see #getAFInfo
+    */
+   public static final int FM_RX_RDS_GRP_RT_EBL         =1;
+   public static final int FM_RX_RDS_GRP_PS_EBL         =2;
+   public static final int FM_RX_RDS_GRP_AF_EBL         =4;
+   public static final int FM_RX_RDS_GRP_PS_SIMPLE_EBL  =16;
+
+
+   private static final int V4L2_CID_PRIVATE_BASE = 0x8000000;
+   private static final int V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH = V4L2_CID_PRIVATE_BASE + 8;
+
+
+   private static final int TAVARUA_BUF_SRCH_LIST=0;
+   private static final int TAVARUA_BUF_EVENTS=1;
+   private static final int TAVARUA_BUF_RT_RDS=2;
+   private static final int TAVARUA_BUF_PS_RDS=3;
+   private static final int TAVARUA_BUF_RAW_RDS=4;
+   private static final int TAVARUA_BUF_AF_LIST=5;
+   private static final int TAVARUA_BUF_MAX=6;
+
+   private FmRxEvCallbacksAdaptor mCallback;
+  /**
+    *  Internal Constants for Signal thresholds
+    *
+    *  @see #setSignalThreshold
+    *  @see #getSignalThreshold
+    */
+   private static final int FM_RX_RSSI_LEVEL_VERY_WEAK   = -105;
+   private static final int FM_RX_RSSI_LEVEL_WEAK        = -100;
+   private static final int FM_RX_RSSI_LEVEL_STRONG      = -96;
+   private static final int FM_RX_RSSI_LEVEL_VERY_STRONG = -90;
+
+   /**
+     * BUF_TYPE
+     */
+   private static final int BUF_ERT = 12;
+   private static final int BUF_RTPLUS = 11;
+
+   private static final int LEN_IND = 0;
+   private static final int RT_OR_ERT_IND = 1;
+   private static final int ENCODE_TYPE_IND = 1;
+   private static final int ERT_DIR_IND = 2;
+   /**
+    * Constructor for the receiver Object
+    */
+   public FmReceiver(){
+      mControl = new FmRxControls();
+      mRdsData = new FmRxRdsData (sFd);
+      mRxEvents = new FmRxEventListner();
+   }
+
+   /**
+   *    Constructor for the receiver Object that takes path to
+   *    radio and event callbacks.
+   *    <p>
+   *    @param devicePath FM Device path String.
+   *    @param callback the callbacks to handle the events
+   *                               events from the FM receiver.
+   *
+   */
+   public FmReceiver(String devicePath,
+                     FmRxEvCallbacksAdaptor callback) throws InstantiationException {
+      mControl = new FmRxControls();
+      mRxEvents = new FmRxEventListner();
+
+      //registerClient(callback);
+      mCallback = callback;
+   }
+
+
+   /*==============================================================
+   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;
+   }
+
+   /*==============================================================
+   FUNCTION:  enable
+   ==============================================================*/
+   /**
+   *    Enables the FM device in Receiver Mode.
+   *    <p>
+   *    This is a synchronous method used to initialize the FM
+   *    receiver. If already initialized this function will
+   *    intialize the receiver with default settings. Only after
+   *    successfully calling this function can many of the FM device
+   *    interfaces be used.
+   *    <p>
+   *    When enabling the receiver, the client must also provide
+   *    the regional settings in which the receiver will operate.
+   *    These settings (included in argument configSettings) are
+   *    typically used for setting up the FM receiver for operating
+   *    in a particular geographical region. These settings can be
+   *    changed after the FM driver is enabled through the use of
+   *    the function {@link #configure}.
+   *    <p>
+   *    This command can only be issued by the owner of an FM
+   *    receiver.  To issue this command, the client must first
+   *    successfully call {@link #acquire}.
+   *    <p>
+   *    @param configSettings  the settings to be applied when
+   *                             turning on the radio
+   *    @return true if Initialization succeeded, false if
+   *            Initialization failed.
+   *    <p>
+   *    @see #enable
+   *    @see #registerClient
+   *    @see #disable
+   *
+   */
+   public boolean enable (FmConfig configSettings){
+      boolean status = false;
+      /*
+       * Check for FM State.
+       * If FMRx already on, then return.
+      */
+      int state = getFMState();
+      if (state == FMState_Rx_Turned_On || state == FMState_Srch_InProg) {
+         Log.d(TAG, "enable: FM already turned On and running");
+         return status;
+      }
+      else if (state == subPwrLevel_FMTurning_Off) {
+         Log.v(TAG, "FM is in the process of turning off.Pls wait for sometime.");
+         return status;
+      }
+      else if (state == subPwrLevel_FMRx_Starting) {
+         Log.v(TAG, "FM is in the process of turning On.Pls wait for sometime.");
+         return status;
+      }
+
+      setFMPowerState(subPwrLevel_FMRx_Starting);
+      Log.v(TAG, "enable: CURRENT-STATE : FMOff ---> NEW-STATE : FMRxStarting");
+      status = super.enable(configSettings, FmTransceiver.FM_RX);
+
+      if( status == true ) {
+         /* Do Receiver Specific Enable Stuff here.*/
+         status = registerClient(mCallback);
+         mRdsData = new FmRxRdsData(sFd);
+      }
+      else {
+         status = false;
+         Log.e(TAG, "enable: Error while turning FM On");
+         Log.e(TAG, "enable: CURRENT-STATE : FMRxStarting ---> NEW-STATE : FMOff");
+         setFMPowerState(FMState_Turned_Off);
+      }
+      return status;
+   }
+
+   /*==============================================================
+   FUNCTION:  reset
+   ==============================================================*/
+   /**
+   *    Reset the FM Device.
+   *    <p>
+   *    This is a synchronous command used to reset the state of FM
+   *    device in case of unrecoverable error. This function is
+   *    expected to be used when the client receives unexpected
+   *    notification of radio disabled. Once called, most
+   *    functionality offered by the FM device will be disabled
+   *    until the client re-enables the device again via
+   *    {@link #enable}.
+   *    <p>
+   *    @return true if reset succeeded, false if reset failed.
+   *    @see #enable
+   *    @see #disable
+   *    @see #registerClient
+   */
+   public boolean reset(){
+      boolean status = false;
+      int state = getFMState();
+
+      if(state == FMState_Turned_Off) {
+         Log.d(TAG, "FM already turned Off.");
+         return false;
+      }
+
+      setFMPowerState(FMState_Turned_Off);
+      Log.v(TAG, "reset: NEW-STATE : FMState_Turned_Off");
+
+      status = unregisterClient();
+
+      release("/dev/radio0");
+
+      return status;
+   }
+
+   /*==============================================================
+   FUNCTION:  disable
+   ==============================================================*/
+   /**
+   *    Disables the FM Device.
+   *    <p>
+   *    This is a synchronous command used to disable the FM
+   *    device. This function is expected to be used when the
+   *    client no longer requires use of the FM device. Once
+   *    called, most functionality offered by the FM device will be
+   *    disabled until the client re-enables the device again via
+   *    {@link #enable}.
+   *    <p>
+   *    @return true if disabling succeeded, false if disabling
+   *            failed.
+   *    @see #enable
+   *    @see #registerClient
+   */
+   public boolean disable(){
+      boolean status = false;
+      /*
+       * Check for FM State. If search is in progress, then cancel the search prior
+       * to disabling FM.
+      */
+      int state = getFMState();
+      switch(state) {
+      case FMState_Turned_Off:
+         Log.d(TAG, "FM already tuned Off.");
+         return false;
+      case FMState_Srch_InProg:
+         Log.v(TAG, "disable: Cancelling the on going search operation prior to disabling FM");
+         setSearchState(subSrchLevel_SrchAbort);
+         cancelSearch();
+         Log.v(TAG, "disable: Wait for the state to change from : Search ---> FMRxOn");
+         try {
+            /*
+             *    The delay of 50ms here is very important.
+             *    This delay is useful for the cleanup purpose
+             *    when HS is abruptly plugged out when search
+             *    is in progress.
+            */
+            Thread.sleep(50);
+         } catch (InterruptedException e) {
+            e.printStackTrace();
+         }
+         break;
+      case subPwrLevel_FMRx_Starting:
+      /*
+       * If, FM is in the process of turning On, then wait for
+       * the turn on operation to complete before turning off.
+      */
+         Log.d(TAG, "disable: FM not yet turned On...");
+         try {
+            Thread.sleep(100);
+         } catch (InterruptedException e) {
+            e.printStackTrace();
+         }
+         /* Check for the state of FM device */
+         state = getFMState();
+         if(state == subPwrLevel_FMRx_Starting) {
+            Log.e(TAG, "disable: FM in bad state");
+            return status;
+         }
+         break;
+      case subPwrLevel_FMTurning_Off:
+      /*
+       * If, FM is in the process of turning Off, then wait for
+       * the turn off operation to complete.
+      */
+         Log.v(TAG, "disable: FM is getting turned Off.");
+            return status;
+      }
+
+      setFMPowerState(subPwrLevel_FMTurning_Off);
+      Log.v(TAG, "disable: CURRENT-STATE : FMRxOn ---> NEW-STATE : FMTurningOff");
+      super.disable();
+
+      return true;
+   }
+
+   /*==============================================================
+   FUNCTION:  getSearchState
+   ==============================================================*/
+   /**
+   *    Gets the current state of the search operation.
+   *    <p>
+   *    This function is expected to be used when searchStations()
+   *    function wants to know whether any seek/scan/auto-select
+   *    operation is already in-progress.
+   *    If a seek command is issued when one is already in-progress,
+   *    we cancel the on-going seek command and start a new search
+   *    operation.
+   *    <p>
+   *    @return current state of FM Search operation:
+   *                SRCH_COMPLETE
+   *                SRCH_INPROGRESS
+   *                SRCH_ABORTED
+   */
+   static int getSearchState()
+   {
+      return mSearchState;
+   }
+
+   /*==============================================================
+   FUNCTION:  setSearchState
+   ==============================================================*/
+   /**
+   *    Sets the current state of the search operation.
+   *    <p>
+   *    This function is used to set the current state of the
+   *    search operation. If a seek command is issued when one
+   *    is already in-progress, we cancel the on-going seek command,
+   *    set the state of search operation to SRCH_ABORTED
+   *    and start a new search.
+   *    <p>
+   *    @return none
+   */
+   static void setSearchState(int state)
+   {
+      mSearchState = state;
+      switch(mSearchState) {
+         case subSrchLevel_SeekInPrg:
+         case subSrchLevel_ScanInProg:
+         case subSrchLevel_SrchListInProg:
+            setFMPowerState(FMState_Srch_InProg);
+            break;
+         case subSrchLevel_SrchComplete:
+            /* Update the state of the FM device */
+            setFMPowerState(FMState_Rx_Turned_On);
+            break;
+      }
+   }
+
+   /*==============================================================
+   FUNCTION:  searchStations
+   ==============================================================*/
+   /**
+   *   Initiates basic seek and scan operations.
+   *    <p>
+   *    This command is used to invoke a basic seek/scan of the FM
+   *    radio band.
+   *    <p>
+   *    <ul>
+   *    This API is used to:
+   *    <li> Invoke basic seek operations ({@link
+   *    #FM_RX_SRCH_MODE_SEEK})
+   *    <li> Invoke basic scan operations ({@link
+   *    #FM_RX_SRCH_MODE_SCAN})
+   *    </ul>
+   *    <p>
+   *    The most basic operation performed by this function
+   *    is a {@link #FM_RX_SRCH_MODE_SEEK} command. The seek
+   *    process is handled incrementing or decrementing the
+   *    frequency in pre-defined channel steps (defined by the
+   *    channel spacing) and measuring the resulting signal level.
+   *    Once a station is successfully tuned and found to meet or
+   *    exceed this signal level, the seek operation will be
+   *    completed and a FmRxEvSearchComplete event will be returned
+   *    to the client. If no stations are found to match the search
+   *    criteria, the frequency will be returned to the originally
+   *    tuned station.
+   *    <p>
+   *    Since seek always results in a frequency being tuned, each
+   *    seek operation will also return a single
+   *    FmRxEvRadioTuneStatus event to the client/application
+   *    layer.
+   *    <p>
+   *    Much like {@link #FM_RX_SRCH_MODE_SEEK}, a {@link
+   *    #FM_RX_SRCH_MODE_SCAN} command can be likened to many back
+   *    to back seeks with a dwell period after each successful
+   *    seek. Once issued, a scan will either increment or
+   *    decrement frequencies by the defined channel spacing until
+   *    a station is found to meet or exceed the set search
+   *    threshold. Once this station is found, and is successfully
+   *    tuned, an FmRxEvRadioTuneStatus event will be returned to
+   *    the client and the station will remain tuned for the
+   *    specific period of time indicated by argument dwellPeriod.
+   *    After that time expires, an FmRxEvSearchInProgress event
+   *    will be sent to the client and a new search will begin for
+   *    the next station that meets the search threshold. After
+   *    scanning the entire band, or after a cancel search has been
+   *    initiated by the client, an FmRxEvRadioTuneStatus event
+   *    will be sent to the client. Similar to a seek command, each
+   *    scan will result in at least one station being tuned, even
+   *    if this is the starting frequency.
+   *    <p>
+   *    Each time the driver initiates a search (seek or scan) the client
+   *    will be notified via an FmRxEvSearchInProgress event.
+   *    Similarly, each time a search completes, the client will be notified via an
+   *    FmRxEvRadioTuneStatus event.
+   *    <p>
+   *    Once issuing a search command, several commands from the client
+   *    may be disallowed until the search is completed or cancelled.
+   *    <p>
+   *    The search can be canceled at any time by using API
+   *    cancelSearch (). Once cancelled, each search will tune to the
+   *    last tuned station and generate both FmRxEvSearchComplete and
+   *    FmRxEvRadioTuneStatus events.
+   *    Valid Values for argument 'mode':
+   *    <ul>
+   *    <li>{@link #FM_RX_SRCH_MODE_SEEK}
+   *    <li>{@link #FM_RX_SRCH_MODE_SCAN}
+   *    </ul>
+   *    <p>
+   *    Valid Values for argument 'dwellPeriod' :
+   *    <ul>
+   *    <li>{@link #FM_RX_DWELL_PERIOD_1S}
+   *    <li>{@link #FM_RX_DWELL_PERIOD_2S}
+   *    <li>{@link #FM_RX_DWELL_PERIOD_3S}
+   *    <li>{@link #FM_RX_DWELL_PERIOD_4S}
+   *    <li>{@link #FM_RX_DWELL_PERIOD_5S}
+   *    <li>{@link #FM_RX_DWELL_PERIOD_6S}
+   *    <li>{@link #FM_RX_DWELL_PERIOD_7S}
+   *    </ul>
+   *    <p>
+   *    Valid Values for argument 'direction' :
+   *    <ul>
+   *    <li>{@link #FM_RX_SEARCHDIR_DOWN}
+   *    <li>{@link #FM_RX_SEARCHDIR_UP}
+   *    </ul>
+   *    <p>
+   *
+   *    <p>
+   *    @param mode the FM search mode.
+   *    @param dwellPeriod the FM scan dwell time. Used only when
+   *    mode={@link #FM_RX_SRCH_MODE_SCAN}
+   *    @param direction the Search Direction.
+   *   <p>
+   *    @return true if Search Initiate succeeded, false if
+   *            Search Initiate  failed.
+   *
+   *   @see #searchStations(int, int, int, int, int)
+   *   @see #searchStationList
+   */
+   public boolean searchStations (int mode,
+                                  int dwellPeriod,
+                                  int direction){
+
+      int state = getFMState();
+      boolean bStatus = true;
+      int re;
+
+      /* Check current state of FM device */
+      if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
+          Log.d(TAG, "searchStations: Device currently busy in executing another command.");
+          return false;
+      }
+
+      Log.d (TAG, "Basic search...");
+
+      /* Validate the arguments */
+      if ( (mode != FM_RX_SRCH_MODE_SEEK) &&
+           (mode != FM_RX_SRCH_MODE_SCAN))
+      {
+         Log.d (TAG, "Invalid search mode: " + mode );
+         bStatus = false;
+      }
+      if ( (dwellPeriod < FM_RX_DWELL_PERIOD_0S ) ||
+           (dwellPeriod > FM_RX_DWELL_PERIOD_7S))
+      {
+         Log.d (TAG, "Invalid dwelling time: " + dwellPeriod);
+         bStatus = false;
+      }
+      if ( (direction != FM_RX_SEARCHDIR_DOWN) &&
+           (direction != FM_RX_SEARCHDIR_UP))
+      {
+         Log.d (TAG, "Invalid search direction: " + direction);
+         bStatus = false;
+      }
+
+      if (bStatus)
+      {
+         Log.d (TAG, "searchStations: mode " + mode + "direction:  " + direction);
+
+         if (mode == FM_RX_SRCH_MODE_SEEK)
+             setSearchState(subSrchLevel_SeekInPrg);
+         else if (mode == FM_RX_SRCH_MODE_SCAN)
+             setSearchState(subSrchLevel_ScanInProg);
+         Log.v(TAG, "searchStations: CURRENT-STATE : FMRxOn ---> NEW-STATE : SearchInProg");
+
+         re = mControl.searchStations(sFd, mode, dwellPeriod, direction, 0, 0);
+         if (re != 0) {
+             Log.e(TAG, "search station failed");
+             if (getFMState() == FMState_Srch_InProg)
+                 setSearchState(subSrchLevel_SrchComplete);
+             return false;
+         }
+         state = getFMState();
+         if (state == FMState_Turned_Off) {
+             Log.d(TAG, "searchStations: CURRENT-STATE : FMState_Off (unexpected)");
+             return false;
+         }
+      }
+      return bStatus;
+   }
+
+   /*==============================================================
+   FUNCTION:  searchStations
+   ==============================================================*/
+   /**
+   *    Initiates RDS based seek and scan operations.
+   *
+   *    <p>
+   *    This command allows the client to issue seeks and scans similar
+   *    to commands found in basic searchStations(mode, scanTime,
+   *    direction). However, each command has an additional RDS/RBDS
+   *    component which must be satisfied before a station is
+   *    successfully tuned. Please see searchStations(mode,
+   *    scanTime, direction) for an understanding of how seeks and
+   *    scans work.
+   *
+   *    <p>
+   *    <ul>
+   *    This API is used to search stations using RDS:
+   *    <li> Invokes seek based on program type ({@link
+   *    #FM_RX_SRCHRDS_MODE_SEEK_PTY})
+   *    <li> Invokes scan based on program type with specified dwell period
+   *    ({@link #FM_RX_SRCHRDS_MODE_SCAN_PTY})
+   *    <li> Invokes seek based on program identification ({@link
+   *    #FM_RX_SRCHRDS_MODE_SEEK_PI})
+   *    <li> Invokes seek for alternate frequency ({@link
+   *    #FM_RX_SRCHRDS_MODE_SEEK_AF})
+   *    </ul>
+   *
+   *    <p>
+   *    Much like {@link #FM_RX_SRCH_MODE_SEEK} in searchStations,
+   *    {@link #FM_RX_SRCHRDS_MODE_SEEK_PTY} allows the client to
+   *    seek to stations which are broadcasting RDS/RBDS groups
+   *    with a particular Program Type that matches the supplied
+   *    Program Type (PTY). The behavior and events generated for a
+   *    {@link #FM_RX_SRCHRDS_MODE_SEEK_PTY} are very similar to
+   *    that of {@link #FM_RX_SRCH_MODE_SEEK}, however only
+   *    stations meeting the set search signal threshold and are
+   *    also broadcasting the specified RDS Program Type (PTY) will
+   *    be tuned. If no matching stations can be found, the
+   *    original station will be re-tuned.
+   *
+   *    <p>
+   *    Just as {@link #FM_RX_SRCHRDS_MODE_SEEK_PTY}'s
+   *    functionality matches {@link #FM_RX_SRCH_MODE_SEEK}, so
+   *    does {@link #FM_RX_SRCHRDS_MODE_SCAN_PTY} match {@link
+   *    #FM_RX_SRCH_MODE_SCAN}. The one of the differences between
+   *    the two is that only stations meeting the set search
+   *    threshold and are also broadcasting a RDS Program Type
+   *    (PTY) matching tucRdsSrchPty are found and tuned. If no
+   *    station is found to have the PTY as specified by argument
+   *    "pty", then the original station will be re-tuned.
+   *
+   *    <p> {@link #FM_RX_SRCHRDS_MODE_SEEK_PI} is used the same
+   *    way as {@link #FM_RX_SRCHRDS_MODE_SEEK_PTY}, but only
+   *    stations which meet the set search threshold and are also
+   *    broadcasting the Program Identification matching the
+   *    argument "pi" are tuned.
+   *
+   *    <p>
+   *    Lastly, {@link #FM_RX_SRCHRDS_MODE_SEEK_AF} functionality
+   *    differs slightly compared to the other commands in this
+   *    function. This command only seeks to stations which are
+   *    known ahead of time to be Alternative Frequencies for the
+   *    currently tune station. If no alternate frequencies are
+   *    known, or if the Alternative Frequencies have weaker signal
+   *    strength than the original frequency, the original
+   *    frequency will be re-tuned.
+   *
+   *    <p>
+   *    Each time the driver initiates an RDS-based search, the client will be
+   *    notified via a FmRxEvSearchInProgress event. Similarly, each
+   *    time an RDS-based search completes, the client will be notified via a
+   *    FmRxEvSearchComplete event.
+   *
+   *    <p>
+   *    Once issuing a search command, several commands from the client may be
+   *    disallowed until the search is completed or canceled.
+   *
+   *    <p>
+   *    The search can be canceled at any time by using API
+   *    cancelSearch (). Once canceled, each search will tune to the
+   *    last tuned station and generate both
+   *    FmRxEvSearchComplete and FmRxEvRadioTuneStatus events.
+   *
+   *    Valid Values for argument 'mode':
+   *    <ul>
+   *    <li>{@link #FM_RX_SRCHRDS_MODE_SEEK_PTY}
+   *    <li>{@link #FM_RX_SRCHRDS_MODE_SCAN_PTY}
+   *    <li>{@link #FM_RX_SRCHRDS_MODE_SEEK_PI}
+   *    <li>{@link #FM_RX_SRCHRDS_MODE_SEEK_AF}
+   *    </ul>
+   *    <p>
+   *    Valid Values for argument 'dwellPeriod' :
+   *    <ul>
+   *    <li>{@link #FM_RX_DWELL_PERIOD_1S}
+   *    <li>{@link #FM_RX_DWELL_PERIOD_2S}
+   *    <li>{@link #FM_RX_DWELL_PERIOD_3S}
+   *    <li>{@link #FM_RX_DWELL_PERIOD_4S}
+   *    <li>{@link #FM_RX_DWELL_PERIOD_5S}
+   *    <li>{@link #FM_RX_DWELL_PERIOD_6S}
+   *    <li>{@link #FM_RX_DWELL_PERIOD_7S}
+   *    </ul>
+   *    <p>
+   *    Valid Values for argument 'direction' :
+   *    <ul>
+   *    <li>{@link #FM_RX_SEARCHDIR_DOWN}
+   *    <li>{@link #FM_RX_SEARCHDIR_UP}
+   *    </ul>
+   *    <p>
+   *    @param mode the FM search mode.
+   *    @param dwellPeriod the FM scan dwell time. Used only when
+   *    mode={@link #FM_RX_SRCHRDS_MODE_SCAN_PTY}
+   *    @param direction the Search Direction.
+   *    @param pty the FM RDS search Program Type
+   *    @param pi the FM RDS search Program Identification Code
+   *    <p>
+   *    @return true if Search Initiate succeeded, false if
+   *            Search Initiate  failed.
+   *
+   *   @see #searchStations(int, int, int)
+   *   @see #searchStationList
+   */
+   public boolean searchStations (int mode,
+                                  int dwellPeriod,
+                                  int direction,
+                                  int pty,
+                                  int pi) {
+      boolean bStatus = true;
+      int state = getFMState();
+      int re;
+
+      /* Check current state of FM device */
+      if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
+          Log.d(TAG, "searchStations: Device currently busy in executing another command.");
+          return false;
+      }
+
+      Log.d (TAG, "RDS search...");
+
+      /* Validate the arguments */
+      if ( (mode != FM_RX_SRCHRDS_MODE_SEEK_PTY)
+           && (mode != FM_RX_SRCHRDS_MODE_SCAN_PTY)
+           && (mode != FM_RX_SRCHRDS_MODE_SEEK_PI)
+           && (mode != FM_RX_SRCHRDS_MODE_SEEK_AF)
+         )
+      {
+         Log.d (TAG, "Invalid search mode: " + mode );
+         bStatus = false;
+      }
+      if ( (dwellPeriod < FM_RX_DWELL_PERIOD_1S) ||
+           (dwellPeriod > FM_RX_DWELL_PERIOD_7S))
+      {
+         Log.d (TAG, "Invalid dwelling time: " + dwellPeriod);
+         bStatus = false;
+      }
+      if ( (direction != FM_RX_SEARCHDIR_DOWN) &&
+           (direction != FM_RX_SEARCHDIR_UP))
+      {
+         Log.d (TAG, "Invalid search direction: " + direction);
+         bStatus = false;
+      }
+
+      if (bStatus)
+      {
+         Log.d (TAG, "searchStations: mode " + mode);
+         Log.d (TAG, "searchStations: dwellPeriod " + dwellPeriod);
+         Log.d (TAG, "searchStations: direction " + direction);
+         Log.d (TAG, "searchStations: pty " + pty);
+         Log.d (TAG, "searchStations: pi " + pi);
+         setSearchState(subSrchLevel_ScanInProg);
+         re = mControl.searchStations(sFd, mode, dwellPeriod, direction, pty, pi);
+         if (re != 0) {
+             Log.e(TAG, "scan station failed");
+             if (getFMState() == FMState_Srch_InProg)
+                 setSearchState(subSrchLevel_SrchComplete);
+             bStatus = false;
+         }
+      }
+      return bStatus;
+   }
+
+   /*==============================================================
+   FUNCTION:  searchStationList
+   ==============================================================*/
+   /** Initiates station list search operations.
+   *    <p> This method will initate a search that will generate
+   *    frequency lists based on strong and weak stations found in
+   *    the FM band.
+   *    <p>
+   *    <ul>
+   *    This API is used to generate station lists which consist of:
+   *    <li>strong stations (FM_RX_SRCHLIST_MODE_STRONG,FM_RX_SRCHLIST_MODE_STRONGEST)
+   *    <li>weak stations   (FM_RX_SRCHLIST_MODE_WEAK, FM_RX_SRCHLIST_MODE_WEAKEST)
+   *    </ul>
+   *    <p>
+   *    The range of frequencies scanned depends on the currently set band.
+   *    The driver searches for all valid stations in the band and when complete,
+   *    returns a channel list based on the client's selection. The client can
+   *    choose to search for a list of the strongest stations in the band, the
+   *    weakest stations in the band, or the first N strong or weak
+   *    stations. By setting the maximumStations argument, the
+   *    client can constrain the number of frequencies returned in
+   *    the list. If user specifies argument maximumStations to be
+   *    0, the search will generate the maximum number of stations
+   *    possible.
+   *    <p>
+   *    Each time the driver initiates a list-based search, the client will be
+   *    notified via an FmRxEvSearchInProgress event. Similarly, each
+   *    time a list-based search completes, the client will be
+   *    notified via an FmRxEvSearchListComplete event.
+   *    <p>
+   *    On completion of the search, the originally tuned station
+   *    will be tuned and the following events will be generated:
+   *    FmRxEvSearchListComplete - The search has completed.
+   *    FmRxEvRadioTuneStatus - The original frequency has been
+   *    re-tuned.
+   *    <p>
+   *    Once issuing a search command, several commands from the client may be
+   *    disallowed until the search is completed or cancelled.
+   *    <p>
+   *    The search can be canceled at any time by using API
+   *    cancelSearch (). A cancelled search is treated as a completed
+   *    search and the following events will be generated:
+   *    FmRxEvSearchComplete  - The search has completed.
+   *    FmRxEvRadioTuneStatus - The original frequency has been re-tuned.
+   *    <p>
+   *    Valid Values for argument 'mode':
+   *    <ul>
+   *    <li>{@link #FM_RX_SRCHLIST_MODE_STRONG}
+   *    <li>{@link #FM_RX_SRCHLIST_MODE_WEAK}
+   *    <li>{@link #FM_RX_SRCHLIST_MODE_STRONGEST}
+   *    <li>{@link #FM_RX_SRCHLIST_MODE_WEAKEST}
+   *    <li>FM_RX_SRCHLIST_MODE_PTY (Will be implemented in the
+   *    future)
+   *    </ul>
+   *    <p>
+   *    Valid Values for argument 'direction' :
+   *    <ul>
+   *    <li>{@link #FM_RX_SEARCHDIR_DOWN}
+   *    <li>{@link #FM_RX_SEARCHDIR_UP}
+   *    </ul>
+   *    <p>
+   *    Valid Values for argument 'maximumStations' : 1-12
+   *    <p>
+   *    @param mode the FM search mode.
+   *    @param direction the Search Direction.
+   *    @param maximumStations the maximum number of stations that
+   *                           can be returned from a search. This parameter is
+   *                           ignored and 12 stations are returned if the
+   *                           search mode is either FM_RX_SRCHLIST_MODE_STRONGEST or
+   *                           FM_RX_SRCHLIST_MODE_WEAKEST
+   *
+   *    @param pty the FM RDS search Program Type (Not used
+   *               currently)
+   *   <p>
+   *    @return true if Search Initiate succeeded, false if
+   *            Search Initiate  failed.
+   *
+   *   @see #searchStations(int, int, int)
+   *   @see #searchStations(int, int, int, int, int)
+   */
+   public boolean searchStationList (int mode,
+                                     int direction,
+                                     int maximumStations,
+                                     int pty){
+
+      int state = getFMState();
+      boolean bStatus = true;
+      int re = 0;
+
+      /* Check current state of FM device */
+      if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
+          Log.d(TAG, "searchStationList: Device currently busy in executing another command.");
+          return false;
+      }
+
+      Log.d (TAG, "searchStations: mode " + mode);
+      Log.d (TAG, "searchStations: direction " + direction);
+      Log.d (TAG, "searchStations: maximumStations " + maximumStations);
+      Log.d (TAG, "searchStations: pty " + pty);
+
+      /* Validate the arguments */
+      if ( (mode != FM_RX_SRCHLIST_MODE_STRONG)
+           && (mode != FM_RX_SRCHLIST_MODE_WEAK )
+           && (mode != FM_RX_SRCHLIST_MODE_STRONGEST )
+           && (mode != FM_RX_SRCHLIST_MODE_WEAKEST )
+         )
+      {
+         bStatus = false;
+      }
+      if ( (maximumStations < 0) ||
+           (maximumStations > FM_RX_SRCHLIST_MAX_STATIONS))
+      {
+         bStatus = false;
+      }
+      if ( (direction != FM_RX_SEARCHDIR_DOWN) &&
+           (direction != FM_RX_SEARCHDIR_UP))
+      {
+         bStatus = false;
+      }
+
+      if (bStatus)
+      {
+         setSearchState(subSrchLevel_SrchListInProg);
+         Log.v(TAG, "searchStationList: CURRENT-STATE : FMRxOn ---> NEW-STATE : SearchInProg");
+         if ((mode == FM_RX_SRCHLIST_MODE_STRONGEST) || (mode == FM_RX_SRCHLIST_MODE_WEAKEST)) {
+             mode = (mode == FM_RX_SRCHLIST_MODE_STRONGEST)?
+                               FM_RX_SRCHLIST_MODE_STRONG: FM_RX_SRCHLIST_MODE_WEAK;
+            re = mControl.searchStationList(sFd, mode, 0, direction, pty);
+         }
+         else
+            re = mControl.searchStationList(sFd, mode, maximumStations, direction, pty);
+
+         if (re != 0) {
+             Log.e(TAG, "search station list failed");
+             if (getFMState() == FMState_Srch_InProg)
+                 setSearchState(subSrchLevel_SrchComplete);
+             bStatus =  false;
+         }
+      }
+
+      return bStatus;
+   }
+
+
+
+   /*==============================================================
+   FUNCTION:  cancelSearch
+   ==============================================================*/
+   /**
+   *  Cancels an ongoing search operation
+   *  (seek, scan, searchlist, etc).
+   * <p>
+   * This method should be used to cancel a previously initiated
+   * search (e.g. Basic Seek/Scan, RDS Seek/Scans, Search list,
+   * etc...).
+   * <p>
+   * Once completed, this command will generate an
+   * FmRxEvSearchCancelledtr event to all registered clients.
+   * Following this event, the client may also receive search events related
+   * to the ongoing search now being complete.
+   *
+   *   <p>
+   *    @return true if Cancel Search initiate succeeded, false if
+   *            Cancel Search initiate failed.
+   *   @see #searchStations(int, int, int)
+   *   @see #searchStations(int, int, int)
+   *   @see #searchStationList
+   */
+   public boolean cancelSearch () {
+      boolean status = false;
+      int state = getFMState();
+      /* Check current state of FM device */
+      if (state == FMState_Srch_InProg) {
+         Log.v(TAG, "cancelSearch: Cancelling the on going search operation");
+         setSearchState(subSrchLevel_SrchAbort);
+         mControl.cancelSearch(sFd);
+         return true;
+      } else
+         Log.d(TAG, "cancelSearch: No on going search operation to cancel");
+      return status;
+   }
+
+   /*==============================================================
+   FUNCTION:  setMuteMode
+   ==============================================================*/
+   /**
+   *    Allows the muting and un-muting of the audio coming
+   *    from the FM receiver.
+   *    <p>
+   *    This is a synchronous command used to mute or un-mute the
+   *    FM audio. This command mutes the audio coming from the FM
+   *    device. It is important to note that this only affects the
+   *    FM audio and not any other audio system being used.
+   *    <p>
+   *    @param mode the mute Mode setting to apply
+   *    <p>
+   *    @return true if setMuteMode call was placed successfully,
+   *           false if setMuteMode failed.
+   *
+   *    @see #enable
+   *    @see #registerClient
+   *
+   */
+   public boolean setMuteMode (int mode) {
+      int state = getFMState();
+      /* Check current state of FM device */
+      if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
+          Log.d(TAG, "setMuteMode: Device currently busy in executing another command.");
+          return false;
+      }
+      switch (mode)
+      {
+      case FM_RX_UNMUTE:
+         mControl.muteControl(sFd, false);
+         break;
+      case FM_RX_MUTE:
+         mControl.muteControl(sFd, true);
+         break;
+      default:
+         break;
+      }
+
+      return true;
+
+   }
+
+   /*==============================================================
+   FUNCTION:  setStereoMode
+   ==============================================================*/
+   /**
+   *    Sets the mono/stereo mode of the FM device.
+   *
+   *    <p>
+   *    This command allows the user to set the mono/stereo mode
+   *    of the FM device. Using this function,
+   *    the user can allow mono/stereo mixing or force the reception
+   *    of mono audio only.
+   *
+   *    @param stereoEnable true: Enable Stereo, false: Force Mono
+   *
+   *   @return true if setStereoMode call was placed successfully,
+   *           false if setStereoMode failed.
+   */
+   public boolean setStereoMode (boolean stereoEnable) {
+      int state = getFMState();
+      /* Check current state of FM device */
+      if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
+          Log.d(TAG, "setStereoMode: Device currently busy in executing another command.");
+          return false;
+      }
+      int re = mControl.stereoControl(sFd, stereoEnable);
+
+      if (re == 0)
+        return true;
+      return false;
+   }
+
+   /*==============================================================
+   FUNCTION:  setSignalThreshold
+   ==============================================================*/
+   /**
+   *    This function sets the threshold which the FM driver
+   *    uses to determine which stations have service available.
+   *
+   *    <p>
+   *    This information is used to determine which stations are
+   *    tuned during searches and Alternative Frequency jumps, as
+   *    well as at what threshold FmRxEvServiceAvailable event
+   *    callback are generated.
+   *    <p>
+   *    This is a command used to set the threshold used by the FM driver
+   *    and/or hardware to determine which stations are "good" stations.
+   *    Using this function, the client can allow very weak stations,
+   *    relatively weak stations, relatively strong stations, or very.
+   *    strong stations to be found during searches. Additionally,
+   *    this threshold will be used to determine at what threshold a
+   *    FmRxEvServiceAvailable event callback is generated.
+   *    <p>
+   *    @param threshold the new signal threshold.
+   *    @return true if setSignalThreshold call was placed
+   *           successfully, false if setSignalThreshold failed.
+   */
+   public boolean setSignalThreshold (int threshold) {
+
+      int state = getFMState();
+      /* Check current state of FM device */
+      if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
+          Log.d(TAG, "setSignalThreshold: Device currently busy in executing another command.");
+          return false;
+      }
+      boolean bStatus = true;
+      int re;
+      Log.d(TAG, "Signal Threshhold input: "+threshold );
+      int rssiLev = 0;
+
+      switch(threshold)
+      {
+      case FM_RX_SIGNAL_STRENGTH_VERY_WEAK:
+         rssiLev = FM_RX_RSSI_LEVEL_VERY_WEAK;
+         break;
+      case FM_RX_SIGNAL_STRENGTH_WEAK:
+         rssiLev = FM_RX_RSSI_LEVEL_WEAK;
+         break;
+      case FM_RX_SIGNAL_STRENGTH_STRONG:
+         rssiLev = FM_RX_RSSI_LEVEL_STRONG;
+         break;
+      case FM_RX_SIGNAL_STRENGTH_VERY_STRONG:
+         rssiLev = FM_RX_RSSI_LEVEL_VERY_STRONG;
+         break;
+      default:
+         /* Should never reach here */
+         bStatus = false;
+         Log.d (TAG, "Invalid threshold: " + threshold );
+         return bStatus;
+      }
+
+      if (bStatus) {
+        re=FmReceiverJNI.setControlNative (sFd, V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH, rssiLev);
+
+        if (re !=0)
+          bStatus = false;
+      }
+
+      return bStatus;
+   }
+
+   /*==============================================================
+   FUNCTION:  getStationParameters
+   ==============================================================*
+   /**
+   *     Returns various Paramaters related to the currently
+   *    tuned station.
+   *
+   *    <p>
+   *    This is method retreives various parameters and statistics
+   *    related to the currently tuned station. Included in these
+   *    statistics are the currently tuned frequency, the RDS/RBDS
+   *    sync status, the RSSI level, current mute settings and the
+   *    stereo/mono status.
+   *
+   *    <p>
+   *    Once completed, this command will generate an asynchronous
+   *    FmRxEvStationParameters event to the registered client.
+   *    This event will contain the station parameters.
+   *
+   *    <p>
+   *    @return      FmStationParameters: Object that contains
+   *                    all the station parameters
+   public FmStationParameters getStationParameters () {
+      return mStationParameters;
+   }
+
+   */
+
+   /*==============================================================
+   FUNCTION:  getTunedFrequency
+   ==============================================================*/
+   /**
+   *    Get the Frequency of the Tuned Station
+   *
+   *    @return frequencyKHz: Tuned Station Frequency (in kHz)
+   *                          (Example: 96500 = 96.5Mhz)
+   *            ERROR       : If device is currently executing another command
+   */
+   public int getTunedFrequency () {
+
+      int state = getFMState();
+      /* Check current state of FM device */
+      if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
+          Log.d(TAG, "getTunedFrequency: Device currently busy in executing another command.");
+          return ERROR;
+      }
+
+      int frequency = FmReceiverJNI.getFreqNative(sFd);
+
+      Log.d(TAG, "getFrequency: "+frequency);
+
+      return frequency;
+   }
+
+   /*==============================================================
+   FUNCTION:  getPSInfo
+   ==============================================================*/
+   /**
+   *    Returns the current RDS/RBDS Program Service
+   *            Information.
+   *    <p>
+   *    This is a command which returns the last complete RDS/RBDS
+   *    Program Service information for the currently tuned station.
+   *    To use this command, the client must first register for
+   *    Program Service info by receiving either the
+   *    FM_RX_RDS_GRP_PS_EBL or FM_RX_RDS_GRP_PS_SIMPLE_EBL event.
+   *    Under normal operating mode, this information will
+   *    automatically be sent to the client. However, if the client
+   *    requires this information be sent again, this function can be
+   *    used.
+   *
+   *    Typicaly this method needs to be called when "FmRxEvRdsPsInfo"
+   *    callback is invoked.
+   *
+   *    <p>
+   *    @return  the RDS data including the Program Service
+   *             Information
+   *
+   */
+   public FmRxRdsData  getPSInfo() {
+
+      byte [] buff = new byte[STD_BUF_SIZE];
+      int piLower = 0;
+      int piHigher = 0;
+
+      FmReceiverJNI.getBufferNative(sFd, buff, 3);
+      /* byte is signed ;(
+      *  knock down signed bits
+      */
+      piLower = buff[3] & 0xFF;
+      piHigher = buff[2] & 0xFF;
+      int pi = ((piHigher << 8) | piLower);
+      mRdsData.setPrgmId (pi);
+      mRdsData.setPrgmType ( (int)( buff[1] & 0x1F));
+      int numOfPs = (int)(buff[0] & 0x0F);
+      try
+      {
+
+	 String rdsStr = new String(buff, 5, numOfPs*8 );
+         mRdsData.setPrgmServices (rdsStr);
+
+      } catch (StringIndexOutOfBoundsException x)
+      {
+         Log.d (TAG, "Number of PS names " + numOfPs);
+      }
+      return mRdsData;
+   }
+
+   /*==============================================================
+   FUNCTION:  getRTInfo
+   ==============================================================*/
+   /**
+   *    Returns the current RDS/RBDS RadioText Information.
+   *
+   *    <p>
+   *    This is a command which returns the last complete RadioText information
+   *    for the currently tuned station. For this command to return meaningful
+   *    information, the client must first register for RadioText events by registerring
+   *    the FM_RX_RDS_GRP_RT_EBL callback function. Under normal operating mode, this information
+   *    will automatically be sent to the client. However, if the client requires
+   *    this information be sent again, this function can be used.
+   *
+   *    <p>
+   *    Typicaly this method needs to be called when
+   *    "FmRxEvRdsRtInfo" callback is invoked.
+   *
+   *    <p>
+   *    @return  the RDS data including the Radio Text Information
+   */
+   public FmRxRdsData getRTInfo () {
+
+      byte [] buff = new byte[STD_BUF_SIZE];
+      int piLower = 0;
+      int piHigher = 0;
+
+      FmReceiverJNI.getBufferNative(sFd, buff, 2);
+      String rdsStr = new String(buff);
+      /* byte is signed ;(
+      *  knock down signed bit
+      */
+      piLower = buff[3] & 0xFF;
+      piHigher = buff[2] & 0xFF;
+      int pi = ((piHigher << 8) | piLower);
+      mRdsData.setPrgmId (pi);
+      mRdsData.setPrgmType ( (int)( buff[1] & 0x1F));
+      try
+      {
+         rdsStr = rdsStr.substring(5, (int) buff[0]+ 5);
+         mRdsData.setRadioText (rdsStr);
+
+      } catch (StringIndexOutOfBoundsException x)
+      {
+         Log.d (TAG, "StringIndexOutOfBoundsException ...");
+      }
+      return mRdsData;
+   }
+
+   public FmRxRdsData getRTPlusInfo() {
+      byte []rt_plus = new byte[STD_BUF_SIZE];
+      int bytes_read;
+      String rt = "";
+      int rt_len;
+      int i, j = 2;
+      byte tag_code, tag_len, tag_start_pos;
+
+      bytes_read = FmReceiverJNI.getBufferNative(sFd, rt_plus, BUF_RTPLUS);
+      if (bytes_read > 0) {
+          if (rt_plus[RT_OR_ERT_IND] == 0)
+              rt = mRdsData.getRadioText();
+          else
+              rt = mRdsData.getERadioText();
+          if ((rt != "") && (rt != null)) {
+              rt_len = rt.length();
+              mRdsData.setTagNums(0);
+              for (i = 1; (i <= 2) && (j < rt_plus[LEN_IND]); i++) {
+                  tag_code = rt_plus[j++];
+                  tag_start_pos = rt_plus[j++];
+                  tag_len = rt_plus[j++];
+                  if (((tag_len + tag_start_pos) <= rt_len) && (tag_code > 0)) {
+                      mRdsData.setTagValue(rt.substring(tag_start_pos,
+                                            (tag_len + tag_start_pos)), i);
+                      mRdsData.setTagCode(tag_code, i);
+                  }
+              }
+          } else {
+              mRdsData.setTagNums(0);
+          }
+      } else {
+              mRdsData.setTagNums(0);
+      }
+      return mRdsData;
+   }
+
+   public FmRxRdsData getERTInfo() {
+      byte [] raw_ert = new byte[STD_BUF_SIZE];
+      byte [] ert_text;
+      int i;
+      String s = "";
+      String encoding_type = "UCS-2";
+      int bytes_read;
+
+      bytes_read = FmReceiverJNI.getBufferNative(sFd, raw_ert, BUF_ERT);
+      if (bytes_read > 0) {
+          ert_text = new byte[raw_ert[LEN_IND]];
+          for(i = 3; (i - 3) < raw_ert[LEN_IND]; i++) {
+              ert_text[i - 3] = raw_ert[i];
+          }
+          if (raw_ert[ENCODE_TYPE_IND] == 1)
+              encoding_type = "UTF-8";
+          try {
+               s = new String (ert_text, encoding_type);
+          } catch (Exception e) {
+               e.printStackTrace();
+          }
+          mRdsData.setERadioText(s);
+          if (raw_ert[ERT_DIR_IND] == 0)
+              mRdsData.setFormatDir(false);
+          else
+              mRdsData.setFormatDir(true);
+          Log.d(TAG, "eRT: " + s + "dir: " +raw_ert[ERT_DIR_IND]);
+      }
+      return mRdsData;
+   }
+
+   /*==============================================================
+   FUNCTION:  getAFInfo
+   ==============================================================*/
+   /**
+   *   Returns the current RDS/RBDS Alternative Frequency
+   *          Information.
+   *
+   *    <p>
+   *    This is a command which returns the last known Alternative Frequency
+   *    information for the currently tuned station. For this command to return
+   *    meaningful information, the client must first register for Alternative
+   *    Frequency events by registering an FM_RX_RDS_GRP_AF_EBL call back function.
+   *    Under normal operating mode, this information will automatically be
+   *    sent to the client. However, if the client requires this information
+   *    be sent again, this function can be used.
+   *
+   *    <p>
+   *    Typicaly this method needs to be called when
+   *    "FmRxEvRdsAfInfo" callback is invoked.
+   *
+   *    @return  the RDS data including the AF Information
+   */
+   public int[] getAFInfo() {
+
+      byte [] buff = new byte[STD_BUF_SIZE];
+      int  [] AfList = new int [40];
+      int lowerBand;
+
+      FmReceiverJNI.getBufferNative(sFd, buff, TAVARUA_BUF_AF_LIST);
+
+      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 (int i=0; i<buff[4]; i++) {
+        AfList[i] = ((buff[i+4] & 0xFF) * 1000) + lowerBand;
+        Log.d (TAG, "AF : " + AfList[i]);
+      }
+
+      return AfList;
+
+   }
+
+   /*==============================================================
+   FUNCTION:  setPowerMode
+   ==============================================================*/
+   /**
+   *    Puts the driver into or out of low power mode.
+   *
+   *    <p>
+   *    This is an synchronous command which can put the FM
+   *    device and driver into and out of low power mode. Low power mode
+   *    should be used when the receiver is tuned to a station and only
+   *    the FM audio is required. The typical scenario for low power mode
+   *    is when the FM application is no longer visible.
+   *
+   *    <p>
+   *    While in low power mode, all normal FM and RDS indications from
+   *    the FM driver will be suppressed. By disabling these indications,
+   *    low power mode can result in fewer interruptions and this may lead
+   *    to a power savings.
+   *
+   *    <p>
+   *    @param powerMode the new driver operating mode.
+   *
+   *    @return true if setPowerMode succeeded, false if
+   *            setPowerMode failed.
+   */
+   public boolean setPowerMode(int powerMode){
+
+      int re;
+
+      if (powerMode == FM_RX_LOW_POWER_MODE) {
+        re = mControl.setLowPwrMode (sFd, true);
+      }
+      else {
+        re = mControl.setLowPwrMode (sFd, false);
+      }
+
+      if (re == 0)
+         return true;
+      return false;
+   }
+
+   /*==============================================================
+  FUNCTION:  getPowerMode
+  ==============================================================*/
+   /**
+   *    Get FM device low power mode.
+   *    <p>
+   *    This is an synchronous method that will read the power mode
+   *    of the FM device and driver.
+   *    <p>
+   *       @return true if the FM Device is in Low power mode and
+   *               false if the FM Device in Normal power mode.
+   *
+   *    @see #setPowerMode
+   */
+   public int getPowerMode(){
+
+      return  mControl.getPwrMode (sFd);
+
+   }
+
+   /*==============================================================
+   FUNCTION:  getRssiLimit
+   ==============================================================*/
+   /**
+   *    Returns the RSSI thresholds for the FM driver.
+   *
+   *    <p>
+   *    This method returns the RSSI thresholds for the FM driver.
+   *    This function returns a structure containing the minimum RSSI needed
+   *    for reception and the minimum RSSI value where reception is perfect.
+   *    The minimum RSSI value for reception is the recommended threshold where
+   *    an average user would consider the station listenable. Similarly,
+   *    the minimum RSSI threshold for perfect reception is the point where
+   *    reception quality will improve only marginally even if the RSSI level
+   *    improves greatly.
+   *
+   *    <p>
+   *    These settings should only be used as a guide for describing
+   *    the RSSI values returned by the FM driver. Used in conjunction
+   *    with getRssiInfo, the client can use the values from this
+   *    function to give meaning to the RSSI levels returned by the driver.
+   *
+   *    <p>
+   *       @return the RSSI level
+   */
+   public int[] getRssiLimit () {
+
+      int[] rssiLimits = {0, 100};
+
+      return rssiLimits;
+   }
+
+   /*==============================================================
+   FUNCTION:  getSignalThreshold
+   ==============================================================*/
+   /**
+   *   This function returns:
+   *          currently set signal threshold - if API invocation
+   *                                           is successful
+   *          ERROR                          - if device is currently
+   *                                           executing another command
+   *    <p>
+   *    This value used by the FM driver/hardware to determine which
+   *    stations are tuned during searches and Alternative Frequency jumps.
+   *    Additionally, this level is used to determine at what
+   *    threshold FmRxEvServiceAvailable are generated.
+   *
+   *    <p>
+   *    This is a command used to return the currently set signal
+   *    threshold used by the FM driver and/or hardware. This
+   *    value is used to determine. which stations are tuned
+   *    during searches and Alternative Frequency jumps as well as
+   *    when Service available events are generated.
+   *
+   *    <p>
+   *    Once completed, this command will generate an asynchronous
+   *    FmRxEvGetSignalThreshold event to the registered client.
+   *    This event will contain the current signal threshold
+   *    level.
+   *
+   *    <p>
+   *    @return the signal threshold
+   */
+   public int getSignalThreshold () {
+      int state = getFMState();
+      /* Check current state of FM device */
+      if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
+          Log.d(TAG, "getSignalThreshold: Device currently busy in executing another command.");
+          return ERROR;
+      }
+     int threshold = FM_RX_SIGNAL_STRENGTH_VERY_WEAK, signalStrength;
+     int rmssiThreshold = FmReceiverJNI.getControlNative (sFd, V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH);
+     Log.d(TAG, "Signal Threshhold: "+rmssiThreshold );
+
+     if ( (FM_RX_RSSI_LEVEL_VERY_WEAK < rmssiThreshold) && (rmssiThreshold <= FM_RX_RSSI_LEVEL_WEAK) )
+     {
+       signalStrength = FM_RX_RSSI_LEVEL_WEAK;
+     }
+     else if ( (FM_RX_RSSI_LEVEL_WEAK < rmssiThreshold) && (rmssiThreshold  <= FM_RX_RSSI_LEVEL_STRONG))
+     {
+       signalStrength = FM_RX_RSSI_LEVEL_STRONG;
+     }
+     else if ((FM_RX_RSSI_LEVEL_STRONG < rmssiThreshold))
+     {
+       signalStrength = FM_RX_RSSI_LEVEL_VERY_STRONG;
+     }
+     else
+     {
+       signalStrength = FM_RX_RSSI_LEVEL_VERY_WEAK;
+     }
+
+     switch(signalStrength)
+     {
+     case FM_RX_RSSI_LEVEL_VERY_WEAK:
+        threshold = FM_RX_SIGNAL_STRENGTH_VERY_WEAK;
+        break;
+     case FM_RX_RSSI_LEVEL_WEAK:
+        threshold = FM_RX_SIGNAL_STRENGTH_WEAK;
+        break;
+     case FM_RX_RSSI_LEVEL_STRONG:
+        threshold = FM_RX_SIGNAL_STRENGTH_STRONG;
+        break;
+     case FM_RX_RSSI_LEVEL_VERY_STRONG:
+        threshold = FM_RX_SIGNAL_STRENGTH_VERY_STRONG;
+        break;
+     default:
+        /* Should never reach here */
+        break;
+     }
+
+     return threshold;
+   }
+
+
+   /*==============================================================
+   FUNCTION:  setRdsGroupOptions
+   ==============================================================*/
+   /**
+   *
+   *    This function enables or disables various RDS/RBDS
+   *    group filtering and buffering features.
+   *
+   *    <p>
+   *    Included in these features are the RDS group enable mask, RDS/RBDS group
+   *    change filter, and the RDS/RBDS group buffer size.
+   *    <p>
+   *    This is a function used to set or unset various Rx RDS/RBDS group filtering
+   *    and buffering options in the FM driver.
+   *    <p>
+   *    Included in these options is the ability for the client to select
+   *    which RDS/RBDS groups should be sent to the client. By default, all
+   *    RDS/RBDS groups are filtered out before reaching the client. To allow one
+   *    or more specific groups to be received, the client must set one or mors bits
+   *    within the argument enRdsGrpsMask bitmask. Each bit in this
+   *    mask corresponds to a specific RDS/RBDS group type. Once a
+   *    group is enabled, and when a buffer holding those groups
+   *    reaches the threshold defined by argument rdsBuffSize, the
+   *    group or groups will be sent to the client as a
+   *    FmRxEvRdsGroupData callback.
+   *
+   *    <p>
+   *    Additionally, this function also allows the client to enable or
+   *    disable the RDS/RBDS group change filter. This filter allows the client
+   *    to prevent duplicate groups of the same group type from being received.
+   *    This filter only applies to consecutive groups, so
+   *    identical groups received in different order will not be
+   *    filtered out.
+   *
+   *    <p>
+   *    @param enRdsGrpsMask the bitMask that enables the RT/PS/AF.
+   *
+   *    @param rdsBuffSize the number of RDS/RBDS groups the FM
+   *                        driver should buffer  before sending to
+   *                        the client.
+   *
+   *    @param enRdsChangeFilter the Flag used to determine whether
+   *                              the RDS/RBDS change filter
+   *                              should be enabled.
+   *
+   *    @return true if the command was placed successfully, false
+   *            if command failed.
+   *
+   */
+   public boolean setRdsGroupOptions (int enRdsGrpsMask,
+                                      int rdsBuffSize,
+                                      boolean enRdsChangeFilter)
+   {
+
+      int state = getFMState();
+      /* Check current state of FM device */
+      if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
+          Log.d(TAG, "setRdsGroupOptions: Device currently busy in executing another command.");
+          return false;
+      }
+      // Enable RDS
+      int re = mRdsData.rdsOn(true);
+
+      if (re != 0)
+        return false;
+
+      re = mRdsData.rdsGrpOptions (enRdsGrpsMask, rdsBuffSize, enRdsChangeFilter);
+
+      if (re ==0)
+        return true;
+
+      return false;
+
+   }
+
+   public boolean setRawRdsGrpMask()
+   {
+      return super.setRDSGrpMask(GRP_3A);
+   }
+   /*==============================================================
+   FUNCTION:  registerRdsGroupProcessing
+   ==============================================================*/
+   /**
+   *
+   *    This function enables or disables RDS/RBDS group processing features.
+   *
+   *    <p>
+   *    Included in these features is the ability for the FM driver
+   *    to return Program Service, RadioText, and Alternative
+   *    Frequency information.
+   *
+   *    <p>
+   *    These options free the client from the burden of collecting a continuous
+   *    stream of RDS/RBDS groups and processing them. By setting the
+   *    FM_RX_RDS_GRP_RT_EBL bit in argument fmGrpsToProc, the FM
+   *    hardware or driver will collect RDS/RBDS 2A/2B groups and
+   *    return complete RadioText strings and information in the
+   *    form of a FmRxEvRdsRtInfo event. This event will be
+   *    generated only when the RadioText information changes.
+   *
+   *    <p>
+   *    Similarly, by setting either the FM_RX_RDS_GRP_PS_EBL or
+   *    FM_RX_RDS_GRP_PS_SIMPLE_EBL bit in argument fmGrpsToProc,
+   *    the FM hardware or driver will collect RDS/RBDS 0A/0B
+   *    groups and return Program Service information in the form
+   *    of a FmRxEvRdsPsInfo event. This event will be generated
+   *    whenever the Program Service information changes. This
+   *    event will include one or more collected Program Service
+   *    strings which can be continuously displayed by the client.
+   *
+   *    <p>
+   *    Additionally, by setting the FM_RX_RDS_GRP_AF_EBL bit in
+   *    argument FmGrpsToProc, the FM hardware or driver will
+   *    collect RDS/RBDS 0A/0B groups and return Alternative
+   *    Frequency information in the form of a FmRxEvRdsAfInfo
+   *    event. This event will be generated when the Alternative
+   *    Frequency information changes and will include an up to
+   *    date list of all known Alternative Frequencies.
+   *
+   *    <p>
+   *    Lastly, by setting the FM_RX_RDS_GRP_AF_JUMP_EBL bit in
+   *    argument FmGrpsToProc, the FM hardware or driver will
+   *    collect RDS/RBDS 0A/0B groups and automatically tune to a
+   *    stronger alternative frequency when the signal level falls
+   *    below the search threshold.
+   *
+   *    @param fmGrpsToProc the bitMask that enables the RT/PS/AF.
+   *
+   *    @return true if the command was placed successfully, false
+   *            if command failed.
+   *
+   */
+   public boolean registerRdsGroupProcessing (int fmGrpsToProc){
+
+      if (mRdsData == null)
+         return false;
+
+      int state = getFMState();
+      /* Check current state of FM device */
+      if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
+          Log.d(TAG, "registerRdsGroupProcessing: Device currently busy in executing another command.");
+          return false;
+      }
+
+      // Enable RDS
+      int re = mRdsData.rdsOn(true);
+
+      if (re != 0)
+        return false;
+
+      re = mRdsData.rdsOptions (fmGrpsToProc);
+
+      if (re ==0)
+        return true;
+
+      return false;
+   }
+
+
+   /*==============================================================
+   FUNCTION:  enableAFjump
+   ==============================================================*/
+   /**
+   *    Enables automatic jump to alternative frequency
+   *
+   *    <p>
+   *    This method enables automatic seeking to stations which are
+   *    known ahead of time to be Alternative Frequencies for the
+   *    currently tuned station. If no alternate frequencies are
+   *    known, or if the Alternative Frequencies have weaker signal
+   *    strength than the original frequency, the original frequency
+   *    will be re-tuned.
+   *
+   *    <p>
+   *    @return     true if successful false otherwise.
+   */
+   public boolean enableAFjump (boolean enable) {
+
+      int state = getFMState();
+      /* Check current state of FM device */
+      if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
+          Log.d(TAG, "enableAFjump: Device currently busy in executing another command.");
+          return false;
+      }
+      // Enable RDS
+      int re = mRdsData.rdsOn(true);
+
+      if (re != 0)
+        return false;
+
+      re = mRdsData.enableAFjump(enable);
+
+      if (re == 0)
+        return true;
+
+      return false;
+   }
+
+   /*==============================================================
+   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
+   ==============================================================*/
+   /**
+   *    Returns the signal strength of the currently tuned station
+   *
+   *    <p>
+   *    This method returns the signal strength of the currently
+   *    tuned station.
+   *
+   *    <p>
+   *    @return    RSSI of currently tuned station
+   */
+   public int getRssi()
+   {
+
+       int rssi = FmReceiverJNI.getRSSINative (sFd);
+
+       return rssi;
+   }
+
+   /*==============================================================
+   FUNCTION:  getIoverc
+   ==============================================================*/
+   /**
+   *    Returns the Estimated Interference Over Carrier of the currently tuned station
+   *
+   *    <p>
+   *    This method returns the Estimated Interference Over Carrier of the currently
+   *    tuned station.
+   *
+   *    <p>
+   *    @return    IOVERC of currently tuned station on Success.
+   *		   -1 on failure to retrieve the current IoverC.
+   */
+   public int getIoverc()
+   {
+      int re;
+      re = mControl.IovercControl(sFd);
+      return re;
+   }
+
+   /*==============================================================
+   FUNCTION:  getIntDet
+   ==============================================================*/
+   /**
+   *    Returns the IntDet the currently tuned station
+   *
+   *    <p>
+   *    This method returns the IntDet of the currently
+   *    tuned station.
+   *
+   *    <p>
+   *    @return    IntDet of currently tuned station.
+   *		   -1 on failure to retrieve the current IntDet
+   */
+   public int getIntDet()
+   {
+      int re;
+
+      re = mControl.IntDet(sFd);
+      return re;
+   }
+
+
+   /*==============================================================
+   FUNCTION:  getMpxDcc
+   ==============================================================*/
+   /**
+   *    Returns the MPX_DCC of the currently tuned station
+   *
+   *    <p>
+   *    This method returns the MPX_DCC of the currently
+   *    tuned station.
+   *
+   *    <p>
+   *    @return    MPX_DCC value of currently tuned station.
+   *               -1 on failure to retrieve the current MPX_DCC
+   */
+   public int getMpxDcc()
+   {
+      int re;
+
+      re = mControl.Mpx_Dcc(sFd);
+      return re;
+   }
+/*==============================================================
+   FUNCTION:  setHiLoInj
+   ==============================================================*/
+   /**
+   *    Sets the Hi-Lo injection
+   *
+   *    <p>
+   *    This method sets the hi-low injection.
+   *
+   *    <p>
+   */
+   public void setHiLoInj(int inj)
+   {
+      int re =  mControl.setHiLoInj(sFd, inj);
+   }
+
+/*==============================================================
+   FUNCTION:  getRmssiDelta
+   ==============================================================*/
+   /**
+   *    Gets the value of currently set RMSSI Delta
+   *
+   *    <p>
+   *    This method gets the currently set RMSSI Delta value.
+   *
+   *    <p>
+   */
+   public int getRmssiDelta()
+   {
+      int re =  mControl.getRmssiDelta(sFd);
+      Log.d (TAG, "The value of RMSSI Delta is " + re);
+      return re;
+   }
+
+/*==============================================================
+   FUNCTION:  setRmssiDel
+   ==============================================================*/
+   /**
+   *    Sets the RMSSI Delta
+   *
+   *    <p>
+   *    This method sets the RMSSI Delta.
+   *
+   *    <p>
+   */
+   public void setRmssiDel(int delta)
+   {
+      int re =  mControl.setRmssiDel(sFd, delta);
+   }
+
+   /*==============================================================
+   FUNCTION:  getRawRDS
+   ==============================================================*/
+   /**
+   *    Returns array of Raw RDS data
+   *
+   *    <p>
+   *    This is a non-blocking call and it returns raw RDS data.
+   *    The data is packed in groups of three bytes. The lsb and
+   *    msb bytes contain RDS block while the third byte contains
+   *    Block description. This call is wrapper around V4L2 read
+   *    system call. The FM driver collects RDS/RBDS groups to meet
+   *    the threshold described by setRdsGroupOptions() method.
+   *    The call returns when one or more groups have been enabled
+   *    by setRdsGroupOptions() method.
+   *
+   *    @param numBlocks Number of blocks of RDS data
+   *
+   *    <p>
+   *    @return    byte[]
+   */
+
+   public byte[] getRawRDS (int numBlocks)
+   {
+
+        byte[] rawRds = new byte [numBlocks*3];
+        int re;
+
+        re = FmReceiverJNI.getRawRdsNative (sFd, rawRds, numBlocks*3);
+
+        if (re == (numBlocks*3))
+            return rawRds;
+
+        if (re <= 0)
+          return null;
+
+        byte[] buff = new byte [re];
+
+        System.arraycopy (rawRds, 0, buff, 0 , re);
+
+        return buff;
+
+   }
+
+   /*
+    * getFMState() returns:
+    *     '0' if FM State  is OFF
+    *     '1' if FM Rx     is On
+    *     '2' if FM Tx     is On
+    *     '3' if FM device is Searching
+   */
+   public int getFMState()
+   {
+      /* Current State of FM device */
+      int currFMState = FmTransceiver.getFMPowerState();
+      return currFMState;
+
+   }
+/*==============================================================
+   FUNCTION:  setOnChannelThreshold
+   ==============================================================*/
+   /**
+   *    Sets the On channel threshold value
+   *
+   *    <p>
+   *    This method sets the On channel threshold value.
+   *
+   *    <p>
+   */
+   public boolean setOnChannelThreshold(int data)
+   {
+      int re =  mControl.setOnChannelThreshold(sFd, data);
+      if (re < 0)
+          return false;
+      else
+          return true;
+   }
+
+/*==============================================================
+   FUNCTION:  getOnChannelThreshold
+   ==============================================================*/
+   /**
+   *    Gets the On channel threshold value
+   *
+   *    <p>
+   *    This method gets the currently set On channel threshold value.
+   *
+   *    <p>
+   */
+   public int getOnChannelThreshold()
+   {
+      return mControl.getOnChannelThreshold(sFd);
+   }
+
+/*==============================================================
+   FUNCTION:  setOffChannelThreshold
+   ==============================================================*/
+   /**
+   *    Sets the Off channel threshold value
+   *
+   *    <p>
+   *    This method sets the Off channel threshold value.
+   *
+   *    <p>
+   */
+   public boolean setOffChannelThreshold(int data)
+   {
+      int re =  mControl.setOffChannelThreshold(sFd, data);
+      if (re < 0)
+          return false;
+      else
+          return true;
+   }
+/*==============================================================
+   FUNCTION:  getOffChannelThreshold
+   ==============================================================*/
+   /**
+   *    Gets the Off channel threshold value
+   *
+   *    <p>
+   *    This method gets the currently set Off channel threshold value.
+   *
+   *    <p>
+   */
+   public int getOffChannelThreshold()
+   {
+      return mControl.getOffChannelThreshold(sFd);
+   }
+/*===============================================================
+   FUNCTION:  getSINR
+   ==============================================================*/
+   /**
+   *    Gets the SINR value of currently tuned station
+   *
+   *    <p>
+   *    This method gets the SINR value for  currently tuned station.
+   *
+   *    <p>
+   */
+   public int getSINR()
+   {
+      int re =  mControl.getSINR(sFd);
+      Log.d (TAG, "The value of SINR is " + re);
+      return re;
+   }
+
+/*==============================================================
+   FUNCTION:  setSINRThreshold
+   ==============================================================*/
+   /**
+   *    Sets the SINR threshold value
+   *
+   *    <p>
+   *    This method sets the SINR threshold value.
+   *
+   *    <p>
+   */
+   public boolean setSINRThreshold(int data)
+   {
+      int re =  mControl.setSINRThreshold(sFd, data);
+      if (re < 0)
+          return false;
+      else
+          return true;
+   }
+
+/*==============================================================
+   FUNCTION:  getSINRThreshold
+   ==============================================================*/
+   /**
+   *    Gets the SINR threshold value
+   *
+   *    <p>
+   *    This method gets the currently set SINR threshold value.
+   *
+   *    <p>
+   */
+   public int getSINRThreshold()
+   {
+      return mControl.getSINRThreshold(sFd);
+   }
+
+/*==============================================================
+   FUNCTION:  setSINRsamples
+   ==============================================================*/
+   /**
+   *    Sets the SINR samples
+   *
+   *    <p>
+   *    This method sets the number of SINR samples to calculate the SINR value.
+   *
+   *    <p>
+   */
+   public boolean setSINRsamples(int data)
+   {
+      int re =  mControl.setSINRsamples(sFd, data);
+      if (re < 0)
+          return false;
+      else
+          return true;
+   }
+
+/*==============================================================
+   FUNCTION:  getSINRsamples
+   ==============================================================*/
+   /**
+   *    Gets the SINR samples value
+   *
+   *    <p>
+   *    This method gets the number of currently set SINR samples.
+   *
+   *    <p>
+   */
+   public int getSINRsamples()
+   {
+      return mControl.getSINRsamples(sFd);
+   }
+
+   public int updateSpurFreq(int freq, int rmssi, boolean enable)
+   {
+       return mControl.updateSpurTable(sFd, freq, rmssi, enable);
+   }
+
+   public int configureSpurTable()
+   {
+       return mControl.configureSpurTable(sFd);
+   }
+}
diff --git a/qcom/fmradio/FmReceiverJNI.java b/qcom/fmradio/FmReceiverJNI.java
new file mode 100644
index 0000000..3c779c2
--- /dev/null
+++ b/qcom/fmradio/FmReceiverJNI.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2009-2012, 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;
+
+class FmReceiverJNI {
+    /**
+     * General success
+     */
+    static final int FM_JNI_SUCCESS = 0;
+
+    /**
+     * General failure
+     */
+    static final int FM_JNI_FAILURE = -1;
+
+    /**
+     * native method: Open device
+     * @return The file descriptor of the device
+     *
+     */
+    static native int acquireFdNative(String path);
+
+
+    /**
+     * native method:
+     * @param fd
+     * @param control
+     * @param field
+     * @return
+     */
+    static native int audioControlNative(int fd, int control, int field);
+
+    /**
+     * native method: cancels search
+     * @param fd file descriptor of device
+     * @return May return
+     *             {@link #FM_JNI_SUCCESS}
+     *             {@link #FM_JNI_FAILURE}
+     */
+    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
+     */
+    static native int getFreqNative(int fd);
+
+    /**
+     * native method: set frequency
+     * @param fd file descriptor of device
+     * @param freq freq to be set in int form
+     * @return {@link #FM_JNI_SUCCESS}
+     *         {@link #FM_JNI_FAILURE}
+     *
+     */
+    static native int setFreqNative(int fd, int freq);
+
+    /**
+     * native method: get v4l2 control
+     * @param fd file descriptor of device
+     * @param id v4l2 id to be retrieved
+     * @return Returns current value of the
+     *         v4l2 control
+     */
+    static native int getControlNative (int fd, int id);
+
+    /**
+     * native method: set v4l2 control
+     * @param fd file descriptor of device
+     * @param id v4l2 control to be set
+     * @param value value to be set
+     * @return {@link #FM_JNI_SUCCESS}
+     *         {@link #FM_JNI_FAILURE}
+     */
+    static native int setControlNative (int fd, int id, int value);
+
+    /**
+     * native method: start search
+     * @param fd file descriptor of device
+     * @param dir search direction
+     * @return {@link #FM_JNI_SUCCESS}
+     *         {@link #FM_JNI_FAILURE}
+     */
+    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
+     * @return Returns signal strength in int form
+     *         Signal value range from -120 to 10
+     */
+    static native int getRSSINative (int fd);
+
+    /**
+     * native method: set FM band
+     * @param fd file descriptor of device
+     * @param low lower band
+     * @param high higher band
+     * @return {@link #FM_JNI_SUCCESS}
+     *         {@link #FM_JNI_FAILURE}
+     */
+    static native int setBandNative (int fd, int low, int high);
+
+    /**
+     * native method: get lower band
+     * @param fd file descriptor of device
+     * @return Returns lower band in int form
+     */
+    static native int getLowerBandNative (int fd);
+
+    /**
+     * native method: get upper band
+     * @param fd file descriptor of device
+     * @return Returns upper band in int form
+     */
+    static native int getUpperBandNative (int fd);
+
+    /**
+     * native method: force Mono/Stereo mode
+     * @param fd file descriptor of device
+     * @param val force mono/stereo indicator
+     * @return {@link #FM_JNI_SUCCESS}
+     *         {@link #FM_JNI_FAILURE}
+     */
+    static native int setMonoStereoNative (int fd, int val);
+
+    /**
+     * native method: get Raw RDS data
+     * @param fd file descriptor of device
+     * @param buff[] buffer
+     * @param count number of bytes to be read
+     * @return Returns number of bytes read
+     */
+    static native int getRawRdsNative (int fd, byte  buff[], int count);
+
+    /**
+     * native method: set v4l2 control
+     * @param fd file descriptor of device
+     * @param id v4l2 control to be set
+     * @param value value to be set
+     * @return {@link #FM_JNI_SUCCESS}
+     *         {@link #FM_JNI_FAILURE}
+     */
+    static native int setNotchFilterNative(int fd, int id, boolean value);
+
+    /**
+     * native method: enable/disable Analog Mode
+     */
+    static native int setAnalogModeNative(boolean value);
+
+    /**
+     * native method: Starts the RT transmission
+     * @param fd file descriptor of device
+     * @param buff[] buffer
+     * @param count number of bytes to be read
+     * @return Returns number of bytes read
+     */
+    static native int startRTNative(int fd, String str, int count);
+
+    /**
+     * native method: Stops the RT transmission
+     * @param fd file descriptor of device
+     * @param buff[] buffer
+     * @param count number of bytes to be read
+     * @return Returns number of bytes read
+     */
+    static native int stopRTNative(int fd);
+
+    /**
+     * native method: Starts the PS transmission
+     * @param fd file descriptor of device
+     * @param buff[] buffer
+     * @param count number of bytes to be read
+     * @return Returns number of bytes read
+     */
+    static native int startPSNative(int fd, String str, int count);
+
+    /**
+     * native method: Stops the PS transmission
+     * @param fd file descriptor of device
+     * @param buff[] buffer
+     * @param count number of bytes to be read
+     */
+    static native int stopPSNative(int fd);
+   /**
+     * native method: Sets the Programme type for transmission
+     * @param fd file descriptor of device
+     * @param pty program type to be transmited
+     * @return {@link #FM_JNI_SUCCESS}
+     *         {@link #FM_JNI_FAILURE}
+     */
+    static native int setPTYNative (int fd, int pty);
+
+   /**
+     * native method: Sets the Programme Id for transmission
+     * @param fd file descriptor of device
+     * @param pty program Id to be transmited
+     * @return {@link #FM_JNI_SUCCESS}
+     *         {@link #FM_JNI_FAILURE}
+     */
+    static native int setPINative (int fd, int pi);
+
+
+   /**
+     * native method: Sets the repeat count for Programme service
+     * transmission.
+     * @param fd file descriptor of device
+     * @param repeatcount  number of times PS string to be transmited
+     *                     repeatedly.
+     * @return {@link #FM_JNI_SUCCESS}
+     *         {@link #FM_JNI_FAILURE}
+     */
+    static native int setPSRepeatCountNative(int fd, int repeatCount);
+   /**
+     * native method: Sets the power level for the tramsmitter
+     * transmission.
+     * @param fd file descriptor of device
+     * @param powLevel is the level at which transmitter operates.
+     * @return {@link #FM_JNI_SUCCESS}
+     *         {@link #FM_JNI_FAILURE}
+     */
+    static native int setTxPowerLevelNative(int fd, int powLevel);
+   /**
+     * native method: Sets the calibration
+     * @param fd file descriptor of device
+     * @return {@link #FM_JNI_SUCCESS}
+     *         {@link #FM_JNI_FAILURE}
+     */
+    static native int SetCalibrationNative(int fd);
+
+   /**
+     * native method: Configures the spur table
+     * @param fd file descriptor of device
+     * @return {@link #FM_JNI_SUCCESS}
+     *         {@link #FM_JNI_FAILURE}
+     */
+    static native int configureSpurTable(int fd);
+}
diff --git a/qcom/fmradio/FmRxControls.java b/qcom/fmradio/FmRxControls.java
new file mode 100644
index 0000000..5c2d42c
--- /dev/null
+++ b/qcom/fmradio/FmRxControls.java
@@ -0,0 +1,550 @@
+/*
+ * Copyright (c) 2009-2012, 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 android.util.Log;
+
+
+class FmRxControls
+{
+
+   private boolean mStateStereo;
+   private boolean mStateMute;
+   private int mFreq;
+
+   static final int FREQ_MUL = 1000;
+   static final int SEEK_FORWARD = 0;
+   static final int SEEK_BACKWARD = 1;
+   static final int SCAN_FORWARD = 2;
+   static final int SCAN_BACKWARD = 3;
+   static final int FM_DIGITAL_PATH = 0;
+   static final int FM_ANALOG_PATH  = 1;
+   private int mSrchMode;
+   private int mScanTime;
+   private int mSrchDir;
+   private int mSrchListMode;
+   private int mPrgmType;
+   private int mPrgmId;
+   private static final String TAG = "FmRxControls";
+
+
+   /* V4l2 Controls */
+   private static final int V4L2_CID_PRIVATE_BASE                          = 0x8000000;
+   private static final int V4L2_CID_PRIVATE_TAVARUA_SRCHMODE              = V4L2_CID_PRIVATE_BASE + 1;
+   private static final int V4L2_CID_PRIVATE_TAVARUA_SCANDWELL             = V4L2_CID_PRIVATE_BASE + 2;
+   private static final int V4L2_CID_PRIVATE_TAVARUA_SRCHON                = V4L2_CID_PRIVATE_BASE + 3;
+   private static final int V4L2_CID_PRIVATE_TAVARUA_STATE                 = V4L2_CID_PRIVATE_BASE + 4;
+   private static final int V4L2_CID_PRIVATE_TAVARUA_TRANSMIT_MODE         = V4L2_CID_PRIVATE_BASE + 5;
+   private static final int V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK         = V4L2_CID_PRIVATE_BASE + 6;
+   private static final int V4L2_CID_PRIVATE_TAVARUA_REGION                = V4L2_CID_PRIVATE_BASE + 7;
+   private static final int V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH             = V4L2_CID_PRIVATE_BASE + 8;
+   private static final int V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY              = V4L2_CID_PRIVATE_BASE + 9;
+   private static final int V4L2_CID_PRIVATE_TAVARUA_SRCH_PI               = V4L2_CID_PRIVATE_BASE + 10;
+   private static final int V4L2_CID_PRIVATE_TAVARUA_SRCH_CNT              = V4L2_CID_PRIVATE_BASE + 11;
+   private static final int V4L2_CID_PRIVATE_TAVARUA_EMPHASIS              = V4L2_CID_PRIVATE_BASE + 12;
+   private static final int V4L2_CID_PRIVATE_TAVARUA_RDS_STD               = V4L2_CID_PRIVATE_BASE + 13;
+   private static final int V4L2_CID_PRIVATE_TAVARUA_SPACING               = V4L2_CID_PRIVATE_BASE + 14;
+   private static final int V4L2_CID_PRIVATE_TAVARUA_RDSON                 = V4L2_CID_PRIVATE_BASE + 15;
+   private static final int V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC         = V4L2_CID_PRIVATE_BASE + 16;
+   private static final int V4L2_CID_PRIVATE_TAVARUA_LP_MODE               = V4L2_CID_PRIVATE_BASE + 17;
+   private static final int V4L2_CID_PRIVATE_TAVARUA_IOVERC                = V4L2_CID_PRIVATE_BASE + 24;
+   private static final int V4L2_CID_PRIVATE_TAVARUA_INTDET                = V4L2_CID_PRIVATE_BASE + 25;
+   private static final int V4L2_CID_PRIVATE_TAVARUA_MPX_DCC               = V4L2_CID_PRIVATE_BASE + 26;
+   private static final int V4L2_CID_PRIVATE_TAVARUA_AF_JUMP               = V4L2_CID_PRIVATE_BASE + 27;
+   private static final int V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA            = V4L2_CID_PRIVATE_BASE + 28;
+   private static final int V4L2_CID_PRIVATE_TAVARUA_HLSI                  = V4L2_CID_PRIVATE_BASE + 29;
+   private static final int V4L2_CID_PRIVATE_TAVARUA_SET_AUDIO_PATH        = V4L2_CID_PRIVATE_BASE + 41;
+   private static final int V4L2_CID_PRIVATE_SINR                          = V4L2_CID_PRIVATE_BASE + 44;
+   private static final int V4L2_CID_PRIVATE_TAVARUA_ON_CHANNEL_THRESHOLD  = V4L2_CID_PRIVATE_BASE + 0x2D;
+   private static final int V4L2_CID_PRIVATE_TAVARUA_OFF_CHANNEL_THRESHOLD = V4L2_CID_PRIVATE_BASE + 0x2E;
+   private static final int V4L2_CID_PRIVATE_TAVARUA_SINR_THRESHOLD        = V4L2_CID_PRIVATE_BASE + 0x2F;
+   private static final int V4L2_CID_PRIVATE_TAVARUA_SINR_SAMPLES          = V4L2_CID_PRIVATE_BASE + 0x30;
+   private static final int V4L2_CID_PRIVATE_SPUR_FREQ                     = V4L2_CID_PRIVATE_BASE + 0x31;
+   private static final int V4L2_CID_PRIVATE_SPUR_FREQ_RMSSI               = V4L2_CID_PRIVATE_BASE + 0x32;
+   private static final int V4L2_CID_PRIVATE_SPUR_SELECTION                = V4L2_CID_PRIVATE_BASE + 0x33;
+
+   private static final int V4L2_CTRL_CLASS_USER = 0x980000;
+   private static final int V4L2_CID_BASE        = V4L2_CTRL_CLASS_USER | 0x900;
+   private static final int V4L2_CID_AUDIO_MUTE  = V4L2_CID_BASE + 9;
+
+   private int sOnData  ;
+   private int sOffData ;
+
+
+
+   /*
+    * Turn on FM Rx/Tx.
+    * Rx = 1 and Tx = 2
+    */
+   public void fmOn(int fd, int device) {
+      int re;
+      FmReceiverJNI.setControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_STATE, device );
+      setAudioPath(fd, false);
+      re = FmReceiverJNI.SetCalibrationNative(fd);
+      if (re != 0)
+         Log.d(TAG,"Calibration failed");
+   }
+
+   /*
+    * Turn off FM Rx/Tx
+    */
+   public void fmOff(int fd){
+      FmReceiverJNI.setControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_STATE, 0 );
+   }
+
+   /*
+    * set mute control
+    */
+   public void muteControl(int fd, boolean on) {
+      if (on)
+      {
+         int err = FmReceiverJNI.setControlNative(fd, V4L2_CID_AUDIO_MUTE, 3 );
+      } else
+      {
+         int err = FmReceiverJNI.setControlNative(fd, V4L2_CID_AUDIO_MUTE, 0 );
+      }
+   }
+   /*
+    * Get Interference over channel
+    */
+   public int IovercControl(int fd)
+   {
+      int ioverc = FmReceiverJNI.getControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_IOVERC);
+      Log.d(TAG, "IOVERC value is : "+ioverc);
+      return ioverc;
+   }
+   /*
+    * Get IntDet
+    */
+   public int IntDet(int fd)
+   {
+      int intdet =  FmReceiverJNI.getControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_INTDET);
+      Log.d(TAG, "IOVERC value is : "+intdet);
+      return intdet;
+   }
+
+   /*
+    * Get MPX_DCC
+    */
+   public int Mpx_Dcc(int fd)
+   {
+      int mpx_dcc =  FmReceiverJNI.getControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_MPX_DCC);
+      Log.d(TAG, "MPX_DCC value is : " + mpx_dcc);
+      return mpx_dcc;
+   }
+
+   /*
+    * Set Hi-Low injection
+    */
+   public int setHiLoInj(int fd, int inj)
+   {
+      int re =  FmReceiverJNI.setControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_HLSI, inj);
+      return re;
+   }
+
+   /*
+    * Set On channel threshold
+    */
+   public int setOnChannelThreshold(int fd, int sBuff)
+   {
+      int re = FmReceiverJNI.setControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_ON_CHANNEL_THRESHOLD, sBuff);
+      if ( re < 0)
+         Log.e(TAG, "Failed to set On channel threshold data");
+      return re;
+   }
+
+   /*
+    * Set Off channel threshold
+    */
+   public int setOffChannelThreshold(int fd, int sBuff)
+   {
+      int re = FmReceiverJNI.setControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_OFF_CHANNEL_THRESHOLD, sBuff);
+      if ( re < 0)
+         Log.e(TAG, "Failed to set Off channel Threshold data");
+      return re;
+   }
+
+   /*
+    * Get On channel threshold
+    */
+   public int getOnChannelThreshold(int fd)
+   {
+      return FmReceiverJNI.getControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_ON_CHANNEL_THRESHOLD);
+   }
+
+   /*
+    * Get Off channel threshold
+    */
+   public int getOffChannelThreshold(int fd)
+   {
+      return FmReceiverJNI.getControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_OFF_CHANNEL_THRESHOLD);
+   }
+
+   /*
+    * Set sinr threshold
+    */
+   public int setSINRThreshold(int fd, int sBuff)
+   {
+      int re = FmReceiverJNI.setControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_SINR_THRESHOLD, sBuff);
+      if ( re < 0)
+         Log.e(TAG, "Failed to set SINR threshold data");
+      return re;
+   }
+
+   /*
+    * Set number of sinr samples to take in to account for SINR avg calculation
+    */
+   public int setSINRsamples(int fd, int sBuff)
+   {
+      int re = FmReceiverJNI.setControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_SINR_SAMPLES, sBuff);
+      if ( re < 0)
+         Log.e(TAG, "Failed to set SINR samples ");
+      return re;
+   }
+
+   /*
+    * Get SINR threshold
+    */
+   public int getSINRThreshold(int fd)
+   {
+      return  FmReceiverJNI.getControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_SINR_THRESHOLD);
+   }
+
+   /*
+    * Get SINR samples
+    */
+   public int getSINRsamples(int fd)
+   {
+      return  FmReceiverJNI.getControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_SINR_SAMPLES);
+   }
+
+   /*
+    * Get RMSSI Delta
+    */
+   public int getRmssiDelta(int fd)
+   {
+      int rmssiDel =  FmReceiverJNI.getControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA);
+      return rmssiDel;
+   }
+
+   /*
+    * Set RMSSI Delta
+    */
+   public int setRmssiDel(int fd, int delta)
+   {
+      int re =  FmReceiverJNI.setControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA, delta);
+      return re;
+   }
+
+   /*
+    * Set the audio path as analog/digital
+    */
+   public int setAudioPath(int fd, boolean value)
+   {
+      int mode;
+      if (value)
+         mode = FM_ANALOG_PATH;
+      else
+         mode = FM_DIGITAL_PATH;
+      int re =  FmReceiverJNI.setControlNative(fd, V4L2_CID_PRIVATE_TAVARUA_SET_AUDIO_PATH, mode);
+      return re;
+   }
+
+   /*
+    * Tune FM core to specified freq.
+    */
+   public int setStation(int fd) {
+      Log.d(TAG, "** Tune Using: "+fd);
+      int ret = FmReceiverJNI.setFreqNative(fd, mFreq);
+      Log.d(TAG, "** Returned: "+ret);
+      return ret;
+   }
+
+  /*
+   * Get currently tuned freq
+   */
+   public int getTunedFrequency(int fd) {
+      int frequency = FmReceiverJNI.getFreqNative(fd);
+      Log.d(TAG, "getTunedFrequency: "+frequency);
+      return frequency;
+   }
+
+   public int getFreq (){
+      return mFreq;
+   }
+
+   public void setFreq (int f){
+      mFreq = f;
+   }
+    /*
+    * Get SINR value
+    */
+   public int getSINR(int fd)
+   {
+      return  FmReceiverJNI.getControlNative(fd, V4L2_CID_PRIVATE_SINR);
+   }
+
+
+   /*
+    * Start search list for auto presets
+    */
+   public int searchStationList (int fd, int mode, int preset_num,
+                                   int dir, int pty )
+   {
+      int re;
+
+
+     /* set search mode. */
+      re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCHMODE, mode);
+      if (re != 0) {
+         return re;
+      }
+
+      /* set number of stations to be returned in the list */
+      re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCH_CNT, preset_num);
+      if (re != 0) {
+         return re;
+      }
+
+      // RDS search list?
+      if (pty > 0 ){
+        re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY, pty);
+      }
+      if (re != 0) {
+         return re;
+      }
+
+      /* This triigers the search and once completed the FM core generates
+       * searchListComplete event */
+      re = FmReceiverJNI.startSearchNative (fd, dir );
+      if (re != 0) {
+         return re;
+      }
+      else {
+         return 0;
+      }
+
+   }
+
+   /* 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,
+                               int dir, int pty, int pi){
+      int re = 0;
+
+
+      Log.d(TAG, "Mode is " + mode + " Dwell is " + dwell);
+      Log.d(TAG, "dir is "  + dir + " PTY is " + pty);
+      Log.d(TAG, "pi is " + pi + " id " +  V4L2_CID_PRIVATE_TAVARUA_SRCHMODE);
+
+
+
+      re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCHMODE, mode);
+      if (re != 0) {
+          Log.e(TAG, "setting of search mode failed");
+          return re;
+      }
+      re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SCANDWELL, dwell);
+      if (re != 0) {
+          Log.e(TAG, "setting of scan dwell time failed");
+          return re;
+      }
+      if (pty != 0)
+      {
+         re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY, pty);
+         if (re != 0) {
+             Log.e(TAG, "setting of PTY failed");
+             return re;
+         }
+      }
+
+      if (pi != 0)
+      {
+         re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCH_PI, pi);
+         if (re != 0) {
+             Log.e(TAG, "setting of PI failed");
+             return re;
+         }
+      }
+
+      re = FmReceiverJNI.startSearchNative (fd, dir );
+      return re;
+   }
+
+   /* force mono/stereo mode */
+   public int stereoControl(int fd, boolean stereo) {
+
+     if (stereo){
+       return  FmReceiverJNI.setMonoStereoNative (fd, 1);
+     }
+     else {
+       return  FmReceiverJNI.setMonoStereoNative (fd, 0);
+     }
+
+
+   }
+
+
+   public void searchRdsStations(int mode,int dwelling,
+                                 int direction, int RdsSrchPty, int RdsSrchPI){
+   }
+
+   /*   public void searchStationList(int listMode,int direction,
+                                 int listMax,int pgmType) {
+   }
+   */
+
+   /* cancel search in progress */
+   public void cancelSearch (int fd){
+      FmReceiverJNI.cancelSearchNative(fd);
+   }
+
+   /* Set LPM. This disables all FM core interrupts */
+   public int setLowPwrMode (int fd, boolean lpmOn){
+
+      int re=0;
+
+      if (lpmOn){
+        re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_LP_MODE, 1);
+      }
+      else {
+        re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_LP_MODE, 0);
+      }
+
+      return re;
+
+   }
+
+   /* get current powermode of the FM core. 1 for LPM and 0 Normal mode */
+   public int getPwrMode (int fd) {
+
+      int re=0;
+
+      re = FmReceiverJNI.getControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_LP_MODE);
+
+      return re;
+
+   }
+
+   public int updateSpurTable(int fd, int freq, int rmssi, boolean enable) {
+
+      int re;
+
+      re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_SPUR_FREQ, freq);
+      if (re < 0) {
+        Log.e(TAG, "Failed to program the Spur frequency value");
+        return re;
+      }
+
+      re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_SPUR_FREQ_RMSSI, rmssi);
+      if (re < 0) {
+        Log.e(TAG, "Failed to program the RMSSI level of the Spur frequency");
+        return re;
+      }
+
+      if (enable) {
+        re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_SPUR_SELECTION, 1);
+      }
+      else {
+        re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_SPUR_SELECTION, 0);
+      }
+      if (re < 0) {
+        Log.e(TAG, "Failed to program Spur selection");
+        return re;
+      }
+
+      return re;
+   }
+
+   public int configureSpurTable(int fd) {
+      return FmReceiverJNI.configureSpurTable(fd);
+   }
+}
diff --git a/qcom/fmradio/FmRxEvCallbacks.java b/qcom/fmradio/FmRxEvCallbacks.java
new file mode 100644
index 0000000..50d2fb2
--- /dev/null
+++ b/qcom/fmradio/FmRxEvCallbacks.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2009,2012 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;
+interface FmRxEvCallbacks {
+
+    public void FmRxEvEnableReceiver();
+    public void FmRxEvDisableReceiver();
+    public void FmRxEvRadioReset();
+    public void FmRxEvRadioTuneStatus(int freq);
+    public void FmRxEvRdsLockStatus(boolean rdsAvail);
+    public void FmRxEvStereoStatus(boolean stereo);
+    public void FmRxEvServiceAvailable(boolean service);
+    public void FmRxEvSearchInProgress();
+    public void FmRxEvSearchCancelled();
+    public void FmRxEvSearchComplete(int freq);
+    public void FmRxEvSearchListComplete();
+    public void FmRxEvRdsGroupData();
+    public void FmRxEvRdsPsInfo();
+    public void FmRxEvRdsRtInfo();
+    public void FmRxEvRdsAfInfo();
+    public void FmRxEvRTPlus();
+    public void FmRxEvERTInfo();
+}
diff --git a/qcom/fmradio/FmRxEvCallbacksAdaptor.java b/qcom/fmradio/FmRxEvCallbacksAdaptor.java
new file mode 100644
index 0000000..458ff59
--- /dev/null
+++ b/qcom/fmradio/FmRxEvCallbacksAdaptor.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2009,2012 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;
+/**
+ *
+ * Class to be implemented for event callbacks
+ * @hide
+ */
+
+public class FmRxEvCallbacksAdaptor implements FmRxEvCallbacks {
+    public void FmRxEvEnableReceiver() {};
+    public void FmRxEvDisableReceiver() {};
+    public void FmRxEvRadioReset() {};
+    public void FmRxEvRadioTuneStatus(int freq) {};
+    public void FmRxEvRdsLockStatus(boolean rdsAvail) {};
+    public void FmRxEvStereoStatus(boolean stereo) {};
+    public void FmRxEvServiceAvailable(boolean service) {};
+    public void FmRxEvSearchInProgress() {};
+    public void FmRxEvSearchCancelled() {};
+    public void FmRxEvSearchComplete(int freq) {};
+    public void FmRxEvSearchListComplete() {};
+    public void FmRxEvRdsGroupData() {};
+    public void FmRxEvRdsPsInfo() {};
+    public void FmRxEvRdsRtInfo() {};
+    public void FmRxEvRdsAfInfo() {};
+    public void FmRxEvRTPlus() {};
+    public void FmRxEvERTInfo() {};
+}
+
diff --git a/qcom/fmradio/FmRxEventListner.java b/qcom/fmradio/FmRxEventListner.java
new file mode 100644
index 0000000..376e430
--- /dev/null
+++ b/qcom/fmradio/FmRxEventListner.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2009,2012, 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();
+                                }
+                                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);
+                                if (freq > 0)
+                                    cb.FmRxEvRadioTuneStatus(freq);
+                                else
+                                    Log.e(TAG, "get frequency command failed");
+                                break;
+                            case 2:
+                                Log.d(TAG, "Got SEEK_COMPLETE_EVENT");
+                                state = FmReceiver.getSearchState();
+                                switch(state) {
+                                   case FmTransceiver.subSrchLevel_SeekInPrg :
+                                   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.FmRxEvSearchCancelled();
+                                      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) {
+                                    /*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();
+                                } else {
+                                    Log.d(TAG, "Unexpected RADIO_DISABLED recvd");
+                                    cb.FmRxEvRadioReset();
+                                }
+                                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;
+                            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/FmRxRdsData.java b/qcom/fmradio/FmRxRdsData.java
new file mode 100644
index 0000000..dac4194
--- /dev/null
+++ b/qcom/fmradio/FmRxRdsData.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2009,2012, 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 android.util.Log;
+/**
+ *
+ * @hide
+ */
+public class FmRxRdsData {
+
+
+    private String mRadioText = "";
+    private String mPrgmServices;
+    private String mERadioText = "";
+    // false means left-right
+    // true means right-left
+    private boolean formatting_dir = false;
+    private byte []mTagCode = new byte[2];
+    private String []mTag = new String[2];
+    private int tag_nums = 0;
+    private static final int MAX_NUM_TAG = 2;
+    private boolean rt_ert_flag;
+    private int mPrgmId;
+    private int mPrgmType;
+    private int mFd;
+
+    /* V4L2 controls */
+    private static final int V4L2_CID_PRIVATE_BASE = 0x8000000;
+    private static final int V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK = V4L2_CID_PRIVATE_BASE + 6;
+    private static final int V4L2_CID_PRIVATE_TAVARUA_RDSON = V4L2_CID_PRIVATE_BASE + 15;
+    private static final int V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC = V4L2_CID_PRIVATE_BASE + 16;
+    private static final int V4L2_CID_PRIVATE_TAVARUA_RDSD_BUF = V4L2_CID_PRIVATE_BASE + 19;
+    private static final int V4L2_CID_PRIVATE_TAVARUA_PSALL = V4L2_CID_PRIVATE_BASE + 20;
+    private static final int V4L2_CID_PRIVATE_TAVARUA_AF_JUMP = V4L2_CID_PRIVATE_BASE + 27;
+
+
+    private static final int RDS_GROUP_RT = 0x1;
+    private static final int RDS_GROUP_PS = 1 << 1;
+    private static final int RDS_GROUP_AF = 1 << 2;
+    private static final int RDS_AF_AUTO  = 1 << 6;
+    private static final int RDS_PS_ALL   = 1 << 4;
+    private static final int RDS_AF_JUMP  = 0x1;
+    private static final int MAX_TAG_CODES = 64;
+
+    private static final String LOGTAG="FmRxRdsData";
+
+
+    public FmRxRdsData (int fd)
+    {
+      mFd = fd;
+    }
+
+    /* turn on/off RDS processing */
+    public int rdsOn (boolean on)
+    {
+
+      int ret;
+
+      Log.d(LOGTAG, "In rdsOn: RDS is " + on);
+
+      if (on) {
+        ret = FmReceiverJNI.setControlNative (mFd, V4L2_CID_PRIVATE_TAVARUA_RDSON, 1);
+      }
+      else {
+        ret = FmReceiverJNI.setControlNative (mFd, V4L2_CID_PRIVATE_TAVARUA_RDSON, 0);
+      }
+
+
+      return ret;
+
+
+    }
+
+    /* process raw RDS group filtering */
+    public int rdsGrpOptions (int grpMask, int buffSize, boolean rdsFilter)
+    {
+
+        int rdsFilt;
+        int re;
+
+        byte rds_group_mask = (byte)FmReceiverJNI.getControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC);
+
+        rds_group_mask &= 0xFE;
+
+
+        if (rdsFilter)
+          rdsFilt = 1;
+        else
+          rdsFilt = 0;
+
+        rds_group_mask |= rdsFilt;
+
+        re = FmReceiverJNI.setControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC, rds_group_mask);
+
+        if (re != 0)
+          return re;
+
+        re = FmReceiverJNI.setControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_RDSD_BUF, buffSize);
+
+        if (re != 0)
+          return re;
+
+
+        re = FmReceiverJNI.setControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK, grpMask);
+
+        return re;
+
+
+    }
+
+    /* configure RT/PS/AF RDS processing */
+    public int rdsOptions (int rdsMask)
+    {
+
+        int re=0;
+
+        byte rds_group_mask = (byte)FmReceiverJNI.getControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC);
+        byte rdsFilt = 0;
+        int  psAllVal=rdsMask & RDS_PS_ALL;
+
+        Log.d(LOGTAG, "In rdsOptions: rdsMask: " + rdsMask);
+
+
+        rds_group_mask &= 0xC7;
+
+
+        rds_group_mask  |= ((rdsMask & 0x07) << 3);
+
+
+        re = FmReceiverJNI.setControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC, rds_group_mask);
+
+        re = FmReceiverJNI.setControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_PSALL, psAllVal >> 4 );
+
+        return re;
+
+    }
+
+    /* Enable auto seek to alternate frequency */
+    public int enableAFjump(boolean AFenable)
+    {
+      int re;
+      int rds_group_mask = 0;
+
+      Log.d(LOGTAG, "In enableAFjump: AFenable : " + AFenable);
+
+      rds_group_mask = FmReceiverJNI.getControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC);
+      Log.d(LOGTAG, "Currently set rds_group_mask : " + rds_group_mask);
+
+      if (AFenable)
+        re = FmReceiverJNI.setControlNative(mFd ,V4L2_CID_PRIVATE_TAVARUA_AF_JUMP, 1);
+      else
+        re = FmReceiverJNI.setControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_AF_JUMP, 0);
+
+      rds_group_mask = FmReceiverJNI.getControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC);
+
+      if (AFenable)
+        Log.d(LOGTAG, "After enabling the rds_group_mask is : " + rds_group_mask);
+      else
+        Log.d(LOGTAG, "After disabling the rds_group_mask is : " + rds_group_mask);
+
+      return re;
+    }
+
+
+    public String getRadioText () {
+        return mRadioText;
+    }
+
+    public void setRadioText (String x) {
+
+        mRadioText = x;
+    }
+
+    public String getPrgmServices () {
+        return mPrgmServices;
+    }
+    public void setPrgmServices (String x) {
+        mPrgmServices = x;
+    }
+
+    public int getPrgmId () {
+        return mPrgmId;
+    }
+    public void setPrgmId (int x) {
+        mPrgmId = x;
+    }
+
+    public int getPrgmType () {
+        return mPrgmType;
+    }
+    public void setPrgmType (int x) {
+         mPrgmType = x;
+    }
+    public String getERadioText () {
+         return mERadioText;
+    }
+    public void setERadioText (String x) {
+         mERadioText = x;
+    }
+    public boolean getFormatDir() {
+         return formatting_dir;
+    }
+    public void setFormatDir(boolean dir) {
+         formatting_dir = dir;
+    }
+    public void setTagValue (String x, int tag_num) {
+        if ((tag_num > 0) && (tag_num <= MAX_NUM_TAG)) {
+            mTag[tag_num - 1] = x;
+            tag_nums++;
+        }
+    }
+    public void setTagCode (byte tag_code, int tag_num) {
+        if ((tag_num > 0) && (tag_num <= MAX_NUM_TAG))
+            mTagCode[tag_num - 1] = tag_code;
+    }
+    public String getTagValue (int tag_num) {
+        if ((tag_num > 0) && (tag_num <= MAX_NUM_TAG))
+            return mTag[tag_num - 1];
+        else
+            return "";
+    }
+    public byte getTagCode (int tag_num) {
+        if ((tag_num > 0) && (tag_num <= MAX_NUM_TAG))
+            return mTagCode[tag_num - 1];
+        else
+            return 0;
+    }
+    public int getTagNums() {
+        return tag_nums;
+    }
+    public void setTagNums(int x) {
+        if ((x >= 0) && (x <= MAX_NUM_TAG))
+            tag_nums = x;
+    }
+}
diff --git a/qcom/fmradio/FmTransceiver.java b/qcom/fmradio/FmTransceiver.java
new file mode 100644
index 0000000..8a02c2d
--- /dev/null
+++ b/qcom/fmradio/FmTransceiver.java
@@ -0,0 +1,644 @@
+/*
+ * Copyright (c) 2009-2012, 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 android.util.Log;
+
+/** <code>FmTransceiver</code> is the superclass of classes
+ * <code>FmReceiver</code> and <code>FmTransmitter</code>
+ * @hide
+ */
+public class FmTransceiver
+{
+   /* Primary FM States :
+    * FM will be in one of the 4 states at any point of time
+    *    '0'  - FMState_Turned_Off
+    *    '1'  - FMState_Rx_Turned_On
+    *    '2'  - FMState_Tx_Turned_On
+    *    '3'  - FMState_Srch_InProg
+   */
+   public static final int FMState_Turned_Off   = 0;
+   public static final int FMState_Rx_Turned_On = 1;
+   public static final int FMState_Tx_Turned_On = 2;
+   public static final int FMState_Srch_InProg  = 3;
+
+   /* Intermediate FM power levels */
+   public static final int subPwrLevel_FMRx_Starting = 4;
+   public static final int subPwrLevel_FMTx_Starting = 5;
+   public static final int subPwrLevel_FMTurning_Off = 6;
+
+   /* Intermediate FM search levels :
+    * These are the sub-levels of FM Search operations : seek/scan/auto-preset.
+    * Used internally for distinguishing between the various search operations.
+   */
+   public static final int subSrchLevel_SeekInPrg      = 0;
+   public static final int subSrchLevel_ScanInProg     = 1;
+   public static final int subSrchLevel_SrchListInProg = 2;
+   public static final int subSrchLevel_SrchComplete   = 3;
+   public static final int subSrchLevel_SrchAbort      = 4;
+
+   /* Holds the current state of the FM device */
+   public static int FMState = FMState_Turned_Off;
+
+   /**
+    * FMConfigure FM Radio band setting for US/Europe
+    */
+   public static final int FM_US_BAND              = 0;
+   /**
+    * FMConfigure FM Radio band setting for US/Europe
+    */
+   public static final int FM_EU_BAND              = 1;
+   /**
+    * FMConfigure FM Radio band setting for Japan
+    */
+   public static final int FM_JAPAN_STANDARD_BAND  = 2;
+   /**
+    * FMConfigure FM Radio band setting for Japan-Wideband
+    */
+   public static final int FM_JAPAN_WIDE_BAND      = 3;
+   /**
+    * FMConfigure FM Radio band setting for "User defined" band
+    */
+   public static final int FM_USER_DEFINED_BAND    = 4;
+
+   /**
+    * FM channel spacing settings = 200KHz
+    */
+   public static final int FM_CHSPACE_200_KHZ  =0;
+   /**
+    * FM channel spacing settings = 100KHz
+    */
+   public static final int FM_CHSPACE_100_KHZ  =1;
+   /**
+    * FM channel spacing settings = 50KHz
+    */
+   public static final int FM_CHSPACE_50_KHZ   =2;
+
+   /**
+    * FM de-emphasis/pre-emphasis settings = 75KHz
+    */
+   public static final int FM_DE_EMP75 = 0;
+   /**
+    * FM de-emphasis/pre-emphasis settings = 50KHz
+    */
+   public static final int FM_DE_EMP50 = 1;
+
+   /**
+    * RDS standard type: RBDS (North America)
+    */
+   public static final int FM_RDS_STD_RBDS    =0;
+   /**
+    * RDS standard type: RDS (Rest of the world)
+    */
+   public static final int FM_RDS_STD_RDS     =1;
+   /**
+    * RDS standard type: No RDS
+    */
+   public static final int FM_RDS_STD_NONE    =2;
+
+   protected static final int FM_RX    =1;
+   protected static final int FM_TX    =2;
+
+   private final int READY_EVENT = 0x01;
+   private final int TUNE_EVENT = 0x02;
+   private final int RDS_EVENT = 0x08;
+   private final int MUTE_EVENT = 0x04;
+   private final int SEEK_COMPLETE_EVENT = 0x03;
+
+   private static final int V4L2_CID_PRIVATE_BASE = 0x8000000;
+   private static final int V4L2_CID_PRIVATE_TAVARUA_ANTENNA   = V4L2_CID_PRIVATE_BASE + 18;
+   private static final int V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK = V4L2_CID_PRIVATE_BASE + 6;
+   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;
+   protected FmTxEventListner mTxEvents;
+
+   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:  registerTransmitClient
+   ==============================================================*/
+   /**
+   *    Registers a callback for FM Transmitter event
+   *    notifications.
+   *    <p>
+   *    This is a synchronous call used to register for event
+   *    notifications from the FM Transmitter 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 Transmitter.
+   *    @return true if Callback registered, false if Callback
+   *            registration failed.
+   *
+   *    @see #acquire
+   *    @see #unregisterTransmitClient
+   *
+   */
+   public boolean registerTransmitClient( FmTransmitterCallbacks callback){
+      boolean bReturnStatus = false;
+      if (callback!=null)
+      {
+         mTxEvents.startListner(sFd, callback);
+         bReturnStatus = true;
+      } else
+      {
+         Log.d(TAG, "Null, do nothing");
+      }
+      return bReturnStatus;
+   }
+
+   /*==============================================================
+   FUNCTION:  unregisterTransmitClient
+   ==============================================================*/
+   /**
+   *    Unregisters Transmitter event notification callback.
+   *    <p>
+   *    This is a synchronous call used to unregister a Transmitter
+   *    client's event callback.
+   *    <p>
+   *    @return true always.
+   *
+   *    @see  #acquire
+   *    @see  #release
+   *    @see  #registerTransmitClient
+   *
+   */
+   public boolean unregisterTransmitClient () {
+      mTxEvents.stopListener();
+      return true;
+   }
+
+   /*==============================================================
+   FUNCTION:  enable
+   ==============================================================*/
+   /**
+   *    Initializes the FM device.
+   *    <p>
+   *    This is a synchronous call is used to initialize the FM
+   *    tranceiver. If already initialized this function will
+   *    intialize the tranceiver with default settings. Only after
+   *    successfully calling this function can many of the FM device
+   *    interfaces be used.
+   *    <p>
+   *    When enabling the receiver, the client must also provide
+   *    the regional settings in which the receiver will operate.
+   *    These settings (included in configSettings) are typically
+   *    used for setting up the FM receiver for operating in a
+   *    particular geographical region. These settings can be
+   *    changed after the FM driver is enabled through the use of
+   *    the function #configure.
+   *    <p>
+   *    This call can only be issued by the owner of an FM
+   *    receiver.  To issue this call, the client must first
+   *    successfully call #acquire.
+   *    <p>
+   *    @param configSettings  the settings to be applied when
+   *                             turning on the radio
+   *    @return true if Initialization succeeded, false if
+   *            Initialization failed.
+   *    @see   #registerClient
+   *    @see   #disable
+   *
+   */
+   public boolean enable (FmConfig configSettings, int device){
+
+      boolean status;
+      //Acquire the deviceon Enable
+      if( !acquire("/dev/radio0")){
+         return false;
+      }
+      Log.d(TAG, "turning on " + device);
+      mControl.fmOn(sFd, device);
+
+      Log.d(TAG, "Calling fmConfigure");
+      status = FmConfig.fmConfigure (sFd, configSettings);
+      if (!status) {
+          Log.d(TAG, "fmConfigure failed");
+          FmReceiverJNI.closeFdNative(sFd);
+          sFd = 0;
+      }
+      return status;
+   }
+
+   /*==============================================================
+   FUNCTION:  disable
+   ==============================================================*/
+   /**
+   *    Disables the FM Device.
+   *    <p>
+   *    This is a synchronous call used to disable the FM
+   *    device. This function is expected to be used when the
+   *    client no longer requires use of the FM device. Once
+   *    called, most functionality offered by the FM device will be
+   *    disabled until the client re-enables the device again via
+   *    #enable.
+   *    <p>
+   *    @return true if disabling succeeded, false if disabling
+   *            failed.
+   *    <p>
+   *    @see   #enable
+   *    @see   #registerClient
+   */
+   public boolean disable(){
+      mControl.fmOff(sFd);
+      return true;
+   }
+
+   /*==============================================================
+   FUNCTION:  configure
+   ==============================================================*/
+   /**
+   *     Reconfigures the device's regional settings
+   *    (FM Band, De-Emphasis, Channel Spacing, RDS/RBDS mode).
+   *    <p>
+   *    This is a synchronous call used to reconfigure settings on
+   *    the FM device. Included in the passed structure are
+   *    settings which typically differ from one geographical
+   *    region to another.
+   *    <p>
+   *    @param configSettings    Contains settings for the FM radio
+   *                             (FM band, De-emphasis, channel
+   *                             spacing, RDS/RBDS mode)
+   *    <p>
+   *    @return      true if configure succeeded, false if
+   *                 configure failed.
+   */
+   public boolean configure(FmConfig configSettings){
+      boolean status=true;
+      int lowerFreq = configSettings.getLowerLimit();
+      Log.d(TAG, "fmConfigure");
+      status = FmConfig.fmConfigure (sFd, configSettings);
+      status = setStation (lowerFreq);
+      return status;
+   }
+
+   /*==============================================================
+   FUNCTION:  setStation
+   ==============================================================*/
+   /**
+    *    Tunes the FM device to the specified FM frequency.
+    *    <p>
+    *    This method tunes the FM device to a station specified by the
+    *    provided frequency. Only valid frequencies within the band
+    *    set by enable or configure can be tuned by this function.
+    *    Attempting to tune to frequencies outside of the set band
+    *    will result in an error.
+    *    <p>
+    *    Once tuning to the specified frequency is completed, the
+    *    event callback FmRxEvRadioTuneStatus will be called.
+    *
+    *    @param frequencyKHz  Frequency (in kHz) to be tuned
+    *                         (Example: 96500 = 96.5Mhz)
+    *   @return true if setStation call was placed successfully,
+    *           false if setStation failed.
+    */
+   public boolean setStation (int frequencyKHz) {
+      int ret;
+
+      mControl.setFreq(frequencyKHz);
+      ret = mControl.setStation(sFd);
+      if(ret < 0 )
+      {
+         return false;
+      }
+      else
+      {
+         return true;
+      }
+   }
+
+   /*==============================================================
+   FUNCTION:  SetNotchFilter
+   ==============================================================*/
+   /**
+    *    Sets the desired notch filter for WAN avoidance.
+    *    <p>
+    *    This method sets the required Notch filter based on the current
+    *    WAN band frequency to achieve the FM-WAN concurrency.
+    *    Application should listen to Data call events and call the function
+    *    on every data call connection set-u, to achieve the FM-WAN concurrency.
+    *
+    */
+   public void setNotchFilter(boolean value) {
+	FmReceiverJNI.setNotchFilterNative(sFd, V4L2_CID_PRIVATE_TAVARUA_SET_NOTCH_FILTER, value);
+   }
+
+   /*==============================================================
+   FUNCTION:  SetAnalogMode
+   ==============================================================*/
+   /**
+    *    Enable/Disable the Analog lowpower mode.
+    *    <p>
+    *    This method enables/disables the analog lowpower mode.
+    *
+    */
+   public boolean setAnalogMode(boolean value) {
+        int re = mControl.setAudioPath(sFd, value);
+        re = FmReceiverJNI.setAnalogModeNative(value);
+        if (re == 1)
+            return true;
+        return false;
+   }
+
+   /*==============================================================
+   FUNCTION:  getInternalAntenna
+   ==============================================================*/
+   /**
+   *    Returns true if internal FM antenna is available
+   *
+   *    <p>
+   *    This method returns true is internal FM antenna is
+   *    available, false otherwise
+   *
+   *    <p>
+   *    @return    true/false
+   */
+   public boolean getInternalAntenna()
+   {
+
+       int re = FmReceiverJNI.getControlNative (sFd, V4L2_CID_PRIVATE_TAVARUA_ANTENNA);
+
+       if (re == 1)
+         return true;
+
+       return false;
+   }
+
+   /*==============================================================
+   FUNCTION:  setInternalAntenna
+   ==============================================================*/
+   /**
+   *    Returns true if successful, false otherwise
+   *
+   *    <p>
+   *    This method sets internal antenna type to true/false
+   *
+   *    @param intAntenna true is Internal antenna is present
+   *
+   *    <p>
+   *    @return    true/false
+   */
+   public boolean setInternalAntenna(boolean intAnt)
+   {
+
+       int iAntenna ;
+
+       if (intAnt)
+          iAntenna = 1;
+       else
+          iAntenna = 0;
+
+
+       int re = FmReceiverJNI.setControlNative (sFd, V4L2_CID_PRIVATE_TAVARUA_ANTENNA, iAntenna);
+
+       if (re == 0)
+         return true;
+
+       return false;
+   }
+/*==============================================================
+   FUNCTION:  setFMPowerState
+   ==============================================================*/
+   /**
+   *    Sets the FM power state
+   *
+   *    <p>
+   *    This method sets the FM power state.
+   *
+   *    <p>
+   */
+   static void setFMPowerState(int state)
+   {
+      FMState = state;
+   }
+/*==============================================================
+   FUNCTION:  getFMPowerState
+   ==============================================================*/
+   /**
+   *    Returns :
+   *
+   *        FMOff        - If the FM Radio is turned off
+   *        FMRxOn       - If the FM Receiver is currently turned on
+   *        FMTxOn       - If the FM Transmitter is currently turned on
+   *        FMReset      - If the FM Radio is reset
+   *
+   *    Gets the FM power state
+   *
+   *    <p>
+   *    This method gets the FM power state.
+   *
+   *    <p>
+   */
+   public static int getFMPowerState()
+   {
+      return FMState;
+   }
+   public static boolean setRDSGrpMask(int mask)
+   {
+      int re;
+      re = FmReceiverJNI.setControlNative(sFd,
+                   V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK, mask);
+      if (re == 0)
+          return true;
+      else
+          return false;
+   }
+}
diff --git a/qcom/fmradio/FmTransmitter.java b/qcom/fmradio/FmTransmitter.java
new file mode 100644
index 0000000..1ae356b
--- /dev/null
+++ b/qcom/fmradio/FmTransmitter.java
@@ -0,0 +1,923 @@
+/*
+ * Copyright (c) 2009-2012, 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 android.util.Log;
+
+
+/**
+ * This class contains all interfaces and types needed to control the FM transmitter.
+ * @hide
+ */
+public class FmTransmitter extends FmTransceiver
+{
+   private final String TAG = "FmTransmitter";
+ /**
+   *  An object that contains the PS Features that SoC supports
+   *
+   *  @see #getPSFeatures
+   */
+    public class FmPSFeatures
+    {
+       public int maxPSCharacters;
+       public int maxPSStringRepeatCount;
+    };
+
+
+  /**
+    *  Command types for the RDS group transmission.
+    *  This is used as argument to #transmitRdsGroupControl to
+    *  control the RDS group transmission.
+    *
+    *  @see #transmitRdsGroupControl
+    */
+
+   public static final int RDS_GRPS_TX_PAUSE    =  0;           /* Pauses the Group transmission*/
+
+   public static final int RDS_GRPS_TX_RESUME   =  1;          /* Resumes the Group transmission*/
+
+   public static final int RDS_GRPS_TX_STOP     =  2;        /* Stops and clear the Group transmission */
+
+   public static final int FM_TX_MAX_PS_LEN           =  (96+1);
+   public static final int FM_TX_MAX_RT_LEN           =  (64-1); /*One space to include NULL*/
+
+   private static final int MAX_PS_CHARS = 97;
+   private static final int MAX_PS_REP_COUNT = 15;
+   private static final int MAX_RDS_GROUP_BUF_SIZE = 62;
+
+   private FmTransmitterCallbacksAdaptor mTxCallbacks;
+   private boolean mPSStarted = false;
+   private boolean mRTStarted = false;
+   private static final int V4L2_CID_PRIVATE_BASE = 0x8000000;
+   private static final int V4L2_CID_PRIVATE_TAVARUA_ANTENNA   = V4L2_CID_PRIVATE_BASE + 18;
+
+   /**
+    * Power settings
+    *
+    * @see #setPowerMode
+    * @see #getPowerMode
+    */
+   public static final int FM_TX_NORMAL_POWER_MODE   =0;
+   public static final int FM_TX_LOW_POWER_MODE      =1;
+
+   /**
+    * Transmit Power level settings
+    *
+    * @see #setTxPowerLevel
+    */
+   public static final int FM_TX_PWR_LEVEL_0   =0;
+   public static final int FM_TX_PWR_LEVEL_1   =1;
+   public static final int FM_TX_PWR_LEVEL_2   =2;
+   public static final int FM_TX_PWR_LEVEL_3   =3;
+   public static final int FM_TX_PWR_LEVEL_4   =4;
+   public static final int FM_TX_PWR_LEVEL_5   =5;
+   public static final int FM_TX_PWR_LEVEL_6   =6;
+   public static final int FM_TX_PWR_LEVEL_7   =7;
+
+
+   /**
+    *  Constructor for the transmitter class that takes path to
+    *  radio device and event callback adapter
+    */
+   public FmTransmitter(String path, FmTransmitterCallbacksAdaptor callbacks) throws InstantiationException{
+
+       mTxEvents = new FmTxEventListner();
+       mControl = new FmRxControls();
+       mTxCallbacks = callbacks;
+   }
+
+   /*==============================================================
+   FUNCTION:  enable
+   ==============================================================*/
+   /**
+    *  Enables the FM device in Transmit Mode.
+    *  <p>
+    *  This is a synchronous method used to initialize the FM
+    *  device in transmitt mode. If already initialized this function will
+    *  intialize the Fm device with default settings. Only after
+    *  successfully calling this function can many of the FM device
+    *  interfaces be used.
+    *  <p>
+    *  When enabling the transmitter, the application must also
+    *  provide the regional settings in which the transmitter will
+    *  operate. These settings (included in argument
+    *  configSettings) are typically used for setting up the FM
+    *  Transmitter for operating in a particular geographical
+    *  region. These settings can be changed after the FM driver
+    *  is enabled through the use of the function {@link
+    *  #configure}.
+    *  <p>
+    *  This command can only be issued by the owner of an FM
+    *  transmitter.
+    *
+    *  @param configSettings  the settings to be applied when
+    *                           turning on the radio
+    *  @return true if Initialization succeeded, false if
+    *          Initialization failed.
+    *  <p>
+    *  @see #enable
+    *  @see #registerTransmitClient
+    *  @see #disable
+    *
+    */
+   public boolean enable (FmConfig configSettings){
+      boolean status = true;
+
+      int state = getFMState();
+      if (state == FMState_Tx_Turned_On) {
+          Log.d(TAG, "enable: FM Tx already turned On and running");
+          return status;
+      } else if (state == subPwrLevel_FMTurning_Off) {
+          Log.v(TAG, "FM is in the process of turning off.Pls wait for sometime.");
+          return status;
+      } else if(state == subPwrLevel_FMTx_Starting) {
+          Log.v(TAG, "FM is in the process of turning On.Pls wait for sometime.");
+          return status;
+      }
+      setFMPowerState(subPwrLevel_FMTx_Starting);
+      Log.v(TAG, "enable: CURRENT-STATE : FMOff ---> NEW-STATE : FMTxStarting");
+      status = super.enable(configSettings, FmTransceiver.FM_TX);
+      if(status == true) {
+         registerTransmitClient(mTxCallbacks);
+         mRdsData = new FmRxRdsData(sFd);
+      } else {
+         status = false;
+         Log.e(TAG, "enable: failed to turn On FM TX");
+         Log.e(TAG, "enable: CURRENT-STATE : FMTxStarting ---> NEW-STATE : FMOff");
+         setFMPowerState(FMState_Turned_Off);
+      }
+      return status;
+   }
+   /*==============================================================
+   FUNCTION:  setRdsOn
+   ==============================================================*/
+   /**
+   *
+   *    This function enables RDSCTRL register for SoC.
+   *
+   *    <p>
+   *    This API enables the ability of the FM driver
+   *    to send Program Service, RadioText  information.
+   *
+   *
+   *    @return true if the command was placed successfully, false
+   *            if command failed.
+   *
+   */
+   public boolean setRdsOn (){
+
+      if (mRdsData == null)
+         return false;
+      // Enable RDS
+      int re = mRdsData.rdsOn(true);
+
+      if (re ==0)
+        return true;
+
+      return false;
+   }
+
+   /*==============================================================
+   FUNCTION:  disable
+   ==============================================================*/
+   /**
+    *  Disables the FM Transmitter Device.
+    *  <p>
+    *  This is a synchronous command used to disable the FM
+    *  device. This function is expected to be used when the
+    *  application no longer requires use of the FM device. Once
+    *  called, most functionality offered by the FM device will be
+    *  disabled until the application re-enables the device again
+    *  via {@link #enable}.
+    *
+    *  <p>
+    *  @return true if disabling succeeded, false if disabling
+    *          failed.
+    *
+    *  @see #enable
+    *  @see #registerTransmitClient
+    */
+   public boolean disable(){
+      boolean status = false;
+      int state;
+
+      state = getFMState();
+      switch(state) {
+         case FMState_Turned_Off:
+              Log.d(TAG, "FM already tuned Off.");
+              return true;
+         case subPwrLevel_FMTx_Starting:
+              /*
+               * If, FM is in the process of turning On, then wait for
+               * the turn on operation to complete before turning off.
+               */
+              Log.d(TAG, "disable: FM not yet turned On...");
+              try {
+                   Thread.sleep(100);
+              } catch (InterruptedException e) {
+                   e.printStackTrace();
+              }
+              /* Check for the state of FM device */
+              state = getFMState();
+              if(state == subPwrLevel_FMTx_Starting) {
+                 Log.e(TAG, "disable: FM in bad state");
+                 return status;
+              }
+              break;
+         case subPwrLevel_FMTurning_Off:
+              /*
+               * If, FM is in the process of turning Off, then wait for
+               * the turn off operation to complete.
+               */
+              Log.v(TAG, "disable: FM is getting turned Off.");
+              return status;
+      }
+      setFMPowerState(subPwrLevel_FMTurning_Off);
+      Log.v(TAG, "disable: CURRENT-STATE : FMTxOn ---> NEW-STATE : FMTurningOff");
+      //Stop all the RDS transmissions if there any
+      if(mPSStarted) {
+         if(!stopPSInfo()) {
+            Log.d(TAG, "FmTrasmitter:stopPSInfo failed\n");
+         }
+      }
+      if(mRTStarted) {
+        if(!stopRTInfo()) {
+           Log.d(TAG, "FmTrasmitter:stopRTInfo failed\n");
+        }
+      }
+      if(!transmitRdsGroupControl(RDS_GRPS_TX_STOP) ) {
+         Log.d(TAG, "FmTrasmitter:transmitRdsGroupControl failed\n");
+      }
+      super.disable();
+      return true;
+   }
+
+   /*==============================================================
+   FUNCTION:  reset
+   ==============================================================*/
+   /**
+   *    Reset the FM Device.
+   *    <p>
+   *    This is a synchronous command used to reset the state of FM
+   *    device in case of unrecoverable error. This function is
+   *    expected to be used when the client receives unexpected
+   *    notification of radio disabled. Once called, most
+   *    functionality offered by the FM device will be disabled
+   *    until the client re-enables the device again via
+   *    {@link #enable}.
+   *    <p>
+   *    @return true if reset succeeded, false if reset failed.
+   *    @see #enable
+   *    @see #disable
+   *    @see #registerTransmitClient
+   */
+   public boolean reset(){
+      boolean status = false;
+
+      status = unregisterTransmitClient();
+      return status;
+   }
+
+  /*==============================================================
+   FUNCTION:  setStation
+   ==============================================================*/
+   /**
+    *    Tunes the FM device to the specified FM frequency.
+    *    <p>
+    *    This method tunes the FM device to a station specified by the
+    *    provided frequency. Only valid frequencies within the band
+    *    set by enable or configure can be tuned by this function.
+    *    Attempting to tune to frequencies outside of the set band
+    *    will result in an error.
+    *    <p>
+    *    Once tuning to the specified frequency is completed, the
+    *    event callback FmTransmitterCallbacks::onTuneStatusChange will be called.
+    *
+    *    @param frequencyKHz  Frequency (in kHz) to be tuned
+    *                         (Example: 96500 = 96.5Mhz)
+    *   @return true if setStation call was placed successfully,
+    *           false if setStation failed.
+    */
+   public boolean setStation (int frequencyKHz) {
+
+      //Stop  If there is any ongoing RDS transmissions
+      boolean status = false;
+      if( mPSStarted ){
+          Log.d(TAG,"FmTransmitter:setStation mPSStarted");
+         if( !stopPSInfo() ) return status;
+      }
+      if( mRTStarted ) {
+          Log.d(TAG,"FmTransmitter:setStation mRTStarted");
+        if(!stopRTInfo()) return status;
+      }
+      if(!transmitRdsGroupControl(RDS_GRPS_TX_STOP) )return status;
+
+      Log.d(TAG, "FmTrasmitter:SetStation\n");
+      status = super.setStation(frequencyKHz);
+
+      return status;
+   }
+   /*==============================================================
+   FUNCTION:  setPowerMode
+   ==============================================================*/
+   /**
+   *    Puts the driver into or out of low power mode.
+   *
+   *    <p>
+   *    This is an synchronous command which can put the FM
+   *    device and driver into and out of low power mode. Low power mode
+   *    should be used when the receiver is tuned to a station and only
+   *    the FM audio is required. The typical scenario for low power mode
+   *    is when the FM application is no longer visible.
+   *
+   *    <p>
+   *    While in low power mode, all normal FM and RDS indications from
+   *    the FM driver will be suppressed. By disabling these indications,
+   *    low power mode can result in fewer interruptions and this may lead
+   *    to a power savings.
+   *
+   *    <p>
+   *    @param powerMode the new driver operating mode.
+   *
+   *    @return true if setPowerMode succeeded, false if
+   *            setPowerMode failed.
+   */
+   public boolean setPowerMode(int powerMode){
+
+      int re;
+
+      if (powerMode == FM_TX_LOW_POWER_MODE) {
+        re = mControl.setLowPwrMode (sFd, true);
+      }
+      else {
+        re = mControl.setLowPwrMode (sFd, false);
+      }
+
+      if (re == 0)
+         return true;
+      return false;
+   }
+
+
+   /*==============================================================
+   FUNCTION:  getPSFeatures
+   ==============================================================*/
+   /**
+    *  This function returns the features supported by the FM
+    *  driver when using {@link #setPSInfo}.
+    *  <p>
+    *  This function is used to get the features the FM driver
+    *  supports when transmitting Program Service information.
+    *  Included in the returned features is the number of Program
+    *  Service (PS) characters which can be transmitted using
+    *  {@link #setPSInfo}. If the driver supports continuous
+    *  transmission of Program Service Information, this function
+    *  will return a value greater than 0 for
+    *  FmPSFeatures.maxPSCharacters. Although the RDS/RBDS
+    *  standard defines each Program Service (PS) string as eight
+    *  characters in length, the FM driver may have the ability to
+    *  accept a string that is greater than eight character. This
+    *  extended string will thenbe broken up into multiple strings
+    *  of length eight and transmitted continuously.
+    *  <p>
+    *  When transmitting more than one string, the application may
+    *  want to control the timing of how long each string is
+    *  transmitted. Included in the features returned from this
+    *  function is the maximum Program Service string repeat count
+    *  (FmPSFeatures.maxPSStringRepeatCount). When using the
+    *  function {@link #setPSInfo}, the application can specify how
+    *  many times each string is repeated before the next string is
+    *  transmitted.
+    *
+    *  @return the Program service maximum characters and repeat
+    *          count
+    *
+    *  @see #setPSInfo
+    *
+    */
+   public FmPSFeatures getPSFeatures(){
+      FmPSFeatures psFeatures = new FmPSFeatures();
+
+      psFeatures.maxPSCharacters = MAX_PS_CHARS;
+      psFeatures.maxPSStringRepeatCount = MAX_PS_REP_COUNT;
+      return psFeatures;
+   }
+
+   /*==============================================================
+   FUNCTION:  startPSInfo
+   ==============================================================*/
+   /**
+    *  Continuously transmit RDS/RBDS Program Service information
+    *  over an already tuned station.
+    *  <p>
+    *  This is a synchronous function used to continuously transmit Program
+    *  Service information over an already tuned station. While
+    *  Program Service information can be transmitted using {@link
+    *  #transmitRdsGroups} and 0A/0B groups, this function makes
+    *  the same output possible with limited input needed from the
+    *  application.
+    *  <p>
+    *  Included in the Program Service information is an RDS/RBDS
+    *  program type (PTY), and one or more Program Service
+    *  strings. The program type (PTY) is used to describe the
+    *  content being transmitted and follows the RDS/RBDS program
+    *  types described in the RDS/RBDS specifications.
+    *  <p>
+    *  Program Service information also includes an eight
+    *  character string. This string can be used to display any
+    *  information, but is typically used to display information
+    *  about the audio being transmitted. Although the RDS/RBDS
+    *  standard defines a Program Service (PS) string as eight
+    *  characters in length, the FM driver may have the ability to
+    *  accept a string that is greater than eight characters. This
+    *  extended string will then be broken up into multiple eight
+    *  character strings which will be transmitted continuously.
+    *  All strings passed to this function must be terminated by a
+    *  null character (0x00).
+    *  <p>
+    *  When transmitting more than one string, the application may
+    *  want to control the timing of how long each string is
+    *  transmitted. To control this timing and to ensure that the FM
+    *  receiver receives each string, the application can specify
+    *  how many times each string is repeated before the next string
+    *  is transmitted. This command can only be issued by the owner
+    *  of an FM transmitter.
+    *  <p>
+    *  Maximux Programme service string lenght that can be sent is
+    *  FM_TX_MAX_PS_LEN. If the application sends PS string longer than
+    *  this threshold, string will be truncated to FM_TX_MAX_PS_LEN.
+    *
+    *  @param psStr the program service strings to transmit
+    *  @param pty   the program type to use in the program Service
+    *               information.
+    *  @param pi    the program type to use in the program Service
+    *               information.
+    *  @param repeatCount the number of times each 8 char string is
+    *                     repeated before next string
+    *
+    *  @return true if PS information was successfully sent to the
+    *             driver, false if PS information could not be sent
+    *             to the driver.
+    *
+    *  @see #getPSFeatures
+    *  @see #stopPSInfo
+    */
+   public boolean startPSInfo(String psStr, int pty, int pi, int repeatCount){
+
+       //Set the PTY
+       if((pty < 0) || (pty > 31 )) {
+           Log.d(TAG,"pTy is expected from 0 to 31");
+           return false;
+       }
+
+       int err = FmReceiverJNI.setPTYNative( sFd, pty );
+       if( err < 0 ){
+           Log.d(TAG,"setPTYNative is failure");
+          return false;
+       }
+
+       if((pi < 0) || (pi > 65535)) {
+           Log.d(TAG,"pi is expected from 0 to 65535");
+           return false;
+       }
+
+       //Set the PI
+       err = FmReceiverJNI.setPINative( sFd, pi );
+       if( err < 0 ){
+           Log.d(TAG,"setPINative is failure");
+          return false;
+       }
+
+       if((repeatCount < 0) || (repeatCount > 15)) {
+           Log.d(TAG,"repeat count is expected from 0 to 15");
+           return false;
+       }
+
+       err = FmReceiverJNI.setPSRepeatCountNative( sFd, repeatCount );
+       if( err < 0 ){
+           Log.d(TAG,"setPSRepeatCountNative is failure");
+          return false;
+       }
+
+       if( psStr.length() > FM_TX_MAX_PS_LEN ){
+          /*truncate the PS string to
+          MAX possible length*/
+          psStr = psStr.substring( 0, FM_TX_MAX_PS_LEN );
+
+       }
+
+       err = FmReceiverJNI.startPSNative( sFd, psStr , psStr.length() );
+       Log.d(TAG,"return for startPS is "+err);
+
+       if( err < 0 ){
+           Log.d(TAG, "FmReceiverJNI.startPSNative returned false\n");
+           return false;
+
+       }   else {
+           Log.d(TAG,"startPSNative is successful");
+          mPSStarted = true;
+          return true;
+       }
+   }
+
+   /*==============================================================
+   FUNCTION:  stopPSInfo
+   ==============================================================*/
+   /**
+    *  Stops an active Program Service transmission.
+    *
+    *  <p>
+    *  This is a synchrnous function used to stop an active Program Service transmission
+    *  started by {@link #startPSInfo}.
+    *
+    *  @return true if Stop PS information was successfully sent to
+    *             the driver, false if Stop PS information could not
+    *             be sent to the driver.
+    *
+    *  @see #getPSFeatures
+    *  @see #startPSInfo
+    *
+    */
+   public boolean stopPSInfo(){
+       int err =0;
+       if( (err =FmReceiverJNI.stopPSNative( sFd )) < 0  ){
+           Log.d(TAG,"return for startPS is "+err);
+          return false;
+       }    else{
+           Log.d(TAG,"stopPSNative is successful");
+          mPSStarted = false;
+          return true;
+       }
+   }
+
+
+   /*==============================================================
+   FUNCTION:  startRTInfo
+   ==============================================================*/
+   /**
+    *  Continuously transmit RDS/RBDS RadioText information over an
+    *  already tuned station.
+    *
+    *  <p>
+    *  This is a synchronous function used to continuously transmit RadioText
+    *  information over an already tuned station. While RadioText
+    *  information can be transmitted using
+    *  {@link #transmitRdsGroups} and 2A/2B groups, this function
+    *  makes the same output possible with limited input needed from
+    *  the application.
+    *  <p>
+    *  Included in the RadioText information is an RDS/RBDS program type (PTY),
+    *  and a single string of up to 64 characters. The program type (PTY) is used
+    *  to describe the content being transmitted and follows the RDS/RBDS program
+    *  types described in the RDS/RBDS specifications.
+    *  <p>
+    *  RadioText information also includes a string that consists of up to 64
+    *  characters. This string can be used to display any information, but is
+    *  typically used to display information about the audio being transmitted.
+    *  This RadioText string is expected to be at 64 characters in length, or less
+    *  than 64 characters and terminated by a return carriage (0x0D). All strings
+    *  passed to this function must be terminated by a null character (0x00).
+    *  <p>
+    *  <p>
+    *  Maximux Radio Text string length that can be sent is
+    *  FM_TX_MAX_RT_LEN. If the application sends RT string longer than
+    *  this threshold, string will be truncated to FM_TX_MAX_RT_LEN.
+    *
+    *  @param rtStr the Radio Text string to transmit
+    *  @param pty the program type to use in the Radio text
+    *             transmissions.
+    *  @param pi the program identifier to use in the Radio text
+    *             transmissions.
+    *
+    *  @return true if RT information String was successfully sent
+    *             to the driver, false if RT information string
+    *             could not be sent to the driver.
+    *
+    *  @see #stopRTInfo
+    */
+   public boolean startRTInfo(String rtStr, int pty, int pi){
+
+       if((pty < 0) || (pty > 31 )) {
+           Log.d(TAG,"pTy is expected from 0 to 31");
+           return false;
+       }
+       //Set the PTY
+       int err = FmReceiverJNI.setPTYNative( sFd, pty );
+       if( err < 0 ){
+           Log.d(TAG,"setPTYNative is failure");
+          return false;
+       }
+
+       if((pi < 0) || (pi > 65535)) {
+           Log.d(TAG,"pi is expected from 0 to 65535");
+           return false;
+       }
+
+       err = FmReceiverJNI.setPINative( sFd, pi );
+       if( err < 0 ){
+           Log.d(TAG,"setPINative is failure");
+          return false;
+       }
+
+
+       if( rtStr.length() > FM_TX_MAX_RT_LEN )
+       {
+          //truncate it to max length
+          rtStr = rtStr.substring( 0, FM_TX_MAX_RT_LEN );
+       }
+
+       err = FmReceiverJNI.startRTNative( sFd, rtStr, rtStr.length() );
+
+       if( err < 0 ){
+          Log.d(TAG, "FmReceiverJNI.startRTNative returned false\n");
+          return false;
+       }   else {
+           Log.d(TAG,"mRTStarted is true");
+          mRTStarted = true;
+          return true;
+       }
+   }
+
+   /*==============================================================
+   FUNCTION:  stopRTInfo
+   ==============================================================*/
+   /**
+    *  Stops an active Radio Text information transmission.
+    *
+    *  <p>
+    *  This is a synchrnous function used to stop an active Radio Text
+    *  transmission started by {@link #startRTInfo}.
+    *
+    *  @return true if Stop RT information was successfully sent to
+    *             the driver, false if Stop RT information could not
+    *             be sent to the driver.
+    *
+    *  @see #startRTInfo
+    *
+    */
+   public boolean stopRTInfo(){
+
+      if( FmReceiverJNI.stopRTNative( sFd ) < 0  ){
+          Log.d(TAG,"stopRTNative is failure");
+          return false;
+       }    else{
+           Log.d(TAG,"mRTStarted is false");
+          mRTStarted = false;
+          return true;
+       }
+   }
+
+  /*==============================================================
+   FUNCTION:  getRdsGroupBufSize
+   ==============================================================*/
+   /**
+    *  Get the maximum number of RDS/RBDS groups which can be passed
+    *  to the FM driver.
+    *  <p>
+    *  This is a function used to determine the maximum RDS/RBDS
+    *  buffer size for use when calling {@link #transmitRdsGroups}
+    *
+    *  @return the maximum number of RDS/RBDS groups which can be
+    *  passed to the FM driver at any one time.
+    *
+    */
+   public int getRdsGroupBufSize(){
+
+   return MAX_RDS_GROUP_BUF_SIZE;
+   }
+
+
+   /*==============================================================
+   FUNCTION:  transmitRdsGroups
+   ==============================================================*/
+   /**
+    *  This function will transmit RDS/RBDS groups
+    *  over an already tuned station.
+    *  This is an asynchronous function used to transmit RDS/RBDS
+    *  groups over an already tuned station. This functionality is
+    *  is currently unsupported.
+    *  <p>
+    *  This function accepts a buffer (rdsGroups) containing one or
+    *  more RDS groups. When sending this buffer, the application
+    *  must also indicate how many groups should be taken from this
+    *  buffer (numGroupsToTransmit). It may be possible that the FM
+    *  driver can not accept the number of group contained in the
+    *  buffer and will indicate how many group were actually
+    *  accepted through the return value.
+    *
+    *  <p>
+    *  The FM driver will indicate to the application when it is
+    *  ready to accept more data via both the
+    *  "onRDSGroupsAvailable()" and "onRDSGroupsComplete()" events
+    *  callbacks. The "onRDSGroupsAvailable()" callback will
+    *  indicate to the application that the FM driver can accept
+    *  additional groups even though all groups may not have been
+    *  passed to the FM transmitter. The onRDSGroupsComplete()
+    *  callback will indicate when the FM driver has a complete
+    *  buffer to transmit RDS data. In many cases all data passed to
+    *  the FM driver will be passed to the FM hardware and only a
+    *  onRDSGroupsComplete() event will be generated by the
+    *  FM driver.
+    *  <p> If the application attempts to send more groups than the
+    *  FM driver can handle, the application must wait until it
+    *  receives a onRDSGroupsAvailable or a onRDSGroupsComplete
+    *  event before attempting to transmit more groups. Failure to
+    *  do so may result in no group being consumed by the FM driver.
+    *  <p> It is important to note that switching between continuous
+    *  and non-continuous transmission of RDS groups can only happen
+    *  when no RDS/RBDS group transmission is underway. If an
+    *  RDS/RBDS group transmission is already underway, the
+    *  application must wait for a onRDSGroupsComplete. If the application
+    *  wishes to switch from continuous to non-continuous (or
+    *  vice-versa) without waiting for the current transmission to
+    *  complete, the application can clear all remaining groups
+    *  using the {@link #transmitRdsGroupControl} command.
+    *  <p>
+    *  Once completed, this command will generate a
+    *  onRDSGroupsComplete event to all registered applications.
+    *
+    *  @param rdsGroups The RDS/RBDS groups buffer to transmit.
+    *  @param numGroupsToTransmit The number of groups in the buffer
+    *                             to transmit.
+    *
+    *  @return The number of groups the FM driver actually accepted.
+    *          A value >0 indicates the command was successfully
+    *          accepted and a return value of "-1" indicates error.
+    *
+    *  @see #transmitRdsGroupControl
+    */
+
+   public int transmitRdsGroups(byte[] rdsGroups, long numGroupsToTransmit){
+      /*
+       * This functionality is currently unsupported
+       */
+
+    return -1;
+   }
+   /*==============================================================
+   FUNCTION:  transmitContRdsGroups
+   ==============================================================*/
+   /**
+    *  This function will continuously transmit RDS/RBDS groups over an already tuned station.
+    *  <p>
+    *  This is an asynchronous function used to continuously
+    *  transmit RDS/RBDS groups over an already tuned station.
+    *  This functionality is currently unsupported.
+    *  <p>
+    *  This function accepts a buffer (rdsGroups) containing one or
+    *  more RDS groups. When sending this buffer, the application
+    *  must also indicate how many groups should be taken from this
+    *  buffer (numGroupsToTransmit). It may be possible that the FM
+    *  driver can not accept the number of group contained in the
+    *  buffer and will indicate how many group were actually
+    *  accepted through the return value.
+    *
+    *  <p>
+    *  Application can send a complete RDS group buffer for the transmission.
+    *  This data will be sent continuously to the driver. Only single RDS
+    *  group can be continuously transmitter at a time. So, application has to
+    *  send the complete RDS buffer it intends to transmit. trying to pass the
+    *  single buffer in two calls will be interprted as two different RDS/RBDS
+    *  groups and hence all the unset groups will be cleared.
+    *  <p>
+    *  As continuous RDS/RBDS group transmission is done over single buffer,
+    *  Application has to wait for the "onContRDSGroupsComplete()" callback
+    *  to initiate the further RDS/RBDS group transmissions. Failure to
+    *  do so may result in no group being consumed by the FM driver.
+    *  <p> It is important to note that switching between continuous
+    *  and non-continuous transmission of RDS groups can only happen
+    *  when no RDS/RBDS group transmission is underway. If an
+    *  RDS/RBDS group transmission is already underway, the
+    *  application must wait for a onRDSGroupsComplete or onContRDSGroupsComplete.
+    *   If the application wishes to switch from continuous to non-continuous (or
+    *  vice-versa) without waiting for the current transmission to
+    *  complete, the application can clear all remaining groups
+    *  using the {@link #transmitRdsGroupControl} command.
+    *  <p>
+    *  Once completed, this command will generate a
+    *  onRDSContGroupsComplete event to all registered applications.
+    *
+    *  @param rdsGroups The RDS/RBDS groups buffer to transmit.
+    *  @param numGroupsToTransmit The number of groups in the buffer
+    *                             to transmit.
+    *
+    *  @return The number of groups the FM driver actually accepted.
+    *          A value >0 indicates the command was successfully
+    *          accepted and a return value of "-1" indicates error.
+    *
+    *  @see #transmitRdsGroupControl
+    */
+
+   public int transmitRdsContGroups(byte[] rdsGroups, long numGroupsToTransmit){
+      /*
+       * This functionality is currently unsupported.
+       */
+     return -1;
+   }
+
+   /*==============================================================
+   FUNCTION:  transmitRdsGroupControl
+   ==============================================================*/
+   /**
+    *  Pause/Resume RDS/RBDS group transmission, or stop and clear
+    *  all RDS groups.
+    *  <p>
+    *  This is a function used to pause/resume RDS/RBDS
+    *  group transmission, or stop and clear all RDS groups. This
+    *  function can be used to control continuous and
+    *  non-continuous RDS/RBDS group transmissions. This functionality
+    *  is currently unsupported.
+    *  <p>
+    *  @param ctrlCmd The Tx RDS group control.This should be one of the
+    *                 contants RDS_GRPS_TX_PAUSE/RDS_GRPS_TX_RESUME/RDS_GRPS_TX_STOP
+    *
+    *  @return true if RDS Group Control command was
+    *             successfully sent to the driver, false if RDS
+    *             Group Control command could not be sent to the
+    *             driver.
+    *
+    *  @see #rdsGroupControlCmdType
+    *  @see #transmitRdsGroups
+    */
+   public boolean transmitRdsGroupControl(int ctrlCmd){
+      boolean bStatus = true;
+      /*
+       * This functionality is currently unsupported.
+       */
+      int val = 0;
+      switch( ctrlCmd ) {
+         case RDS_GRPS_TX_PAUSE:break;
+         case RDS_GRPS_TX_RESUME:break;
+         case RDS_GRPS_TX_STOP:break;
+         default:
+                /*Shouldn't reach here*/
+         bStatus = false;
+      }
+      return bStatus;
+   }
+
+   /*==============================================================
+   FUNCTION:  setTxPowerLevel
+   ==============================================================*/
+   /**
+    *  Sets the transmitter power level.
+    *
+    *  <p>
+    *  This is a function used for setting the power level of
+    *  Tx device.
+    *  <p>
+    *  @param powLevel The Tx power level value to be set. The value should be
+    *                  in range 0-7.If input is -ve level will be set to 0
+    *                  and if it is above 7 level will be set to max i.e.,7.
+    *
+    *  @return true on success, false on failure.
+    *
+    */
+   public boolean setTxPowerLevel(int powLevel){
+      boolean bStatus = true;
+       int err = FmReceiverJNI.setTxPowerLevelNative( sFd, powLevel );
+       if( err < 0 ){
+           Log.d(TAG,"setTxPowerLevel is failure");
+          return false;
+      }
+      return bStatus;
+   }
+
+   /*
+    * getFMState() returns:
+    *     '0' if FM State  is OFF
+    *     '1' if FM Rx     is On
+    *     '2' if FM Tx     is On
+    *     '3' if FM device is Searching
+    */
+   public int getFMState() {
+      /* Current State of FM device */
+      int currFMState = FmTransceiver.getFMPowerState();
+      return currFMState;
+   }
+};
diff --git a/qcom/fmradio/FmTransmitterCallbacks.java b/qcom/fmradio/FmTransmitterCallbacks.java
new file mode 100644
index 0000000..a868c29
--- /dev/null
+++ b/qcom/fmradio/FmTransmitterCallbacks.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2011-2012, 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;
+   /** @hide
+    *  The interface that provides the applications to get callback
+    *  for asynchronous events.
+    *  An Adapter that implements this interface needs to be used to
+    *  register to receive the callbacks using {@link
+    *  #FmTransmitter}.
+    *  <p>
+    *  Application has to register for these callbacks by sending
+    *  a valid instance of TransmitterCallbacks's adapter while
+    *  instantiating the FMTransmitter.
+    *
+    *  @see #FmTransmitter
+    */
+   public interface FmTransmitterCallbacks
+   {
+      /**
+       *  The callback indicates that the transmitter is tuned to a
+       *  new frequency Typically received after setStation.
+       */
+      public void FmTxEvTuneStatusChange(int freq);
+
+      /**
+       * The callback to indicate to the application that the FM
+       * driver can accept additional groups even though all groups
+       * may not have been passed to the FM transmitter.
+       *
+       * Application can start to send down the remaining groups
+       * to the available group buffers upon recieving this callback.
+       */
+      public void FmTxEvRDSGroupsAvailable();
+      /**
+       * The callback will indicate the succesful completion of #transmitRdsGroups.
+       * This indicates that the FM driver has a complete buffer to transmit the
+       * RDS/RBDS data to the Application. Application can free to switch between continuous or
+       * non-continuous RDS/RBDS group transmissions.
+       */
+      public void FmTxEvRDSGroupsComplete();
+     /**
+       * The callback will indicate the succesful completion of #transmitRdsContGroups.
+       * This indicates that the FM driver has a complete buffer to transmit the
+       * RDS/RBDS data to the Application. Application can free to switch between continuous or
+       * non-continuous RDS/RBDS group transmissions.
+       *
+       */
+      public void FmTxEvContRDSGroupsComplete();
+     /**
+       * The callback indicates that Radio has been Disabled.
+       * This indicates that the FM driver has disabled the radio.
+       *
+       */
+      public void FmTxEvRadioDisabled();
+     /**
+       * The callback indicates that Radio has been Enabled.
+       * This indicates that the FM driver has Enabled the radio.
+       *
+       */
+      public void FmTxEvRadioEnabled();
+     /**
+       * The callback indicates that Radio has been Reset.
+       * This indicates that the FM driver has reset the radio.
+       *
+       */
+      public void FmTxEvRadioReset();
+   };
diff --git a/qcom/fmradio/FmTransmitterCallbacksAdaptor.java b/qcom/fmradio/FmTransmitterCallbacksAdaptor.java
new file mode 100644
index 0000000..8e30bd5
--- /dev/null
+++ b/qcom/fmradio/FmTransmitterCallbacksAdaptor.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2011-2012, 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;
+    /**
+    * @hide
+    * Class to be implemented for Tx events callbacks
+    *
+    */
+   public class FmTransmitterCallbacksAdaptor implements FmTransmitterCallbacks
+   {
+      public void FmTxEvTuneStatusChange(int freq) {};
+      public void FmTxEvRDSGroupsAvailable() {};
+      public void FmTxEvRDSGroupsComplete() {};
+      public void FmTxEvContRDSGroupsComplete() {};
+      public void FmTxEvRadioDisabled() {};
+      public void FmTxEvRadioEnabled() {};
+      public void FmTxEvRadioReset() {};
+   };
+
diff --git a/qcom/fmradio/FmTxEventListner.java b/qcom/fmradio/FmTxEventListner.java
new file mode 100644
index 0000000..998ef30
--- /dev/null
+++ b/qcom/fmradio/FmTxEventListner.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2011,2012, 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 android.util.Log;
+import qcom.fmradio.FmTransceiver;
+
+class FmTxEventListner {
+
+
+    private final int EVENT_LISTEN  = 1;
+
+    private final int TUNE_EVENT = 1;                   /*Tune completion event*/
+    private final int TXRDSDAT_EVENT = 16;               /*RDS Group available event*/
+    private final int TXRDSDONE_EVENT = 17;              /*RDS group complete event */
+    private final int RADIO_DISABLED = 18;
+    private final int READY_EVENT = 0;
+    private byte []buff = new byte[128];
+    private Thread mThread;
+    private static final String TAG = "FMTxEventListner";
+
+    public void startListner (final int fd, final FmTransmitterCallbacks cb) {
+        /* start a thread and listen for messages */
+        mThread = new Thread(){
+            public void run(){
+
+                Log.d(TAG, "Starting Tx Event listener " + fd);
+
+                while((!Thread.currentThread().isInterrupted())) {
+                   try {
+                        int index = 0;
+                        int freq = 0;
+                        Log.d(TAG, "getBufferNative called");
+                        int eventCount = FmReceiverJNI.getBufferNative
+                                                       (fd, buff, EVENT_LISTEN);
+                        Log.d(TAG, "Received event. Count: " + eventCount);
+
+                        for(index = 0; index < eventCount; index++) {
+                            Log.d(TAG, "Received <" +buff[index]+ ">" );
+                            switch(buff[index]){
+                                case READY_EVENT:
+                                   Log.d(TAG, "Got RADIO_ENABLED");
+                                   if(FmTransceiver.getFMPowerState() ==
+                                       FmTransceiver.subPwrLevel_FMTx_Starting) {
+                                      /*Set the state as FMRxOn */
+                                      FmTransceiver.setFMPowerState
+                                         (FmTransceiver.FMState_Tx_Turned_On);
+                                      Log.v(TAG, "TxEvtList: CURRENT-STATE:" +
+                                            "FMTxStarting ---> NEW-STATE : FMTxOn");
+                                      cb.FmTxEvRadioEnabled();
+                                   }
+                                   break;
+                                case TUNE_EVENT:
+                                   Log.d(TAG, "Got TUNE_EVENT");
+                                   freq = FmReceiverJNI.getFreqNative(fd);
+                                   if (freq > 0)
+                                       cb.FmTxEvTuneStatusChange(freq);
+                                   else
+                                       Log.e(TAG, "get frqency cmd failed");
+                                   break;
+                                case TXRDSDAT_EVENT:
+                                   Log.d(TAG, "Got TXRDSDAT_EVENT");
+                                   cb.FmTxEvRDSGroupsAvailable();
+                                   break;
+                                case TXRDSDONE_EVENT:
+                                   Log.d(TAG, "Got TXRDSDONE_EVENT");
+                                   cb.FmTxEvContRDSGroupsComplete();
+                                   break;
+                                case RADIO_DISABLED:
+                                   Log.d(TAG, "Got RADIO_DISABLED");
+                                   if(FmTransceiver.getFMPowerState() ==
+                                      FmTransceiver.subPwrLevel_FMTurning_Off) {
+                                      /*Set the state as FMOff */
+                                      FmTransceiver.setFMPowerState
+                                            (FmTransceiver.FMState_Turned_Off);
+                                      Log.v(TAG, "TxEvtList:CURRENT-STATE :" +
+                                            "FMTurningOff ---> NEW-STATE: FMOff");
+                                      FmTransceiver.release("/dev/radio0");
+                                      cb.FmTxEvRadioDisabled();
+                                      Thread.currentThread().interrupt();
+                                   } else {
+                                      Log.d(TAG, "Unexpected RADIO_DISABLED recvd");
+                                      cb.FmTxEvRadioReset();
+                                   }
+                                   break;
+                                default:
+                                   Log.d(TAG, "Unknown event");
+                                   break;
+                            }//switch
+                        }//for
+                      }catch (Exception ex) {
+                        Log.d( TAG,  "RunningThread InterruptedException");
+                        Thread.currentThread().interrupt();
+                      }//try
+               }//while
+               Log.d(TAG, "Came out of the while loop");
+          }
+        };
+        mThread.start();
+    }
+
+    public void stopListener(){
+        Log.d(TAG, "Thread Stopped\n");
+        //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();
+        }
+        Log.d(TAG, "Thread Stopped\n");
+    }
+}