macloader: Add support to set nvram calibration file.

Change-Id: I0eb99ad6084eb8cd4452a91b13dd75384785f5a8
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit e283a09f99d0cbad2cf8b903ffe2da1c3e44663e)
diff --git a/macloader/Android.mk b/macloader/Android.mk
index 722325f..ee843be 100644
--- a/macloader/Android.mk
+++ b/macloader/Android.mk
@@ -3,6 +3,14 @@
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
+ifdef WIFI_DRIVER_NVRAM_PATH
+LOCAL_CFLAGS += -DWIFI_DRIVER_NVRAM_PATH=\"$(WIFI_DRIVER_NVRAM_PATH)\"
+endif
+
+ifdef WIFI_DRIVER_NVRAM_PATH_PARAM
+LOCAL_CFLAGS += -DWIFI_DRIVER_NVRAM_PATH_PARAM=\"$(WIFI_DRIVER_NVRAM_PATH_PARAM)\"
+endif
+
 LOCAL_SRC_FILES := \
     macloader.c
 
diff --git a/macloader/macloader.c b/macloader/macloader.c
index 0e29e28..a71afb0 100644
--- a/macloader/macloader.c
+++ b/macloader/macloader.c
@@ -22,12 +22,22 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/types.h>
 #include <sys/stat.h>
+#include <fcntl.h>
 #include <unistd.h>
 #include <pwd.h>
 
 #include <cutils/log.h>
 
+#ifndef WIFI_DRIVER_NVRAM_PATH
+#define WIFI_DRIVER_NVRAM_PATH		NULL
+#endif
+
+#ifndef WIFI_DRIVER_NVRAM_PATH_PARAM
+#define WIFI_DRIVER_NVRAM_PATH_PARAM "/sys/module/wlan/parameters/nvram_path"
+#endif
+
 #define MACADDR_PATH "/efs/wifi/.mac.info"
 #define CID_PATH "/data/.cid.info"
 
@@ -41,6 +51,82 @@
     WISOL
 };
 
+static int wifi_change_nvram_calibration(const char *nvram_file,
+                                         const char *type)
+{
+    int len;
+    int fd = -1;
+    int ret = 0;
+    struct stat sb;
+    char nvram_str[1024] = { 0 };
+
+    if (nvram_file == NULL || type == NULL) {
+        return -1;
+    }
+
+    ret = stat(nvram_file, &sb);
+    if (ret != 0) {
+        ALOGE("Failed to check for NVRAM calibration file '%s' - error: %s",
+              nvram_file,
+              strerror(errno));
+        return -1;
+    }
+
+    ALOGD("Using NVRAM calibration file: %s\n", nvram_file);
+
+    fd = TEMP_FAILURE_RETRY(open(WIFI_DRIVER_NVRAM_PATH_PARAM, O_WRONLY));
+    if (fd < 0) {
+        ALOGE("Failed to open wifi nvram config path %s - error: %s",
+              WIFI_DRIVER_NVRAM_PATH_PARAM, strerror(errno));
+        return -1;
+    }
+
+    len = strlen(nvram_file) + 1;
+    if (TEMP_FAILURE_RETRY(write(fd, nvram_file, len)) != len) {
+        ALOGE("Failed to write to wifi config path %s - error: %s",
+              WIFI_DRIVER_NVRAM_PATH_PARAM, strerror(errno));
+        ret = -1;
+        goto out;
+    }
+
+    snprintf(nvram_str, sizeof(nvram_str), "%s_%s",
+             nvram_file, type);
+
+    ALOGD("Changing NVRAM calibration file for %s chipset\n", type);
+
+    ret = stat(nvram_str, &sb);
+    if (ret != 0) {
+        ALOGW("NVRAM calibration file '%s' doesn't exist", nvram_str);
+        /*
+         * We were able to write the default calibration file. So
+         * continue here without returning an error.
+         */
+        ret = 0;
+        goto out;
+    }
+
+    len = strlen(nvram_str) + 1;
+    if (TEMP_FAILURE_RETRY(write(fd, nvram_str, len)) != len) {
+        ALOGW("Failed to write to wifi config path %s - error: %s",
+              WIFI_DRIVER_NVRAM_PATH_PARAM, strerror(errno));
+        /*
+         * We were able to write the default calibration file. So
+         * continue here without returning an error.
+         */
+        ret = 0;
+        goto out;
+    }
+
+    ALOGD("NVRAM calibration file set to '%s'\n", nvram_str);
+
+    ret = 0;
+out:
+    if (fd != -1) {
+        close(fd);
+    }
+    return ret;
+}
+
 int main() {
     FILE* file;
     FILE* cidfile;
@@ -120,6 +206,7 @@
     }
 
     if (type != NONE) {
+        const char *nvram_file;
         const char *type_str;
         struct passwd *pwd;
         int fd;
@@ -191,6 +278,14 @@
                   CID_PATH, strerror(errno));
             return 1;
         }
+
+        nvram_file = WIFI_DRIVER_NVRAM_PATH;
+        if (nvram_file != NULL) {
+            ret = wifi_change_nvram_calibration(nvram_file, type_str);
+            if (ret != 0) {
+                return 1;
+            }
+        }
     } else {
         /* delete cid file if no specific type */
         ALOGD("Deleting file %s\n", CID_PATH);