Revert "FM: Remove Ioctl base code"
This reverts commit 5156eb1ae2b6a385ccfee8a1ddadf5811dce8f82.
Change-Id: I68fb8a81cadde7a49d83f9189d592e88d1b35ba8
diff --git a/jni/Android.bp b/jni/Android.bp
index 1d6e8e0..29da75c 100755
--- a/jni/Android.bp
+++ b/jni/Android.bp
@@ -4,6 +4,10 @@
system_ext_specific: true,
srcs: [
"android_hardware_fm.cpp",
+ "ConfFileParser.cpp",
+ "ConfigFmThs.cpp",
+ "FmIoctlsInterface.cpp",
+ "FmPerformanceParams.cpp",
],
host_ldlibs: ["-ldl"],
diff --git a/jni/ConfFileParser.cpp b/jni/ConfFileParser.cpp
new file mode 100644
index 0000000..d270690
--- /dev/null
+++ b/jni/ConfFileParser.cpp
@@ -0,0 +1,930 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ConfFileParser.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <math.h>
+#include <utils/Log.h>
+
+//declaration of functions only specific to this file
+static char parse_line
+(
+ group_table *key_file,
+ const char *line,
+ char **cur_grp
+);
+
+static char parse_load_frm_fhandler
+(
+ group_table *key_file,
+ FILE *fp
+);
+
+static char line_is_grp
+(
+ group_table *key_file,
+ const char *str,
+ char **cur_grp
+);
+
+static void free_grp_list
+(
+ group *a
+);
+
+static void free_key_list
+(
+ key_value_pair_list *a
+);
+
+static char line_is_key_value_pair
+(
+ group_table *key_file,
+ const char *str,
+ const char *cur_grp
+);
+
+static char line_is_comment
+(
+ const char *str
+);
+
+static char grp_exist
+(
+ const group_table *key_file,
+ const char *new_grp
+);
+
+static char add_grp
+(
+ group_table *key_file,
+ const char *new_grp
+);
+
+static group *alloc_group
+(
+ void
+);
+
+static key_value_pair_list *alloc_key_value_pair
+(
+ void
+);
+
+static char add_key_value_pair
+(
+ group_table *key_file,
+ const char *cur_grp,
+ const char *key,
+ const char *val
+);
+
+
+//Definitions
+void free_strs
+(
+ char **str_array
+)
+{
+ char **str_array_cpy = str_array;
+ if(str_array != NULL) {
+ while(*str_array != NULL) {
+ free(*str_array);
+ str_array++;
+ }
+ }
+ free(str_array_cpy);
+}
+//ToDo: Come up with code hashing
+//function
+unsigned int get_hash_code
+(
+ const char *str
+)
+{
+
+ unsigned len = strlen(str);
+ unsigned int i;
+ unsigned int hash_code = 0;
+
+ for(i = 0; len > 0; len--, i++) {
+ hash_code += (int)((str[i] * pow(2, len))) % INT_MAX;
+ hash_code %= INT_MAX;
+ }
+ return hash_code;
+}
+
+static key_value_pair_list *alloc_key_value_pair
+(
+ void
+)
+{
+ key_value_pair_list *key_list = NULL;
+
+ key_list = (key_value_pair_list *)malloc(
+ sizeof(key_value_pair_list));
+ if(key_list != NULL) {
+ key_list->key = NULL;
+ key_list->next = NULL;
+ key_list->value = NULL;
+ }
+ return key_list;
+}
+
+static group * alloc_group
+(
+ void
+)
+{
+ group *grp = NULL;
+ unsigned int i;
+
+ grp = (group *)malloc(sizeof(group));
+ if(grp != NULL) {
+ grp->grp_name = NULL;
+ grp->grp_next = NULL;
+ grp->num_of_keys = 0;
+ grp->keys_hash_size = MAX_UNIQ_KEYS;
+ grp->list = (key_value_pair_list **)malloc
+ (sizeof(key_value_pair_list *) * grp->keys_hash_size);
+ if(grp->list == NULL) {
+ ALOGE("Could not alloc group\n");
+ free(grp);
+ grp = NULL;
+ }else {
+ for(i = 0; i < grp->keys_hash_size; i++) {
+ grp->list[i] = NULL;
+ }
+ }
+ }
+ return grp;
+}
+
+group_table *get_key_file
+(
+)
+{
+ group_table *t = NULL;
+ unsigned int i;
+
+ t = (group_table *)malloc(sizeof(group_table));
+ if (t != NULL) {
+ t->grps_hash_size = MAX_UNIQ_GRPS;
+ t->num_of_grps = 0;
+ t->grps_hash = (group **)malloc(sizeof(group *)
+ * t->grps_hash_size);
+ if (t->grps_hash == NULL) {
+ free(t);
+ return NULL;
+ }
+ for(i = 0; i < t->grps_hash_size; i++) {
+ t->grps_hash[i] = NULL;
+ }
+ }
+ return t;
+}
+
+void free_key_file(
+ group_table *key_file
+)
+{
+ unsigned int i;
+
+ if(key_file != NULL) {
+ if(key_file->grps_hash != NULL) {
+ for(i = 0; i < key_file->grps_hash_size; i++) {
+ free_grp_list(key_file->grps_hash[i]);
+ }
+ }
+ free(key_file->grps_hash);
+ free(key_file);
+ }
+}
+
+static void free_grp_list
+(
+ group *a
+)
+{
+ group *next;
+ unsigned int i;
+
+ while(a != NULL) {
+ next = a->grp_next;
+ if(a->list != NULL) {
+ for(i = 0; i < a->keys_hash_size; i++) {
+ free_key_list(a->list[i]);
+ }
+ }
+ free(a->grp_name);
+ free(a->list);
+ free(a);
+ a = next;
+ }
+}
+
+static void free_key_list
+(
+ key_value_pair_list *a
+)
+{
+ key_value_pair_list *next;
+
+ while(a != NULL) {
+ next = a->next;
+ free(a->key);
+ free(a->value);
+ free(a);
+ a = next;
+ }
+}
+//return all the groups
+//present in the file
+char **get_grps
+(
+ const group_table *key_file
+)
+{
+ char **grps = NULL;
+ unsigned int i = 0;
+ unsigned int j = 0;
+ unsigned int grp_len;
+ group *grp_list;
+
+ if((key_file == NULL)
+ || (key_file->grps_hash == NULL)
+ || (key_file->grps_hash_size == 0)
+ || (key_file->num_of_grps == 0)) {
+ return grps;
+ }
+ grps = (char **)calloc((key_file->num_of_grps + 1),
+ sizeof(char *));
+ if(grps == NULL) {
+ return grps;
+ }
+ for(i = 0; i < key_file->grps_hash_size; i++) {
+ grp_list = key_file->grps_hash[i];
+ while(grp_list != NULL) {
+ grp_len = strlen(grp_list->grp_name);
+ grps[j] = (char *)malloc(sizeof(char) *
+ (grp_len + 1));
+ if(grps[j] == NULL) {
+ free_strs(grps);
+ grps = NULL;
+ return grps;
+ }
+ memcpy(grps[j], grp_list->grp_name,
+ (grp_len + 1));
+ grp_list = grp_list->grp_next;
+ j++;
+ }
+ }
+ grps[j] = NULL;
+ return grps;
+}
+
+//returns the list of keys
+//associated with group name
+char **get_keys
+(
+ const group_table *key_file,
+ const char *grp_name
+)
+{
+ unsigned int grp_hash_code;
+ unsigned int grp_index;
+ unsigned int num_of_keys;
+ unsigned int i;
+ unsigned int j = 0;
+ unsigned int key_len;
+ group *grp;
+ key_value_pair_list *key_val_list;
+ char **keys = NULL;
+
+ if((key_file == NULL) || (grp_name == NULL)
+ || (key_file->num_of_grps == 0) ||
+ (key_file->grps_hash_size == 0) ||
+ (key_file->grps_hash == NULL) ||
+ (!strcmp(grp_name, ""))) {
+ return keys;
+ }
+ grp_hash_code = get_hash_code(grp_name);
+ grp_index = (grp_hash_code % key_file->grps_hash_size);
+ grp = key_file->grps_hash[grp_index];
+ while(grp != NULL) {
+ if(!strcmp(grp_name, grp->grp_name)) {
+ if((grp->num_of_keys == 0)
+ || (grp->keys_hash_size == 0)
+ || (grp->list == 0)) {
+ return keys;
+ }
+ keys = (char **)calloc((grp->num_of_keys + 1),
+ sizeof(char *));
+ if(keys == NULL) {
+ return keys;
+ }
+ for(i = 0; i < grp->keys_hash_size; i++) {
+ key_val_list = grp->list[i];
+ while(key_val_list != NULL) {
+ key_len = strlen(key_val_list->key);
+ keys[j] = (char *)malloc(sizeof(char) *
+ (key_len + 1));
+ if(keys[j] == NULL) {
+ free_strs(keys);
+ keys = NULL;
+ return keys;
+ }
+ memcpy(keys[j], key_val_list->key,
+ (key_len + 1));
+ j++;
+ key_val_list = key_val_list->next;
+ }
+ }
+ keys[j] = NULL;
+ return keys;
+ }
+ grp = grp->grp_next;
+ }
+ return keys;
+}
+
+char *get_value
+(
+ const group_table *key_file,
+ const char *grp_name,
+ const char *key
+)
+{
+ unsigned int grp_hash_code;
+ unsigned int key_hash_code;
+ unsigned int grp_index;
+ unsigned int key_index;
+ unsigned val_len;
+ char *val = NULL;
+ group *grp;
+ key_value_pair_list *list;
+
+ if((key_file == NULL) || (grp_name == NULL)
+ || (key == NULL) || (key_file->grps_hash == NULL)
+ || (key_file->grps_hash_size == 0) || !strcmp(grp_name, "")
+ ||(!strcmp(key, ""))) {
+ return NULL;
+ }
+ grp_hash_code = get_hash_code(grp_name);
+ key_hash_code = get_hash_code(key);
+ grp_index = (grp_hash_code % key_file->grps_hash_size);
+ grp = key_file->grps_hash[grp_index];
+ while(grp != NULL) {
+ if(!strcmp(grp_name, grp->grp_name) && grp->keys_hash_size
+ && grp->list) {
+ key_index = (key_hash_code % grp->keys_hash_size);
+ list = grp->list[key_index];
+ while((list != NULL) && (strcmp(list->key, key))) {
+ list = list->next;
+ }
+ if(list != NULL) {
+ val_len = strlen(list->value);
+ val = (char *)malloc(sizeof(char) * (val_len + 1));
+ if(val != NULL) {
+ memcpy(val, list->value, val_len);
+ val[val_len] = '\0';
+ }
+ }
+ return val;
+ }
+ grp = grp->grp_next;
+ }
+ return val;
+}
+//open the file,
+//read, parse and load
+//returns PARSE_SUCCESS if successfully
+//loaded else PARSE_FAILED
+char parse_load_file
+(
+ group_table *key_file,
+ const char *file
+)
+{
+ FILE *fp;
+ char ret = FALSE;
+
+ if((file == NULL) || !strcmp(file, "")) {
+ ALOGE("File name is null or empty \n");
+ return ret;
+ }
+
+ fp = fopen(file, "r");
+ if(fp == NULL) {
+ ALOGE("could not open file for read\n");
+ return ret;
+ }
+
+ ret = parse_load_frm_fhandler(key_file, fp);
+ fclose(fp);
+
+ return ret;
+}
+
+//Read block of data from file handler
+//extract each line, check kind of line(comment,
+//group, key value pair)
+static char parse_load_frm_fhandler
+(
+ group_table *key_file,
+ FILE *fp
+)
+{
+ char buf[MAX_LINE_LEN];
+ char ret = TRUE;
+ char *line = NULL;
+ void *new_line;
+ char *cur_grp = NULL;
+ unsigned line_len = 0;
+ unsigned line_allocated = 0;
+ unsigned int bytes_read = 0;
+ unsigned int i;
+ bool has_carriage_rtn = false;
+
+ while((bytes_read = fread(buf, 1, MAX_LINE_LEN, fp))) {
+ for(i = 0; i < bytes_read; i++) {
+ if(line_len == line_allocated) {
+ line_allocated += 25;
+ new_line = realloc(line, line_allocated);
+ if(new_line == NULL) {
+ ret = FALSE;
+ ALOGE("memory allocation failed for line\n");
+ break;
+ }
+ line = (char *)new_line;
+ }
+ if((buf[i] == '\n')) {
+ has_carriage_rtn = false;
+ line[line_len] = '\0';
+ ret = parse_line(key_file, line, &cur_grp);
+ line_len = 0;
+ if(ret == FALSE) {
+ ALOGE("could not parse the line, line not proper\n");
+ break;
+ }
+ }else if(buf[i] == '\r') {
+ ALOGE("File has carriage return\n");
+ has_carriage_rtn = true;
+ }else if(has_carriage_rtn) {
+ ALOGE("File format is not proper, no line character\
+ after carraige return\n");
+ ret = FALSE;
+ break;
+ }else {
+ line[line_len] = buf[i];
+ line_len++;
+ }
+ }
+ if (!ret) {
+ break;
+ }
+ }
+ free(line);
+ free(cur_grp);
+
+ return ret;
+}
+
+//checks whether a line is
+//comment or grp or key pair value
+//and accordingly adds to list
+static char parse_line
+(
+ group_table *key_file,
+ const char *line,
+ char **cur_grp
+)
+{
+ const char *line_begin;
+ char *grp_name;
+ unsigned int len;
+
+ if((line == NULL) || (key_file == NULL)) {
+ ALOGE("key file or line is null\n");
+ return FALSE;
+ }
+
+ for(line_begin = line; isspace(*line_begin);
+ line_begin++);
+
+ if(line_is_comment(line_begin)) {
+ ALOGE("line is comment\n");
+ return TRUE;
+ }else if(line_is_grp(key_file, line_begin, cur_grp)) {
+ ALOGE("line is grp\n");
+ return TRUE;
+ }else if(line_is_key_value_pair(key_file, line_begin, *cur_grp)) {
+ ALOGE("line is key value pair\n");
+ return TRUE;
+ }else {
+ ALOGE("line is neither comment, grp nor key value pair\n");
+ return FALSE;
+ }
+}
+
+static char line_is_comment
+(
+ const char *str
+)
+{
+ if(str == NULL) {
+ return FALSE;
+ }else if(((*str) == '#') || ((*str) == '\0')
+ || ((*str) == '\n')) {
+ return TRUE;
+ }else {
+ ALOGE("line is not comment\n");
+ return FALSE;
+ }
+}
+
+//return true if a group
+//name already exist
+//else false
+static char grp_exist
+(
+ const group_table *key_file,
+ const char *new_grp
+)
+{
+ unsigned hash_code;
+ unsigned int index;
+ group *grp;
+
+ if((key_file == NULL) || (new_grp == NULL)
+ || (!key_file->grps_hash_size)) {
+ return FALSE;
+ }else {
+ hash_code = get_hash_code(new_grp);
+ index = hash_code % key_file->grps_hash_size;
+ grp = key_file->grps_hash[index];
+ while(grp != NULL) {
+ if (!strcmp(grp->grp_name, new_grp))
+ return TRUE;
+ grp = grp->grp_next;
+ }
+ return FALSE;
+ }
+}
+
+//Add a group to group
+//table if it does not exist
+static char add_grp
+(
+ group_table *key_file,
+ const char *new_grp
+)
+{
+ unsigned int hash_code;
+ unsigned int index;
+ unsigned int grp_name_len;
+ group *grp;
+
+ if(!grp_exist(key_file, new_grp)) {
+ if((key_file == NULL) || (new_grp == NULL)
+ || !key_file->grps_hash_size) {
+ return FALSE;
+ }
+ hash_code = get_hash_code(new_grp);
+ ALOGE("group hash code is: %u\n", hash_code);
+ index = hash_code % key_file->grps_hash_size;
+ ALOGE("group index is: %u\n", index);
+ grp = alloc_group();
+ if(grp == NULL) {
+ return FALSE;
+ }
+ grp_name_len = strlen(new_grp);
+ grp->grp_name = (char *)malloc(
+ sizeof(char) * (grp_name_len + 1));
+ if(grp->grp_name == NULL) {
+ ALOGE("could not alloc memory for group name\n");
+ ALOGE("Add group failed\n");
+ free_grp_list(grp);
+ return FALSE;
+ }else {
+ memcpy(grp->grp_name, new_grp, (grp_name_len + 1));
+ }
+ grp->grp_next = key_file->grps_hash[index];
+ key_file->grps_hash[index] = grp;
+ key_file->num_of_grps++;
+ return TRUE;
+ }else {
+ return FALSE;
+ }
+}
+
+//checks validity of a group
+//a valid group is
+//inside [] group name must be
+//alphanumeric
+//Example: [grpName]
+static char line_is_grp
+(
+ group_table *key_file,
+ const char *str,
+ char **cur_grp
+)
+{
+ const char *g_start;
+ const char *g_end;
+ char *new_grp;
+ unsigned int grp_len;
+
+ if ((str == NULL) || (key_file == NULL)) {
+ ALOGE("str is null or key file is null\n");
+ return FALSE;
+ }
+ //checks start mark char ']'
+ if(((*str) != '[')) {
+ ALOGE("start mark is not '['\n");
+ return FALSE;
+ }else {
+ str++;
+ g_start = str;
+ }
+ //checks the end char '['
+ while((*str != '\0') && ((*str) != ']')) {
+ str++;
+ }
+ //if end mark group not found
+ if ((*str) != ']') {
+ ALOGE("grp end mark is not '['\n");
+ return FALSE;
+ }else {
+ g_end = (str - 1);
+ }
+
+ str++;
+ //if end mark found checks the rest chars as well
+ //rest chars should be space
+ while(((*str) == ' ') || ((*str) == '\t')) {
+ str++;
+ }
+ if(*str) {
+ ALOGE("after ']' there are some character\n");
+ return FALSE;
+ }
+
+ str = g_start;
+ while((*g_start != '\0') && (g_start != g_end)
+ && isalnum(*g_start)) {
+ g_start++;
+ }
+ if((g_start == g_end) && isalnum(*g_start)) {
+ //look up if already exist
+ //return false else insert the grp in grp table
+ grp_len = (g_end - str + 1);
+ new_grp = (char *)malloc(sizeof(char) * (grp_len + 1));
+ if (new_grp == NULL) {
+ ALOGE("could not alloc memory for new group\n");
+ return FALSE;
+ }
+ memcpy(new_grp, str, grp_len);
+ new_grp[grp_len] = '\0';
+
+ if(add_grp(key_file, new_grp)) {
+ free(*cur_grp);
+ *cur_grp = new_grp;
+ return TRUE;
+ }else {
+ ALOGE("could not add group to group table\n");
+ return FALSE;
+ }
+ }else {
+ return FALSE;
+ }
+}
+
+static char key_exist
+(
+ const group_table *key_file,
+ const char *cur_grp,
+ const char *key
+)
+{
+ unsigned int grp_hash_code;
+ unsigned int key_hash_code;
+ unsigned int grp_index;
+ unsigned int key_index;
+ group *grp = NULL;
+ key_value_pair_list *list = NULL;
+
+ if((key_file != NULL) && (cur_grp != NULL)
+ && (key != NULL) && ((key_file->grps_hash != NULL))
+ && (strcmp(key, ""))) {
+ grp_hash_code = get_hash_code(cur_grp);
+ grp_index = (grp_hash_code % key_file->grps_hash_size);
+ grp = key_file->grps_hash[grp_index];
+ key_hash_code = get_hash_code(key);
+ while((grp != NULL)) {
+ if(!strcmp(cur_grp, grp->grp_name)) {
+ key_index = (key_hash_code % grp->keys_hash_size);
+ if(grp->list)
+ list = grp->list[key_index];
+ while((list != NULL) && strcmp(key, list->key)) {
+ list = list->next;
+ }
+ if(list != NULL){
+ return TRUE;
+ }else{
+ return FALSE;
+ }
+ }
+ grp = grp->grp_next;
+ }
+ if(!grp) {
+ return TRUE;
+ }else {
+ return FALSE;
+ }
+ }else {
+ return FALSE;
+ }
+}
+
+//checks validity of key
+//a valid key must start in
+//a seperate line and key must
+//be alphanumeric and before '='
+//there must not be any space
+//Example: key=value
+static char line_is_key_value_pair
+(
+ group_table *key_file,
+ const char *str,
+ const char *cur_grp
+)
+{
+ const char *equal_start;
+ char *key = NULL;
+ char *val = NULL;
+ unsigned key_len;
+ unsigned val_len;
+
+ if((str == NULL) || (cur_grp == NULL) ||
+ !strcmp(cur_grp, "") || (key_file == NULL)) {
+ ALOGE("line is null or cur group or key file is null or empty\n");
+ return FALSE;
+ }
+ equal_start = strchr(str, '=');
+ key_len = (equal_start - str);
+ if((equal_start == NULL) || (equal_start == str)) {
+ ALOGE("line does not have '=' character or no key\n");
+ return FALSE;
+ }
+ while((str != equal_start) && isalnum(*str))
+ str++;
+ if((str == equal_start)) {
+ key = (char *)malloc(sizeof(char) * (key_len + 1));
+ if(key == NULL) {
+ ALOGE("could not alloc memory for new key\n");
+ return FALSE;
+ }
+ equal_start++;
+ val_len = strlen(equal_start);
+ val = (char *)malloc(sizeof(char) * (val_len + 1));
+ if(val == NULL) {
+ ALOGE("could not alloc memory for value\n");
+ if(key){
+ free(key);
+ key = NULL;
+ }
+ return FALSE;
+ }
+ memcpy(key, (str - key_len), key_len);
+ memcpy(val, equal_start, val_len);
+ key[key_len] = '\0';
+ val[val_len] = '\0';
+ ALOGE("Grp: %s, key: %s, value: %s\n", cur_grp, key, val);
+ return add_key_value_pair(key_file,
+ cur_grp, key, val);
+ }else {
+ ALOGE("key name doesnot have alpha numeric char\n");
+ return FALSE;
+ }
+}
+
+static char add_key_value_pair
+(
+ group_table *key_file,
+ const char *cur_grp,
+ const char *key,
+ const char *val
+)
+{
+ unsigned int grp_hash_code;
+ unsigned int key_hash_code;
+ unsigned int grp_index;
+ unsigned int key_index;
+ unsigned key_len = 0;
+ unsigned val_len = 0;
+ group *grp = NULL;
+ key_value_pair_list *list = NULL;
+
+ if((key_file != NULL) && (cur_grp != NULL)
+ && (key != NULL) && ((key_file->grps_hash != NULL))
+ && (strcmp(key, ""))) {
+ grp_hash_code = get_hash_code(cur_grp);
+ ALOGE("grp hash code is %u\n", grp_hash_code);
+ grp_index = (grp_hash_code % key_file->grps_hash_size);
+ ALOGE("grp index is %u\n", grp_index);
+ grp = key_file->grps_hash[grp_index];
+ key_hash_code = get_hash_code(key);
+ while((grp != NULL)) {
+ if(!strcmp(cur_grp, grp->grp_name)) {
+ key_index = (key_hash_code % grp->keys_hash_size);
+ if(grp->list) {
+ list = grp->list[key_index];
+ }else {
+ ALOGE("group list is null\n");
+ goto err;
+ }
+ while((list != NULL) && strcmp(key, list->key)) {
+ list = list->next;
+ }
+ if(list != NULL) {
+ ALOGE("group already contains the key\n");
+ goto err;
+ }else{
+ list = alloc_key_value_pair();
+ if(list == NULL) {
+ ALOGE("add key value failed as could not alloc memory for key\
+ val pair\n");
+ goto err;
+ }
+ if(key) {
+ key_len = strlen(key);
+ }
+ list->key = (char *)malloc(sizeof(char) *
+ (key_len + 1));
+ if(list->key == NULL) {
+ ALOGE("could not alloc memory for key\n");
+ free(list);
+ goto err;
+ }
+ if(val) {
+ val_len = strlen(val);
+ }
+ list->value = (char *)malloc(sizeof(char) *
+ (val_len + 1));
+ if(!list->value) {
+ free(list->key);
+ free(list);
+ goto err;
+ }
+ memcpy(list->key, key, key_len);
+ memcpy(list->value, val, val_len);
+ if (key) free((char*)key);
+ if (val) free((char*)val);
+ list->key[key_len] = '\0';
+ list->value[val_len] = '\0';
+ list->next = grp->list[key_index];
+ grp->list[key_index] = list;
+ grp->num_of_keys++;
+ return TRUE;
+ }
+ }
+ grp = grp->grp_next;
+ }
+ ALOGE("group does not exist\n");
+ goto err;
+ }
+err:
+ if (key) free((char*)key);
+ if (val) free((char*)val);
+ return FALSE;
+}
diff --git a/jni/ConfFileParser.h b/jni/ConfFileParser.h
new file mode 100644
index 0000000..33b86ce
--- /dev/null
+++ b/jni/ConfFileParser.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef __CONF_FILE_PARSER_H__
+#define __CONF_FILE_PARSER_H__
+
+#define MAX_LINE_LEN 512
+#define MAX_UNIQ_KEYS 5
+#define MAX_UNIQ_GRPS 10
+#define TRUE 1
+#define FALSE 0
+
+struct key_value_pair_list
+{
+ char *key;
+ char *value;
+ key_value_pair_list *next;
+};
+
+struct group
+{
+ char *grp_name;
+ unsigned int num_of_keys;
+ unsigned int keys_hash_size;
+ key_value_pair_list **list;
+ group *grp_next;
+};
+
+struct group_table
+{
+ unsigned int grps_hash_size;
+ unsigned int num_of_grps;
+ group **grps_hash;
+};
+
+enum CONF_PARSE_ERRO_CODE
+{
+ PARSE_SUCCESS,
+ INVALID_FILE_NAME,
+ FILE_OPEN_FAILED,
+ FILE_NOT_PROPER,
+ MEMORY_ALLOC_FAILED,
+ PARSE_FAILED,
+};
+
+unsigned int get_hash_code(const char *str);
+group_table *get_key_file();
+void free_strs(char **str_array);
+void free_key_file(group_table *key_file);
+char parse_load_file(group_table *key_file, const char *file);
+char **get_grps(const group_table *key_file);
+char **get_keys(const group_table *key_file, const char *grp);
+char *get_value(const group_table *key_file, const char *grp,
+ const char *key);
+
+#endif //__CONF_FILE_PARSER_H__
diff --git a/jni/ConfigFmThs.cpp b/jni/ConfigFmThs.cpp
new file mode 100644
index 0000000..3845dfd
--- /dev/null
+++ b/jni/ConfigFmThs.cpp
@@ -0,0 +1,528 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <cstdlib>
+#include <cstring>
+#include "ConfigFmThs.h"
+#include "FmPerformanceParams.h"
+#include <utils/Log.h>
+
+static int compare_name
+(
+ const void *name1, const void *name2
+)
+{
+ char *first = (char *)name1;
+ struct NAME_MAP *second = (struct NAME_MAP *)name2;
+
+ return(strcmp(first, second->name));
+}
+
+ConfigFmThs :: ConfigFmThs
+(
+)
+{
+ keyfile = NULL;
+}
+
+ConfigFmThs :: ~ConfigFmThs
+(
+)
+{
+ free_key_file(keyfile);
+}
+
+void ConfigFmThs :: set_af_ths
+(
+ UINT fd
+)
+{
+ signed char ret = FM_SUCCESS;
+ char **keys;
+ char **keys_cpy;
+ char *key_value;
+ int value;
+ FmPerformanceParams perf_params;
+ struct NAME_MAP *found;
+
+ if(keyfile != NULL) {
+ keys_cpy = keys = get_keys(keyfile, GRPS_MAP[0].name);
+ if(keys != NULL) {
+ while(*keys != NULL) {
+ ALOGE("key found is: %s\n", *keys);
+ found = (NAME_MAP *)bsearch(*keys, AF_PARAMS_MAP,
+ MAX_AF_PARAMS, sizeof(NAME_MAP), compare_name);
+ if(found != NULL) {
+ key_value = get_value(keyfile,
+ GRPS_MAP[0].name, found->name);
+ if((key_value != NULL) && strcmp(key_value, "")) {
+ value = atoi(key_value);
+ switch(found->num) {
+ case AF_RMSSI_TH:
+ if((value >= AF_RMSSI_TH_MIN)
+ && (value <= AF_RMSSI_TH_MAX)) {
+ ALOGE("Set af rmssi th: %d\n", value);
+ ret = perf_params.SetAfRmssiTh(fd, value);
+ if(ret == FM_FAILURE) {
+ ALOGE("Error in setting Af Rmssi th\n");
+ break;
+ }
+ unsigned short th;
+ ret = perf_params.GetAfRmssiTh(fd, th);
+ if(ret == FM_SUCCESS) {
+ ALOGE("Read af rmssith: %hd\n", th);
+ }else {
+ ALOGE("Error in reading Af Rmssi th\n");
+ }
+ }
+ break;
+ case AF_RMSSI_SAMPLES:
+ if((value >= AF_RMSSI_SAMPLES_MIN)
+ && (value <= AF_RMSSI_SAMPLES_MAX)) {
+ ALOGE("Set af rmssi samples cnt: %d\n", value);
+ ret = perf_params.SetAfRmssiSamplesCnt(fd, value);
+ if(ret == FM_FAILURE) {
+ ALOGE("Error in setting af rmssi samples\n");
+ break;
+ }
+ unsigned char cnt;
+ ret = perf_params.GetAfRmssiSamplesCnt(fd, cnt);
+ if(ret == FM_SUCCESS) {
+ ALOGE("Read af rmssi samples cnt: %hhd\n", cnt);
+ }else {
+ ALOGE("Error in reading rmssi samples\n");
+ }
+ }
+ break;
+ case GOOD_CH_RMSSI_TH:
+ if((value >= GOOD_CH_RMSSI_TH_MIN)
+ && (value <= GOOD_CH_RMSSI_TH_MAX)) {
+ ALOGE("Set Good channle rmssi th: %d\n", value);
+ ret = perf_params.SetGoodChannelRmssiTh(fd, value);
+ if(ret == FM_FAILURE) {
+ ALOGE("Error in setting Good channle rmssi th\n");
+ break;
+ }
+ signed char th;
+ ret = perf_params.GetGoodChannelRmssiTh(fd, th);
+ if(ret == FM_SUCCESS) {
+ ALOGE("Read good channel rmssi th: %d\n", th);
+ }else {
+ ALOGE("Error in reading Good channle rmssi th\n");
+ }
+ }
+ break;
+ }
+ }else {
+ ALOGE("key_val for key: %s is empty\n",
+ *keys);
+ }
+ free(key_value);
+ }
+ keys++;
+ }
+ }else {
+ ALOGE("No of keys found is zero\n");
+ }
+ free_strs(keys_cpy);
+ }else {
+ ALOGE("key file is null\n");
+ }
+}
+
+void ConfigFmThs :: set_srch_ths
+(
+ UINT fd
+)
+{
+ signed char ret = FM_SUCCESS;
+ char **keys = NULL;
+ char **keys_cpy = NULL;
+ char *key_value = NULL;
+ int value;
+ FmPerformanceParams perf_params;
+ struct NAME_MAP *found = NULL;
+
+ if(keyfile != NULL) {
+ keys_cpy = keys = get_keys(keyfile, GRPS_MAP[2].name);
+ if(keys != NULL) {
+ while(*keys != NULL) {
+ found = (NAME_MAP *)bsearch(*keys, SEACH_PARAMS_MAP,
+ MAX_SRCH_PARAMS, sizeof(NAME_MAP), compare_name);
+ if(found != NULL) {
+ key_value = get_value(keyfile, GRPS_MAP[2].name, found->name);
+ ALOGE("found srch ths: %s: %s\n", found->name, key_value);
+ if((key_value != NULL) && strcmp(key_value, "")) {
+ value = atoi(key_value);
+ switch(found->num) {
+ case SINR_FIRST_STAGE:
+ if((value >= SINR_FIRST_STAGE_MIN)
+ && (value <= SINR_FIRST_STAGE_MAX)) {
+ ALOGE("Set sinr first stage: %d\n", value);
+ ret = perf_params.SetSinrFirstStage(fd, value);
+ if(ret == FM_FAILURE) {
+ ALOGE("Error in setting sinr first stage\n");
+ break;
+ }
+ signed char th;
+ ret = perf_params.GetSinrFirstStage(fd, th);
+ if(ret == FM_SUCCESS) {
+ ALOGE("Read sinr first stage: %d\n", th);
+ }else {
+ ALOGE("Error in reading sinr first stage\n");
+ }
+ }
+ break;
+ case RMSSI_FIRST_STAGE:
+ if((value >= RMSSI_FIRST_STAGE_MIN)
+ && (value <= RMSSI_FIRST_STAGE_MAX)) {
+ ALOGE("Set rmssi first stage: %d\n", value);
+ ret = perf_params.SetRmssiFirstStage(fd, value);
+ if(ret == FM_FAILURE) {
+ ALOGE("Error in setting rmssi first stage\n");
+ break;
+ }
+ signed char th;
+ ret = perf_params.GetRmssiFirstStage(fd, th);
+ if(ret == FM_SUCCESS) {
+ ALOGE("Read rmssi first stage: %d\n", th);
+ }else {
+ ALOGE("Error in reading rmssi first stage\n");
+ }
+ }
+ break;
+ case INTF_LOW_TH:
+ if((value >= INTF_LOW_TH_MIN)
+ && (value <= INTF_LOW_TH_MAX)) {
+ ALOGE("Set intf low th: %d\n", value);
+ ret = perf_params.SetIntfLowTh(fd, value);
+ if(ret == FM_FAILURE) {
+ ALOGE("Error in setting intf low th\n");
+ break;
+ }
+ unsigned char th;
+ ret = perf_params.GetIntfLowTh(fd, th);
+ if(ret == FM_SUCCESS) {
+ ALOGE("Read intf low th: %u\n", th);
+ }else {
+ ALOGE("Error in reading intf low th\n");
+ }
+ }
+ break;
+ case INTF_HIGH_TH:
+ if((value >= INTF_HIGH_TH_MIN)
+ && (value <= INTF_HIGH_TH_MAX)) {
+ ALOGE("Set intf high th: %d\n", value);
+ ret = perf_params.SetIntfHighTh(fd, value);
+ if(ret == FM_FAILURE) {
+ ALOGE("Error in setting intf high th\n");
+ break;
+ }
+ unsigned char th;
+ ret = perf_params.GetIntfHighTh(fd, th);
+ if(ret == FM_SUCCESS) {
+ ALOGE("Read intf high th: %u\n", th);
+ }else {
+ ALOGE("Error in reading intf high th\n");
+ }
+ }
+ break;
+ case CF0_TH:
+ ALOGE("Set cf0 th: %d\n", value);
+ ret = perf_params.SetCf0Th12(fd, value);
+ if(ret == FM_FAILURE) {
+ ALOGE("Error in setting cf0 th\n");
+ break;
+ }
+ int th;
+ ret = perf_params.GetCf0Th12(fd, th);
+ if(ret == FM_SUCCESS) {
+ ALOGE("Read CF012 th: %d\n", th);
+ }else {
+ ALOGE("Error in reading cf0 th\n");
+ }
+ break;
+ case SRCH_ALGO_TYPE:
+ if((value >= SRCH_ALGO_TYPE_MIN)
+ && (value <= SRCH_ALGO_TYPE_MAX)) {
+ ALOGE("Set search algo type: %d\n", value);
+ ret = perf_params.SetSrchAlgoType(fd, value);
+ if(ret == FM_FAILURE) {
+ ALOGE("Error in setting search algo type\n");
+ break;
+ }
+ unsigned char algo;
+ ret = perf_params.GetSrchAlgoType(fd, algo);
+ if(ret == FM_SUCCESS) {
+ ALOGE("Read algo type: %u\n", algo);
+ }else {
+ ALOGE("Error in reading search algo type\n");
+ }
+ }
+ break;
+ case SINR_SAMPLES:
+ if((value >= SINR_SAMPLES_CNT_MIN)
+ && (value <= SINR_SAMPLES_CNT_MAX)) {
+ ALOGE("Set sinr samples count: %d\n", value);
+ ret = perf_params.SetSinrSamplesCnt(fd, value);
+ if(ret == FM_FAILURE) {
+ ALOGE("Error in setting sinr samples count\n");
+ break;
+ }
+ unsigned char cnt;
+ ret = perf_params.GetSinrSamplesCnt(fd, cnt);
+ if(ret == FM_SUCCESS) {
+ ALOGE("Read sinr samples cnt: %u\n", cnt);
+ }else {
+ ALOGE("Error in reading sinr samples count\n");
+ }
+ }
+ break;
+ case SINR:
+ if((value >= SINR_FINAL_STAGE_MIN)
+ && (value <= SINR_FINAL_STAGE_MAX)) {
+ ALOGE("Set final stage sinr: %d\n", value);
+ ret = perf_params.SetSinrFinalStage(fd, value);
+ if(ret == FM_FAILURE) {
+ ALOGE("Error in setting final stage sinr\n");
+ break;
+ }
+ signed char th;
+ ret = perf_params.GetSinrFinalStage(fd, th);
+ if(ret == FM_SUCCESS) {
+ ALOGE("Read final stage sinr: %d\n", th);
+ }else {
+ ALOGE("Error in reading final stage sinr\n");
+ }
+ }
+ break;
+ }
+ }else {
+ ALOGE("key_value for key: %s is empty\n",
+ *keys);
+ }
+ free(key_value);
+ }
+ keys++;
+ }
+ }else {
+ ALOGE("No of keys found is zero\n");
+ }
+ free_strs(keys_cpy);
+ }else {
+ ALOGE("key file is null\n");
+ }
+}
+
+void ConfigFmThs :: set_hybrd_list
+(
+ UINT fd
+)
+{
+ signed char ret = FM_SUCCESS;
+ char **keys = NULL;
+ char **keys_cpy = NULL;
+ char *key_value = NULL;
+ char *freqs = NULL;
+ unsigned int *freqs_array = NULL;
+ signed char *sinrs_array = NULL;
+ char *sinrs = NULL;
+ int value;
+ unsigned int freq_cnt = 0;
+ unsigned int sinr_cnt = 0;
+ FmPerformanceParams perf_params;
+ struct NAME_MAP *found;
+
+ ALOGE("Inside hybrid srch list\n");
+ if(keyfile != NULL) {
+ keys_cpy = keys = get_keys(keyfile, GRPS_MAP[1].name);
+ if(keys != NULL) {
+ while(*keys != NULL) {
+ found = (NAME_MAP *)bsearch(*keys, HYBRD_SRCH_MAP,
+ MAX_HYBRID_SRCH_PARAMS, sizeof(NAME_MAP), compare_name);
+ if(found != NULL) {
+ key_value = get_value(keyfile, GRPS_MAP[1].name, found->name);
+ if((key_value != NULL) && strcmp(key_value, "")) {
+ switch(found->num) {
+ case FREQ_LIST:
+ freqs = key_value;
+ break;
+ case SINR_LIST:
+ sinrs = key_value;
+ break;
+ default:
+ free(key_value);
+ break;
+ }
+ }
+ }
+ keys++;
+ }
+ free_strs(keys_cpy);
+ }else {
+ ALOGE("No of keys found is zero\n");
+ }
+ }else {
+ ALOGE("key file is null\n");
+ }
+
+ freq_cnt = extract_comma_sep_freqs(freqs, &freqs_array, ",");
+ sinr_cnt = extract_comma_sep_sinrs(sinrs, &sinrs_array, ",");
+
+ if((freq_cnt == sinr_cnt) && (sinr_cnt > 0)) {
+ perf_params.SetHybridSrchList(fd, freqs_array, sinrs_array, freq_cnt);
+ }
+
+ free(freqs);
+ free(sinrs);
+ free(freqs_array);
+ free(sinrs_array);
+}
+
+unsigned int ConfigFmThs :: extract_comma_sep_freqs
+(
+ char *freqs,
+ unsigned int **freqs_arr,
+ const char *str
+)
+{
+ char *next_freq;
+ char *saveptr = NULL;
+ unsigned int freq;
+ unsigned int *freqs_new_arr;
+ unsigned int size = 0;
+ unsigned int len = 0;
+
+ next_freq = strtok_r(freqs, str, &saveptr);
+ while(next_freq != NULL) {
+ freq = atoi(next_freq);
+ ALOGD("HYBRID_SRCH freq: %u\n", freq);
+ if(size == len) {
+ size <<= 1;
+ if(size == 0)
+ size = 1;
+ freqs_new_arr = (unsigned int *)realloc(*freqs_arr,
+ size * sizeof(unsigned int));
+ if(freqs_new_arr == NULL) {
+ free(*freqs_arr);
+ *freqs_arr = NULL;
+ break;
+ }
+ *freqs_arr = freqs_new_arr;
+ }
+ (*freqs_arr)[len] = freq;
+ len++;
+ next_freq = strtok_r(NULL, str, &saveptr);
+ }
+ return len;
+}
+
+unsigned int ConfigFmThs :: extract_comma_sep_sinrs
+(
+ char *sinrs,
+ signed char **sinrs_arr,
+ const char *str
+)
+{
+ char *next_sinr;
+ char *saveptr = NULL;
+ signed char *sinrs_new_arr;
+ unsigned int size = 0;
+ unsigned int len = 0;
+ signed char sinr;
+
+ next_sinr = strtok_r(sinrs, str, &saveptr);
+ while(next_sinr != NULL) {
+ sinr = atoi(next_sinr);
+ ALOGD("HYBRID_SRCH sinr: %d\n", sinr);
+ if(size == len) {
+ size <<= 1;
+ if(size == 0)
+ size = 1;
+ sinrs_new_arr = (signed char *)realloc(*sinrs_arr,
+ size * sizeof(signed char));
+ if(sinrs_new_arr == NULL) {
+ free(*sinrs_arr);
+ *sinrs_arr = NULL;
+ break;
+ }
+ *sinrs_arr = sinrs_new_arr;
+ }
+ (*sinrs_arr)[len] = sinr;
+ len++;
+ next_sinr = strtok_r(NULL, str, &saveptr);
+ }
+ return len;
+}
+
+void ConfigFmThs :: SetRxSearchAfThs
+(
+ const char *file, UINT fd
+)
+{
+ int index;
+ struct NAME_MAP *found;
+ char **grps = NULL;
+ char **grps_cpy = NULL;
+
+ keyfile = get_key_file();
+
+ ALOGE("file name is: %s\n", file);
+ if(!parse_load_file(keyfile, file)) {
+ ALOGE("Error in loading threshold file\n");
+ }else {
+ grps_cpy = grps = get_grps(keyfile);
+ if(grps != NULL) {
+ while(*grps != NULL) {
+ ALOGE("Search grp: %s\n", *grps);
+ found = (NAME_MAP *)bsearch(*grps, GRPS_MAP, MAX_GRPS,
+ sizeof(NAME_MAP), compare_name);
+ if(found != NULL) {
+ ALOGE("Found group: %s\n", found->name);
+ switch(found->num) {
+ case AF_THS:
+ set_af_ths(fd);
+ break;
+ case SRCH_THS:
+ set_srch_ths(fd);
+ break;
+ case HYBRD_SRCH_LIST:
+ set_hybrd_list(fd);
+ break;
+ }
+ }
+ grps++;
+ }
+ }else {
+ ALOGE("No of groups found is zero\n");
+ }
+ free_strs(grps_cpy);
+ }
+ free_key_file(keyfile);
+ keyfile = NULL;
+}
diff --git a/jni/ConfigFmThs.h b/jni/ConfigFmThs.h
new file mode 100644
index 0000000..0a791f7
--- /dev/null
+++ b/jni/ConfigFmThs.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CONFIG_FM_THS_H__
+#define __CONFIG_FM_THS_H__
+
+#include <cstring>
+#include "FmConst.h"
+#include "ConfFileParser.h"
+
+#define MAX_GRPS 3
+#define MAX_SRCH_PARAMS 8
+#define MAX_AF_PARAMS 3
+
+#define SINR_SAMPLES_CNT_MIN 0
+#define SINR_SAMPLES_CNT_MAX 255
+#define SINR_FIRST_STAGE_MIN -128
+#define SINR_FIRST_STAGE_MAX 127
+#define RMSSI_FIRST_STAGE_MIN -128
+#define RMSSI_FIRST_STAGE_MAX 127
+#define INTF_LOW_TH_MIN 0
+#define INTF_LOW_TH_MAX 255
+#define INTF_HIGH_TH_MIN 0
+#define INTF_HIGH_TH_MAX 255
+#define SRCH_ALGO_TYPE_MIN 0
+#define SRCH_ALGO_TYPE_MAX 1
+#define SINR_FINAL_STAGE_MIN -128
+#define SINR_FINAL_STAGE_MAX 127
+
+#define AF_RMSSI_TH_MIN 0
+#define AF_RMSSI_TH_MAX 65535
+#define AF_RMSSI_SAMPLES_MIN 0
+#define AF_RMSSI_SAMPLES_MAX 255
+#define GOOD_CH_RMSSI_TH_MIN -128
+#define GOOD_CH_RMSSI_TH_MAX 127
+
+const unsigned char MAX_HYBRID_SRCH_PARAMS = 2;
+
+struct NAME_MAP
+{
+ const char name[50];
+ const int num;
+};
+
+enum PERFORMANCE_GRPS
+{
+ AF_THS,
+ SRCH_THS,
+ HYBRD_SRCH_LIST,
+};
+
+enum PERFORMANCE_SRCH_PARAMS
+{
+ SRCH_ALGO_TYPE,
+ CF0_TH,
+ SINR_FIRST_STAGE,
+ SINR,
+ RMSSI_FIRST_STAGE,
+ INTF_LOW_TH,
+ INTF_HIGH_TH,
+ SINR_SAMPLES,
+};
+
+enum PERFORMANCE_AF_PARAMS
+{
+ AF_RMSSI_TH,
+ AF_RMSSI_SAMPLES,
+ GOOD_CH_RMSSI_TH,
+};
+
+enum HYBRID_SRCH_PARAMS
+{
+ FREQ_LIST,
+ SINR_LIST,
+};
+
+//Keep this list in sorted order (ascending order in terms of "name")
+//Don't change the name of GRPS, if changed please also change accordingly
+//file: fm_srch_af_th.conf
+static struct NAME_MAP GRPS_MAP[] =
+{
+ {"AFTHRESHOLDS", AF_THS},
+ {"HYBRIDSEARCHLIST", HYBRD_SRCH_LIST},
+ {"SEARCHTHRESHOLDS", SRCH_THS},
+};
+
+//Keep this list in sorted order (ascending order in terms of "name")
+//Don't change the name of SEARCH thresholds,
+//if changed please also change accordingly
+//file: fm_srch_af_th.conf
+static struct NAME_MAP SEACH_PARAMS_MAP[] =
+{
+ {"Cf0Th12", CF0_TH},
+ {"IntfHighTh", INTF_HIGH_TH},
+ {"IntfLowTh", INTF_LOW_TH},
+ {"RmssiFirstStage", RMSSI_FIRST_STAGE},
+ {"SearchAlgoType", SRCH_ALGO_TYPE},
+ {"Sinr", SINR},
+ {"SinrFirstStage", SINR_FIRST_STAGE},
+ {"SinrSamplesCnt", SINR_SAMPLES},
+};
+
+//Keep this list in sorted order (ascending order in terms of "name")
+//Don't change the name of SEARCH thresholds,
+//if changed please also change accordingly
+//file: fm_srch_af_th.conf
+static struct NAME_MAP AF_PARAMS_MAP[] =
+{
+ {"AfRmssiSamplesCnt", AF_RMSSI_SAMPLES},
+ {"AfRmssiTh", AF_RMSSI_TH},
+ {"GoodChRmssiTh", GOOD_CH_RMSSI_TH},
+};
+
+static struct NAME_MAP HYBRD_SRCH_MAP[] =
+{
+ {"Freqs", FREQ_LIST},
+ {"Sinrs", SINR_LIST},
+};
+
+class ConfigFmThs {
+ private:
+ group_table *keyfile;
+ void set_srch_ths(UINT fd);
+ void set_af_ths(UINT fd);
+ unsigned int extract_comma_sep_freqs(char *freqs, unsigned int **freqs_arr, const char *str);
+ unsigned int extract_comma_sep_sinrs(char *sinrs, signed char **sinrs_arr, const char *str);
+ void set_hybrd_list(UINT fd);
+ public:
+ ConfigFmThs();
+ ~ConfigFmThs();
+ void SetRxSearchAfThs(const char *file, UINT fd);
+};
+
+#endif //__CONFIG_FM_THS_H__
diff --git a/jni/FmConst.h b/jni/FmConst.h
new file mode 100644
index 0000000..e37160f
--- /dev/null
+++ b/jni/FmConst.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2014, 2015, The Linux Foundation. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __FM_CONST_H__
+#define __FM_CONST_H__
+
+
+typedef unsigned int UINT;
+typedef unsigned long ULINT;
+
+//return related
+const int IOCTL_SUCC = 0;
+const int FM_SUCCESS = 0;
+const int FM_FAILURE = -1;
+const int PROP_SET_SUCC = 0;
+
+#define TUNE_MULT 16
+const UINT CAL_DATA_SIZE = 23;
+#define STD_BUF_SIZE 256
+
+const char *const FM_PERFORMANCE_PARAMS = "/etc/fm/fm_srch_af_th.conf";
+const char *const CALIB_DATA_NAME = "/data/misc/fm/Riva_fm_cal";
+
+#define V4L2_CTRL_CLASS_USER 0x00980000
+#define V4L2_CID_BASE (V4L2_CTRL_CLASS_USER | 0x900)
+#define V4L2_CID_AUDIO_MUTE (V4L2_CID_BASE + 9)
+const UINT SEARCH_DWELL_TIME = 2;
+const UINT SEEK_DWELL_TIME = 0;
+
+enum FM_AUDIO_PATH
+{
+ AUDIO_DIGITAL_PATH,
+ AUDIO_ANALOG_PATH,
+};
+
+enum FM_DEVICE
+{
+ FM_DEV_NONE,
+ FM_RX,
+ FM_TX,
+};
+
+enum BUFF_INDEXES
+{
+ STATION_LIST_IND,
+ EVENT_IND,
+ RT_IND,
+ PS_IND,
+ AF_LIST_IND = PS_IND + 2,
+ RT_PLUS_IND = 11,
+ ERT_IND,
+};
+
+enum SEARCH_MODE
+{
+ SEEK_MODE,
+ SCAN_MODE,
+};
+
+enum SEARCH_DIR
+{
+ SEARCH_DOWN,
+ SEARCH_UP,
+};
+
+enum AUDIO_MODE
+{
+ MONO,
+ STEREO,
+};
+
+//V4L2 CONTROLS FOR FM DRIVER
+enum FM_V4L2_PRV_CONTROLS
+{
+ V4L2_CID_PRV_BASE = 0x8000000,
+ V4L2_CID_PRV_SRCHMODE,
+ V4L2_CID_PRV_SCANDWELL,
+ V4L2_CID_PRV_SRCHON,
+ V4L2_CID_PRV_STATE,
+ V4L2_CID_PRV_TRANSMIT_MODE,
+ V4L2_CID_PRV_RDSGROUP_MASK,
+ V4L2_CID_PRV_REGION,
+ V4L2_CID_PRV_SIGNAL_TH,
+ V4L2_CID_PRV_SRCH_PTY,
+ V4L2_CID_PRV_SRCH_PI,
+ V4L2_CID_PRV_SRCH_CNT,
+ V4L2_CID_PRV_EMPHASIS,
+ V4L2_CID_PRV_RDS_STD,
+ V4L2_CID_PRV_CHAN_SPACING,
+ V4L2_CID_PRV_RDSON,
+ V4L2_CID_PRV_RDSGROUP_PROC,
+ V4L2_CID_PRV_LP_MODE,
+ V4L2_CID_PRV_INTDET = V4L2_CID_PRV_BASE + 25,
+ V4L2_CID_PRV_AF_JUMP = V4L2_CID_PRV_BASE + 27,
+ V4L2_CID_PRV_SOFT_MUTE = V4L2_CID_PRV_BASE + 30,
+ V4L2_CID_PRV_AUDIO_PATH = V4L2_CID_PRV_BASE + 41,
+ V4L2_CID_PRV_SINR = V4L2_CID_PRV_BASE + 44,
+ V4L2_CID_PRV_ON_CHANNEL_THRESHOLD = V4L2_CID_PRV_BASE + 0x2D,
+ V4L2_CID_PRV_OFF_CHANNEL_THRESHOLD,
+ V4L2_CID_PRV_SINR_THRESHOLD,
+ V4L2_CID_PRV_SINR_SAMPLES,
+ V4L2_CID_PRV_SPUR_FREQ,
+ V4L2_CID_PRV_SPUR_FREQ_RMSSI,
+ V4L2_CID_PRV_SPUR_SELECTION,
+ V4L2_CID_PRV_AF_RMSSI_TH = V4L2_CID_PRV_BASE + 0x36,
+ V4L2_CID_PRV_AF_RMSSI_SAMPLES,
+ V4L2_CID_PRV_GOOD_CH_RMSSI_TH,
+ V4L2_CID_PRV_SRCHALGOTYPE,
+ V4L2_CID_PRV_CF0TH12,
+ V4L2_CID_PRV_SINRFIRSTSTAGE,
+ V4L2_CID_PRV_RMSSIFIRSTSTAGE,
+ V4L2_CID_PRV_SOFT_MUTE_TH,
+ V4L2_CID_PRV_IRIS_RDSGRP_RT,
+ V4L2_CID_PRV_IRIS_RDSGRP_PS_SIMPLE,
+ V4L2_CID_PRV_IRIS_RDSGRP_AFLIST,
+ V4L2_CID_PRV_IRIS_RDSGRP_ERT,
+ V4L2_CID_PRV_IRIS_RDSGRP_RT_PLUS,
+ V4L2_CID_PRV_IRIS_RDSGRP_3A,
+
+ V4L2_CID_PRV_IRIS_READ_DEFAULT = V4L2_CTRL_CLASS_USER + 0x928,
+ V4L2_CID_PRV_IRIS_WRITE_DEFAULT,
+ V4L2_CID_PRV_SET_CALIBRATION = V4L2_CTRL_CLASS_USER + 0x92A,
+ HCI_FM_HELIUM_SET_SPURTABLE = 0x0098092D,
+ HCI_FM_HELIUM_GET_SPUR_TBL = 0x0098092E,
+ V4L2_CID_PRV_IRIS_FREQ,
+ V4L2_CID_PRV_IRIS_SEEK,
+ V4L2_CID_PRV_IRIS_UPPER_BAND,
+ V4L2_CID_PRV_IRIS_LOWER_BAND,
+ V4L2_CID_PRV_IRIS_AUDIO_MODE,
+ V4L2_CID_PRV_IRIS_RMSSI,
+
+ V4L2_CID_PRV_ENABLE_SLIMBUS = 0x00980940,
+};
+
+#endif
diff --git a/jni/FmIoctlsInterface.cpp b/jni/FmIoctlsInterface.cpp
new file mode 100644
index 0000000..640a90f
--- /dev/null
+++ b/jni/FmIoctlsInterface.cpp
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "FmIoctlsInterface.h"
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <fcntl.h>
+#include <utils/Log.h>
+#include <cutils/properties.h>
+#include <sys/ioctl.h>
+#include <linux/videodev2.h>
+#include <math.h>
+
+char const * const FmIoctlsInterface::LOGTAG = "FmIoctlsInterface";
+
+int FmIoctlsInterface :: get_cur_freq
+(
+ UINT fd, long &freq
+)
+{
+ int ret;
+ struct v4l2_frequency channel;
+
+ channel.type = V4L2_TUNER_RADIO;
+ ret = ioctl(fd, VIDIOC_G_FREQUENCY, &channel);
+
+ if(ret < IOCTL_SUCC) {
+ return FM_FAILURE;
+ }else {
+ freq = (channel.frequency / TUNE_MULT);
+ return FM_SUCCESS;
+ }
+}
+
+int FmIoctlsInterface :: set_freq
+(
+ UINT fd, ULINT freq
+)
+{
+ int ret;
+ struct v4l2_frequency channel;
+
+ channel.type = V4L2_TUNER_RADIO;
+ channel.frequency = (freq * TUNE_MULT);
+
+ ret = ioctl(fd, VIDIOC_S_FREQUENCY, &channel);
+ if(ret < IOCTL_SUCC) {
+ return FM_FAILURE;
+ }else {
+ return FM_SUCCESS;
+ }
+}
+
+int FmIoctlsInterface :: set_control
+(
+ UINT fd, UINT id, int val
+)
+{
+ int ret;
+ struct v4l2_control control;
+
+ control.value = val;
+ control.id = id;
+
+ for(int i = 0; i < 3; i++) {
+ ret = ioctl(fd, VIDIOC_S_CTRL, &control);
+ if(ret < IOCTL_SUCC) {
+ ret = FM_FAILURE;
+ }else {
+ ret = FM_SUCCESS;
+ break;
+ }
+ }
+ return ret;
+}
+
+int FmIoctlsInterface :: set_calibration
+(
+ UINT fd
+)
+{
+ int ret;
+ FILE *cal_fp;
+ struct v4l2_ext_control ext_ctl;
+ struct v4l2_ext_controls v4l2_ctls;
+ char cal_data[CAL_DATA_SIZE] = {0};
+
+ memset(&v4l2_ctls, 0, sizeof(v4l2_ctls));
+ memset(&ext_ctl, 0, sizeof(ext_ctl));
+
+ cal_fp = fopen(CALIB_DATA_NAME, "r");
+ if(cal_fp != NULL) {
+ if(fread(&cal_data[0], 1, CAL_DATA_SIZE, cal_fp)
+ < CAL_DATA_SIZE) {
+ fclose(cal_fp);
+ ALOGE("%s: calibration file read failed\n", LOGTAG);
+ return FM_FAILURE;
+ }
+ fclose(cal_fp);
+ ext_ctl.id = V4L2_CID_PRV_SET_CALIBRATION;
+ ext_ctl.string = cal_data;
+ ext_ctl.size = CAL_DATA_SIZE;
+ v4l2_ctls.ctrl_class = V4L2_CTRL_CLASS_USER;
+ v4l2_ctls.count = 1;
+ v4l2_ctls.controls = &ext_ctl;
+ ret = ioctl(fd, VIDIOC_S_EXT_CTRLS, &v4l2_ctls);
+ if(ret < IOCTL_SUCC) {
+ ALOGE("%s: ioctl call failed\n", LOGTAG);
+ return FM_FAILURE;
+ }else {
+ return FM_SUCCESS;
+ }
+ }else {
+ return FM_SUCCESS;
+ }
+}
+
+int FmIoctlsInterface :: get_control
+(
+ UINT fd, UINT id, long &val
+)
+{
+ int ret;
+ struct v4l2_control control;
+
+ control.id = id;
+ ret = ioctl(fd, VIDIOC_G_CTRL, &control);
+ if(ret < IOCTL_SUCC) {
+ return FM_FAILURE;
+ }else {
+ val = control.value;
+ return FM_SUCCESS;
+ }
+}
+
+int FmIoctlsInterface :: start_search
+(
+ UINT fd, UINT dir
+)
+{
+ int ret;
+ struct v4l2_hw_freq_seek hw_seek;
+
+ hw_seek.seek_upward = dir;
+ hw_seek.type = V4L2_TUNER_RADIO;
+
+ ret = ioctl(fd, VIDIOC_S_HW_FREQ_SEEK, &hw_seek);
+ if(ret < IOCTL_SUCC) {
+ return FM_FAILURE;
+ }else {
+ return FM_SUCCESS;
+ }
+}
+
+int FmIoctlsInterface :: set_band
+(
+ UINT fd, ULINT low, ULINT high
+)
+{
+ int ret;
+ struct v4l2_tuner tuner;
+
+ tuner.index = 0;
+ tuner.signal = 0;
+ tuner.rangelow = (low * TUNE_MULT);
+ tuner.rangehigh = (high * TUNE_MULT);
+
+ ret = ioctl(fd, VIDIOC_S_TUNER, &tuner);
+ ret = set_control(fd, V4L2_CID_PRV_REGION, 0);
+ if(ret < IOCTL_SUCC) {
+ return FM_FAILURE;
+ }else {
+ return FM_SUCCESS;
+ }
+}
+
+int FmIoctlsInterface :: get_rmssi
+(
+ UINT fd, long &rmssi
+)
+{
+ struct v4l2_tuner tuner;
+ int ret;
+
+ tuner.index = 0;
+ tuner.signal = 0;
+ ret = ioctl(fd, VIDIOC_G_TUNER, &tuner);
+ if(ret < IOCTL_SUCC) {
+ ret = FM_FAILURE;
+ }else {
+ rmssi = tuner.signal;
+ ret = FM_SUCCESS;
+ }
+ return ret;
+}
+
+int FmIoctlsInterface :: get_upperband_limit
+(
+ UINT fd, ULINT &freq
+)
+{
+ int ret;
+ struct v4l2_tuner tuner;
+
+ tuner.index = 0;
+ ret = ioctl(fd, VIDIOC_G_TUNER, &tuner);
+ if(ret < IOCTL_SUCC) {
+ return FM_FAILURE;
+ }else {
+ freq = (tuner.rangehigh / TUNE_MULT);
+ return FM_SUCCESS;
+ }
+}
+
+int FmIoctlsInterface :: get_lowerband_limit
+(
+ UINT fd, ULINT &freq
+)
+{
+ int ret;
+ struct v4l2_tuner tuner;
+
+ tuner.index = 0;
+ ret = ioctl(fd, VIDIOC_G_TUNER, &tuner);
+ if(ret < IOCTL_SUCC) {
+ return FM_FAILURE;
+ }else {
+ freq = (tuner.rangelow / TUNE_MULT);
+ return FM_SUCCESS;
+ }
+}
+
+int FmIoctlsInterface :: set_audio_mode
+(
+ UINT fd, enum AUDIO_MODE mode
+)
+{
+ int ret;
+ struct v4l2_tuner tuner;
+
+ tuner.index = 0;
+ ret = ioctl(fd, VIDIOC_G_TUNER, &tuner);
+ if(ret < IOCTL_SUCC) {
+ return FM_FAILURE;
+ }else {
+ tuner.audmode = mode;
+ ret = ioctl(fd, VIDIOC_S_TUNER, &tuner);
+ if(ret < IOCTL_SUCC) {
+ return FM_FAILURE;
+ }else {
+ return FM_SUCCESS;
+ }
+ }
+}
+
+int FmIoctlsInterface :: get_buffer
+(
+ UINT fd, char *buff, UINT len, UINT index
+)
+{
+ int ret;
+ struct v4l2_buffer v4l2_buf;
+
+ if((len < STD_BUF_SIZE) || (buff == NULL)) {
+ return FM_FAILURE;
+ }else {
+ memset(&v4l2_buf, 0, sizeof(v4l2_buf));
+ v4l2_buf.index = index;
+ v4l2_buf.type = V4L2_BUF_TYPE_PRIVATE;
+ v4l2_buf.length = STD_BUF_SIZE;
+ v4l2_buf.m.userptr = (ULINT)buff;
+ ret = ioctl(fd, VIDIOC_DQBUF, &v4l2_buf);
+ if(ret < IOCTL_SUCC) {
+ return FM_FAILURE;
+ }else {
+ return v4l2_buf.bytesused;
+ }
+ }
+}
+
+int FmIoctlsInterface :: set_ext_control
+(
+ UINT fd,
+ struct v4l2_ext_controls *v4l2_ctls
+)
+{
+ int ret;
+
+ ret = ioctl(fd, VIDIOC_S_EXT_CTRLS, v4l2_ctls);
+
+ if(ret < IOCTL_SUCC) {
+ return FM_FAILURE;
+ }else {
+ return FM_SUCCESS;
+ }
+}
+
diff --git a/jni/FmIoctlsInterface.h b/jni/FmIoctlsInterface.h
new file mode 100644
index 0000000..eda28ee
--- /dev/null
+++ b/jni/FmIoctlsInterface.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __FM_IOCTL_INTERFACE_H__
+#define __FM_IOCTL_INTERFACE_H__
+
+#include "FmConst.h"
+
+#include <linux/videodev2.h>
+
+class FmIoctlsInterface
+{
+ private:
+ static char const * const LOGTAG;
+ public:
+ static int start_fm_patch_dl(UINT fd);
+ static int close_fm_patch_dl(void);
+ static int get_cur_freq(UINT fd, long &freq);
+ static int set_freq(UINT fd, ULINT freq);
+ static int set_control(UINT fd, UINT id, int val);
+ static int set_calibration(UINT fd);
+ static int get_control(UINT fd, UINT id, long &val);
+ static int start_search(UINT fd, UINT dir);
+ static int set_band(UINT fd, ULINT low, ULINT high);
+ static int get_upperband_limit(UINT fd, ULINT &freq);
+ static int get_lowerband_limit(UINT fd, ULINT &freq);
+ static int set_audio_mode(UINT fd, enum AUDIO_MODE mode);
+ static int get_buffer(UINT fd, char *buff, UINT len, UINT index);
+ static int get_rmssi(UINT fd, long &rmssi);
+ static int set_ext_control(UINT fd, struct v4l2_ext_controls *v4l2_ctls);
+};
+
+//char const *FmIoctlsInterface::LOGTAG = "FmIoctlsInterface";
+
+#endif //__FM_IOCTL_INTERFACE_H__
diff --git a/jni/FmPerformanceParams.cpp b/jni/FmPerformanceParams.cpp
new file mode 100644
index 0000000..bdd0a43
--- /dev/null
+++ b/jni/FmPerformanceParams.cpp
@@ -0,0 +1,422 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "FmPerformanceParams.h"
+#include "FmIoctlsInterface.h"
+
+#include <cstdio>
+#include <linux/videodev2.h>
+#include <utils/Log.h>
+
+signed char FmPerformanceParams :: SetAfRmssiTh
+(
+ UINT fd, unsigned short th
+)
+{
+ signed char ret = FM_FAILURE;
+
+ ret = FmIoctlsInterface::set_control(fd,
+ V4L2_CID_PRV_AF_RMSSI_TH, th);
+
+ return ret;
+}
+
+signed char FmPerformanceParams :: SetAfRmssiSamplesCnt
+(
+ UINT fd, unsigned char cnt
+)
+{
+ signed char ret = FM_FAILURE;
+
+ ret = FmIoctlsInterface::set_control(fd,
+ V4L2_CID_PRV_AF_RMSSI_SAMPLES, cnt);
+
+ return ret;
+}
+
+signed char FmPerformanceParams :: SetGoodChannelRmssiTh
+(
+ UINT fd, signed char th
+)
+{
+ signed char ret = FM_FAILURE;
+
+ ret = FmIoctlsInterface::set_control(fd,
+ V4L2_CID_PRV_GOOD_CH_RMSSI_TH, th);
+
+ return ret;
+}
+
+signed char FmPerformanceParams :: SetSrchAlgoType
+(
+ UINT fd, unsigned char algo
+)
+{
+ signed char ret = FM_FAILURE;
+
+ ret = FmIoctlsInterface::set_control(fd,
+ V4L2_CID_PRV_SRCHALGOTYPE, algo);
+
+ return ret;
+}
+
+signed char FmPerformanceParams :: SetSinrFirstStage
+(
+ UINT fd, signed char th
+)
+{
+ signed char ret = FM_FAILURE;
+
+ ret = FmIoctlsInterface::set_control(fd,
+ V4L2_CID_PRV_SINRFIRSTSTAGE, th);
+
+ return ret;
+}
+
+signed char FmPerformanceParams :: SetRmssiFirstStage
+(
+ UINT fd, signed char th
+)
+{
+ signed char ret = FM_FAILURE;
+
+ ret = FmIoctlsInterface::set_control(fd,
+ V4L2_CID_PRV_RMSSIFIRSTSTAGE, th);
+
+ return ret;
+}
+
+signed char FmPerformanceParams :: SetCf0Th12
+(
+ UINT fd, int th
+)
+{
+ signed char ret = FM_FAILURE;
+
+ ret = FmIoctlsInterface::set_control(fd,
+ V4L2_CID_PRV_CF0TH12, th);
+ return ret;
+}
+
+signed char FmPerformanceParams :: SetSinrSamplesCnt
+(
+ UINT fd, unsigned char cnt
+)
+{
+ signed char ret = FM_FAILURE;
+
+ ret = FmIoctlsInterface::set_control(fd,
+ V4L2_CID_PRV_SINR_SAMPLES, cnt);
+
+ return ret;
+}
+
+signed char FmPerformanceParams :: SetIntfLowTh
+(
+ UINT fd, unsigned char th
+)
+{
+ signed char ret = FM_FAILURE;
+
+ ret = FmIoctlsInterface::set_control(fd,
+ V4L2_CID_PRV_ON_CHANNEL_THRESHOLD, th);
+
+ return ret;
+}
+
+signed char FmPerformanceParams :: SetIntfHighTh
+(
+ UINT fd, unsigned char th
+)
+{
+ signed char ret = FM_FAILURE;
+
+ ret = FmIoctlsInterface::set_control(fd,
+ V4L2_CID_PRV_OFF_CHANNEL_THRESHOLD, th);
+ return ret;
+}
+
+signed char FmPerformanceParams :: SetSinrFinalStage
+(
+ UINT fd, signed char th
+)
+{
+ signed char ret = FM_FAILURE;
+
+ ret = FmIoctlsInterface::set_control(fd,
+ V4L2_CID_PRV_SINR_THRESHOLD, th);
+
+ return ret;
+}
+
+signed char FmPerformanceParams :: GetAfRmssiTh
+(
+ UINT fd, unsigned short &th
+)
+{
+ long int af_rmssi_th;
+ signed char ret = FM_FAILURE;
+
+ ret = FmIoctlsInterface::get_control(fd,
+ V4L2_CID_PRV_AF_RMSSI_TH, af_rmssi_th);
+ if(ret == FM_SUCCESS) {
+ th = af_rmssi_th;
+ }
+ return ret;
+}
+
+signed char FmPerformanceParams :: GetAfRmssiSamplesCnt
+(
+ UINT fd, unsigned char &cnt
+)
+{
+ long int af_samples_cnt;
+ signed char ret = FM_FAILURE;
+
+ ret = FmIoctlsInterface::get_control(fd,
+ V4L2_CID_PRV_AF_RMSSI_SAMPLES, af_samples_cnt);
+ if(ret == FM_SUCCESS) {
+ cnt = af_samples_cnt;
+ }
+ return ret;
+}
+
+signed char FmPerformanceParams :: GetGoodChannelRmssiTh
+(
+ UINT fd, signed char &th
+)
+{
+ long int gd_chan_rmssi_th;
+ signed char ret = FM_FAILURE;
+
+ ret = FmIoctlsInterface::get_control(fd,
+ V4L2_CID_PRV_GOOD_CH_RMSSI_TH, gd_chan_rmssi_th);
+ if(ret == FM_SUCCESS) {
+ th = gd_chan_rmssi_th;
+ }
+ return ret;
+}
+
+signed char FmPerformanceParams :: GetSrchAlgoType
+(
+ UINT fd, unsigned char &algo
+)
+{
+ long int srch_algo_type;
+ signed char ret = FM_FAILURE;
+
+ ret = FmIoctlsInterface::get_control(fd,
+ V4L2_CID_PRV_SRCHALGOTYPE, srch_algo_type);
+ if(ret == FM_SUCCESS) {
+ algo = srch_algo_type;
+ }
+ return ret;
+}
+
+signed char FmPerformanceParams :: GetSinrFirstStage
+(
+ UINT fd, signed char &th
+)
+{
+ long int sinr_first_stage;
+ signed char ret = FM_FAILURE;
+
+ ret = FmIoctlsInterface::get_control(fd,
+ V4L2_CID_PRV_SINRFIRSTSTAGE, sinr_first_stage);
+ if(ret == FM_SUCCESS) {
+ th = sinr_first_stage;
+ }
+ return ret;
+}
+
+signed char FmPerformanceParams :: GetRmssiFirstStage
+(
+ UINT fd, signed char &th
+)
+{
+ long int rmssi_first_stage;
+ signed char ret = FM_FAILURE;
+
+ ret = FmIoctlsInterface::get_control(fd,
+ V4L2_CID_PRV_RMSSIFIRSTSTAGE, rmssi_first_stage);
+ if(ret == FM_SUCCESS) {
+ th = rmssi_first_stage;
+ }
+ return ret;
+}
+
+signed char FmPerformanceParams :: GetCf0Th12
+(
+ UINT fd, int &th
+)
+{
+ long int cf0th12;
+ signed char ret = FM_FAILURE;
+
+ ret = FmIoctlsInterface::get_control(fd,
+ V4L2_CID_PRV_CF0TH12, cf0th12);
+ if(ret == FM_SUCCESS) {
+ th = cf0th12;
+ }
+ return ret;
+}
+
+signed char FmPerformanceParams :: GetSinrSamplesCnt
+(
+ UINT fd, unsigned char &cnt
+)
+{
+ long int sinr_samples_cnt;
+ signed char ret = FM_FAILURE;
+
+ ret = FmIoctlsInterface::get_control(fd,
+ V4L2_CID_PRV_SINR_SAMPLES, sinr_samples_cnt);
+ if(ret == FM_SUCCESS) {
+ cnt = sinr_samples_cnt;
+ }
+ return ret;
+}
+
+signed char FmPerformanceParams :: GetIntfLowTh
+(
+ UINT fd, unsigned char &th
+)
+{
+ long int intf_low_th;
+ signed char ret = FM_FAILURE;
+
+ ret = FmIoctlsInterface::get_control(fd,
+ V4L2_CID_PRV_ON_CHANNEL_THRESHOLD, intf_low_th);
+ if(ret == FM_SUCCESS) {
+ th = intf_low_th;
+ }
+ return ret;
+}
+
+signed char FmPerformanceParams :: GetIntfHighTh
+(
+ UINT fd, unsigned char &th
+)
+{
+ long int intf_high_th;
+ signed char ret = FM_FAILURE;
+
+ ret = FmIoctlsInterface::get_control(fd,
+ V4L2_CID_PRV_OFF_CHANNEL_THRESHOLD, intf_high_th);
+ if(ret == FM_SUCCESS) {
+ th = intf_high_th;
+ }
+ return ret;
+}
+
+signed char FmPerformanceParams :: GetIntfDet
+(
+ UINT fd, unsigned char &th
+)
+{
+ long int int_det;
+ signed char ret = FM_FAILURE;
+
+ ret = FmIoctlsInterface::get_control(fd,
+ V4L2_CID_PRV_INTDET, int_det);
+ if(ret == FM_SUCCESS) {
+ th = int_det;
+ }
+ return ret;
+}
+signed char FmPerformanceParams :: GetSinrFinalStage
+(
+ UINT fd, signed char &th
+)
+{
+ signed char ret = FM_FAILURE;
+ long int sinr;
+
+ ret = FmIoctlsInterface::get_control(fd,
+ V4L2_CID_PRV_SINR_THRESHOLD, sinr);
+
+ if(ret == FM_SUCCESS) {
+ th = sinr;
+ }
+ return ret;
+}
+
+signed char FmPerformanceParams :: SetHybridSrchList
+(
+ UINT fd,
+ unsigned int *freqs,
+ signed char *sinrs,
+ unsigned int n
+)
+{
+ struct v4l2_ext_control ext_ctl;
+ struct v4l2_ext_controls v4l2_ctls;
+ unsigned int freq;
+ signed char sinr;
+ unsigned int size = 0;
+ char *data = NULL;
+ signed char ret = FM_FAILURE;
+
+ if(n <= 0) {
+ return ret;
+ }
+ data = new char[(n * 3 + 3)];
+
+ if(data != NULL) {
+ data[size++] = 0x40;
+ data[size++] = ((n * 3) + 1);
+ data[size++] = n;
+ while((size < (n * 3 + 2)) && (freqs != NULL)
+ && (sinrs != NULL)) {
+ freq = (*freqs - 76000) / 50;
+ data[size++] = (freq & 0xff);
+ data[size++] = ((freq >> 8) & 0xff);
+ data[size++] = *sinrs;
+ freqs++;
+ sinrs++;
+ }
+ if(size == (n * 3 + 3)) {
+ ext_ctl.id = V4L2_CID_PRV_IRIS_WRITE_DEFAULT;
+ ext_ctl.string = data;
+ ext_ctl.size = size;
+ v4l2_ctls.ctrl_class = V4L2_CTRL_CLASS_USER;
+ v4l2_ctls.count = 1;
+ v4l2_ctls.controls = &ext_ctl;
+ ret = FmIoctlsInterface::set_ext_control(fd, &v4l2_ctls);
+ if(ret == FM_SUCCESS) {
+ ALOGE("hybrid srch list sent successfully\n");
+ }else {
+ ALOGE("hybrid srch list setting failed\n");
+ }
+ }
+ }
+
+ delete []data;
+
+ return ret;
+}
diff --git a/jni/FmPerformanceParams.h b/jni/FmPerformanceParams.h
new file mode 100644
index 0000000..fd9ee52
--- /dev/null
+++ b/jni/FmPerformanceParams.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of The Linux Foundation nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __FM_PERFORMANCE_PARAMS_H__
+#define __FM_PERFORMANCE_PARAMS_H__
+
+#include "FmConst.h"
+
+class FmPerformanceParams
+{
+ private:
+ public:
+ signed char SetAfRmssiTh(UINT fd, unsigned short th);
+ signed char SetAfRmssiSamplesCnt(UINT fd, unsigned char cnt);
+ signed char SetGoodChannelRmssiTh(UINT fd, signed char th);
+ signed char SetSrchAlgoType(UINT fd, unsigned char algo);
+ signed char SetSinrFirstStage(UINT fd, signed char th);
+ signed char SetRmssiFirstStage(UINT fd, signed char th);
+ signed char SetCf0Th12(UINT fd, int th);
+ signed char SetSinrSamplesCnt(UINT fd, unsigned char cnt);
+ signed char SetIntfLowTh(UINT fd, unsigned char th);
+ signed char SetIntfHighTh(UINT fd, unsigned char th);
+ signed char SetSinrFinalStage(UINT fd, signed char th);
+ signed char SetHybridSrchList(UINT fd, unsigned int *freqs, signed char *sinrs, unsigned int n);
+
+ signed char GetAfRmssiTh(UINT fd, unsigned short &th);
+ signed char GetAfRmssiSamplesCnt(UINT fd, unsigned char &cnt);
+ signed char GetGoodChannelRmssiTh(UINT fd, signed char &th);
+ signed char GetSrchAlgoType(UINT fd, unsigned char &algo);
+ signed char GetSinrFirstStage(UINT fd, signed char &th);
+ signed char GetRmssiFirstStage(UINT fd, signed char &th);
+ signed char GetCf0Th12(UINT fd, int &th);
+ signed char GetSinrSamplesCnt(UINT fd, unsigned char &cnt);
+ signed char GetIntfLowTh(UINT fd, unsigned char &th);
+ signed char GetIntfHighTh(UINT fd, unsigned char &th);
+ signed char GetIntfDet(UINT fd, unsigned char &th);
+ signed char GetSinrFinalStage(UINT fd, signed char &th);
+};
+
+#endif //__FM_PERFORMANCE_PARAMS_H__
diff --git a/jni/android_hardware_fm.cpp b/jni/android_hardware_fm.cpp
index 76490ee..622d4e9 100644
--- a/jni/android_hardware_fm.cpp
+++ b/jni/android_hardware_fm.cpp
@@ -32,6 +32,8 @@
#include <nativehelper/JNIHelp.h>
#include <utils/Log.h>
#include "utils/misc.h"
+#include "FmIoctlsInterface.h"
+#include "ConfigFmThs.h"
#include <cutils/properties.h>
#include <fcntl.h>
#include <math.h>
@@ -45,9 +47,7 @@
#include <vector>
#include "radio-helium.h"
-typedef unsigned int UINT;
-typedef unsigned long ULINT;
-#define STD_BUF_SIZE 256
+#define RADIO "/dev/radio0"
#define FM_JNI_SUCCESS 0L
#define FM_JNI_FAILURE -1L
#define SEARCH_DOWN 0
@@ -74,68 +74,6 @@
#define MASK_PTY (0x0000001F)
#define MASK_TXREPCOUNT (0x0000000F)
-enum FM_V4L2_PRV_CONTROLS
-{
- V4L2_CID_PRV_BASE = 0x8000000,
- V4L2_CID_PRV_SRCHMODE,
- V4L2_CID_PRV_SCANDWELL,
- V4L2_CID_PRV_SRCHON,
- V4L2_CID_PRV_STATE,
- V4L2_CID_PRV_TRANSMIT_MODE,
- V4L2_CID_PRV_RDSGROUP_MASK,
- V4L2_CID_PRV_REGION,
- V4L2_CID_PRV_SIGNAL_TH,
- V4L2_CID_PRV_SRCH_PTY,
- V4L2_CID_PRV_SRCH_PI,
- V4L2_CID_PRV_SRCH_CNT,
- V4L2_CID_PRV_EMPHASIS,
- V4L2_CID_PRV_RDS_STD,
- V4L2_CID_PRV_CHAN_SPACING,
- V4L2_CID_PRV_RDSON,
- V4L2_CID_PRV_RDSGROUP_PROC,
- V4L2_CID_PRV_LP_MODE,
- V4L2_CID_PRV_INTDET = V4L2_CID_PRV_BASE + 25,
- V4L2_CID_PRV_AF_JUMP = V4L2_CID_PRV_BASE + 27,
- V4L2_CID_PRV_SOFT_MUTE = V4L2_CID_PRV_BASE + 30,
- V4L2_CID_PRV_AUDIO_PATH = V4L2_CID_PRV_BASE + 41,
- V4L2_CID_PRV_SINR = V4L2_CID_PRV_BASE + 44,
- V4L2_CID_PRV_ON_CHANNEL_THRESHOLD = V4L2_CID_PRV_BASE + 0x2D,
- V4L2_CID_PRV_OFF_CHANNEL_THRESHOLD,
- V4L2_CID_PRV_SINR_THRESHOLD,
- V4L2_CID_PRV_SINR_SAMPLES,
- V4L2_CID_PRV_SPUR_FREQ,
- V4L2_CID_PRV_SPUR_FREQ_RMSSI,
- V4L2_CID_PRV_SPUR_SELECTION,
- V4L2_CID_PRV_AF_RMSSI_TH = V4L2_CID_PRV_BASE + 0x36,
- V4L2_CID_PRV_AF_RMSSI_SAMPLES,
- V4L2_CID_PRV_GOOD_CH_RMSSI_TH,
- V4L2_CID_PRV_SRCHALGOTYPE,
- V4L2_CID_PRV_CF0TH12,
- V4L2_CID_PRV_SINRFIRSTSTAGE,
- V4L2_CID_PRV_RMSSIFIRSTSTAGE,
- V4L2_CID_PRV_SOFT_MUTE_TH,
- V4L2_CID_PRV_IRIS_RDSGRP_RT,
- V4L2_CID_PRV_IRIS_RDSGRP_PS_SIMPLE,
- V4L2_CID_PRV_IRIS_RDSGRP_AFLIST,
- V4L2_CID_PRV_IRIS_RDSGRP_ERT,
- V4L2_CID_PRV_IRIS_RDSGRP_RT_PLUS,
- V4L2_CID_PRV_IRIS_RDSGRP_3A,
-
- V4L2_CID_PRV_IRIS_READ_DEFAULT = V4L2_CTRL_CLASS_USER + 0x928,
- V4L2_CID_PRV_IRIS_WRITE_DEFAULT,
- V4L2_CID_PRV_SET_CALIBRATION = V4L2_CTRL_CLASS_USER + 0x92A,
- HCI_FM_HELIUM_SET_SPURTABLE = 0x0098092D,
- HCI_FM_HELIUM_GET_SPUR_TBL = 0x0098092E,
- V4L2_CID_PRV_IRIS_FREQ,
- V4L2_CID_PRV_IRIS_SEEK,
- V4L2_CID_PRV_IRIS_UPPER_BAND,
- V4L2_CID_PRV_IRIS_LOWER_BAND,
- V4L2_CID_PRV_IRIS_AUDIO_MODE,
- V4L2_CID_PRV_IRIS_RMSSI,
-
- V4L2_CID_PRV_ENABLE_SLIMBUS = 0x00980940,
-};
-
enum search_dir_t {
SEEK_UP,
SEEK_DN,
@@ -648,6 +586,13 @@
};
/* native interface */
+static bool is_soc_pronto() {
+ if(strcmp(soc_name, "pronto") == 0)
+ return true;
+ else
+ return false;
+}
+
static void get_property(int ptype, char *value)
{
std::vector<vendor_property_t> vPropList;
@@ -660,6 +605,83 @@
}
}
+static jint android_hardware_fmradio_FmReceiverJNI_acquireFdNative
+ (JNIEnv* env, jobject thiz, jstring path)
+{
+ int fd;
+ int i,err;
+ char value[PROPERTY_VALUE_MAX] = {'\0'};
+ int init_success = 0;
+ jboolean isCopy;
+ v4l2_capability cap;
+ const char* radio_path = env->GetStringUTFChars(path, &isCopy);
+
+ if(radio_path == NULL){
+ return FM_JNI_FAILURE;
+ }
+ fd = open(radio_path, O_RDONLY, O_NONBLOCK);
+ if(isCopy == JNI_TRUE){
+ env->ReleaseStringUTFChars(path, radio_path);
+ }
+ if(fd < 0){
+ return FM_JNI_FAILURE;
+ }
+ //Read the driver verions
+ err = ioctl(fd, VIDIOC_QUERYCAP, &cap);
+
+ ALOGD("VIDIOC_QUERYCAP returns :%d: version: %d \n", err , cap.version );
+
+ if (is_soc_pronto())
+ {
+ /*Set the mode for soc downloader*/
+ if (bt_configstore_intf != NULL) {
+ bt_configstore_intf->set_vendor_property(FM_PROP_HW_MODE, "normal");
+
+ /* Need to clear the hw.fm.init firstly */
+ bt_configstore_intf->set_vendor_property(FM_PROP_HW_INIT, "0");
+ bt_configstore_intf->set_vendor_property(FM_PROP_CTL_START, "fm_dl");
+
+ sched_yield();
+ for(i=0; i<45; i++) {
+ get_property(FM_PROP_HW_INIT, value);
+ if (strcmp(value, "1") == 0) {
+ init_success = 1;
+ break;
+ } else {
+ usleep(WAIT_TIMEOUT);
+ }
+ }
+ ALOGE("init_success:%d after %f seconds \n", init_success, 0.2*i);
+ if(!init_success) {
+ bt_configstore_intf->set_vendor_property(FM_PROP_CTL_STOP,"fm_dl");
+ // close the fd(power down)
+ close(fd);
+ return FM_JNI_FAILURE;
+ }
+ }
+ }
+ return fd;
+}
+
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_closeFdNative
+ (JNIEnv * env, jobject thiz, jint fd)
+{
+ if (is_soc_pronto() && bt_configstore_intf != NULL)
+ {
+ bt_configstore_intf->set_vendor_property(FM_PROP_CTL_STOP,"fm_dl");
+ }
+ close(fd);
+ return FM_JNI_SUCCESS;
+}
+
+static bool is_soc_cherokee() {
+ if(strcmp(soc_name, "cherokee") == 0)
+ return true;
+ else
+ return false;
+}
+
/********************************************************************
* Current JNI
*******************************************************************/
@@ -670,13 +692,31 @@
{
int err;
long freq;
-
- err = vendor_interface->get_fm_ctrl(V4L2_CID_PRV_IRIS_FREQ, (int *)&freq);
- if (err == FM_JNI_SUCCESS) {
- err = freq;
- } else {
- err = FM_JNI_FAILURE;
- ALOGE("%s: get freq failed\n", LOG_TAG);
+ if (is_soc_cherokee())
+ {
+ err = vendor_interface->get_fm_ctrl(V4L2_CID_PRV_IRIS_FREQ, (int *)&freq);
+ if (err == FM_JNI_SUCCESS) {
+ err = freq;
+ } else {
+ err = FM_JNI_FAILURE;
+ ALOGE("%s: get freq failed\n", LOG_TAG);
+ }
+ }
+ else
+ {
+ if (fd >= 0) {
+ err = FmIoctlsInterface :: get_cur_freq(fd, freq);
+ if(err < 0) {
+ err = FM_JNI_FAILURE;
+ ALOGE("%s: get freq failed\n", LOG_TAG);
+ } else {
+ err = freq;
+ }
+ } else {
+ ALOGE("%s: get freq failed because fd is negative, fd: %d\n",
+ LOG_TAG, fd);
+ err = FM_JNI_FAILURE;
+ }
}
return err;
}
@@ -686,9 +726,26 @@
(JNIEnv * env, jobject thiz, jint fd, jint freq)
{
int err;
-
- err = vendor_interface->set_fm_ctrl(V4L2_CID_PRV_IRIS_FREQ, freq);
-
+ if (is_soc_cherokee())
+ {
+ err = vendor_interface->set_fm_ctrl(V4L2_CID_PRV_IRIS_FREQ, freq);
+ }
+ else
+ {
+ if ((fd >= 0) && (freq > 0)) {
+ err = FmIoctlsInterface :: set_freq(fd, freq);
+ if (err < 0) {
+ ALOGE("%s: set freq failed, freq: %d\n", LOG_TAG, freq);
+ err = FM_JNI_FAILURE;
+ } else {
+ err = FM_JNI_SUCCESS;
+ }
+ } else {
+ ALOGE("%s: set freq failed because either fd/freq is negative,\
+ fd: %d, freq: %d\n", LOG_TAG, fd, freq);
+ err = FM_JNI_FAILURE;
+ }
+ }
return err;
}
@@ -698,9 +755,26 @@
{
int err;
ALOGE("id(%x) value: %x\n", id, value);
-
- err = vendor_interface->set_fm_ctrl(id, value);
-
+ if (is_soc_cherokee())
+ {
+ err = vendor_interface->set_fm_ctrl(id, value);
+ }
+ else
+ {
+ if ((fd >= 0) && (id >= 0)) {
+ err = FmIoctlsInterface :: set_control(fd, id, value);
+ if (err < 0) {
+ ALOGE("%s: set control failed, id: %d\n", LOG_TAG, id);
+ err = FM_JNI_FAILURE;
+ } else {
+ err = FM_JNI_SUCCESS;
+ }
+ } else {
+ ALOGE("%s: set control failed because either fd/id is negavtive,\
+ fd: %d, id: %d\n", LOG_TAG, fd, id);
+ err = FM_JNI_FAILURE;
+ }
+ }
return err;
}
@@ -712,13 +786,33 @@
long val;
ALOGE("id(%x)\n", id);
- err = vendor_interface->get_fm_ctrl(id, (int *)&val);
- if (err < 0) {
- ALOGE("%s: get control failed, id: %d\n", LOG_TAG, id);
- err = FM_JNI_FAILURE;
- } else {
- err = val;
+ if (is_soc_cherokee())
+ {
+ err = vendor_interface->get_fm_ctrl(id, (int *)&val);
+ if (err < 0) {
+ ALOGE("%s: get control failed, id: %d\n", LOG_TAG, id);
+ err = FM_JNI_FAILURE;
+ } else {
+ err = val;
+ }
}
+ else
+ {
+ if ((fd >= 0) && (id >= 0)) {
+ err = FmIoctlsInterface :: get_control(fd, id, val);
+ if (err < 0) {
+ ALOGE("%s: get control failed, id: %d\n", LOG_TAG, id);
+ err = FM_JNI_FAILURE;
+ } else {
+ err = val;
+ }
+ } else {
+ ALOGE("%s: get control failed because either fd/id is negavtive,\
+ fd: %d, id: %d\n", LOG_TAG, fd, id);
+ err = FM_JNI_FAILURE;
+ }
+ }
+
return err;
}
@@ -727,15 +821,33 @@
(JNIEnv * env, jobject thiz, jint fd, jint dir)
{
int err;
-
- err = vendor_interface->set_fm_ctrl(V4L2_CID_PRV_IRIS_SEEK, dir);
- if (err < 0) {
- ALOGE("%s: search failed, dir: %d\n", LOG_TAG, dir);
- err = FM_JNI_FAILURE;
- } else {
- err = FM_JNI_SUCCESS;
+ if (is_soc_cherokee())
+ {
+ err = vendor_interface->set_fm_ctrl(V4L2_CID_PRV_IRIS_SEEK, dir);
+ if (err < 0) {
+ ALOGE("%s: search failed, dir: %d\n", LOG_TAG, dir);
+ err = FM_JNI_FAILURE;
+ } else {
+ err = FM_JNI_SUCCESS;
+ }
}
-
+ else
+ {
+ if ((fd >= 0) && (dir >= 0)) {
+ ALOGD("startSearchNative: Issuing the VIDIOC_S_HW_FREQ_SEEK");
+ err = FmIoctlsInterface :: start_search(fd, dir);
+ if (err < 0) {
+ ALOGE("%s: search failed, dir: %d\n", LOG_TAG, dir);
+ err = FM_JNI_FAILURE;
+ } else {
+ err = FM_JNI_SUCCESS;
+ }
+ } else {
+ ALOGE("%s: search failed because either fd/dir is negative,\
+ fd: %d, dir: %d\n", LOG_TAG, fd, dir);
+ err = FM_JNI_FAILURE;
+ }
+ }
return err;
}
@@ -745,14 +857,32 @@
{
int err;
- err = vendor_interface->set_fm_ctrl(V4L2_CID_PRV_SRCHON, 0);
- if (err < 0) {
- ALOGE("%s: cancel search failed\n", LOG_TAG);
- err = FM_JNI_FAILURE;
- } else {
- err = FM_JNI_SUCCESS;
+ if (is_soc_cherokee())
+ {
+ err = vendor_interface->set_fm_ctrl(V4L2_CID_PRV_SRCHON, 0);
+ if (err < 0) {
+ ALOGE("%s: cancel search failed\n", LOG_TAG);
+ err = FM_JNI_FAILURE;
+ } else {
+ err = FM_JNI_SUCCESS;
+ }
}
-
+ else
+ {
+ if (fd >= 0) {
+ err = FmIoctlsInterface :: set_control(fd, V4L2_CID_PRV_SRCHON, 0);
+ if (err < 0) {
+ ALOGE("%s: cancel search failed\n", LOG_TAG);
+ err = FM_JNI_FAILURE;
+ } else {
+ err = FM_JNI_SUCCESS;
+ }
+ } else {
+ ALOGE("%s: cancel search failed because fd is negative, fd: %d\n",
+ LOG_TAG, fd);
+ err = FM_JNI_FAILURE;
+ }
+ }
return err;
}
@@ -763,14 +893,32 @@
int err;
long rmssi;
- err = vendor_interface->get_fm_ctrl(V4L2_CID_PRV_IRIS_RMSSI, (int *)&rmssi);
- if (err < 0) {
- ALOGE("%s: Get Rssi failed", LOG_TAG);
- err = FM_JNI_FAILURE;
- } else {
- err = FM_JNI_SUCCESS;
+ if (is_soc_cherokee())
+ {
+ err = vendor_interface->get_fm_ctrl(V4L2_CID_PRV_IRIS_RMSSI, (int *)&rmssi);
+ if (err < 0) {
+ ALOGE("%s: Get Rssi failed", LOG_TAG);
+ err = FM_JNI_FAILURE;
+ } else {
+ err = FM_JNI_SUCCESS;
+ }
}
-
+ else
+ {
+ if (fd >= 0) {
+ err = FmIoctlsInterface :: get_rmssi(fd, rmssi);
+ if (err < 0) {
+ ALOGE("%s: get rmssi failed\n", LOG_TAG);
+ err = FM_JNI_FAILURE;
+ } else {
+ err = rmssi;
+ }
+ } else {
+ ALOGE("%s: get rmssi failed because fd is negative, fd: %d\n",
+ LOG_TAG, fd);
+ err = FM_JNI_FAILURE;
+ }
+ }
return err;
}
@@ -779,21 +927,39 @@
(JNIEnv * env, jobject thiz, jint fd, jint low, jint high)
{
int err;
-
- err = vendor_interface->set_fm_ctrl(V4L2_CID_PRV_IRIS_UPPER_BAND, high);
- if (err < 0) {
- ALOGE("%s: set band failed, high: %d\n", LOG_TAG, high);
- err = FM_JNI_FAILURE;
- return err;
+ if (is_soc_cherokee())
+ {
+ err = vendor_interface->set_fm_ctrl(V4L2_CID_PRV_IRIS_UPPER_BAND, high);
+ if (err < 0) {
+ ALOGE("%s: set band failed, high: %d\n", LOG_TAG, high);
+ err = FM_JNI_FAILURE;
+ return err;
+ }
+ err = vendor_interface->set_fm_ctrl(V4L2_CID_PRV_IRIS_LOWER_BAND, low);
+ if (err < 0) {
+ ALOGE("%s: set band failed, low: %d\n", LOG_TAG, low);
+ err = FM_JNI_FAILURE;
+ } else {
+ err = FM_JNI_SUCCESS;
+ }
}
- err = vendor_interface->set_fm_ctrl(V4L2_CID_PRV_IRIS_LOWER_BAND, low);
- if (err < 0) {
- ALOGE("%s: set band failed, low: %d\n", LOG_TAG, low);
- err = FM_JNI_FAILURE;
- } else {
- err = FM_JNI_SUCCESS;
+ else
+ {
+ if ((fd >= 0) && (low >= 0) && (high >= 0)) {
+ err = FmIoctlsInterface :: set_band(fd, low, high);
+ if (err < 0) {
+ ALOGE("%s: set band failed, low: %d, high: %d\n",
+ LOG_TAG, low, high);
+ err = FM_JNI_FAILURE;
+ } else {
+ err = FM_JNI_SUCCESS;
+ }
+ } else {
+ ALOGE("%s: set band failed because either fd/band is negative,\
+ fd: %d, low: %d, high: %d\n", LOG_TAG, fd, low, high);
+ err = FM_JNI_FAILURE;
+ }
}
-
return err;
}
@@ -803,7 +969,8 @@
{
int err;
ULINT freq;
-
+if (is_soc_cherokee())
+{
err = vendor_interface->get_fm_ctrl(V4L2_CID_PRV_IRIS_LOWER_BAND, (int *)&freq);
if (err < 0) {
ALOGE("%s: get lower band failed\n", LOG_TAG);
@@ -811,7 +978,24 @@
} else {
err = freq;
}
-
+ return err;
+}
+else
+{
+ if (fd >= 0) {
+ err = FmIoctlsInterface :: get_lowerband_limit(fd, freq);
+ if (err < 0) {
+ ALOGE("%s: get lower band failed\n", LOG_TAG);
+ err = FM_JNI_FAILURE;
+ } else {
+ err = freq;
+ }
+ } else {
+ ALOGE("%s: get lower band failed because fd is negative,\
+ fd: %d\n", LOG_TAG, fd);
+ err = FM_JNI_FAILURE;
+ }
+}
return err;
}
@@ -821,7 +1005,8 @@
{
int err;
ULINT freq;
-
+if (is_soc_cherokee())
+{
err = vendor_interface->get_fm_ctrl(V4L2_CID_PRV_IRIS_UPPER_BAND, (int *)&freq);
if (err < 0) {
ALOGE("%s: get upper band failed\n", LOG_TAG);
@@ -829,7 +1014,24 @@
} else {
err = freq;
}
-
+ return err;
+}
+else
+{
+ if (fd >= 0) {
+ err = FmIoctlsInterface :: get_upperband_limit(fd, freq);
+ if (err < 0) {
+ ALOGE("%s: get lower band failed\n", LOG_TAG);
+ err = FM_JNI_FAILURE;
+ } else {
+ err = freq;
+ }
+ } else {
+ ALOGE("%s: get lower band failed because fd is negative,\
+ fd: %d\n", LOG_TAG, fd);
+ err = FM_JNI_FAILURE;
+ }
+}
return err;
}
@@ -838,7 +1040,8 @@
{
int err;
-
+if (is_soc_cherokee())
+{
err = vendor_interface->set_fm_ctrl(V4L2_CID_PRV_IRIS_AUDIO_MODE, val);
if (err < 0) {
ALOGE("%s: set audio mode failed\n", LOG_TAG);
@@ -846,6 +1049,51 @@
} else {
err = FM_JNI_SUCCESS;
}
+ return err;
+}
+else
+{
+ if (fd >= 0) {
+ err = FmIoctlsInterface :: set_audio_mode(fd, (enum AUDIO_MODE)val);
+ if (err < 0) {
+ err = FM_JNI_FAILURE;
+ } else {
+ err = FM_JNI_SUCCESS;
+ }
+ } else {
+ err = FM_JNI_FAILURE;
+ }
+}
+ return err;
+}
+
+
+/* native interface */
+static jint android_hardware_fmradio_FmReceiverJNI_getBufferNative
+ (JNIEnv * env, jobject thiz, jint fd, jbyteArray buff, jint index)
+{
+ int err;
+ jboolean isCopy;
+ jbyte *byte_buffer = NULL;
+
+ if ((fd >= 0) && (index >= 0)) {
+ ALOGE("index: %d\n", index);
+ byte_buffer = env->GetByteArrayElements(buff, &isCopy);
+ err = FmIoctlsInterface :: get_buffer(fd,
+ (char *)byte_buffer,
+ STD_BUF_SIZE,
+ index);
+ if (err < 0) {
+ err = FM_JNI_FAILURE;
+ }
+ if (buff != NULL) {
+ ALOGE("Free the buffer\n");
+ env->ReleaseByteArrayElements(buff, byte_buffer, 0);
+ byte_buffer = NULL;
+ }
+ } else {
+ err = FM_JNI_FAILURE;
+ }
return err;
}
@@ -862,28 +1110,81 @@
static jint android_hardware_fmradio_FmReceiverJNI_configureSpurTable
(JNIEnv * env, jobject thiz, jint fd)
{
+ int err;
+
ALOGD("->android_hardware_fmradio_FmReceiverJNI_configureSpurTable\n");
- return FM_JNI_SUCCESS;
+ if (fd >= 0) {
+ err = FmIoctlsInterface :: set_control(fd,
+ V4L2_CID_PRIVATE_UPDATE_SPUR_TABLE,
+ 0);
+ if (err < 0) {
+ err = FM_JNI_FAILURE;
+ } else {
+ err = FM_JNI_SUCCESS;
+ }
+ } else {
+ err = FM_JNI_FAILURE;
+ }
+
+ return err;
}
static jint android_hardware_fmradio_FmReceiverJNI_setPSRepeatCountNative
(JNIEnv * env, jobject thiz, jint fd, jint repCount)
{
+ int masked_ps_repeat_cnt;
+ int err;
ALOGE("->android_hardware_fmradio_FmReceiverJNI_setPSRepeatCountNative\n");
- return FM_JNI_SUCCESS;
+ if (fd >= 0) {
+ masked_ps_repeat_cnt = repCount & MASK_TXREPCOUNT;
+ err = FmIoctlsInterface :: set_control(fd,
+ V4L2_CID_PRIVATE_TAVARUA_TX_SETPSREPEATCOUNT,
+ masked_ps_repeat_cnt);
+ if (err < 0) {
+ err = FM_JNI_FAILURE;
+ } else {
+ err = FM_JNI_SUCCESS;
+ }
+ } else {
+ err = FM_JNI_FAILURE;
+ }
+ return err;
}
static jint android_hardware_fmradio_FmReceiverJNI_setTxPowerLevelNative
(JNIEnv * env, jobject thiz, jint fd, jint powLevel)
{
+ int err;
ALOGE("->android_hardware_fmradio_FmReceiverJNI_setTxPowerLevelNative\n");
- return FM_JNI_SUCCESS;
+ if (fd >= 0) {
+ err = FmIoctlsInterface :: set_control(fd,
+ V4L2_CID_TUNE_POWER_LEVEL,
+ powLevel);
+ if (err < 0) {
+ err = FM_JNI_FAILURE;
+ } else {
+ err = FM_JNI_SUCCESS;
+ }
+ } else {
+ err = FM_JNI_FAILURE;
+ }
+
+ return err;
+}
+
+static void android_hardware_fmradio_FmReceiverJNI_configurePerformanceParams
+ (JNIEnv * env, jobject thiz, jint fd)
+{
+
+ ConfigFmThs thsObj;
+
+ thsObj.SetRxSearchAfThs(FM_PERFORMANCE_PARAMS, fd);
}
/* native interface */
@@ -891,7 +1192,37 @@
(JNIEnv * env, jobject thiz, jint fd, jshortArray buff, jint count)
{
ALOGE("entered JNI's setSpurDataNative\n");
+ int err, i = 0;
+ struct v4l2_ext_control ext_ctl;
+ struct v4l2_ext_controls v4l2_ctls;
+ uint8_t *data;
+ short *spur_data = env->GetShortArrayElements(buff, NULL);
+ if (spur_data == NULL) {
+ ALOGE("Spur data is NULL\n");
+ return FM_JNI_FAILURE;
+ }
+ data = (uint8_t *) malloc(count);
+ if (data == NULL) {
+ ALOGE("Allocation failed for data\n");
+ return FM_JNI_FAILURE;
+ }
+ for(i = 0; i < count; i++)
+ data[i] = (uint8_t) spur_data[i];
+ ext_ctl.id = V4L2_CID_PRIVATE_IRIS_SET_SPURTABLE;
+ ext_ctl.string = (char*)data;
+ ext_ctl.size = count;
+ v4l2_ctls.ctrl_class = V4L2_CTRL_CLASS_USER;
+ v4l2_ctls.count = 1;
+ v4l2_ctls.controls = &ext_ctl;
+
+ err = ioctl(fd, VIDIOC_S_EXT_CTRLS, &v4l2_ctls );
+ if (err < 0){
+ ALOGE("Set ioctl failed\n");
+ free(data);
+ return FM_JNI_FAILURE;
+ }
+ free(data);
return FM_JNI_SUCCESS;
}
@@ -900,8 +1231,9 @@
{
ALOGD("%s: val = %d\n", __func__, val);
int err = JNI_ERR;
+if (is_soc_cherokee()) {
err = vendor_interface->set_fm_ctrl(V4L2_CID_PRV_ENABLE_SLIMBUS, val);
-
+}
return err;
}
@@ -945,8 +1277,9 @@
{
ALOGD("%s: val = %d\n", __func__, val);
int err = JNI_ERR;
+if (is_soc_cherokee()) {
err = vendor_interface->set_fm_ctrl(V4L2_CID_PRV_SOFT_MUTE, val);
-
+}
return err;
}
@@ -1026,6 +1359,7 @@
}
static void initNative(JNIEnv *env, jobject object) {
+if (is_soc_cherokee()) {
int status;
ALOGI("Init native called \n");
@@ -1040,12 +1374,15 @@
}
mCallbacksObj = env->NewGlobalRef(object);
}
+}
static void cleanupNative(JNIEnv *env, jobject object) {
- if (mCallbacksObj != NULL) {
- env->DeleteGlobalRef(mCallbacksObj);
- mCallbacksObj = NULL;
+ if (is_soc_cherokee()) {
+ if (mCallbacksObj != NULL) {
+ env->DeleteGlobalRef(mCallbacksObj);
+ mCallbacksObj = NULL;
+ }
}
}
/*
@@ -1056,6 +1393,10 @@
{ "classInitNative", "()V", (void*)classInitNative},
{ "initNative", "()V", (void*)initNative},
{"cleanupNative", "()V", (void *) cleanupNative},
+ { "acquireFdNative", "(Ljava/lang/String;)I",
+ (void*)android_hardware_fmradio_FmReceiverJNI_acquireFdNative},
+ { "closeFdNative", "(I)I",
+ (void*)android_hardware_fmradio_FmReceiverJNI_closeFdNative},
{ "getFreqNative", "(I)I",
(void*)android_hardware_fmradio_FmReceiverJNI_getFreqNative},
{ "setFreqNative", "(II)I",
@@ -1076,6 +1417,8 @@
(void*)android_hardware_fmradio_FmReceiverJNI_getLowerBandNative},
{ "getUpperBandNative", "(I)I",
(void*)android_hardware_fmradio_FmReceiverJNI_getUpperBandNative},
+ { "getBufferNative", "(I[BI)I",
+ (void*)android_hardware_fmradio_FmReceiverJNI_getBufferNative},
{ "setMonoStereoNative", "(II)I",
(void*)android_hardware_fmradio_FmReceiverJNI_setMonoStereoNative},
{ "getRawRdsNative", "(I[BI)I",
@@ -1088,6 +1431,8 @@
(void*)android_hardware_fmradio_FmReceiverJNI_configureSpurTable},
{ "setSpurDataNative", "(I[SI)I",
(void*)android_hardware_fmradio_FmReceiverJNI_setSpurDataNative},
+ { "configurePerformanceParams", "(I)V",
+ (void*)android_hardware_fmradio_FmReceiverJNI_configurePerformanceParams},
{ "enableSlimbus", "(II)I",
(void*)android_hardware_fmradio_FmReceiverJNI_enableSlimbusNative},
{ "enableSoftMute", "(II)I",