Merge changes from topic 'hal_firmware_reload'

* changes:
  wifi: Implement chip mode combinations
  wifi: Split out initialize and  start in WifiLegacyHal
  wifi: Add firmware mode controller
diff --git a/wifi/1.0/default/Android.mk b/wifi/1.0/default/Android.mk
index 931a314..382d350 100644
--- a/wifi/1.0/default/Android.mk
+++ b/wifi/1.0/default/Android.mk
@@ -24,6 +24,7 @@
     wifi_ap_iface.cpp \
     wifi_chip.cpp \
     wifi_legacy_hal.cpp \
+    wifi_mode_controller.cpp \
     wifi_nan_iface.cpp \
     wifi_p2p_iface.cpp \
     wifi_rtt_controller.cpp \
@@ -39,6 +40,7 @@
     liblog \
     libnl \
     libutils \
+    libwifi-hal \
     libwifi-system
 LOCAL_WHOLE_STATIC_LIBRARIES := $(LIB_WIFI_HAL)
 LOCAL_INIT_RC := android.hardware.wifi@1.0-service.rc
diff --git a/wifi/1.0/default/wifi.cpp b/wifi/1.0/default/wifi.cpp
index 19f7e53..30adcc0 100644
--- a/wifi/1.0/default/wifi.cpp
+++ b/wifi/1.0/default/wifi.cpp
@@ -34,6 +34,7 @@
 
 Wifi::Wifi()
     : legacy_hal_(new legacy_hal::WifiLegacyHal()),
+      mode_controller_(new mode_controller::WifiModeController()),
       run_state_(RunState::STOPPED) {}
 
 bool Wifi::isValid() {
@@ -96,25 +97,29 @@
     return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE,
                             "HAL is stopping");
   }
-
-  LOG(INFO) << "Starting HAL";
-  legacy_hal::wifi_error legacy_status = legacy_hal_->start();
-  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-    LOG(ERROR) << "Failed to start Wifi HAL: "
-               << legacyErrorToString(legacy_status);
-    return createWifiStatusFromLegacyError(legacy_status,
-                                           "Failed to start HAL");
+  WifiStatus wifi_status = initializeLegacyHal();
+  if (wifi_status.code == WifiStatusCode::SUCCESS) {
+    // Create the chip instance once the HAL is started.
+    chip_ = new WifiChip(kChipId, legacy_hal_, mode_controller_);
+    run_state_ = RunState::STARTED;
+    for (const auto& callback : event_callbacks_) {
+      if (!callback->onStart().getStatus().isOk()) {
+        LOG(ERROR) << "Failed to invoke onStart callback";
+      };
+    }
+    for (const auto& callback : event_callbacks_) {
+      if (!callback->onFailure(wifi_status).getStatus().isOk()) {
+        LOG(ERROR) << "Failed to invoke onFailure callback";
+      }
+    }
+  } else {
+    for (const auto& callback : event_callbacks_) {
+      if (!callback->onFailure(wifi_status).getStatus().isOk()) {
+        LOG(ERROR) << "Failed to invoke onFailure callback";
+      }
+    }
   }
-
-  // Create the chip instance once the HAL is started.
-  chip_ = new WifiChip(kChipId, legacy_hal_);
-  run_state_ = RunState::STARTED;
-  for (const auto& callback : event_callbacks_) {
-    if (!callback->onStart().getStatus().isOk()) {
-      LOG(ERROR) << "Failed to invoke onStart callback";
-    };
-  }
-  return createWifiStatus(WifiStatusCode::SUCCESS);
+  return wifi_status;
 }
 
 WifiStatus Wifi::stopInternal() {
@@ -124,34 +129,21 @@
     return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE,
                             "HAL is stopping");
   }
-
-  LOG(INFO) << "Stopping HAL";
-  run_state_ = RunState::STOPPING;
-  const auto on_complete_callback_ = [&]() {
-    if (chip_.get()) {
-      chip_->invalidate();
-    }
-    chip_.clear();
-    run_state_ = RunState::STOPPED;
+  WifiStatus wifi_status = stopLegacyHalAndDeinitializeModeController();
+  if (wifi_status.code == WifiStatusCode::SUCCESS) {
     for (const auto& callback : event_callbacks_) {
       if (!callback->onStop().getStatus().isOk()) {
         LOG(ERROR) << "Failed to invoke onStop callback";
       };
     }
-  };
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_->stop(on_complete_callback_);
-  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-    LOG(ERROR) << "Failed to stop Wifi HAL: "
-               << legacyErrorToString(legacy_status);
-    WifiStatus wifi_status =
-        createWifiStatusFromLegacyError(legacy_status, "Failed to stop HAL");
+  } else {
     for (const auto& callback : event_callbacks_) {
-      callback->onFailure(wifi_status);
+      if (!callback->onFailure(wifi_status).getStatus().isOk()) {
+        LOG(ERROR) << "Failed to invoke onFailure callback";
+      }
     }
-    return wifi_status;
   }
-  return createWifiStatus(WifiStatusCode::SUCCESS);
+  return wifi_status;
 }
 
 std::pair<WifiStatus, std::vector<ChipId>> Wifi::getChipIdsInternal() {
@@ -171,6 +163,41 @@
   }
   return {createWifiStatus(WifiStatusCode::SUCCESS), chip_};
 }
+
+WifiStatus Wifi::initializeLegacyHal() {
+  LOG(INFO) << "Initializing legacy HAL";
+  legacy_hal::wifi_error legacy_status = legacy_hal_->initialize();
+  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+    LOG(ERROR) << "Failed to initialize legacy HAL: "
+               << legacyErrorToString(legacy_status);
+    return createWifiStatusFromLegacyError(legacy_status);
+  }
+  return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus Wifi::stopLegacyHalAndDeinitializeModeController() {
+  LOG(INFO) << "Stopping legacy HAL";
+  run_state_ = RunState::STOPPING;
+  const auto on_complete_callback_ = [&]() {
+    if (chip_.get()) {
+      chip_->invalidate();
+    }
+    chip_.clear();
+    run_state_ = RunState::STOPPED;
+  };
+  legacy_hal::wifi_error legacy_status =
+      legacy_hal_->stop(on_complete_callback_);
+  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+    LOG(ERROR) << "Failed to stop legacy HAL: "
+               << legacyErrorToString(legacy_status);
+    return createWifiStatusFromLegacyError(legacy_status);
+  }
+  if (!mode_controller_->deinitialize()) {
+    LOG(ERROR) << "Failed to deinitialize firmware mode controller";
+    return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+  }
+  return createWifiStatus(WifiStatusCode::SUCCESS);
+}
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace wifi
diff --git a/wifi/1.0/default/wifi.h b/wifi/1.0/default/wifi.h
index 7872303..40d3552 100644
--- a/wifi/1.0/default/wifi.h
+++ b/wifi/1.0/default/wifi.h
@@ -25,6 +25,7 @@
 
 #include "wifi_chip.h"
 #include "wifi_legacy_hal.h"
+#include "wifi_mode_controller.h"
 
 namespace android {
 namespace hardware {
@@ -62,9 +63,13 @@
   std::pair<WifiStatus, std::vector<ChipId>> getChipIdsInternal();
   std::pair<WifiStatus, sp<IWifiChip>> getChipInternal(ChipId chip_id);
 
+  WifiStatus initializeLegacyHal();
+  WifiStatus stopLegacyHalAndDeinitializeModeController();
+
   // Instance is created in this root level |IWifi| HIDL interface object
   // and shared with all the child HIDL interface objects.
   std::shared_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+  std::shared_ptr<mode_controller::WifiModeController> mode_controller_;
   RunState run_state_;
   std::vector<sp<IWifiEventCallback>> event_callbacks_;
   sp<WifiChip> chip_;
diff --git a/wifi/1.0/default/wifi_chip.cpp b/wifi/1.0/default/wifi_chip.cpp
index 3ab6052..2487d9f 100644
--- a/wifi/1.0/default/wifi_chip.cpp
+++ b/wifi/1.0/default/wifi_chip.cpp
@@ -24,6 +24,12 @@
 using android::sp;
 using android::hardware::hidl_vec;
 using android::hardware::hidl_string;
+using android::hardware::wifi::V1_0::IWifiChip;
+using android::hardware::wifi::V1_0::IfaceType;
+
+constexpr uint32_t kStaChipModeId = 0;
+constexpr uint32_t kApChipModeId = 1;
+constexpr uint32_t kInvalidModeId = UINT32_MAX;
 
 template <typename Iface>
 void invalidateAndClear(sp<Iface>& iface) {
@@ -41,9 +47,15 @@
 namespace implementation {
 using hidl_return_util::validateAndCall;
 
-WifiChip::WifiChip(ChipId chip_id,
-                   const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
-    : chip_id_(chip_id), legacy_hal_(legacy_hal), is_valid_(true) {}
+WifiChip::WifiChip(
+    ChipId chip_id,
+    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+    const std::weak_ptr<mode_controller::WifiModeController> mode_controller)
+    : chip_id_(chip_id),
+      legacy_hal_(legacy_hal),
+      mode_controller_(mode_controller),
+      is_valid_(true),
+      current_mode_id_(kInvalidModeId) {}
 
 void WifiChip::invalidate() {
   invalidateAndRemoveAllIfaces();
@@ -301,19 +313,84 @@
 
 std::pair<WifiStatus, std::vector<IWifiChip::ChipMode>>
 WifiChip::getAvailableModesInternal() {
-  // TODO add implementation
-  return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
+  // The chip combination supported for current devices is fixed for now with
+  // 2 separate modes of operation:
+  // Mode 1 (STA mode): Will support 1 STA and 1 P2P or NAN iface operations
+  // concurrently.
+  // Mode 2 (AP mode): Will support 1 AP iface operations.
+  // TODO (b/32997844): Read this from some device specific flags in the
+  // makefile.
+  // STA mode iface combinations.
+  const IWifiChip::ChipIfaceCombinationLimit
+      sta_chip_iface_combination_limit_1 = {{IfaceType::STA}, 1};
+  const IWifiChip::ChipIfaceCombinationLimit
+      sta_chip_iface_combination_limit_2 = {{IfaceType::P2P, IfaceType::NAN},
+                                            1};
+  const IWifiChip::ChipIfaceCombination sta_chip_iface_combination = {
+      {sta_chip_iface_combination_limit_1, sta_chip_iface_combination_limit_2}};
+  const IWifiChip::ChipMode sta_chip_mode = {kStaChipModeId,
+                                             {sta_chip_iface_combination}};
+  // AP mode iface combinations.
+  const IWifiChip::ChipIfaceCombinationLimit ap_chip_iface_combination_limit = {
+      {IfaceType::AP}, 1};
+  const IWifiChip::ChipIfaceCombination ap_chip_iface_combination = {
+      {ap_chip_iface_combination_limit}};
+  const IWifiChip::ChipMode ap_chip_mode = {kApChipModeId,
+                                            {ap_chip_iface_combination}};
+  return {createWifiStatus(WifiStatusCode::SUCCESS),
+          {sta_chip_mode, ap_chip_mode}};
 }
 
-WifiStatus WifiChip::configureChipInternal(uint32_t /* mode_id */) {
-  invalidateAndRemoveAllIfaces();
-  // TODO add implementation
+WifiStatus WifiChip::configureChipInternal(uint32_t mode_id) {
+  if (mode_id != kStaChipModeId && mode_id != kApChipModeId) {
+    return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+  }
+  if (mode_id == current_mode_id_) {
+    LOG(DEBUG) << "Already in the specified mode " << mode_id;
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+  }
+  // If the chip is already configured in a different mode, stop
+  // the legacy HAL and then start it after firmware mode change.
+  if (current_mode_id_ != kInvalidModeId) {
+    invalidateAndRemoveAllIfaces();
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->stop([]() {});
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+      LOG(ERROR) << "Failed to stop legacy HAL: "
+                 << legacyErrorToString(legacy_status);
+      // TODO(b/33038823): Need to invoke onChipReconfigureFailure()
+      return createWifiStatusFromLegacyError(legacy_status);
+    }
+  }
+  bool success;
+  if (mode_id == kStaChipModeId) {
+    success = mode_controller_.lock()->changeFirmwareMode(IfaceType::STA);
+  } else {
+    success = mode_controller_.lock()->changeFirmwareMode(IfaceType::AP);
+  }
+  if (!success) {
+    // TODO(b/33038823): Need to invoke onChipReconfigureFailure()
+    return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+  }
+  legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->start();
+  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+    LOG(ERROR) << "Failed to start legacy HAL: "
+               << legacyErrorToString(legacy_status);
+    // TODO(b/33038823): Need to invoke onChipReconfigureFailure()
+    return createWifiStatusFromLegacyError(legacy_status);
+  }
+  for (const auto& callback : event_callbacks_) {
+    callback->onChipReconfigured(mode_id);
+  }
+  current_mode_id_ = mode_id;
   return createWifiStatus(WifiStatusCode::SUCCESS);
 }
 
 std::pair<WifiStatus, uint32_t> WifiChip::getModeInternal() {
-  // TODO add implementation
-  return {createWifiStatus(WifiStatusCode::SUCCESS), 0};
+  if (current_mode_id_ == kInvalidModeId) {
+    return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE),
+            current_mode_id_};
+  }
+  return {createWifiStatus(WifiStatusCode::SUCCESS), current_mode_id_};
 }
 
 std::pair<WifiStatus, IWifiChip::ChipDebugInfo>
diff --git a/wifi/1.0/default/wifi_chip.h b/wifi/1.0/default/wifi_chip.h
index c1a7173..764445f 100644
--- a/wifi/1.0/default/wifi_chip.h
+++ b/wifi/1.0/default/wifi_chip.h
@@ -24,6 +24,7 @@
 
 #include "wifi_ap_iface.h"
 #include "wifi_legacy_hal.h"
+#include "wifi_mode_controller.h"
 #include "wifi_nan_iface.h"
 #include "wifi_p2p_iface.h"
 #include "wifi_rtt_controller.h"
@@ -42,8 +43,10 @@
  */
 class WifiChip : public IWifiChip {
  public:
-  WifiChip(ChipId chip_id,
-           const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
+  WifiChip(
+      ChipId chip_id,
+      const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+      const std::weak_ptr<mode_controller::WifiModeController> mode_controller);
   // HIDL does not provide a built-in mechanism to let the server invalidate
   // a HIDL interface object after creation. If any client process holds onto
   // a reference to the object in their context, any method calls on that
@@ -156,6 +159,7 @@
 
   ChipId chip_id_;
   std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+  std::weak_ptr<mode_controller::WifiModeController> mode_controller_;
   std::vector<sp<IWifiChipEventCallback>> event_callbacks_;
   sp<WifiApIface> ap_iface_;
   sp<WifiNanIface> nan_iface_;
@@ -163,6 +167,7 @@
   sp<WifiStaIface> sta_iface_;
   std::vector<sp<WifiRttController>> rtt_controllers_;
   bool is_valid_;
+  uint32_t current_mode_id_;
 
   DISALLOW_COPY_AND_ASSIGN(WifiChip);
 };
diff --git a/wifi/1.0/default/wifi_legacy_hal.cpp b/wifi/1.0/default/wifi_legacy_hal.cpp
index 560a273..de1eb39 100644
--- a/wifi/1.0/default/wifi_legacy_hal.cpp
+++ b/wifi/1.0/default/wifi_legacy_hal.cpp
@@ -18,10 +18,11 @@
 
 #include <android-base/logging.h>
 #include <cutils/properties.h>
-#include <wifi_system/interface_tool.h>
 
 #include "wifi_legacy_hal.h"
 
+using android::wifi_system::InterfaceTool;
+
 namespace android {
 namespace hardware {
 namespace wifi {
@@ -241,12 +242,7 @@
       wlan_interface_handle_(nullptr),
       awaiting_event_loop_termination_(false) {}
 
-wifi_error WifiLegacyHal::start() {
-  // Ensure that we're starting in a good state.
-  CHECK(!global_handle_ && !wlan_interface_handle_ &&
-        !awaiting_event_loop_termination_);
-
-  android::wifi_system::InterfaceTool if_tool;
+wifi_error WifiLegacyHal::initialize() {
   // TODO: Add back the HAL Tool if we need to. All we need from the HAL tool
   // for now is this function call which we can directly call.
   wifi_error status = init_wifi_vendor_hal_func_table(&global_func_table_);
@@ -254,13 +250,19 @@
     LOG(ERROR) << "Failed to initialize legacy hal function table";
     return WIFI_ERROR_UNKNOWN;
   }
-  if (!if_tool.SetWifiUpState(true)) {
+  return WIFI_SUCCESS;
+}
+
+wifi_error WifiLegacyHal::start() {
+  // Ensure that we're starting in a good state.
+  CHECK(global_func_table_.wifi_initialize && !global_handle_ &&
+        !wlan_interface_handle_ && !awaiting_event_loop_termination_);
+  if (!iface_tool_.SetWifiUpState(true)) {
     LOG(ERROR) << "Failed to set WiFi interface up";
     return WIFI_ERROR_UNKNOWN;
   }
-
   LOG(INFO) << "Starting legacy HAL";
-  status = global_func_table_.wifi_initialize(&global_handle_);
+  wifi_error status = global_func_table_.wifi_initialize(&global_handle_);
   if (status != WIFI_SUCCESS || !global_handle_) {
     LOG(ERROR) << "Failed to retrieve global handle";
     return status;
@@ -280,10 +282,11 @@
   LOG(INFO) << "Stopping legacy HAL";
   on_stop_complete_internal_callback = [&](wifi_handle handle) {
     CHECK_EQ(global_handle_, handle) << "Handle mismatch";
-    on_stop_complete_user_callback();
     // Invalidate all the internal pointers now that the HAL is
     // stopped.
     invalidate();
+    iface_tool_.SetWifiUpState(false);
+    on_stop_complete_user_callback();
   };
   awaiting_event_loop_termination_ = true;
   global_func_table_.wifi_cleanup(global_handle_, onStopComplete);
@@ -974,8 +977,6 @@
   }
   LOG(VERBOSE) << "Legacy HAL event loop terminated";
   awaiting_event_loop_termination_ = false;
-  android::wifi_system::InterfaceTool if_tool;
-  if_tool.SetWifiUpState(false);
 }
 
 std::pair<wifi_error, std::vector<wifi_cached_scan_results>>
diff --git a/wifi/1.0/default/wifi_legacy_hal.h b/wifi/1.0/default/wifi_legacy_hal.h
index 62b773e..b569dbd 100644
--- a/wifi/1.0/default/wifi_legacy_hal.h
+++ b/wifi/1.0/default/wifi_legacy_hal.h
@@ -21,6 +21,8 @@
 #include <thread>
 #include <vector>
 
+#include <wifi_system/interface_tool.h>
+
 namespace android {
 namespace hardware {
 namespace wifi {
@@ -125,7 +127,9 @@
   std::string getP2pIfaceName();
   std::string getStaIfaceName();
 
-  // Initialize the legacy HAL and start the event looper thread.
+  // Initialize the legacy HAL function table.
+  wifi_error initialize();
+  // Start the legacy HAL and the event looper thread.
   wifi_error start();
   // Deinitialize the legacy HAL and stop the event looper thread.
   wifi_error stop(const std::function<void()>& on_complete_callback);
@@ -245,6 +249,7 @@
   wifi_interface_handle wlan_interface_handle_;
   // Flag to indicate if we have initiated the cleanup of legacy HAL.
   bool awaiting_event_loop_termination_;
+  wifi_system::InterfaceTool iface_tool_;
 };
 
 }  // namespace legacy_hal
diff --git a/wifi/1.0/default/wifi_mode_controller.cpp b/wifi/1.0/default/wifi_mode_controller.cpp
new file mode 100644
index 0000000..42dd9ad
--- /dev/null
+++ b/wifi/1.0/default/wifi_mode_controller.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <private/android_filesystem_config.h>
+
+#include "wifi_mode_controller.h"
+
+using android::hardware::wifi::V1_0::IfaceType;
+using android::wifi_hal::DriverTool;
+
+namespace {
+int convertIfaceTypeToFirmwareMode(IfaceType type) {
+  int mode;
+  switch (type) {
+    case IfaceType::AP:
+      mode = DriverTool::kFirmwareModeAp;
+      break;
+    case IfaceType::P2P:
+      mode = DriverTool::kFirmwareModeP2p;
+      break;
+    case IfaceType::NAN:
+      // NAN is exposed in STA mode currently.
+      mode = DriverTool::kFirmwareModeSta;
+      break;
+    case IfaceType::STA:
+      mode = DriverTool::kFirmwareModeSta;
+      break;
+  }
+  return mode;
+}
+}
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_0 {
+namespace implementation {
+namespace mode_controller {
+
+WifiModeController::WifiModeController() : driver_tool_(new DriverTool) {}
+
+bool WifiModeController::isFirmwareModeChangeNeeded(IfaceType type) {
+  return driver_tool_->IsFirmwareModeChangeNeeded(
+      convertIfaceTypeToFirmwareMode(type));
+}
+
+bool WifiModeController::changeFirmwareMode(IfaceType type) {
+  if (!driver_tool_->LoadDriver()) {
+    LOG(ERROR) << "Failed to load WiFi driver";
+    return false;
+  }
+  if (!driver_tool_->IsFirmwareModeChangeNeeded(
+          convertIfaceTypeToFirmwareMode(type))) {
+    LOG(ERROR) << "Failed to change firmware mode";
+    return false;
+  }
+  return true;
+}
+
+bool WifiModeController::deinitialize() {
+  if (!driver_tool_->UnloadDriver()) {
+    LOG(ERROR) << "Failed to unload WiFi driver";
+    return false;
+  }
+  return true;
+}
+}  // namespace mode_controller
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.0/default/wifi_mode_controller.h b/wifi/1.0/default/wifi_mode_controller.h
new file mode 100644
index 0000000..a4147a9
--- /dev/null
+++ b/wifi/1.0/default/wifi_mode_controller.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef WIFI_MODE_CONTROLLER_H_
+#define WIFI_MODE_CONTROLLER_H_
+
+#include <wifi_hal/driver_tool.h>
+
+#include <android/hardware/wifi/1.0/IWifi.h>
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_0 {
+namespace implementation {
+namespace mode_controller {
+/**
+ * Class that encapsulates all firmware mode configuration.
+ * This class will perform the necessary firmware reloads to put the chip in the
+ * required state (essentially a wrapper over DriverTool).
+ */
+class WifiModeController {
+ public:
+  WifiModeController();
+
+  // Checks if a firmware mode change is necessary to support the specified
+  // iface type operations.
+  bool isFirmwareModeChangeNeeded(IfaceType type);
+  // Change the firmware mode to support the specified iface type operations.
+  bool changeFirmwareMode(IfaceType type);
+  // Unload the driver. This should be invoked whenever |IWifi.stop()| is
+  // invoked.
+  bool deinitialize();
+
+ private:
+  std::unique_ptr<wifi_hal::DriverTool> driver_tool_;
+};
+
+}  // namespace mode_controller
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_MODE_CONTROLLER_H_