From 1c2c4355c22213cd1dffdda725e8b3e66fc4074a Mon Sep 17 00:00:00 2001
From: Venkateshwarlu Domakonda <vdomak@codeaurora.org>
Date: Mon, 26 May 2014 14:35:12 +0530
Subject: [PATCH] fm: Added support for configuring performance parameters

Add apis to configure fm performance related parameters.

CRs-Fixed: 671803
Change-Id: I37565c21a731023e42372be71fb28edc30154672
---
 jni/Android.mk                     |   6 +-
 jni/ConfFileParser.cpp             | 917 +++++++++++++++++++++++++++++
 jni/ConfFileParser.h               |  82 +++
 jni/ConfigFmThs.cpp                | 526 +++++++++++++++++
 jni/ConfigFmThs.h                  | 159 +++++
 jni/FmConst.h                      | 149 +++++
 jni/FmIoctlsInterface.cpp          | 320 ++++++++++
 jni/FmIoctlsInterface.h            |  60 ++
 jni/FmPerformanceParams.cpp        | 422 +++++++++++++
 jni/FmPerformanceParams.h          |  65 ++
 jni/android_hardware_fm.cpp        | 557 +++++++++++-------
 qcom/fmradio/FmReceiverJNI.java    |   1 +
 qcom/fmradio/FmRxEventListner.java |   3 +-
 13 files changed, 3041 insertions(+), 226 deletions(-)
 create mode 100644 jni/ConfFileParser.cpp
 create mode 100644 jni/ConfFileParser.h
 create mode 100644 jni/ConfigFmThs.cpp
 create mode 100644 jni/ConfigFmThs.h
 create mode 100644 jni/FmConst.h
 create mode 100644 jni/FmIoctlsInterface.cpp
 create mode 100644 jni/FmIoctlsInterface.h
 create mode 100644 jni/FmPerformanceParams.cpp
 create mode 100644 jni/FmPerformanceParams.h

diff --git a/jni/Android.mk b/jni/Android.mk
index c3b3a42..d253498 100644
--- a/jni/Android.mk
+++ b/jni/Android.mk
@@ -3,7 +3,11 @@ LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-android_hardware_fm.cpp
+android_hardware_fm.cpp \
+ConfFileParser.cpp \
+ConfigFmThs.cpp \
+FmIoctlsInterface.cpp \
+FmPerformanceParams.cpp
 
 LOCAL_SHARED_LIBRARIES := \
         libnativehelper \
diff --git a/jni/ConfFileParser.cpp b/jni/ConfFileParser.cpp
new file mode 100644
index 0000000..103c240
--- /dev/null
+++ b/jni/ConfFileParser.cpp
@@ -0,0 +1,917 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *        * Redistributions of source code must retain the above copyright
+ *            notice, this list of conditions and the following disclaimer.
+ *        * Redistributions in binary form must reproduce the above copyright
+ *            notice, this list of conditions and the following disclaimer in the
+ *            documentation and/or other materials provided with the distribution.
+ *        * Neither the name of The Linux Foundation nor
+ *            the names of its contributors may be used to endorse or promote
+ *            products derived from this software without specific prior written
+ *            permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED.    IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ConfFileParser.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <math.h>
+#include <utils/Log.h>
+
+//declaration of functions only specific to this file
+static char parse_line
+(
+  group_table *key_file,
+  const char *line,
+  char **cur_grp
+);
+
+static char parse_load_frm_fhandler
+(
+  group_table *key_file,
+  FILE *fp
+);
+
+static char line_is_grp
+(
+  group_table *key_file,
+  const char *str,
+  char **cur_grp
+);
+
+static void free_grp_list
+(
+  group *a
+);
+
+static void free_key_list
+(
+  key_value_pair_list *a
+);
+
+static char line_is_key_value_pair
+(
+  group_table *key_file,
+  const char *str,
+  const char *cur_grp
+);
+
+static char line_is_comment
+(
+  const char *str
+);
+
+static char grp_exist
+(
+  const group_table *key_file,
+  const char *new_grp
+);
+
+static char add_grp
+(
+  group_table *key_file,
+  const char *new_grp
+);
+
+static group *alloc_group
+(
+  void
+);
+
+static key_value_pair_list *alloc_key_value_pair
+(
+  void
+);
+
+static char add_key_value_pair
+(
+  group_table *key_file,
+  const char *cur_grp,
+  const char *key,
+  const char *val
+);
+
+
+//Definitions
+void free_strs
+(
+  char **str_array
+)
+{
+  char **str_array_cpy = str_array;
+  if(str_array != NULL) {
+     while(*str_array != NULL) {
+           free(*str_array);
+           str_array++;
+     }
+  }
+  free(str_array_cpy);
+}
+//ToDo: Come up with code hashing
+//function
+unsigned int get_hash_code
+(
+  const char *str
+)
+{
+
+  unsigned len = strlen(str);
+  unsigned int i;
+  unsigned int hash_code = 0;
+
+  for(i = 0; len > 0; len--, i++) {
+      hash_code += (int)((str[i] * pow(2, len))) % INT_MAX;
+      hash_code %= INT_MAX;
+  }
+  return hash_code;
+}
+
+static key_value_pair_list *alloc_key_value_pair
+(
+  void
+)
+{
+  key_value_pair_list *key_list = NULL;
+
+  key_list = (key_value_pair_list *)malloc(
+                                       sizeof(key_value_pair_list));
+  if(key_list != NULL) {
+     key_list->key = NULL;
+     key_list->next = NULL;
+     key_list->value = NULL;
+  }
+  return key_list;
+}
+
+static group * alloc_group
+(
+  void
+)
+{
+  group *grp = NULL;
+  unsigned int i;
+
+  grp = (group *)malloc(sizeof(group));
+  if(grp != NULL) {
+     grp->grp_name = NULL;
+     grp->grp_next = NULL;
+     grp->num_of_keys = 0;
+     grp->keys_hash_size = MAX_UNIQ_KEYS;
+     grp->list = (key_value_pair_list **)malloc
+                    (sizeof(key_value_pair_list *) * grp->keys_hash_size);
+     if(grp->list == NULL) {
+        ALOGE("Could not alloc group\n");
+        free(grp);
+        grp = NULL;
+     }else {
+        for(i = 0; i < grp->keys_hash_size; i++) {
+            grp->list[i] = NULL;
+        }
+     }
+  }
+  return grp;
+}
+
+group_table *get_key_file
+(
+)
+{
+  group_table *t = NULL;
+  unsigned int i;
+
+  t = (group_table *)malloc(sizeof(group_table));
+  if (t != NULL) {
+      t->grps_hash_size = MAX_UNIQ_GRPS;
+      t->num_of_grps = 0;
+      t->grps_hash = (group **)malloc(sizeof(group *)
+                                       * t->grps_hash_size);
+      if (t->grps_hash == NULL) {
+          free(t);
+          return NULL;
+      }
+      for(i = 0; i < t->grps_hash_size; i++) {
+          t->grps_hash[i] = NULL;
+      }
+  }
+  return t;
+}
+
+void free_key_file(
+  group_table *key_file
+)
+{
+  unsigned int i;
+
+  if(key_file != NULL) {
+     if(key_file->grps_hash != NULL) {
+        for(i = 0; i < key_file->grps_hash_size; i++) {
+            free_grp_list(key_file->grps_hash[i]);
+        }
+     }
+     free(key_file->grps_hash);
+     free(key_file);
+  }
+}
+
+static void free_grp_list
+(
+  group *a
+)
+{
+  group *next;
+  unsigned int i;
+
+  while(a != NULL) {
+       next = a->grp_next;
+       if(a->list != NULL) {
+          for(i = 0; i < a->keys_hash_size; i++) {
+              free_key_list(a->list[i]);
+          }
+       }
+       free(a->grp_name);
+       free(a->list);
+       free(a);
+       a = next;
+  }
+}
+
+static void free_key_list
+(
+  key_value_pair_list *a
+)
+{
+  key_value_pair_list *next;
+
+  while(a != NULL) {
+       next = a->next;
+       free(a->key);
+       free(a->value);
+       free(a);
+       a = next;
+  }
+}
+//return all the groups
+//present in the file
+char **get_grps
+(
+  const group_table *key_file
+)
+{
+  char **grps = NULL;
+  unsigned int i = 0;
+  unsigned int j = 0;
+  unsigned int grp_len;
+  group *grp_list;
+
+  if((key_file == NULL)
+     || (key_file->grps_hash == NULL)
+     || (key_file->grps_hash_size == 0)
+     || (key_file->num_of_grps == 0)) {
+     return grps;
+  }
+  grps = (char **)calloc((key_file->num_of_grps + 1),
+                           sizeof(char *));
+  if(grps == NULL) {
+     return grps;
+  }
+  for(i = 0; i < key_file->grps_hash_size; i++) {
+      grp_list = key_file->grps_hash[i];
+      while(grp_list != NULL) {
+            grp_len = strlen(grp_list->grp_name);
+            grps[j] = (char *)malloc(sizeof(char) *
+                                     (grp_len + 1));
+            if(grps[j] == NULL) {
+               free_strs(grps);
+               grps = NULL;
+               return grps;
+            }
+            memcpy(grps[j], grp_list->grp_name,
+                   (grp_len + 1));
+            grp_list = grp_list->grp_next;
+            j++;
+      }
+  }
+  grps[j] = NULL;
+  return grps;
+}
+
+//returns the list of keys
+//associated with group name
+char **get_keys
+(
+  const group_table *key_file,
+  const char *grp_name
+)
+{
+  unsigned int grp_hash_code;
+  unsigned int grp_index;
+  unsigned int num_of_keys;
+  unsigned int i;
+  unsigned int j = 0;
+  unsigned int key_len;
+  group *grp;
+  key_value_pair_list *key_val_list;
+  char **keys = NULL;
+
+  if((key_file == NULL) || (grp_name == NULL)
+     || (key_file->num_of_grps == 0) ||
+     (key_file->grps_hash_size == 0) ||
+     (key_file->grps_hash == NULL) ||
+     (!strcmp(grp_name, ""))) {
+      return keys;
+  }
+  grp_hash_code = get_hash_code(grp_name);
+  grp_index = (grp_hash_code % key_file->grps_hash_size);
+  grp = key_file->grps_hash[grp_index];
+  while(grp != NULL) {
+        if(!strcmp(grp_name, grp->grp_name)) {
+            if((grp->num_of_keys == 0)
+               || (grp->keys_hash_size == 0)
+               || (grp->list == 0)) {
+               return keys;
+            }
+            keys = (char **)calloc((grp->num_of_keys + 1),
+                                   sizeof(char *));
+            if(keys == NULL) {
+                return keys;
+            }
+            for(i = 0; i < grp->keys_hash_size; i++) {
+                key_val_list = grp->list[i];
+                while(key_val_list != NULL) {
+                     key_len = strlen(key_val_list->key);
+                     keys[j] = (char *)malloc(sizeof(char) *
+                                              (key_len + 1));
+                     if(keys[j] == NULL) {
+                         free_strs(keys);
+                         keys = NULL;
+                         return keys;
+                     }
+                     memcpy(keys[j], key_val_list->key,
+                            (key_len + 1));
+                     j++;
+                     key_val_list = key_val_list->next;
+                }
+            }
+            keys[j] = NULL;
+            return keys;
+        }
+        grp = grp->grp_next;
+  }
+  return keys;
+}
+
+char *get_value
+(
+   const group_table *key_file,
+   const char *grp_name,
+   const char *key
+)
+{
+   unsigned int grp_hash_code;
+   unsigned int key_hash_code;
+   unsigned int grp_index;
+   unsigned int key_index;
+   unsigned val_len;
+   char *val = NULL;
+   group *grp;
+   key_value_pair_list *list;
+
+   if((key_file == NULL) || (grp_name == NULL)
+      || (key == NULL) || (key_file->grps_hash == NULL)
+      || (key_file->grps_hash_size == 0) || !strcmp(grp_name, "")
+      ||(!strcmp(key, ""))) {
+       return NULL;
+   }
+   grp_hash_code = get_hash_code(grp_name);
+   key_hash_code = get_hash_code(key);
+   grp_index = (grp_hash_code % key_file->grps_hash_size);
+   grp = key_file->grps_hash[grp_index];
+   while(grp != NULL) {
+         if(!strcmp(grp_name, grp->grp_name) && grp->keys_hash_size
+            && grp->list) {
+            key_index = (key_hash_code % grp->keys_hash_size);
+            list = grp->list[key_index];
+            while((list != NULL) && (strcmp(list->key, key))) {
+                   list = list->next;
+            }
+            if(list != NULL) {
+                val_len = strlen(list->value);
+                val = (char *)malloc(sizeof(char) * (val_len + 1));
+                if(val != NULL) {
+                   memcpy(val, list->value, val_len);
+                   val[val_len] = '\0';
+                }
+            }
+            return val;
+         }
+         grp = grp->grp_next;
+   }
+   return val;
+}
+//open the file,
+//read, parse and load
+//returns PARSE_SUCCESS if successfully
+//loaded else PARSE_FAILED
+char parse_load_file
+(
+  group_table *key_file,
+  const char *file
+)
+{
+  FILE *fp;
+  char ret = FALSE;
+
+  if((file == NULL) || !strcmp(file, "")) {
+     ALOGE("File name is null or empty \n");
+     return ret;
+  }
+
+  fp = fopen(file, "r");
+  if(fp == NULL) {
+     ALOGE("could not open file for read\n");
+     return ret;
+  }
+
+  ret = parse_load_frm_fhandler(key_file, fp);
+  fclose(fp);
+
+  return ret;
+}
+
+//Read block of data from file handler
+//extract each line, check kind of line(comment,
+//group, key value pair)
+static char parse_load_frm_fhandler
+(
+  group_table *key_file,
+  FILE *fp
+)
+{
+  char buf[MAX_LINE_LEN];
+  char ret = TRUE;
+  char *line = NULL;
+  void *new_line;
+  char *cur_grp = NULL;
+  unsigned line_len = 0;
+  unsigned line_allocated = 0;
+  unsigned int bytes_read = 0;
+  unsigned int i;
+  bool has_carriage_rtn = false;
+
+  while((bytes_read = fread(buf, 1, MAX_LINE_LEN, fp))) {
+        for(i = 0; i < bytes_read; i++) {
+            if(line_len == line_allocated) {
+                line_allocated += 25;
+                new_line = realloc(line, line_allocated);
+                if(new_line == NULL) {
+                   ret = FALSE;
+                   ALOGE("memory allocation failed for line\n");
+                   break;
+                }
+                line = (char *)new_line;
+            }
+            if((buf[i] == '\n')) {
+                has_carriage_rtn = false;
+                line[line_len] = '\0';
+                ret = parse_line(key_file, line, &cur_grp);
+                line_len = 0;
+                if(ret == FALSE) {
+                   ALOGE("could not parse the line, line not proper\n");
+                   break;
+                }
+            }else if(buf[i] == '\r') {
+                ALOGE("File has carriage return\n");
+                has_carriage_rtn = true;
+            }else if(has_carriage_rtn) {
+                ALOGE("File format is not proper, no line character\
+                        after carraige return\n");
+                ret = FALSE;
+                break;
+            }else {
+                line[line_len] = buf[i];
+                line_len++;
+            }
+        }
+        if (!ret) {
+            break;
+        }
+  }
+  free(line);
+  free(cur_grp);
+
+  return ret;
+}
+
+//checks whether a line is
+//comment or grp or key pair value
+//and accordingly adds to list
+static char parse_line
+(
+  group_table *key_file,
+  const char *line,
+  char **cur_grp
+)
+{
+  const char *line_begin;
+  char *grp_name;
+  unsigned int len;
+
+  if((line == NULL) || (key_file == NULL)) {
+      ALOGE("key file or line is null\n");
+      return FALSE;
+  }
+
+  for(line_begin = line; isspace(*line_begin);
+          line_begin++);
+
+  if(line_is_comment(line_begin)) {
+      ALOGE("line is comment\n");
+      return TRUE;
+  }else if(line_is_grp(key_file, line_begin, cur_grp)) {
+      ALOGE("line is grp\n");
+      return TRUE;
+  }else if(line_is_key_value_pair(key_file, line_begin, *cur_grp)) {
+      ALOGE("line is key value pair\n");
+      return TRUE;
+  }else {
+     ALOGE("line is neither comment, grp nor key value pair\n");
+     return FALSE;
+  }
+}
+
+static char line_is_comment
+(
+  const char *str
+)
+{
+  if(str == NULL) {
+      return FALSE;
+  }else if(((*str) == '#') || ((*str) == '\0')
+       || ((*str) == '\n')) {
+      return TRUE;
+  }else {
+      ALOGE("line is not comment\n");
+      return FALSE;
+  }
+}
+
+//return true if a group
+//name already exist
+//else false
+static char grp_exist
+(
+  const group_table *key_file,
+  const char *new_grp
+)
+{
+  unsigned hash_code;
+  unsigned int index;
+  group *grp;
+
+  if((key_file == NULL) || (new_grp == NULL)
+     || (!key_file->grps_hash_size)) {
+     return FALSE;
+  }else {
+    hash_code = get_hash_code(new_grp);
+    index = hash_code % key_file->grps_hash_size;
+    grp = key_file->grps_hash[index];
+    while(grp != NULL) {
+          if (!strcmp(grp->grp_name, new_grp))
+              return TRUE;
+          grp = grp->grp_next;
+    }
+    return FALSE;
+  }
+}
+
+//Add a group to group
+//table if it does not exist
+static char add_grp
+(
+  group_table *key_file,
+  const char *new_grp
+)
+{
+  unsigned int hash_code;
+  unsigned int index;
+  unsigned int grp_name_len;
+  group *grp;
+
+  if(!grp_exist(key_file, new_grp)) {
+      if((key_file == NULL) || (new_grp == NULL)
+         || !key_file->grps_hash_size) {
+         return FALSE;
+      }
+      hash_code = get_hash_code(new_grp);
+      ALOGE("group hash code is: %u\n", hash_code);
+      index = hash_code % key_file->grps_hash_size;
+      ALOGE("group index is: %u\n", index);
+      grp = alloc_group();
+      if(grp == NULL) {
+         return FALSE;
+      }
+      grp_name_len = strlen(new_grp);
+      grp->grp_name = (char *)malloc(
+                                  sizeof(char) * (grp_name_len + 1));
+      if(grp->grp_name == NULL) {
+         ALOGE("could not alloc memory for group name\n");
+         ALOGE("Add group failed\n");
+         free_grp_list(grp);
+         return FALSE;
+      }else {
+         memcpy(grp->grp_name, new_grp, (grp_name_len + 1));
+      }
+      grp->grp_next = key_file->grps_hash[index];
+      key_file->grps_hash[index] = grp;
+      key_file->num_of_grps++;
+      return TRUE;
+  }else {
+     return FALSE;
+  }
+}
+
+//checks validity of a group
+//a valid group is
+//inside [] group name must be
+//alphanumeric
+//Example: [grpName]
+static char line_is_grp
+(
+  group_table *key_file,
+  const char *str,
+  char **cur_grp
+)
+{
+  const char *g_start;
+  const char *g_end;
+  char *new_grp;
+  unsigned int grp_len;
+
+  if ((str == NULL) || (key_file == NULL)) {
+      ALOGE("str is null or key file is null\n");
+      return FALSE;
+  }
+  //checks start mark char ']'
+  if(((*str) != '[')) {
+      ALOGE("start mark is not '['\n");
+      return FALSE;
+  }else {
+      str++;
+      g_start = str;
+  }
+  //checks the end char '['
+  while((*str != '\0') && ((*str) != ']')) {
+        str++;
+  }
+  //if end mark group not found
+  if ((*str) != ']') {
+       ALOGE("grp end mark is not '['\n");
+       return FALSE;
+  }else {
+       g_end = (str - 1);
+  }
+
+  str++;
+  //if end mark found checks the rest chars as well
+  //rest chars should be space
+  while(((*str) == ' ') || ((*str) == '\t')) {
+        str++;
+  }
+  if(*str) {
+     ALOGE("after ']' there are some character\n");
+     return FALSE;
+  }
+
+  str = g_start;
+  while((*g_start != '\0') && (g_start != g_end)
+         && isalnum(*g_start)) {
+        g_start++;
+  }
+  if((g_start == g_end) && isalnum(*g_start)) {
+      //look up if already exist
+      //return false else insert the grp in grp table
+      grp_len = (g_end - str + 1);
+      new_grp = (char *)malloc(sizeof(char) * (grp_len + 1));
+      if (new_grp == NULL) {
+          ALOGE("could not alloc memory for new group\n");
+          return FALSE;
+      }
+      memcpy(new_grp, str, grp_len);
+      new_grp[grp_len] = '\0';
+
+      if(add_grp(key_file, new_grp)) {
+          free(*cur_grp);
+         *cur_grp = new_grp;
+         return TRUE;
+      }else {
+         ALOGE("could not add group to group table\n");
+         return FALSE;
+      }
+  }else {
+      return FALSE;
+  }
+}
+
+static char key_exist
+(
+  const group_table *key_file,
+  const char *cur_grp,
+  const char *key
+)
+{
+  unsigned int grp_hash_code;
+  unsigned int key_hash_code;
+  unsigned int grp_index;
+  unsigned int key_index;
+  group *grp = NULL;
+  key_value_pair_list *list = NULL;
+
+  if((key_file != NULL) && (cur_grp != NULL)
+      && (key != NULL) && ((key_file->grps_hash != NULL))
+      && (strcmp(key, ""))) {
+     grp_hash_code = get_hash_code(cur_grp);
+     grp_index = (grp_hash_code % key_file->grps_hash_size);
+     grp = key_file->grps_hash[grp_index];
+     key_hash_code = get_hash_code(key);
+     while((grp != NULL)) {
+           if(!strcmp(cur_grp, grp->grp_name)) {
+              key_index = (key_hash_code % grp->keys_hash_size);
+              if(!grp->list)
+                 list = grp->list[key_index];
+              while((list != NULL) && strcmp(key, list->key)) {
+                    list = list->next;
+              }
+              if(list != NULL){
+                  return TRUE;
+              }else{
+                  return FALSE;
+              }
+           }
+           grp = grp->grp_next;
+     }
+     if(!grp) {
+        return TRUE;
+     }else {
+        return FALSE;
+     }
+  }else {
+     return FALSE;
+  }
+}
+
+//checks validity of key
+//a valid key must start in
+//a seperate line and key must
+//be alphanumeric and before '='
+//there must not be any space
+//Example: key=value
+static char line_is_key_value_pair
+(
+  group_table *key_file,
+  const char *str,
+  const char *cur_grp
+)
+{
+  char *equal_start;
+  char *key;
+  char *val;
+  unsigned key_len;
+  unsigned val_len;
+
+  if((str == NULL) || (cur_grp == NULL) ||
+     !strcmp(cur_grp, "") || (key_file == NULL)) {
+     ALOGE("line is null or cur group or key file is null or empty\n");
+     return FALSE;
+  }
+  equal_start = strchr(str, '=');
+  key_len = (equal_start - str);
+  if((equal_start == NULL) || (equal_start == str)) {
+     ALOGE("line does not have '=' character or no key\n");
+     return FALSE;
+  }
+  while((str != equal_start) && isalnum(*str))
+        str++;
+  if((str == equal_start)) {
+      key = (char *)malloc(sizeof(char) * (key_len + 1));
+      if(key == NULL) {
+         ALOGE("could not alloc memory for new key\n");
+         return FALSE;
+      }
+      equal_start++;
+      val_len = strlen(equal_start);
+      val = (char *)malloc(sizeof(char) * (val_len + 1));
+      if(val == NULL) {
+         ALOGE("could not alloc memory for value\n");
+         return FALSE;
+      }
+      memcpy(key, (str - key_len), key_len);
+      memcpy(val, equal_start, val_len);
+      key[key_len] = '\0';
+      val[val_len] = '\0';
+      ALOGE("Grp: %s, key: %s, value: %s\n", cur_grp, key, val);
+      return add_key_value_pair(key_file,
+                                 cur_grp, key, val);
+  }else {
+     ALOGE("key name doesnot have alpha numeric char\n");
+     return FALSE;
+  }
+}
+
+static char add_key_value_pair
+(
+  group_table *key_file,
+  const char *cur_grp,
+  const char *key,
+  const char *val
+)
+{
+  unsigned int grp_hash_code;
+  unsigned int key_hash_code;
+  unsigned int grp_index;
+  unsigned int key_index;
+  unsigned key_len, val_len;
+  group *grp = NULL;
+  key_value_pair_list *list = NULL;
+
+  if((key_file != NULL) && (cur_grp != NULL)
+      && (key != NULL) && ((key_file->grps_hash != NULL))
+      && (strcmp(key, ""))) {
+     grp_hash_code = get_hash_code(cur_grp);
+     ALOGE("grp hash code is %u\n", grp_hash_code);
+     grp_index = (grp_hash_code % key_file->grps_hash_size);
+     ALOGE("grp index is %u\n", grp_index);
+     grp = key_file->grps_hash[grp_index];
+     key_hash_code = get_hash_code(key);
+     while((grp != NULL)) {
+           if(!strcmp(cur_grp, grp->grp_name)) {
+              key_index = (key_hash_code % grp->keys_hash_size);
+              if(grp->list) {
+                 list = grp->list[key_index];
+              }else {
+                 ALOGE("group list is null\n");
+                 return FALSE;
+              }
+              while((list != NULL) && strcmp(key, list->key)) {
+                    list = list->next;
+              }
+              if(list != NULL) {
+                  ALOGE("group already contains the key\n");
+                  return FALSE;
+              }else{
+                  list = alloc_key_value_pair();
+                  if(list == NULL) {
+                     ALOGE("add key value failed as could not alloc memory for key\
+                            val pair\n");
+                     return FALSE;
+                  }
+                  key_len = strlen(key);
+                  list->key = (char *)malloc(sizeof(char) *
+                                              (key_len + 1));
+                  if(list->key == NULL) {
+                     ALOGE("could not alloc memory for key\n");
+                     free(list);
+                     return FALSE;
+                  }
+                  val_len = strlen(val);
+                  list->value = (char *)malloc(sizeof(char) *
+                                                (val_len + 1));
+                  if(!list->value) {
+                      free(list->key);
+                      free(list);
+                      return FALSE;
+                  }
+                  memcpy(list->key, key, key_len);
+                  memcpy(list->value, val, val_len);
+                  list->key[key_len] = '\0';
+                  list->value[val_len] = '\0';
+                  list->next = grp->list[key_index];
+                  grp->list[key_index] = list;
+                  grp->num_of_keys++;
+                  return TRUE;
+              }
+           }
+           grp = grp->grp_next;
+     }
+     ALOGE("group does not exist\n");
+     return FALSE;
+  }else {
+     return FALSE;
+  }
+}
diff --git a/jni/ConfFileParser.h b/jni/ConfFileParser.h
new file mode 100644
index 0000000..33b86ce
--- /dev/null
+++ b/jni/ConfFileParser.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *        * Redistributions of source code must retain the above copyright
+ *            notice, this list of conditions and the following disclaimer.
+ *        * Redistributions in binary form must reproduce the above copyright
+ *            notice, this list of conditions and the following disclaimer in the
+ *            documentation and/or other materials provided with the distribution.
+ *        * Neither the name of The Linux Foundation nor
+ *            the names of its contributors may be used to endorse or promote
+ *            products derived from this software without specific prior written
+ *            permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED.    IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef __CONF_FILE_PARSER_H__
+#define __CONF_FILE_PARSER_H__
+
+#define MAX_LINE_LEN 512
+#define MAX_UNIQ_KEYS 5
+#define MAX_UNIQ_GRPS 10
+#define TRUE 1
+#define FALSE 0
+
+struct key_value_pair_list
+{
+   char *key;
+   char *value;
+   key_value_pair_list *next;
+};
+
+struct group
+{
+    char *grp_name;
+    unsigned int num_of_keys;
+    unsigned int keys_hash_size;
+    key_value_pair_list **list;
+    group *grp_next;
+};
+
+struct group_table
+{
+    unsigned int grps_hash_size;
+    unsigned int num_of_grps;
+    group **grps_hash;
+};
+
+enum CONF_PARSE_ERRO_CODE
+{
+  PARSE_SUCCESS,
+  INVALID_FILE_NAME,
+  FILE_OPEN_FAILED,
+  FILE_NOT_PROPER,
+  MEMORY_ALLOC_FAILED,
+  PARSE_FAILED,
+};
+
+unsigned int get_hash_code(const char *str);
+group_table *get_key_file();
+void free_strs(char **str_array);
+void free_key_file(group_table *key_file);
+char parse_load_file(group_table *key_file, const char *file);
+char **get_grps(const group_table *key_file);
+char **get_keys(const group_table *key_file, const char *grp);
+char *get_value(const group_table *key_file, const char *grp,
+                 const char *key);
+
+#endif //__CONF_FILE_PARSER_H__
diff --git a/jni/ConfigFmThs.cpp b/jni/ConfigFmThs.cpp
new file mode 100644
index 0000000..09529c5
--- /dev/null
+++ b/jni/ConfigFmThs.cpp
@@ -0,0 +1,526 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *        * Redistributions of source code must retain the above copyright
+ *            notice, this list of conditions and the following disclaimer.
+ *        * Redistributions in binary form must reproduce the above copyright
+ *            notice, this list of conditions and the following disclaimer in the
+ *            documentation and/or other materials provided with the distribution.
+ *        * Neither the name of The Linux Foundation nor
+ *            the names of its contributors may be used to endorse or promote
+ *            products derived from this software without specific prior written
+ *            permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED.    IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <cstdlib>
+#include <cstring>
+#include "ConfigFmThs.h"
+#include "FmPerformanceParams.h"
+#include <utils/Log.h>
+
+static int compare_name
+(
+   const void *name1, const void *name2
+)
+{
+    char *first = (char *)name1;
+    struct NAME_MAP *second = (struct NAME_MAP *)name2;
+
+    return(strcmp(first, second->name));
+}
+
+ConfigFmThs :: ConfigFmThs
+(
+)
+{
+    keyfile = NULL;
+}
+
+ConfigFmThs :: ~ConfigFmThs
+(
+)
+{
+   free_key_file(keyfile);
+}
+
+void ConfigFmThs :: set_af_ths
+(
+   UINT fd
+)
+{
+    signed char ret = FM_SUCCESS;
+    char **keys;
+    char **keys_cpy;
+    char *key_value;
+    int value;
+    FmPerformanceParams perf_params;
+    struct NAME_MAP *found;
+
+    if(keyfile != NULL) {
+       keys_cpy = keys = get_keys(keyfile, GRPS_MAP[0].name);
+       if(keys != NULL) {
+          while(*keys != NULL) {
+              ALOGE("key found is: %s\n", *keys);
+              found = (NAME_MAP *)bsearch(*keys, AF_PARAMS_MAP,
+                          MAX_AF_PARAMS, sizeof(NAME_MAP), compare_name);
+              if(found != NULL) {
+                 key_value = get_value(keyfile,
+                                     GRPS_MAP[0].name, found->name);
+                 if((key_value != NULL) && strcmp(key_value, "")) {
+                    value = atoi(key_value);
+                    switch(found->num) {
+                    case AF_RMSSI_TH:
+                         if((value >= AF_RMSSI_TH_MIN)
+                             && (value <= AF_RMSSI_TH_MAX)) {
+                             ALOGE("Set af rmssi th: %d\n", value);
+                             ret = perf_params.SetAfRmssiTh(fd, value);
+                             if(ret == FM_FAILURE) {
+                                ALOGE("Error in setting Af Rmssi th\n");
+                                break;
+                             }
+                             unsigned short th;
+                             ret = perf_params.GetAfRmssiTh(fd, th);
+                             if(ret == FM_SUCCESS) {
+                                ALOGE("Read af rmssith: %hd\n", th);
+                             }else {
+                                ALOGE("Error in reading Af Rmssi th\n");
+                             }
+                         }
+                         break;
+                    case AF_RMSSI_SAMPLES:
+                         if((value >= AF_RMSSI_SAMPLES_MIN)
+                             && (value <= AF_RMSSI_SAMPLES_MAX)) {
+                             ALOGE("Set af rmssi samples cnt: %d\n", value);
+                             ret = perf_params.SetAfRmssiSamplesCnt(fd, value);
+                             if(ret == FM_FAILURE) {
+                                ALOGE("Error in setting af rmssi samples\n");
+                                break;
+                             }
+                             unsigned char cnt;
+                             ret = perf_params.GetAfRmssiSamplesCnt(fd, cnt);
+                             if(ret == FM_SUCCESS) {
+                                ALOGE("Read af rmssi samples cnt: %hhd\n", cnt);
+                             }else {
+                                 ALOGE("Error in reading rmssi samples\n");
+                             }
+                         }
+                         break;
+                    case GOOD_CH_RMSSI_TH:
+                         if((value >= GOOD_CH_RMSSI_TH_MIN)
+                             && (value <= GOOD_CH_RMSSI_TH_MAX)) {
+                             ALOGE("Set Good channle rmssi th: %d\n", value);
+                             ret = perf_params.SetGoodChannelRmssiTh(fd, value);
+                             if(ret == FM_FAILURE) {
+                                ALOGE("Error in setting Good channle rmssi th\n");
+                                break;
+                             }
+                             signed char th;
+                             ret = perf_params.GetGoodChannelRmssiTh(fd, th);
+                             if(ret == FM_SUCCESS) {
+                                ALOGE("Read good channel rmssi th: %d\n", th);
+                             }else {
+                                ALOGE("Error in reading Good channle rmssi th\n");
+                             }
+                         }
+                         break;
+                   }
+                 }else {
+                   ALOGE("key_val for key: %s is empty\n",
+                             *keys);
+                 }
+                 free(key_value);
+              }
+              keys++;
+          }
+       }else {
+          ALOGE("No of keys found is zero\n");
+       }
+       free_strs(keys_cpy);
+    }else {
+       ALOGE("key file is null\n");
+    }
+}
+
+void ConfigFmThs :: set_srch_ths
+(
+    UINT fd
+)
+{
+    signed char ret = FM_SUCCESS;
+    char **keys = NULL;
+    char **keys_cpy = NULL;
+    char *key_value = NULL;
+    int value;
+    FmPerformanceParams perf_params;
+    struct NAME_MAP *found = NULL;
+
+    if(keyfile != NULL) {
+       keys_cpy = keys = get_keys(keyfile, GRPS_MAP[2].name);
+       if(keys != NULL) {
+          while(*keys != NULL) {
+              found = (NAME_MAP *)bsearch(*keys, SEACH_PARAMS_MAP,
+                           MAX_SRCH_PARAMS, sizeof(NAME_MAP), compare_name);
+              if(found != NULL) {
+                 key_value = get_value(keyfile, GRPS_MAP[2].name, found->name);
+                 ALOGE("found srch ths: %s: %s\n", found->name, key_value);
+                 if((key_value != NULL) && strcmp(key_value, "")) {
+                    value = atoi(key_value);
+                    switch(found->num) {
+                    case SINR_FIRST_STAGE:
+                         if((value >= SINR_FIRST_STAGE_MIN)
+                             && (value <= SINR_FIRST_STAGE_MAX)) {
+                             ALOGE("Set sinr first stage: %d\n", value);
+                             ret = perf_params.SetSinrFirstStage(fd, value);
+                             if(ret == FM_FAILURE) {
+                                ALOGE("Error in setting sinr first stage\n");
+                                break;
+                             }
+                             signed char th;
+                             ret = perf_params.GetSinrFirstStage(fd, th);
+                             if(ret == FM_SUCCESS) {
+                                ALOGE("Read sinr first stage: %d\n", th);
+                             }else {
+                                ALOGE("Error in reading sinr first stage\n");
+                             }
+                         }
+                         break;
+                    case RMSSI_FIRST_STAGE:
+                         if((value >= RMSSI_FIRST_STAGE_MIN)
+                             && (value <= RMSSI_FIRST_STAGE_MAX)) {
+                             ALOGE("Set rmssi first stage: %d\n", value);
+                             ret = perf_params.SetRmssiFirstStage(fd, value);
+                             if(ret == FM_FAILURE) {
+                                ALOGE("Error in setting rmssi first stage\n");
+                                break;
+                             }
+                             signed char th;
+                             ret = perf_params.GetRmssiFirstStage(fd, th);
+                             if(ret == FM_SUCCESS) {
+                                ALOGE("Read rmssi first stage: %d\n", th);
+                             }else {
+                                ALOGE("Error in reading rmssi first stage\n");
+                             }
+                         }
+                         break;
+                    case INTF_LOW_TH:
+                         if((value >= INTF_LOW_TH_MIN)
+                             && (value <= INTF_LOW_TH_MAX)) {
+                            ALOGE("Set intf low th: %d\n", value);
+                            ret = perf_params.SetIntfLowTh(fd, value);
+                            if(ret == FM_FAILURE) {
+                                ALOGE("Error in setting intf low th\n");
+                                break;
+                            }
+                            unsigned char th;
+                            ret = perf_params.GetIntfLowTh(fd, th);
+                            if(ret == FM_SUCCESS) {
+                               ALOGE("Read intf low th: %u\n", th);
+                            }else {
+                               ALOGE("Error in reading intf low th\n");
+                            }
+                         }
+                         break;
+                    case INTF_HIGH_TH:
+                         if((value >= INTF_HIGH_TH_MIN)
+                             && (value <= INTF_HIGH_TH_MAX)) {
+                            ALOGE("Set intf high th: %d\n", value);
+                            ret = perf_params.SetIntfHighTh(fd, value);
+                            if(ret == FM_FAILURE) {
+                                ALOGE("Error in setting intf high th\n");
+                                break;
+                            }
+                            unsigned char th;
+                            ret = perf_params.GetIntfHighTh(fd, th);
+                            if(ret == FM_SUCCESS) {
+                               ALOGE("Read intf high th: %u\n", th);
+                            }else {
+                               ALOGE("Error in reading intf high th\n");
+                            }
+                         }
+                         break;
+                    case CF0_TH:
+                         ALOGE("Set cf0 th: %d\n", value);
+                         ret = perf_params.SetCf0Th12(fd, value);
+                         if(ret == FM_FAILURE) {
+                            ALOGE("Error in setting cf0 th\n");
+                            break;
+                         }
+                         int th;
+                         ret = perf_params.GetCf0Th12(fd, th);
+                         if(ret == FM_SUCCESS) {
+                            ALOGE("Read CF012 th: %d\n", th);
+                         }else {
+                            ALOGE("Error in reading cf0 th\n");
+                         }
+                         break;
+                    case SRCH_ALGO_TYPE:
+                         if((value >= SRCH_ALGO_TYPE_MIN)
+                             && (value <= SRCH_ALGO_TYPE_MAX)) {
+                             ALOGE("Set search algo type: %d\n", value);
+                             ret = perf_params.SetSrchAlgoType(fd, value);
+                             if(ret == FM_FAILURE) {
+                                ALOGE("Error in setting search algo type\n");
+                                break;
+                             }
+                             unsigned char algo;
+                             ret = perf_params.GetSrchAlgoType(fd, algo);
+                             if(ret == FM_SUCCESS) {
+                                ALOGE("Read algo type: %u\n", algo);
+                             }else {
+                                ALOGE("Error in reading search algo type\n");
+                             }
+                         }
+                         break;
+                    case SINR_SAMPLES:
+                         if((value >= SINR_SAMPLES_CNT_MIN)
+                             && (value <= SINR_SAMPLES_CNT_MAX)) {
+                             ALOGE("Set sinr samples count: %d\n", value);
+                             ret = perf_params.SetSinrSamplesCnt(fd, value);
+                             if(ret == FM_FAILURE) {
+                                ALOGE("Error in setting sinr samples count\n");
+                                break;
+                             }
+                             unsigned char cnt;
+                             ret = perf_params.GetSinrSamplesCnt(fd, cnt);
+                             if(ret == FM_SUCCESS) {
+                                ALOGE("Read sinr samples cnt: %u\n", cnt);
+                             }else {
+                                ALOGE("Error in reading sinr samples count\n");
+                             }
+                         }
+                         break;
+                    case SINR:
+                         if((value >= SINR_FINAL_STAGE_MIN)
+                             && (value <= SINR_FINAL_STAGE_MAX)) {
+                             ALOGE("Set final stage sinr: %d\n", value);
+                             ret = perf_params.SetSinrFinalStage(fd, value);
+                             if(ret == FM_FAILURE) {
+                                ALOGE("Error in setting final stage sinr\n");
+                                break;
+                             }
+                             signed char th;
+                             ret = perf_params.GetSinrFinalStage(fd, th);
+                             if(ret == FM_SUCCESS) {
+                                ALOGE("Read final stage sinr: %d\n", th);
+                             }else {
+                                ALOGE("Error in reading final stage sinr\n");
+                             }
+                         }
+                         break;
+                    }
+                 }else {
+                    ALOGE("key_value for key: %s is empty\n",
+                                  *keys);
+                 }
+                 free(key_value);
+              }
+              keys++;
+          }
+       }else {
+          ALOGE("No of keys found is zero\n");
+       }
+       free_strs(keys_cpy);
+    }else {
+       ALOGE("key file is null\n");
+    }
+}
+
+void ConfigFmThs :: set_hybrd_list
+(
+    UINT fd
+)
+{
+    signed char ret = FM_SUCCESS;
+    char **keys = NULL;
+    char **keys_cpy = NULL;
+    char *key_value = NULL;
+    char *freqs = NULL;
+    unsigned int *freqs_array = NULL;
+    signed char *sinrs_array = NULL;
+    char *sinrs = NULL;
+    int value;
+    unsigned int freq_cnt = 0;
+    unsigned int sinr_cnt = 0;
+    FmPerformanceParams perf_params;
+    struct NAME_MAP *found;
+
+    ALOGE("Inside hybrid srch list\n");
+    if(keyfile != NULL) {
+       keys_cpy = keys = get_keys(keyfile, GRPS_MAP[1].name);
+       if(keys != NULL) {
+          while(*keys != NULL) {
+              found = (NAME_MAP *)bsearch(*keys, HYBRD_SRCH_MAP,
+                           MAX_HYBRID_SRCH_PARAMS, sizeof(NAME_MAP), compare_name);
+              if(found != NULL) {
+                 key_value = get_value(keyfile, GRPS_MAP[1].name, found->name);
+                 if((key_value != NULL) && strcmp(key_value, "")) {
+                     switch(found->num) {
+                     case FREQ_LIST:
+                          freqs = key_value;
+                          break;
+                     case SINR_LIST:
+                          sinrs = key_value;
+                          break;
+                     default:
+                          free(key_value);
+                          break;
+                     }
+                 }
+              }
+              keys++;
+          }
+          free_strs(keys_cpy);
+       }else {
+          ALOGE("No of keys found is zero\n");
+       }
+    }else {
+       ALOGE("key file is null\n");
+    }
+
+    freq_cnt = extract_comma_sep_freqs(freqs, &freqs_array, ",");
+    sinr_cnt = extract_comma_sep_sinrs(sinrs, &sinrs_array, ",");
+
+    if((freq_cnt == sinr_cnt) && (sinr_cnt > 0)) {
+       perf_params.SetHybridSrchList(fd, freqs_array, sinrs_array, freq_cnt);
+    }
+
+    free(freqs);
+    free(sinrs);
+    free(freqs_array);
+    free(sinrs_array);
+}
+
+unsigned int ConfigFmThs :: extract_comma_sep_freqs
+(
+    char *freqs,
+    unsigned int **freqs_arr,
+    const char *str
+)
+{
+    char *next_freq;
+    unsigned int freq;
+    unsigned int *freqs_new_arr;
+    unsigned int size = 0;
+    unsigned int len = 0;
+
+    next_freq = strtok(freqs, str);
+    while(next_freq != NULL) {
+          freq = atoi(next_freq);
+          ALOGD("HYBRID_SRCH freq: %u\n", freq);
+          if(size == len) {
+             size <<= 1;
+             if(size == 0)
+                size = 1;
+             freqs_new_arr = (unsigned int *)realloc(*freqs_arr,
+                                              size * sizeof(unsigned int));
+             if(freqs_new_arr == NULL) {
+                free(*freqs_arr);
+                *freqs_arr = NULL;
+                break;
+             }
+             *freqs_arr = freqs_new_arr;
+          }
+          (*freqs_arr)[len] = freq;
+          len++;
+          next_freq = strtok(NULL, str);
+    }
+    return len;
+}
+
+unsigned int ConfigFmThs :: extract_comma_sep_sinrs
+(
+    char *sinrs,
+    signed char **sinrs_arr,
+    const char *str
+)
+{
+    char *next_sinr;
+    signed char *sinrs_new_arr;
+    unsigned int size = 0;
+    unsigned int len = 0;
+    signed char sinr;
+
+    next_sinr = strtok(sinrs, str);
+    while(next_sinr != NULL) {
+          sinr = atoi(next_sinr);
+          ALOGD("HYBRID_SRCH sinr: %d\n", sinr);
+          if(size == len) {
+             size <<= 1;
+             if(size == 0)
+                size = 1;
+             sinrs_new_arr = (signed char *)realloc(*sinrs_arr,
+                                               size * sizeof(signed char));
+             if(sinrs_new_arr == NULL) {
+                free(*sinrs_arr);
+                *sinrs_arr = NULL;
+                break;
+             }
+             *sinrs_arr = sinrs_new_arr;
+          }
+          (*sinrs_arr)[len] = sinr;
+          len++;
+          next_sinr = strtok(NULL, str);
+    }
+    return len;
+}
+
+void  ConfigFmThs :: SetRxSearchAfThs
+(
+    const char *file, UINT fd
+)
+{
+    int index;
+    struct NAME_MAP *found;
+    char **grps = NULL;
+    char **grps_cpy = NULL;
+
+    keyfile = get_key_file();
+
+    ALOGE("file name is: %s\n", file);
+    if(!parse_load_file(keyfile, file)) {
+       ALOGE("Error in loading threshold file\n");
+    }else {
+       grps_cpy = grps = get_grps(keyfile);
+       if(grps != NULL) {
+          while(*grps != NULL) {
+              ALOGE("Search grp: %s\n", *grps);
+              found = (NAME_MAP *)bsearch(*grps, GRPS_MAP, MAX_GRPS,
+                             sizeof(NAME_MAP), compare_name);
+              if(found != NULL) {
+                 ALOGE("Found group: %s\n", found->name);
+                 switch(found->num) {
+                 case AF_THS:
+                      set_af_ths(fd);
+                      break;
+                 case SRCH_THS:
+                      set_srch_ths(fd);
+                      break;
+                 case HYBRD_SRCH_LIST:
+                      set_hybrd_list(fd);
+                      break;
+                 }
+              }
+              grps++;
+          }
+       }else {
+          ALOGE("No of groups found is zero\n");
+       }
+       free_strs(grps_cpy);
+    }
+    free_key_file(keyfile);
+    keyfile = NULL;
+}
diff --git a/jni/ConfigFmThs.h b/jni/ConfigFmThs.h
new file mode 100644
index 0000000..0a791f7
--- /dev/null
+++ b/jni/ConfigFmThs.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *        * Redistributions of source code must retain the above copyright
+ *            notice, this list of conditions and the following disclaimer.
+ *        * Redistributions in binary form must reproduce the above copyright
+ *            notice, this list of conditions and the following disclaimer in the
+ *            documentation and/or other materials provided with the distribution.
+ *        * Neither the name of The Linux Foundation nor
+ *            the names of its contributors may be used to endorse or promote
+ *            products derived from this software without specific prior written
+ *            permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED.    IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CONFIG_FM_THS_H__
+#define __CONFIG_FM_THS_H__
+
+#include <cstring>
+#include "FmConst.h"
+#include "ConfFileParser.h"
+
+#define MAX_GRPS 3
+#define MAX_SRCH_PARAMS 8
+#define MAX_AF_PARAMS 3
+
+#define SINR_SAMPLES_CNT_MIN 0
+#define SINR_SAMPLES_CNT_MAX 255
+#define SINR_FIRST_STAGE_MIN -128
+#define SINR_FIRST_STAGE_MAX 127
+#define RMSSI_FIRST_STAGE_MIN -128
+#define RMSSI_FIRST_STAGE_MAX 127
+#define INTF_LOW_TH_MIN 0
+#define INTF_LOW_TH_MAX  255
+#define INTF_HIGH_TH_MIN 0
+#define INTF_HIGH_TH_MAX 255
+#define SRCH_ALGO_TYPE_MIN 0
+#define SRCH_ALGO_TYPE_MAX 1
+#define SINR_FINAL_STAGE_MIN -128
+#define SINR_FINAL_STAGE_MAX 127
+
+#define AF_RMSSI_TH_MIN 0
+#define AF_RMSSI_TH_MAX 65535
+#define AF_RMSSI_SAMPLES_MIN 0
+#define AF_RMSSI_SAMPLES_MAX 255
+#define GOOD_CH_RMSSI_TH_MIN -128
+#define GOOD_CH_RMSSI_TH_MAX 127
+
+const unsigned char MAX_HYBRID_SRCH_PARAMS = 2;
+
+struct NAME_MAP
+{
+   const char name[50];
+   const int num;
+};
+
+enum PERFORMANCE_GRPS
+{
+    AF_THS,
+    SRCH_THS,
+    HYBRD_SRCH_LIST,
+};
+
+enum PERFORMANCE_SRCH_PARAMS
+{
+    SRCH_ALGO_TYPE,
+    CF0_TH,
+    SINR_FIRST_STAGE,
+    SINR,
+    RMSSI_FIRST_STAGE,
+    INTF_LOW_TH,
+    INTF_HIGH_TH,
+    SINR_SAMPLES,
+};
+
+enum PERFORMANCE_AF_PARAMS
+{
+    AF_RMSSI_TH,
+    AF_RMSSI_SAMPLES,
+    GOOD_CH_RMSSI_TH,
+};
+
+enum HYBRID_SRCH_PARAMS
+{
+    FREQ_LIST,
+    SINR_LIST,
+};
+
+//Keep this list in sorted order (ascending order in terms of "name")
+//Don't change the name of GRPS, if changed please also change accordingly
+//file: fm_srch_af_th.conf
+static struct NAME_MAP GRPS_MAP[] =
+{
+   {"AFTHRESHOLDS", AF_THS},
+   {"HYBRIDSEARCHLIST", HYBRD_SRCH_LIST},
+   {"SEARCHTHRESHOLDS", SRCH_THS},
+};
+
+//Keep this list in sorted order (ascending order in terms of "name")
+//Don't change the name of SEARCH thresholds,
+//if changed please also change accordingly
+//file: fm_srch_af_th.conf
+static struct NAME_MAP SEACH_PARAMS_MAP[] =
+{
+   {"Cf0Th12", CF0_TH},
+   {"IntfHighTh", INTF_HIGH_TH},
+   {"IntfLowTh", INTF_LOW_TH},
+   {"RmssiFirstStage", RMSSI_FIRST_STAGE},
+   {"SearchAlgoType", SRCH_ALGO_TYPE},
+   {"Sinr", SINR},
+   {"SinrFirstStage", SINR_FIRST_STAGE},
+   {"SinrSamplesCnt", SINR_SAMPLES},
+};
+
+//Keep this list in sorted order (ascending order in terms of "name")
+//Don't change the name of SEARCH thresholds,
+//if changed please also change accordingly
+//file: fm_srch_af_th.conf
+static struct NAME_MAP AF_PARAMS_MAP[] =
+{
+   {"AfRmssiSamplesCnt", AF_RMSSI_SAMPLES},
+   {"AfRmssiTh", AF_RMSSI_TH},
+   {"GoodChRmssiTh", GOOD_CH_RMSSI_TH},
+};
+
+static struct NAME_MAP HYBRD_SRCH_MAP[] =
+{
+   {"Freqs", FREQ_LIST},
+   {"Sinrs", SINR_LIST},
+};
+
+class ConfigFmThs {
+   private:
+          group_table *keyfile;
+          void set_srch_ths(UINT fd);
+          void set_af_ths(UINT fd);
+          unsigned int extract_comma_sep_freqs(char *freqs, unsigned int **freqs_arr, const char *str);
+          unsigned int extract_comma_sep_sinrs(char *sinrs, signed char **sinrs_arr, const char *str);
+          void set_hybrd_list(UINT fd);
+   public:
+          ConfigFmThs();
+          ~ConfigFmThs();
+          void SetRxSearchAfThs(const char *file, UINT fd);
+};
+
+#endif //__CONFIG_FM_THS_H__
diff --git a/jni/FmConst.h b/jni/FmConst.h
new file mode 100644
index 0000000..c4cd33b
--- /dev/null
+++ b/jni/FmConst.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *        * Redistributions of source code must retain the above copyright
+ *            notice, this list of conditions and the following disclaimer.
+ *        * Redistributions in binary form must reproduce the above copyright
+ *            notice, this list of conditions and the following disclaimer in the
+ *            documentation and/or other materials provided with the distribution.
+ *        * Neither the name of The Linux Foundation nor
+ *            the names of its contributors may be used to endorse or promote
+ *            products derived from this software without specific prior written
+ *            permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED.    IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __FM_CONST_H__
+#define __FM_CONST_H__
+
+
+typedef  unsigned int UINT;
+typedef  unsigned long ULINT;
+
+//return related
+const int IOCTL_SUCC = 0;
+const int FM_SUCCESS = 0;
+const int FM_FAILURE = -1;
+const int PROP_SET_SUCC = 0;
+
+#define TUNE_MULT  16
+const UINT CAL_DATA_SIZE = 23;
+#define STD_BUF_SIZE  256
+
+const char *const FM_PERFORMANCE_PARAMS = "/etc/fm/fm_srch_af_th.conf";
+const char *const CALIB_DATA_NAME = "/data/app/Riva_fm_cal";
+
+#define V4L2_CTRL_CLASS_USER  0x00980000
+#define V4L2_CID_BASE  (V4L2_CTRL_CLASS_USER | 0x900)
+#define V4L2_CID_AUDIO_MUTE   (V4L2_CID_BASE + 9)
+const UINT SEARCH_DWELL_TIME = 2;
+const UINT SEEK_DWELL_TIME = 0;
+
+enum FM_AUDIO_PATH
+{
+    AUDIO_DIGITAL_PATH,
+    AUDIO_ANALOG_PATH,
+};
+
+enum FM_DEVICE
+{
+    FM_DEV_NONE,
+    FM_RX,
+    FM_TX,
+};
+
+enum BUFF_INDEXES
+{
+    STATION_LIST_IND,
+    EVENT_IND,
+    RT_IND,
+    PS_IND,
+    AF_LIST_IND = PS_IND + 2,
+    RT_PLUS_IND = 11,
+    ERT_IND,
+};
+
+enum SEARCH_MODE
+{
+    SEEK_MODE,
+    SCAN_MODE,
+};
+
+enum SEARCH_DIR
+{
+    SEARCH_DOWN,
+    SEARCH_UP,
+};
+
+enum AUDIO_MODE
+{
+    MONO,
+    STEREO,
+};
+
+//V4L2 CONTROLS FOR FM DRIVER
+enum FM_V4L2_PRV_CONTROLS
+{
+    V4L2_CID_PRV_BASE = 0x8000000,
+    V4L2_CID_PRV_SRCHMODE,
+    V4L2_CID_PRV_SCANDWELL,
+    V4L2_CID_PRV_SRCHON,
+    V4L2_CID_PRV_STATE,
+    V4L2_CID_PRV_TRANSMIT_MODE,
+    V4L2_CID_PRV_RDSGROUP_MASK,
+    V4L2_CID_PRV_REGION,
+    V4L2_CID_PRV_SIGNAL_TH,
+    V4L2_CID_PRV_SRCH_PTY,
+    V4L2_CID_PRV_SRCH_PI,
+    V4L2_CID_PRV_SRCH_CNT,
+    V4L2_CID_PRV_EMPHASIS,
+    V4L2_CID_PRV_RDS_STD,
+    V4L2_CID_PRV_CHAN_SPACING,
+    V4L2_CID_PRV_RDSON,
+    V4L2_CID_PRV_RDSGROUP_PROC,
+    V4L2_CID_PRV_LP_MODE,
+    V4L2_CID_PRV_INTDET = V4L2_CID_PRV_BASE + 25,
+    V4L2_CID_PRV_AF_JUMP = V4L2_CID_PRV_BASE + 27,
+    V4L2_CID_PRV_SOFT_MUTE = V4L2_CID_PRV_BASE + 30,
+    V4L2_CID_PRV_AUDIO_PATH = V4L2_CID_PRV_BASE + 41,
+    V4L2_CID_PRV_SINR = V4L2_CID_PRV_BASE + 44,
+    V4L2_CID_PRV_ON_CHANNEL_THRESHOLD = V4L2_CID_PRV_BASE + 0x2D,
+    V4L2_CID_PRV_OFF_CHANNEL_THRESHOLD,
+    V4L2_CID_PRV_SINR_THRESHOLD,
+    V4L2_CID_PRV_SINR_SAMPLES,
+    V4L2_CID_PRV_SPUR_FREQ,
+    V4L2_CID_PRV_SPUR_FREQ_RMSSI,
+    V4L2_CID_PRV_SPUR_SELECTION,
+    V4L2_CID_PRV_AF_RMSSI_TH = V4L2_CID_PRV_BASE + 0x36,
+    V4L2_CID_PRV_AF_RMSSI_SAMPLES,
+    V4L2_CID_PRV_GOOD_CH_RMSSI_TH,
+    V4L2_CID_PRV_SRCHALGOTYPE,
+    V4L2_CID_PRV_CF0TH12,
+    V4L2_CID_PRV_SINRFIRSTSTAGE,
+    V4L2_CID_PRV_RMSSIFIRSTSTAGE,
+    V4L2_CID_PRV_SOFT_MUTE_TH,
+    V4L2_CID_PRV_IRIS_RDSGRP_RT,
+    V4L2_CID_PRV_IRIS_RDSGRP_PS_SIMPLE,
+    V4L2_CID_PRV_IRIS_RDSGRP_AFLIST,
+    V4L2_CID_PRV_IRIS_RDSGRP_ERT,
+    V4L2_CID_PRV_IRIS_RDSGRP_RT_PLUS,
+    V4L2_CID_PRV_IRIS_RDSGRP_3A,
+
+    V4L2_CID_PRV_IRIS_READ_DEFAULT = V4L2_CTRL_CLASS_USER + 0x928,
+    V4L2_CID_PRV_IRIS_WRITE_DEFAULT,
+    V4L2_CID_PRV_SET_CALIBRATION = V4L2_CTRL_CLASS_USER + 0x92A,
+};
+#endif
diff --git a/jni/FmIoctlsInterface.cpp b/jni/FmIoctlsInterface.cpp
new file mode 100644
index 0000000..7528d89
--- /dev/null
+++ b/jni/FmIoctlsInterface.cpp
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *        * Redistributions of source code must retain the above copyright
+ *            notice, this list of conditions and the following disclaimer.
+ *        * Redistributions in binary form must reproduce the above copyright
+ *            notice, this list of conditions and the following disclaimer in the
+ *            documentation and/or other materials provided with the distribution.
+ *        * Neither the name of The Linux Foundation nor
+ *            the names of its contributors may be used to endorse or promote
+ *            products derived from this software without specific prior written
+ *            permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED.    IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "FmIoctlsInterface.h"
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <fcntl.h>
+#include <utils/Log.h>
+#include <cutils/properties.h>
+#include <sys/ioctl.h>
+#include <linux/videodev2.h>
+#include <math.h>
+
+char const * const FmIoctlsInterface::LOGTAG = "FmIoctlsInterface";
+
+int  FmIoctlsInterface :: get_cur_freq
+(
+    UINT fd, long &freq
+)
+{
+    int ret;
+    struct v4l2_frequency channel;
+
+    channel.type = V4L2_TUNER_RADIO;
+    ret = ioctl(fd, VIDIOC_G_FREQUENCY, &channel);
+
+    if(ret != IOCTL_SUCC) {
+        return FM_FAILURE;
+    }else {
+        freq = (channel.frequency / TUNE_MULT);
+        return FM_SUCCESS;
+    }
+}
+
+int  FmIoctlsInterface :: set_freq
+(
+    UINT fd, ULINT freq
+)
+{
+    int ret;
+    struct v4l2_frequency channel;
+
+    channel.type = V4L2_TUNER_RADIO;
+    channel.frequency = (freq * TUNE_MULT);
+
+    ret = ioctl(fd, VIDIOC_S_FREQUENCY, &channel);
+    if(ret != IOCTL_SUCC) {
+        return FM_FAILURE;
+    }else {
+        return FM_SUCCESS;
+    }
+}
+
+int FmIoctlsInterface :: set_control
+(
+    UINT fd, UINT id, int val
+)
+{
+    int ret;
+    struct v4l2_control control;
+
+    control.value = val;
+    control.id = id;
+
+    for(int i = 0; i < 3; i++) {
+        ret = ioctl(fd, VIDIOC_S_CTRL, &control);
+        if(ret != IOCTL_SUCC) {
+           ret = FM_FAILURE;
+        }else {
+           ret = FM_SUCCESS;
+           break;
+        }
+    }
+    return ret;
+}
+
+int  FmIoctlsInterface :: set_calibration
+(
+    UINT fd
+)
+{
+    int ret;
+    FILE *cal_fp;
+    struct v4l2_ext_control ext_ctl;
+    struct v4l2_ext_controls v4l2_ctls;
+    char cal_data[CAL_DATA_SIZE] = {0};
+
+    cal_fp = fopen(CALIB_DATA_NAME, "r");
+    if(cal_fp != NULL) {
+       if(fread(&cal_data[0], 1, CAL_DATA_SIZE, cal_fp)
+           < CAL_DATA_SIZE) {
+           fclose(cal_fp);
+           ALOGE("%s: calibration file read failed\n", LOGTAG);
+           return FM_FAILURE;
+       }
+       fclose(cal_fp);
+       ext_ctl.id = V4L2_CID_PRV_SET_CALIBRATION;
+       ext_ctl.string = cal_data;
+       ext_ctl.size = CAL_DATA_SIZE;
+       v4l2_ctls.ctrl_class = V4L2_CTRL_CLASS_USER;
+       v4l2_ctls.count = 1;
+       v4l2_ctls.controls = &ext_ctl;
+       ret = ioctl(fd, VIDIOC_S_EXT_CTRLS, &v4l2_ctls);
+       if(ret != IOCTL_SUCC) {
+           ALOGE("%s: ioctl call failed\n", LOGTAG);
+           return FM_FAILURE;
+       }else {
+           return FM_SUCCESS;
+       }
+    }else {
+        return FM_SUCCESS;
+    }
+}
+
+int  FmIoctlsInterface :: get_control
+(
+    UINT fd, UINT id, long &val
+)
+{
+    int ret;
+    struct v4l2_control control;
+
+    control.id = id;
+    ret = ioctl(fd, VIDIOC_G_CTRL, &control);
+    if(ret != IOCTL_SUCC) {
+        return FM_FAILURE;
+    }else {
+        val = control.value;
+        return FM_SUCCESS;
+    }
+}
+
+int  FmIoctlsInterface :: start_search
+(
+    UINT fd, UINT dir
+)
+{
+    int ret;
+    struct v4l2_hw_freq_seek hw_seek;
+
+    hw_seek.seek_upward = dir;
+    hw_seek.type = V4L2_TUNER_RADIO;
+
+    ret = ioctl(fd, VIDIOC_S_HW_FREQ_SEEK, &hw_seek);
+    if(ret != IOCTL_SUCC) {
+        return FM_FAILURE;
+    }else {
+        return FM_SUCCESS;
+    }
+}
+
+int  FmIoctlsInterface :: set_band
+(
+    UINT fd, ULINT low, ULINT high
+)
+{
+    int ret;
+    struct v4l2_tuner tuner;
+
+    tuner.index = 0;
+    tuner.signal = 0;
+    tuner.rangelow = (low * TUNE_MULT);
+    tuner.rangehigh = (high * TUNE_MULT);
+
+    ret = ioctl(fd, VIDIOC_S_TUNER, &tuner);
+    ret = set_control(fd, V4L2_CID_PRV_REGION, 0);
+    if(ret != IOCTL_SUCC) {
+        return FM_FAILURE;
+    }else {
+        return FM_SUCCESS;
+    }
+}
+
+int FmIoctlsInterface :: get_rmssi
+(
+    UINT fd, long &rmssi
+)
+{
+    struct v4l2_tuner tuner;
+    int ret;
+
+    tuner.index = 0;
+    tuner.signal = 0;
+    ret = ioctl(fd, VIDIOC_G_TUNER, &tuner);
+    if(ret != IOCTL_SUCC) {
+        ret = FM_FAILURE;
+    }else {
+        rmssi = tuner.signal;
+        ret = FM_SUCCESS;
+    }
+    return ret;
+}
+
+int FmIoctlsInterface :: get_upperband_limit
+(
+    UINT fd, ULINT &freq
+)
+{
+    int ret;
+    struct v4l2_tuner tuner;
+
+    tuner.index = 0;
+    ret = ioctl(fd, VIDIOC_G_TUNER, &tuner);
+    if(ret != IOCTL_SUCC) {
+        return FM_FAILURE;
+    }else {
+        freq = (tuner.rangehigh / TUNE_MULT);
+        return FM_SUCCESS;
+    }
+}
+
+int FmIoctlsInterface :: get_lowerband_limit
+(
+    UINT fd, ULINT &freq
+)
+{
+    int ret;
+    struct v4l2_tuner tuner;
+
+    tuner.index = 0;
+    ret = ioctl(fd, VIDIOC_G_TUNER, &tuner);
+    if(ret != IOCTL_SUCC) {
+        return FM_FAILURE;
+    }else {
+        freq = (tuner.rangelow / TUNE_MULT);
+        return FM_SUCCESS;
+    }
+}
+
+int FmIoctlsInterface :: set_audio_mode
+(
+    UINT fd, enum AUDIO_MODE mode
+)
+{
+    int ret;
+    struct v4l2_tuner tuner;
+
+    tuner.index = 0;
+    ret = ioctl(fd, VIDIOC_G_TUNER, &tuner);
+    if(ret != IOCTL_SUCC) {
+        return FM_FAILURE;
+    }else {
+        tuner.audmode = mode;
+        ret = ioctl(fd, VIDIOC_S_TUNER, &tuner);
+        if(ret != IOCTL_SUCC) {
+            return FM_FAILURE;
+        }else {
+            return FM_SUCCESS;
+        }
+    }
+}
+
+int FmIoctlsInterface :: get_buffer
+(
+     UINT fd, char *buff, UINT len, UINT index
+)
+{
+    int ret;
+    struct v4l2_buffer v4l2_buf;
+
+    if((len < STD_BUF_SIZE) || (buff == NULL)) {
+        return FM_FAILURE;
+    }else {
+        memset(&v4l2_buf, 0, sizeof(v4l2_buf));
+        v4l2_buf.index = index;
+        v4l2_buf.type = V4L2_BUF_TYPE_PRIVATE;
+        v4l2_buf.length = STD_BUF_SIZE;
+        v4l2_buf.m.userptr = (ULINT)buff;
+        ret = ioctl(fd, VIDIOC_DQBUF, &v4l2_buf);
+        if(ret != IOCTL_SUCC) {
+            return FM_FAILURE;
+        }else {
+            return v4l2_buf.bytesused;
+        }
+    }
+}
+
+int FmIoctlsInterface :: set_ext_control
+(
+    UINT fd,
+    struct v4l2_ext_controls *v4l2_ctls
+)
+{
+    int ret;
+
+    ret = ioctl(fd, VIDIOC_S_EXT_CTRLS, v4l2_ctls);
+
+    if(ret != IOCTL_SUCC) {
+       return FM_FAILURE;
+    }else {
+       return FM_SUCCESS;
+    }
+}
+
diff --git a/jni/FmIoctlsInterface.h b/jni/FmIoctlsInterface.h
new file mode 100644
index 0000000..eda28ee
--- /dev/null
+++ b/jni/FmIoctlsInterface.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *        * Redistributions of source code must retain the above copyright
+ *            notice, this list of conditions and the following disclaimer.
+ *        * Redistributions in binary form must reproduce the above copyright
+ *            notice, this list of conditions and the following disclaimer in the
+ *            documentation and/or other materials provided with the distribution.
+ *        * Neither the name of The Linux Foundation nor
+ *            the names of its contributors may be used to endorse or promote
+ *            products derived from this software without specific prior written
+ *            permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED.    IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __FM_IOCTL_INTERFACE_H__
+#define __FM_IOCTL_INTERFACE_H__
+
+#include "FmConst.h"
+
+#include <linux/videodev2.h>
+
+class FmIoctlsInterface
+{
+    private:
+        static char const * const LOGTAG;
+    public:
+        static int start_fm_patch_dl(UINT fd);
+        static int close_fm_patch_dl(void);
+        static int get_cur_freq(UINT fd, long &freq);
+        static int set_freq(UINT fd, ULINT freq);
+        static int set_control(UINT fd, UINT id, int val);
+        static int set_calibration(UINT fd);
+        static int get_control(UINT fd, UINT id, long &val);
+        static int start_search(UINT fd, UINT dir);
+        static int set_band(UINT fd, ULINT low, ULINT high);
+        static int get_upperband_limit(UINT fd, ULINT &freq);
+        static int get_lowerband_limit(UINT fd, ULINT &freq);
+        static int set_audio_mode(UINT fd, enum AUDIO_MODE mode);
+        static int get_buffer(UINT fd, char *buff, UINT len, UINT index);
+        static int get_rmssi(UINT fd, long &rmssi);
+        static int set_ext_control(UINT fd, struct v4l2_ext_controls *v4l2_ctls);
+};
+
+//char const *FmIoctlsInterface::LOGTAG = "FmIoctlsInterface";
+
+#endif //__FM_IOCTL_INTERFACE_H__
diff --git a/jni/FmPerformanceParams.cpp b/jni/FmPerformanceParams.cpp
new file mode 100644
index 0000000..bdd0a43
--- /dev/null
+++ b/jni/FmPerformanceParams.cpp
@@ -0,0 +1,422 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *        * Redistributions of source code must retain the above copyright
+ *            notice, this list of conditions and the following disclaimer.
+ *        * Redistributions in binary form must reproduce the above copyright
+ *            notice, this list of conditions and the following disclaimer in the
+ *            documentation and/or other materials provided with the distribution.
+ *        * Neither the name of The Linux Foundation nor
+ *            the names of its contributors may be used to endorse or promote
+ *            products derived from this software without specific prior written
+ *            permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED.    IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "FmPerformanceParams.h"
+#include "FmIoctlsInterface.h"
+
+#include <cstdio>
+#include <linux/videodev2.h>
+#include <utils/Log.h>
+
+signed char FmPerformanceParams :: SetAfRmssiTh
+(
+   UINT fd, unsigned short th
+)
+{
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::set_control(fd,
+                V4L2_CID_PRV_AF_RMSSI_TH, th);
+
+   return ret;
+}
+
+signed char FmPerformanceParams :: SetAfRmssiSamplesCnt
+(
+   UINT fd, unsigned char cnt
+)
+{
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::set_control(fd,
+                V4L2_CID_PRV_AF_RMSSI_SAMPLES, cnt);
+
+   return ret;
+}
+
+signed char FmPerformanceParams :: SetGoodChannelRmssiTh
+(
+   UINT fd, signed char th
+)
+{
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::set_control(fd,
+                V4L2_CID_PRV_GOOD_CH_RMSSI_TH, th);
+
+   return ret;
+}
+
+signed char FmPerformanceParams :: SetSrchAlgoType
+(
+   UINT fd, unsigned char algo
+)
+{
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::set_control(fd,
+                V4L2_CID_PRV_SRCHALGOTYPE, algo);
+
+   return ret;
+}
+
+signed char FmPerformanceParams :: SetSinrFirstStage
+(
+   UINT fd, signed char th
+)
+{
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::set_control(fd,
+                V4L2_CID_PRV_SINRFIRSTSTAGE, th);
+
+   return ret;
+}
+
+signed char FmPerformanceParams :: SetRmssiFirstStage
+(
+   UINT fd, signed char th
+)
+{
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::set_control(fd,
+                V4L2_CID_PRV_RMSSIFIRSTSTAGE, th);
+
+   return ret;
+}
+
+signed char FmPerformanceParams :: SetCf0Th12
+(
+   UINT fd, int th
+)
+{
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::set_control(fd,
+                V4L2_CID_PRV_CF0TH12, th);
+   return ret;
+}
+
+signed char FmPerformanceParams :: SetSinrSamplesCnt
+(
+   UINT fd, unsigned char cnt
+)
+{
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::set_control(fd,
+                V4L2_CID_PRV_SINR_SAMPLES, cnt);
+
+   return ret;
+}
+
+signed char FmPerformanceParams :: SetIntfLowTh
+(
+   UINT fd, unsigned char th
+)
+{
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::set_control(fd,
+                V4L2_CID_PRV_ON_CHANNEL_THRESHOLD, th);
+
+   return ret;
+}
+
+signed char FmPerformanceParams :: SetIntfHighTh
+(
+   UINT fd, unsigned char th
+)
+{
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::set_control(fd,
+                V4L2_CID_PRV_OFF_CHANNEL_THRESHOLD, th);
+   return ret;
+}
+
+signed char FmPerformanceParams :: SetSinrFinalStage
+(
+   UINT fd, signed char th
+)
+{
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::set_control(fd,
+                V4L2_CID_PRV_SINR_THRESHOLD, th);
+
+   return ret;
+}
+
+signed char FmPerformanceParams :: GetAfRmssiTh
+(
+   UINT fd, unsigned short &th
+)
+{
+   long int af_rmssi_th;
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::get_control(fd,
+                V4L2_CID_PRV_AF_RMSSI_TH, af_rmssi_th);
+   if(ret == FM_SUCCESS) {
+      th = af_rmssi_th;
+   }
+   return ret;
+}
+
+signed char FmPerformanceParams :: GetAfRmssiSamplesCnt
+(
+   UINT fd, unsigned char &cnt
+)
+{
+   long int af_samples_cnt;
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::get_control(fd,
+                V4L2_CID_PRV_AF_RMSSI_SAMPLES, af_samples_cnt);
+   if(ret == FM_SUCCESS) {
+      cnt = af_samples_cnt;
+   }
+   return ret;
+}
+
+signed char FmPerformanceParams :: GetGoodChannelRmssiTh
+(
+   UINT fd, signed char &th
+)
+{
+   long int gd_chan_rmssi_th;
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::get_control(fd,
+                V4L2_CID_PRV_GOOD_CH_RMSSI_TH, gd_chan_rmssi_th);
+   if(ret == FM_SUCCESS) {
+      th = gd_chan_rmssi_th;
+   }
+   return ret;
+}
+
+signed char FmPerformanceParams :: GetSrchAlgoType
+(
+   UINT fd, unsigned char &algo
+)
+{
+   long int srch_algo_type;
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::get_control(fd,
+                V4L2_CID_PRV_SRCHALGOTYPE, srch_algo_type);
+   if(ret == FM_SUCCESS) {
+      algo = srch_algo_type;
+   }
+   return ret;
+}
+
+signed char FmPerformanceParams :: GetSinrFirstStage
+(
+   UINT fd, signed char &th
+)
+{
+   long int sinr_first_stage;
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::get_control(fd,
+                V4L2_CID_PRV_SINRFIRSTSTAGE, sinr_first_stage);
+   if(ret == FM_SUCCESS) {
+      th = sinr_first_stage;
+   }
+   return ret;
+}
+
+signed char FmPerformanceParams :: GetRmssiFirstStage
+(
+   UINT fd, signed char &th
+)
+{
+   long int rmssi_first_stage;
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::get_control(fd,
+                V4L2_CID_PRV_RMSSIFIRSTSTAGE, rmssi_first_stage);
+   if(ret == FM_SUCCESS) {
+      th = rmssi_first_stage;
+   }
+   return ret;
+}
+
+signed char FmPerformanceParams :: GetCf0Th12
+(
+   UINT fd, int &th
+)
+{
+   long int cf0th12;
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::get_control(fd,
+                V4L2_CID_PRV_CF0TH12, cf0th12);
+   if(ret == FM_SUCCESS) {
+      th = cf0th12;
+   }
+   return ret;
+}
+
+signed char FmPerformanceParams :: GetSinrSamplesCnt
+(
+   UINT fd, unsigned char &cnt
+)
+{
+   long int sinr_samples_cnt;
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::get_control(fd,
+                V4L2_CID_PRV_SINR_SAMPLES, sinr_samples_cnt);
+   if(ret == FM_SUCCESS) {
+      cnt = sinr_samples_cnt;
+   }
+   return ret;
+}
+
+signed char FmPerformanceParams :: GetIntfLowTh
+(
+   UINT fd, unsigned char &th
+)
+{
+   long int intf_low_th;
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::get_control(fd,
+               V4L2_CID_PRV_ON_CHANNEL_THRESHOLD, intf_low_th);
+   if(ret == FM_SUCCESS) {
+      th = intf_low_th;
+   }
+   return ret;
+}
+
+signed char FmPerformanceParams :: GetIntfHighTh
+(
+   UINT fd, unsigned char &th
+)
+{
+   long int intf_high_th;
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::get_control(fd,
+               V4L2_CID_PRV_OFF_CHANNEL_THRESHOLD, intf_high_th);
+   if(ret == FM_SUCCESS) {
+      th = intf_high_th;
+   }
+   return ret;
+}
+
+signed char FmPerformanceParams :: GetIntfDet
+(
+   UINT fd, unsigned char &th
+)
+{
+   long int int_det;
+   signed char ret = FM_FAILURE;
+
+   ret = FmIoctlsInterface::get_control(fd,
+               V4L2_CID_PRV_INTDET, int_det);
+   if(ret == FM_SUCCESS) {
+      th = int_det;
+   }
+   return ret;
+}
+signed char FmPerformanceParams :: GetSinrFinalStage
+(
+   UINT fd, signed char &th
+)
+{
+   signed char ret = FM_FAILURE;
+   long int sinr;
+
+   ret = FmIoctlsInterface::get_control(fd,
+                V4L2_CID_PRV_SINR_THRESHOLD, sinr);
+
+   if(ret == FM_SUCCESS) {
+      th = sinr;
+   }
+   return ret;
+}
+
+signed char FmPerformanceParams :: SetHybridSrchList
+(
+   UINT fd,
+   unsigned int *freqs,
+   signed char *sinrs,
+   unsigned int n
+)
+{
+   struct v4l2_ext_control ext_ctl;
+   struct v4l2_ext_controls v4l2_ctls;
+   unsigned int freq;
+   signed char sinr;
+   unsigned int size = 0;
+   char *data = NULL;
+   signed char ret = FM_FAILURE;
+
+   if(n <= 0) {
+      return ret;
+   }
+   data = new char[(n * 3 + 3)];
+
+   if(data != NULL) {
+      data[size++] = 0x40;
+      data[size++] = ((n * 3) + 1);
+      data[size++] = n;
+      while((size < (n * 3 + 2)) && (freqs != NULL)
+            && (sinrs != NULL)) {
+            freq = (*freqs - 76000) / 50;
+            data[size++] = (freq & 0xff);
+            data[size++] = ((freq >> 8) & 0xff);
+            data[size++] = *sinrs;
+            freqs++;
+            sinrs++;
+      }
+      if(size == (n * 3 + 3)) {
+         ext_ctl.id = V4L2_CID_PRV_IRIS_WRITE_DEFAULT;
+         ext_ctl.string = data;
+         ext_ctl.size = size;
+         v4l2_ctls.ctrl_class = V4L2_CTRL_CLASS_USER;
+         v4l2_ctls.count = 1;
+         v4l2_ctls.controls  = &ext_ctl;
+         ret =  FmIoctlsInterface::set_ext_control(fd, &v4l2_ctls);
+         if(ret == FM_SUCCESS) {
+            ALOGE("hybrid srch list sent successfully\n");
+         }else {
+            ALOGE("hybrid srch list setting failed\n");
+         }
+      }
+   }
+
+   delete []data;
+
+   return ret;
+}
diff --git a/jni/FmPerformanceParams.h b/jni/FmPerformanceParams.h
new file mode 100644
index 0000000..fd9ee52
--- /dev/null
+++ b/jni/FmPerformanceParams.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *        * Redistributions of source code must retain the above copyright
+ *            notice, this list of conditions and the following disclaimer.
+ *        * Redistributions in binary form must reproduce the above copyright
+ *            notice, this list of conditions and the following disclaimer in the
+ *            documentation and/or other materials provided with the distribution.
+ *        * Neither the name of The Linux Foundation nor
+ *            the names of its contributors may be used to endorse or promote
+ *            products derived from this software without specific prior written
+ *            permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED.    IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __FM_PERFORMANCE_PARAMS_H__
+#define __FM_PERFORMANCE_PARAMS_H__
+
+#include "FmConst.h"
+
+class FmPerformanceParams
+{
+      private:
+      public:
+          signed char SetAfRmssiTh(UINT fd, unsigned short th);
+          signed char SetAfRmssiSamplesCnt(UINT fd, unsigned char cnt);
+          signed char SetGoodChannelRmssiTh(UINT fd, signed char th);
+          signed char SetSrchAlgoType(UINT fd, unsigned char algo);
+          signed char SetSinrFirstStage(UINT fd, signed char th);
+          signed char SetRmssiFirstStage(UINT fd, signed char th);
+          signed char SetCf0Th12(UINT fd, int th);
+          signed char SetSinrSamplesCnt(UINT fd, unsigned char cnt);
+          signed char SetIntfLowTh(UINT fd, unsigned char th);
+          signed char SetIntfHighTh(UINT fd, unsigned char th);
+          signed char SetSinrFinalStage(UINT fd, signed char th);
+          signed char SetHybridSrchList(UINT fd, unsigned int *freqs, signed char *sinrs, unsigned int n);
+
+          signed char GetAfRmssiTh(UINT fd, unsigned short &th);
+          signed char GetAfRmssiSamplesCnt(UINT fd, unsigned char &cnt);
+          signed char GetGoodChannelRmssiTh(UINT fd, signed char &th);
+          signed char GetSrchAlgoType(UINT fd, unsigned char &algo);
+          signed char GetSinrFirstStage(UINT fd, signed char &th);
+          signed char GetRmssiFirstStage(UINT fd, signed char &th);
+          signed char GetCf0Th12(UINT fd, int &th);
+          signed char GetSinrSamplesCnt(UINT fd, unsigned char &cnt);
+          signed char GetIntfLowTh(UINT fd, unsigned char &th);
+          signed char GetIntfHighTh(UINT fd, unsigned char &th);
+          signed char GetIntfDet(UINT fd, unsigned char &th);
+          signed char GetSinrFinalStage(UINT fd, signed char &th);
+};
+
+#endif //__FM_PERFORMANCE_PARAMS_H__
diff --git a/jni/android_hardware_fm.cpp b/jni/android_hardware_fm.cpp
index b3090dd..b2b0814 100644
--- a/jni/android_hardware_fm.cpp
+++ b/jni/android_hardware_fm.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2014, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -26,13 +26,15 @@
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#define LOG_TAG "fmradio"
+#define LOG_TAG "android_hardware_fm"
 
 #include "jni.h"
 #include "JNIHelp.h"
 #include "android_runtime/AndroidRuntime.h"
 #include "utils/Log.h"
 #include "utils/misc.h"
+#include "FmIoctlsInterface.h"
+#include "ConfigFmThs.h"
 #include <cutils/properties.h>
 #include <fcntl.h>
 #include <sys/ioctl.h>
@@ -45,7 +47,6 @@
 #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
@@ -58,7 +59,6 @@
 #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,
@@ -167,13 +167,22 @@ 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;
+    long freq;
+
+    if (fd >= 0) {
+        err = FmIoctlsInterface :: get_cur_freq(fd, freq);
+        if(err < 0) {
+           err = FM_JNI_FAILURE;
+           ALOGE("%s: get freq failed\n", LOG_TAG);
+        } else {
+           err = freq;
+        }
+    } else {
+        ALOGE("%s: get freq failed because fd is negative, fd: %d\n",
+              LOG_TAG, fd);
+        err = FM_JNI_FAILURE;
     }
-    return ((freq.frequency*1000)/TUNE_MULT);
+    return err;
 }
 
 /*native interface */
@@ -181,240 +190,282 @@ 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;
+
+    if ((fd >= 0) && (freq > 0)) {
+        err = FmIoctlsInterface :: set_freq(fd, freq);
+        if (err < 0) {
+            ALOGE("%s: set freq failed, freq: %d\n", LOG_TAG, freq);
+            err = FM_JNI_FAILURE;
+        } else {
+            err = FM_JNI_SUCCESS;
+        }
+    } else {
+        ALOGE("%s: set freq failed because either fd/freq is negative,\
+              fd: %d, freq: %d\n", LOG_TAG, fd, freq);
+        err = FM_JNI_FAILURE;
     }
-    return FM_JNI_SUCCESS;
+    return err;
 }
 
 /* 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;
+    if ((fd >= 0) && (id >= 0)) {
+        err = FmIoctlsInterface :: set_control(fd, id, value);
+        if (err < 0) {
+            ALOGE("%s: set control failed, id: %d\n", LOG_TAG, id);
+            err = FM_JNI_FAILURE;
+        } else {
+            err = FM_JNI_SUCCESS;
         }
+    } else {
+        ALOGE("%s: set control failed because either fd/id is negavtive,\
+               fd: %d, id: %d\n", LOG_TAG, fd, id);
+        err = FM_JNI_FAILURE;
     }
-    ALOGE("setControl native returned with err %d", err);
-    return FM_JNI_FAILURE;
+
+    return err;
 }
 
 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;
+   int err;
+
+   if (fd >= 0) {
+       err = FmIoctlsInterface :: set_calibration(fd);
+       if (err < 0) {
+           ALOGE("%s: set calibration failed\n", LOG_TAG);
+           err = FM_JNI_FAILURE;
+       } else {
+           err = FM_JNI_SUCCESS;
+       }
+   } else {
+       ALOGE("%s: set calibration failed because fd is negative, fd: %d\n",
+              LOG_TAG, fd);
+       err = FM_JNI_FAILURE;
+   }
+
+   return err;
 }
 /* native interface */
 static jint android_hardware_fmradio_FmReceiverJNI_getControlNative
     (JNIEnv * env, jobject thiz, jint fd, jint id)
 {
-    struct v4l2_control control;
     int err;
+    long val;
+
     ALOGE("id(%x)\n", id);
 
-    control.id = id;
-    err = ioctl(fd,VIDIOC_G_CTRL,&control);
-    if(err < 0){
-        return FM_JNI_FAILURE;
+    if ((fd >= 0) && (id >= 0)) {
+        err = FmIoctlsInterface :: get_control(fd, id, val);
+        if (err < 0) {
+            ALOGE("%s: get control failed, id: %d\n", LOG_TAG, id);
+            err = FM_JNI_FAILURE;
+        } else {
+            err = val;
+        }
+    } else {
+        ALOGE("%s: get control failed because either fd/id is negavtive,\
+               fd: %d, id: %d\n", LOG_TAG, fd, id);
+        err = FM_JNI_FAILURE;
     }
-    return control.value;
+
+    return err;
 }
 
 /* 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;
+
+    if ((fd >= 0) && (dir >= 0)) {
+        ALOGD("startSearchNative: Issuing the VIDIOC_S_HW_FREQ_SEEK");
+        err = FmIoctlsInterface :: start_search(fd, dir);
+        if (err < 0) {
+            ALOGE("%s: search failed, dir: %d\n", LOG_TAG, dir);
+            err = FM_JNI_FAILURE;
+        } else {
+            err = FM_JNI_SUCCESS;
+        }
+    } else {
+        ALOGE("%s: search failed because either fd/dir is negative,\
+               fd: %d, dir: %d\n", LOG_TAG, fd, dir);
+        err = FM_JNI_FAILURE;
+    }
+
+    return err;
 }
 
 /* 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;
+
+    if (fd >= 0) {
+        err = FmIoctlsInterface :: set_control(fd, V4L2_CID_PRV_SRCHON, 0);
+        if (err < 0) {
+            ALOGE("%s: cancel search failed\n", LOG_TAG);
+            err = FM_JNI_FAILURE;
+        } else {
+            err = FM_JNI_SUCCESS;
+        }
+    } else {
+        ALOGE("%s: cancel search failed because fd is negative, fd: %d\n",
+               LOG_TAG, fd);
+        err = FM_JNI_FAILURE;
     }
-    return FM_JNI_SUCCESS;
+
+    return err;
 }
 
 /* native interface */
 static jint android_hardware_fmradio_FmReceiverJNI_getRSSINative
     (JNIEnv * env, jobject thiz, jint fd)
 {
-    struct v4l2_tuner tuner;
     int err;
+    long rmssi;
 
-    tuner.index = 0;
-    tuner.signal = 0;
-    err = ioctl(fd, VIDIOC_G_TUNER, &tuner);
-    if(err < 0){
-        return FM_JNI_FAILURE;
+    if (fd >= 0) {
+        err = FmIoctlsInterface :: get_rmssi(fd, rmssi);
+        if (err < 0) {
+            ALOGE("%s: get rmssi failed\n", LOG_TAG);
+            err = FM_JNI_FAILURE;
+        } else {
+            err = rmssi;
+        }
+    } else {
+        ALOGE("%s: get rmssi failed because fd is negative, fd: %d\n",
+               LOG_TAG, fd);
+        err = FM_JNI_FAILURE;
     }
-    return tuner.signal;
+
+    return err;
 }
 
 /* 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;
+    if ((fd >= 0) && (low >= 0) && (high >= 0)) {
+        err = FmIoctlsInterface :: set_band(fd, low, high);
+        if (err < 0) {
+            ALOGE("%s: set band failed, low: %d, high: %d\n",
+                   LOG_TAG, low, high);
+            err = FM_JNI_FAILURE;
+        } else {
+            err = FM_JNI_SUCCESS;
+        }
+    } else {
+        ALOGE("%s: set band failed because either fd/band is negative,\
+               fd: %d, low: %d, high: %d\n", LOG_TAG, fd, low, high);
+        err = FM_JNI_FAILURE;
     }
-    return FM_JNI_SUCCESS;
+
+    return err;
 }
 
 /* native interface */
 static jint android_hardware_fmradio_FmReceiverJNI_getLowerBandNative
     (JNIEnv * env, jobject thiz, jint fd)
 {
-    struct v4l2_tuner tuner;
     int err;
-    tuner.index = 0;
+    ULINT freq;
 
-    err = ioctl(fd, VIDIOC_G_TUNER, &tuner);
-    if(err < 0){
-        ALOGE("low_band value: <%x> \n", tuner.rangelow);
-        return FM_JNI_FAILURE;
+    if (fd >= 0) {
+        err = FmIoctlsInterface :: get_lowerband_limit(fd, freq);
+        if (err < 0) {
+            ALOGE("%s: get lower band failed\n", LOG_TAG);
+            err = FM_JNI_FAILURE;
+        } else {
+            err = freq;
+        }
+    } else {
+        ALOGE("%s: get lower band failed because fd is negative,\
+               fd: %d\n", LOG_TAG, fd);
+        err = FM_JNI_FAILURE;
     }
-    return ((tuner.rangelow * 1000)/ TUNE_MULT);
+
+    return err;
 }
 
 /* native interface */
 static jint android_hardware_fmradio_FmReceiverJNI_getUpperBandNative
     (JNIEnv * env, jobject thiz, jint fd)
 {
-    struct v4l2_tuner tuner;
     int err;
-    tuner.index = 0;
+    ULINT freq;
 
-    err = ioctl(fd, VIDIOC_G_TUNER, &tuner);
-    if(err < 0){
-        ALOGE("high_band value: <%x> \n", tuner.rangehigh);
-        return FM_JNI_FAILURE;
+    if (fd >= 0) {
+        err = FmIoctlsInterface :: get_upperband_limit(fd, freq);
+        if (err < 0) {
+            ALOGE("%s: get lower band failed\n", LOG_TAG);
+            err = FM_JNI_FAILURE;
+        } else {
+            err = freq;
+        }
+    } else {
+        ALOGE("%s: get lower band failed because fd is negative,\
+               fd: %d\n", LOG_TAG, fd);
+        err = FM_JNI_FAILURE;
     }
-    return ((tuner.rangehigh * 1000) / TUNE_MULT);
+
+    return err;
 }
 
 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;
+    if (fd >= 0) {
+        err = FmIoctlsInterface :: set_audio_mode(fd, (enum AUDIO_MODE)val);
+        if (err < 0) {
+            err = FM_JNI_FAILURE;
+        } else {
+            err = FM_JNI_SUCCESS;
+        }
+    } else {
+        err = FM_JNI_FAILURE;
+    }
 
+    return err;
 }
 
 
-
 /* native interface */
 static jint android_hardware_fmradio_FmReceiverJNI_getBufferNative
  (JNIEnv * env, jobject thiz, jint fd, 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*/
+    jboolean *bool_buffer;
+
+    if ((fd >= 0) && (index >= 0)) {
+        bool_buffer = env->GetBooleanArrayElements(buff, &isCopy);
+        err = FmIoctlsInterface :: get_buffer(fd,
+                                               (char *)bool_buffer,
+                                               STD_BUF_SIZE,
+                                               index);
+        if (err < 0) {
+            err = FM_JNI_FAILURE;
+        }
         env->ReleaseBooleanArrayElements(buff, bool_buffer, 0);
-        return FM_JNI_FAILURE;
+    } else {
+        err = FM_JNI_FAILURE;
     }
 
-    /* Always copy buffer and free up the memory */
-    env->ReleaseBooleanArrayElements(buff, bool_buffer, 0);
-
-    return v4l2_buf.bytesused;
+    return err;
 }
 
 /* native interface */
@@ -432,8 +483,8 @@ static jint android_hardware_fmradio_FmReceiverJNI_setNotchFilterNative(JNIEnv *
     char value[PROPERTY_VALUE_MAX] = {'\0'};
     int init_success = 0,i;
     char notch[PROPERTY_VALUE_MAX] = {0x00};
-    struct v4l2_control control;
-    int err;
+    int band;
+    int err = 0;
 
     property_get("qcom.bluetooth.soc", value, NULL);
 
@@ -464,20 +515,27 @@ static jint android_hardware_fmradio_FmReceiverJNI_setNotchFilterNative(JNIEnv *
        property_get("notch.value", notch, NULL);
        ALOGE("Notch = %s",notch);
        if (!strncmp("HIGH",notch,strlen("HIGH")))
-           control.value = HIGH_BAND;
+           band = HIGH_BAND;
        else if(!strncmp("LOW",notch,strlen("LOW")))
-           control.value = LOW_BAND;
+           band = LOW_BAND;
        else
-           control.value = 0;
+           band = 0;
 
-       ALOGE("Notch value : %d", control.value);
-       control.id = id;
-       err = ioctl(fd, VIDIOC_S_CTRL,&control );
-       if(err < 0){
-             return FM_JNI_FAILURE;
-       }
+       ALOGE("Notch value : %d", band);
+
+        if ((fd >= 0) && (id >= 0)) {
+            err = FmIoctlsInterface :: set_control(fd, id, band);
+            if (err < 0) {
+                err = FM_JNI_FAILURE;
+            } else {
+                err = FM_JNI_SUCCESS;
+            }
+        } else {
+            err = FM_JNI_FAILURE;
+        }
     }
-    return FM_JNI_SUCCESS;
+
+    return err;
 }
 
 
@@ -528,38 +586,51 @@ static jint android_hardware_fmradio_FmReceiverJNI_setAnalogModeNative(JNIEnv *
 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;
+    int masked_pty;
+    int err;
 
-    control.id = V4L2_CID_RDS_TX_PTY;
-    control.value = pty & MASK_PTY;
+    ALOGE("->android_hardware_fmradio_FmReceiverJNI_setPTYNative\n");
 
-    int err;
-    err = ioctl(fd, VIDIOC_S_CTRL,&control );
-    if(err < 0){
-            return FM_JNI_FAILURE;
+    if (fd >= 0) {
+        masked_pty = pty & MASK_PTY;
+        err = FmIoctlsInterface :: set_control(fd,
+                                                V4L2_CID_RDS_TX_PTY,
+                                                masked_pty);
+        if (err < 0) {
+            err = FM_JNI_FAILURE;
+        } else {
+            err = FM_JNI_SUCCESS;
+        }
+    } else {
+        err = FM_JNI_FAILURE;
     }
-    return FM_JNI_SUCCESS;
+
+    return err;
 }
 
 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;
+    int err;
+    int masked_pi;
 
-    control.id = V4L2_CID_RDS_TX_PI;
-    control.value = pi & MASK_PI;
+    ALOGE("->android_hardware_fmradio_FmReceiverJNI_setPINative\n");
 
-    int err;
-    err = ioctl(fd, VIDIOC_S_CTRL,&control );
-    if(err < 0){
-		ALOGE("->pty native failed");
-            return FM_JNI_FAILURE;
+    if (fd >= 0) {
+        masked_pi = pi & MASK_PI;
+        err = FmIoctlsInterface :: set_control(fd,
+                                                V4L2_CID_RDS_TX_PI,
+                                                masked_pi);
+        if (err < 0) {
+            err = FM_JNI_FAILURE;
+        } else {
+            err = FM_JNI_SUCCESS;
+        }
+    } else {
+        err = FM_JNI_FAILURE;
     }
 
-    return FM_JNI_SUCCESS;
+    return err;
 }
 
 static jint android_hardware_fmradio_FmReceiverJNI_startRTNative
@@ -623,17 +694,23 @@ static jint android_hardware_fmradio_FmReceiverJNI_startRTNative
 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\n");
+    if (fd >= 0) {
+        err = FmIoctlsInterface :: set_control(fd,
+                                                V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_RT,
+                                                0);
+        if (err < 0) {
+            err = FM_JNI_FAILURE;
+        } else {
+            err = FM_JNI_SUCCESS;
+        }
+    } else {
+        err = FM_JNI_FAILURE;
     }
-    ALOGE("->android_hardware_fmradio_FmReceiverJNI_stopRTNative is SUCCESS\n");
-    return FM_JNI_SUCCESS;
+
+    return err;
 }
 
 static jint android_hardware_fmradio_FmReceiverJNI_startPSNative
@@ -696,75 +773,105 @@ static jint android_hardware_fmradio_FmReceiverJNI_startPSNative
 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\n");
+
+    if (fd >= 0) {
+        err = FmIoctlsInterface :: set_control(fd,
+                                                V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_PS_NAME,
+                                                0);
+        if (err < 0) {
+            err = FM_JNI_FAILURE;
+        } else {
+            err = FM_JNI_SUCCESS;
+        }
+    } else {
+        err = FM_JNI_FAILURE;
     }
-    ALOGE("->android_hardware_fmradio_FmReceiverJNI_stopPSNative is SUCCESS\n");
-    return FM_JNI_SUCCESS;
+
+    return err;
 }
 
 static jint android_hardware_fmradio_FmReceiverJNI_configureSpurTable
     (JNIEnv * env, jobject thiz, jint fd)
 {
+    int err;
+
     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");
+    if (fd >= 0) {
+        err = FmIoctlsInterface :: set_control(fd,
+                                                V4L2_CID_PRIVATE_UPDATE_SPUR_TABLE,
+                                                0);
+        if (err < 0) {
+            err = FM_JNI_FAILURE;
+        } else {
+            err = FM_JNI_SUCCESS;
+        }
+    } else {
+        err = FM_JNI_FAILURE;
+    }
 
-    return FM_JNI_SUCCESS;
+    return err;
 }
 
 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;
+    int masked_ps_repeat_cnt;
+    int err;
 
-    control.id = V4L2_CID_PRIVATE_TAVARUA_TX_SETPSREPEATCOUNT;
-    control.value = repCount & MASK_TXREPCOUNT;
+    ALOGE("->android_hardware_fmradio_FmReceiverJNI_setPSRepeatCountNative\n");
 
-    int err;
-    err = ioctl(fd, VIDIOC_S_CTRL,&control );
-    if(err < 0){
-            return FM_JNI_FAILURE;
+    if (fd >= 0) {
+        masked_ps_repeat_cnt = repCount & MASK_TXREPCOUNT;
+        err = FmIoctlsInterface :: set_control(fd,
+                                                V4L2_CID_PRIVATE_TAVARUA_TX_SETPSREPEATCOUNT,
+                                                masked_ps_repeat_cnt);
+        if (err < 0) {
+            err = FM_JNI_FAILURE;
+        } else {
+            err = FM_JNI_SUCCESS;
+        }
+    } else {
+        err = FM_JNI_FAILURE;
     }
 
-    ALOGE("->android_hardware_fmradio_FmReceiverJNI_setPSRepeatCountNative is SUCCESS\n");
-    return FM_JNI_SUCCESS;
+    return err;
 }
 
 static jint android_hardware_fmradio_FmReceiverJNI_setTxPowerLevelNative
     (JNIEnv * env, jobject thiz, jint fd, jint powLevel)
 {
+    int err;
+
     ALOGE("->android_hardware_fmradio_FmReceiverJNI_setTxPowerLevelNative\n");
 
-    struct v4l2_control control;
+    if (fd >= 0) {
+        err = FmIoctlsInterface :: set_control(fd,
+                                                V4L2_CID_TUNE_POWER_LEVEL,
+                                                powLevel);
+        if (err < 0) {
+            err = FM_JNI_FAILURE;
+        } else {
+            err = FM_JNI_SUCCESS;
+        }
+    } else {
+        err = FM_JNI_FAILURE;
+    }
 
-    control.id = V4L2_CID_TUNE_POWER_LEVEL;
-    control.value = powLevel;
+    return err;
+}
 
-    int err;
-    err = ioctl(fd, VIDIOC_S_CTRL,&control );
-    if(err < 0){
-            return FM_JNI_FAILURE;
-    }
+static void android_hardware_fmradio_FmReceiverJNI_configurePerformanceParams
+    (JNIEnv * env, jobject thiz, jint fd)
+{
 
-    ALOGE("->android_hardware_fmradio_FmReceiverJNI_setTxPowerLevelNative is SUCCESS\n");
-    return FM_JNI_SUCCESS;
+     ConfigFmThs thsObj;
+
+     thsObj.SetRxSearchAfThs(FM_PERFORMANCE_PARAMS, fd);
 }
 
 /* native interface */
@@ -867,6 +974,8 @@ static JNINativeMethod gMethods[] = {
             (void*)android_hardware_fmradio_FmReceiverJNI_configureSpurTable},
         { "setSpurDataNative", "(I[SI)I",
             (void*)android_hardware_fmradio_FmReceiverJNI_setSpurDataNative},
+        { "configurePerformanceParams", "(I)V",
+             (void*)android_hardware_fmradio_FmReceiverJNI_configurePerformanceParams},
 };
 
 int register_android_hardware_fm_fmradio(JNIEnv* env)
diff --git a/qcom/fmradio/FmReceiverJNI.java b/qcom/fmradio/FmReceiverJNI.java
index db75ccb..c6ca964 100644
--- a/qcom/fmradio/FmReceiverJNI.java
+++ b/qcom/fmradio/FmReceiverJNI.java
@@ -290,4 +290,5 @@ class FmReceiverJNI {
      *         {@link #FM_JNI_FAILURE}
      */
     static native int setSpurDataNative(int fd, short  buff[], int len);
+    static native void configurePerformanceParams(int fd);
 }
diff --git a/qcom/fmradio/FmRxEventListner.java b/qcom/fmradio/FmRxEventListner.java
index de39d91..5f9a254 100644
--- a/qcom/fmradio/FmRxEventListner.java
+++ b/qcom/fmradio/FmRxEventListner.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009,2012-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009,2012-2014, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -91,6 +91,7 @@ class FmRxEventListner {
                                     FmTransceiver.setFMPowerState(FmTransceiver.FMState_Rx_Turned_On);
                                     Log.v(TAG, "RxEvtList: CURRENT-STATE : FMRxStarting ---> NEW-STATE : FMRxOn");
                                     cb.FmRxEvEnableReceiver();
+                                    FmReceiverJNI.configurePerformanceParams(fd);
                                 }
                                 else if (FmTransceiver.getFMPowerState() == FmTransceiver.subPwrLevel_FMTurning_Off) {
                                     /*Set the state as FMOff */
-- 
GitLab