Add bcm4339 wifi hal for imx6ul

Change-Id: Ia175f518c03ded3ce99bf5c1f5fb11daf9ea4710
Signed-off-by: Guoyin Chen <guoyin.chen@freescale.com>
diff --git a/peripheral/wifi/bcm4339/.gitignore b/peripheral/wifi/bcm4339/.gitignore
new file mode 100644
index 0000000..9cf6616
--- /dev/null
+++ b/peripheral/wifi/bcm4339/.gitignore
@@ -0,0 +1 @@
+bcmdhd
diff --git a/peripheral/wifi/bcm4339/Android.mk b/peripheral/wifi/bcm4339/Android.mk
new file mode 100644
index 0000000..6735f86
--- /dev/null
+++ b/peripheral/wifi/bcm4339/Android.mk
@@ -0,0 +1,32 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+ifeq ($(findstring imx, $(soc_name)), imx)
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_CFLAGS += -Wno-unused-parameter
+LOCAL_C_INCLUDES += device/generic/brillo/wifi_driver_hal/include
+LOCAL_SHARED_LIBRARIES := libcutils
+LOCAL_CPPFLAGS += -DLOG_TAG=\"hal_bcmdhd\"
+#LOCAL_CPPFLAGS += -DBCMDHD_USE_KERNEL_MODULE
+LOCAL_SRC_FILES := wifi_driver_hal_bcmdhd.cpp
+LOCAL_MODULE := wifi_driver.$(soc_name)
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_MODULE_TAGS := eng
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif
diff --git a/peripheral/wifi/bcm4339/peripheral.mk b/peripheral/wifi/bcm4339/peripheral.mk
new file mode 100644
index 0000000..6a88c80
--- /dev/null
+++ b/peripheral/wifi/bcm4339/peripheral.mk
@@ -0,0 +1,29 @@
+#
+# Copyright 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+BCMDHD_FIRMWARE_MK := hardware/bsp/freescale/peripheral/wifi/bcm4339/bcmdhd
+ifeq ($(BCMDHD_FIRMWARE_MK), $(wildcard $(BCMDHD_FIRMWARE_MK)))
+WLAN_FIRMWARE_SRC_FOLDER = hardware/bsp/freescale/peripheral/wifi/bcm4339/bcmdhd/firmware/ZP_BCM4339/
+FIRMWARE_DST_FOLDER = system/vendor/firmware/wlan/bcm4339
+
+SRC_FILES := bcmdhd.ZP.SDIO.cal fw_bcmdhd.bin fw_bcmdhd_apsta.bin
+COPY_FILES += \
+              $(join $(patsubst %, $(WLAN_FIRMWARE_SRC_FOLDER)/%, $(SRC_FILES)), $(patsubst %, :$(FIRMWARE_DST_FOLDER)/%, $(SRC_FILES)))
+endif
+
+PRODUCT_COPY_FILES += $(COPY_FILES)
+WIFI_DRIVER_HAL_MODULE := wifi_driver.$(soc_name)
+WIFI_DRIVER_HAL_PERIPHERAL := bcm4339
diff --git a/peripheral/wifi/bcm4339/wifi_driver_hal_bcmdhd.cpp b/peripheral/wifi/bcm4339/wifi_driver_hal_bcmdhd.cpp
new file mode 100644
index 0000000..64e347d
--- /dev/null
+++ b/peripheral/wifi/bcm4339/wifi_driver_hal_bcmdhd.cpp
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2015 Freescale Semiconductor, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <cutils/log.h>
+#include <cutils/misc.h>
+#include <cutils/memory.h>
+#include <cutils/properties.h>
+#include <hardware_brillo/wifi_driver_hal.h>
+
+#include <string>
+#include <sys/syscall.h>
+
+#if BCMDHD_USE_KERNEL_MODULE
+#define init_module(mod, len, opts) syscall(__NR_init_module, mod, len, opts)
+#endif
+
+namespace {
+
+    enum CheckmodResult{
+        MOD_INSED,
+        NOT_FOUND
+    };
+
+const char kCfg80211KoPath[] = "/system/lib/modules/cfg80211.ko";
+const char kCfg80211KoName[] = "cfg80211";
+const char kBcmdhdDriverPath[] = "/system/lib/modules/bcmdhd.ko";
+const char kBcmdhdDriverName[] = "bcmdhd";
+const char kBcmdhdApFirmwarePath[] = "/system/vendor/firmware/wlan/bcm4339/fw_bcmdhd_apsta.bin";
+const char kBcmdhdStaFirmwarePath[] = "/system/vendor/firmware/wlan/bcm4339/fw_bcmdhd.bin";
+const char kBcmdhdFirmwareConfigPath[] = "/sys/module/bcmdhd/parameters/firmware_path";
+const char kBcmdhdNvramConfigPath[] = "/sys/module/bcmdhd/parameters/nvram_path";
+const char kBcmdhdNvramPath[] = "/system/vendor/firmware/wlan/bcm4339/bcmdhd.ZP.SDIO.cal";
+const char kModulesSysfsPath[] = "/proc/modules";
+
+const char kApDeviceName[] = "wlan0";
+const char kStationDeviceName[] = "wlan0";
+
+
+static bool read_file(const std::string& filename, std::string* buffer,
+                      size_t buffer_size) {
+  int fd = open(filename.c_str(), O_RDONLY);
+  if (fd < 0) {
+    ALOGE("Cannot open %s for reading", filename.c_str());
+    return false;
+  }
+  char buffer_data[buffer_size];
+  ssize_t count = read(fd, buffer_data, buffer_size);
+  close(fd);
+
+  if (count <= 0) {
+    ALOGE("Cannot read any data from %s", filename.c_str());
+    return false;
+  }
+
+  buffer->assign(buffer_data, count);
+  return true;
+}
+
+#if BCMDHD_USE_KERNEL_MODULE
+static int checkmod(const char *mod_name) {
+    std::string module_path(kModulesSysfsPath);
+    std::string module_name(mod_name);
+    std::string module_content;
+    read_file(module_path, &module_content, 1024);
+    if (module_content.find(module_name, 0) == std::string::npos)
+        return NOT_FOUND;
+    else
+        return MOD_INSED;
+
+}
+#endif
+
+#if BCMDHD_USE_KERNEL_MODULE
+static int insmod(const char *filename, const char *args) {
+    void *module;
+    unsigned int size;
+    int ret;
+    module = load_file(filename, &size);
+    if (!module) {
+        ALOGE("insmod:load_file %s  error", filename);
+        return -1;
+    }
+    ret = init_module(module, size, args);
+    free(module);
+    return ret;
+}
+#endif
+
+
+static bool write_file(
+    const std::string& filename, const std::string& content) {
+  int fd = open(filename.c_str(), O_WRONLY);
+  if (fd < 0) {
+    ALOGE("Cannot open %s for writing", filename.c_str());
+    return false;
+  }
+  ssize_t write_count = content.size();
+  ssize_t actual_count = write(fd, content.c_str(), write_count);
+  close(fd);
+
+  if (actual_count != write_count) {
+    ALOGE("Expected to write %d bytes to %s but write returns %d",
+          write_count, filename.c_str(), actual_count);
+    return false;
+  }
+  return true;
+}
+
+
+
+static wifi_driver_error wifi_driver_initialize_bcmdhd() {
+
+    int ret = -1;
+    ALOGD("bcmdhd wifi_driver init.");
+#if BCMDHD_USE_KERNEL_MODULE
+    if (checkmod(kCfg80211KoName) == NOT_FOUND) {
+        if (insmod(kCfg80211KoPath, "")) {
+            ALOGE("Cannot insmod cfg80211");
+            return WIFI_ERROR_UNKNOWN;
+        }
+    }
+    if (checkmod(kBcmdhdDriverName) == NOT_FOUND) {
+        if (insmod(kBcmdhdDriverPath, "")) {
+            ALOGE("Cannot insmod bcmdhd driver.");
+            return WIFI_ERROR_UNKNOWN;
+        }
+    }
+#endif
+    return WIFI_SUCCESS;
+}
+
+static wifi_driver_error wifi_driver_set_mode_bcmdhd(
+    wifi_driver_mode mode,
+    char* wifi_device_name,
+    size_t wifi_device_name_size) {
+  const char* device_name = nullptr;
+  ALOGD("Wifi HAL setup mode: %s to %s mode", wifi_device_name, mode==WIFI_MODE_AP? "AP":"STA");
+  std::string ap_firmware(kBcmdhdApFirmwarePath);
+  std::string sta_firmware(kBcmdhdStaFirmwarePath);
+  std::string firmware_config(kBcmdhdFirmwareConfigPath);
+  std::string nvram_config(kBcmdhdNvramConfigPath);
+  std::string nvram_file(kBcmdhdNvramPath);
+  switch (mode) {
+    case WIFI_MODE_AP:
+      strlcpy(wifi_device_name, kApDeviceName, wifi_device_name_size);
+      write_file(firmware_config, ap_firmware);
+      break;
+
+    case WIFI_MODE_STATION:
+      strlcpy(wifi_device_name, kStationDeviceName, wifi_device_name_size);
+      write_file(firmware_config, sta_firmware);
+      break;
+
+    default:
+      ALOGE("Unkonwn WiFi driver mode %d", mode);
+      return WIFI_ERROR_INVALID_ARGS;
+  }
+  write_file(nvram_config, nvram_file);
+
+  return WIFI_SUCCESS;
+}
+
+static int close_bcmdhd_driver(struct hw_device_t* device) {
+  wifi_driver_device_t* dev = reinterpret_cast<wifi_driver_device_t*>(device);
+  if (dev)
+    free(dev);
+  return 0;
+}
+
+static int open_bcmdhd_driver(const struct hw_module_t* module, const char*,
+                       struct hw_device_t** device) {
+  wifi_driver_device_t* dev = reinterpret_cast<wifi_driver_device_t*>(
+      calloc(1, sizeof(wifi_driver_device_t)));
+
+  dev->common.tag = HARDWARE_DEVICE_TAG;
+  dev->common.version = WIFI_DRIVER_DEVICE_API_VERSION_0_1;
+  // We're forced into this cast by the existing API.  This pattern is
+  // common among users of the HAL.
+  dev->common.module = const_cast<hw_module_t*>(module);
+  dev->common.close = close_bcmdhd_driver;
+  dev->wifi_driver_initialize = wifi_driver_initialize_bcmdhd;
+  dev->wifi_driver_set_mode = wifi_driver_set_mode_bcmdhd;
+
+  *device = &dev->common;
+
+  return 0;
+}
+
+static struct hw_module_methods_t bcmdhd_driver_module_methods = {
+  open: open_bcmdhd_driver
+};
+
+}  // namespace {}
+
+hw_module_t HAL_MODULE_INFO_SYM = {
+  tag: HARDWARE_MODULE_TAG,
+  version_major: 1,
+  version_minor: 0,
+  id: WIFI_DRIVER_HARDWARE_MODULE_ID,
+  name: "BCM4339",
+  author: "Freescale",
+  methods: &bcmdhd_driver_module_methods,
+  dso: NULL,
+  reserved: {0},
+};