1a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley/*
2a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley * Copyright 2016, The Android Open Source Project
3a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley *
4a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley * Licensed under the Apache License, Version 2.0 (the "License");
5a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley * you may not use this file except in compliance with the License.
6a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley * You may obtain a copy of the License at
7a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley *
8a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley *     http://www.apache.org/licenses/LICENSE-2.0
9a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley *
10a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley * Unless required by applicable law or agreed to in writing, software
11a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley * distributed under the License is distributed on an "AS IS" BASIS,
12a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley * See the License for the specific language governing permissions and
14a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley * limitations under the License.
15a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley */
16a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley
17a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley#include "hardware_legacy/wifi.h"
18a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley
19a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley#include <fcntl.h>
20a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley#include <stdlib.h>
21a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley#include <unistd.h>
22a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley
2386105fb24919eca17e71a5ec820d75ac57bbdc65Christopher Wiley#include <android-base/logging.h>
24a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley#include <cutils/misc.h>
25a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley#include <cutils/properties.h>
2693c106de19af6a648c26e4d5f0cd0502740b4c51Ajit Kumar#include <sys/syscall.h>
27a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley
28217f61b2e8d2beed2fe7fa1124e1d4f52a042ab8Alex Vakulenkoextern "C" int init_module(void *, unsigned long, const char *);
29217f61b2e8d2beed2fe7fa1124e1d4f52a042ab8Alex Vakulenkoextern "C" int delete_module(const char *, unsigned int);
30a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley
31a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley#ifndef WIFI_DRIVER_FW_PATH_STA
32af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley#define WIFI_DRIVER_FW_PATH_STA NULL
33a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley#endif
34a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley#ifndef WIFI_DRIVER_FW_PATH_AP
35af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley#define WIFI_DRIVER_FW_PATH_AP NULL
36a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley#endif
37a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley#ifndef WIFI_DRIVER_FW_PATH_P2P
38af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley#define WIFI_DRIVER_FW_PATH_P2P NULL
39a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley#endif
40a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley
41a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley#ifndef WIFI_DRIVER_MODULE_ARG
42af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley#define WIFI_DRIVER_MODULE_ARG ""
43a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley#endif
44a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley
45af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wileystatic const char DRIVER_PROP_NAME[] = "wlan.driver.status";
46a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley#ifdef WIFI_DRIVER_MODULE_PATH
47af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wileystatic const char DRIVER_MODULE_NAME[] = WIFI_DRIVER_MODULE_NAME;
48af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wileystatic const char DRIVER_MODULE_TAG[] = WIFI_DRIVER_MODULE_NAME " ";
49af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wileystatic const char DRIVER_MODULE_PATH[] = WIFI_DRIVER_MODULE_PATH;
50af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wileystatic const char DRIVER_MODULE_ARG[] = WIFI_DRIVER_MODULE_ARG;
51af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wileystatic const char MODULE_FILE[] = "/proc/modules";
52a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley#endif
53a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley
54af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wileystatic int insmod(const char *filename, const char *args) {
55af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  int ret;
5693c106de19af6a648c26e4d5f0cd0502740b4c51Ajit Kumar  int fd;
57a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley
5893c106de19af6a648c26e4d5f0cd0502740b4c51Ajit Kumar  fd = TEMP_FAILURE_RETRY(open(filename, O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
5993c106de19af6a648c26e4d5f0cd0502740b4c51Ajit Kumar  if (fd < 0) {
6093c106de19af6a648c26e4d5f0cd0502740b4c51Ajit Kumar    PLOG(ERROR) << "Failed to open " << filename;
6193c106de19af6a648c26e4d5f0cd0502740b4c51Ajit Kumar    return -1;
6293c106de19af6a648c26e4d5f0cd0502740b4c51Ajit Kumar  }
63a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley
6493c106de19af6a648c26e4d5f0cd0502740b4c51Ajit Kumar  ret = syscall(__NR_finit_module, fd, args, 0);
65a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley
6693c106de19af6a648c26e4d5f0cd0502740b4c51Ajit Kumar  close(fd);
6793c106de19af6a648c26e4d5f0cd0502740b4c51Ajit Kumar  if (ret < 0) {
6893c106de19af6a648c26e4d5f0cd0502740b4c51Ajit Kumar    PLOG(ERROR) << "finit_module return: " << ret;
6993c106de19af6a648c26e4d5f0cd0502740b4c51Ajit Kumar  }
70a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley
71af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  return ret;
72a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley}
73a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley
74af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wileystatic int rmmod(const char *modname) {
75af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  int ret = -1;
76af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  int maxtry = 10;
77af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley
78af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  while (maxtry-- > 0) {
79af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley    ret = delete_module(modname, O_NONBLOCK | O_EXCL);
80af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley    if (ret < 0 && errno == EAGAIN)
81af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley      usleep(500000);
82af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley    else
83af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley      break;
84af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  }
85af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley
86af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  if (ret != 0)
8786105fb24919eca17e71a5ec820d75ac57bbdc65Christopher Wiley    PLOG(DEBUG) << "Unable to unload driver module '" << modname << "'";
88af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  return ret;
89a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley}
90a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley
91a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley#ifdef WIFI_DRIVER_STATE_CTRL_PARAM
92af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wileyint wifi_change_driver_state(const char *state) {
93af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  int len;
94af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  int fd;
95af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  int ret = 0;
96af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley
97af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  if (!state) return -1;
98af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  fd = TEMP_FAILURE_RETRY(open(WIFI_DRIVER_STATE_CTRL_PARAM, O_WRONLY));
99af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  if (fd < 0) {
10086105fb24919eca17e71a5ec820d75ac57bbdc65Christopher Wiley    PLOG(ERROR) << "Failed to open driver state control param";
101af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley    return -1;
102af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  }
103af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  len = strlen(state) + 1;
104af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  if (TEMP_FAILURE_RETRY(write(fd, state, len)) != len) {
10586105fb24919eca17e71a5ec820d75ac57bbdc65Christopher Wiley    PLOG(ERROR) << "Failed to write driver state control param";
106af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley    ret = -1;
107af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  }
108af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  close(fd);
109af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  return ret;
110a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley}
111a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley#endif
112a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley
113a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wileyint is_wifi_driver_loaded() {
114af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  char driver_status[PROPERTY_VALUE_MAX];
115a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley#ifdef WIFI_DRIVER_MODULE_PATH
116af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  FILE *proc;
117af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  char line[sizeof(DRIVER_MODULE_TAG) + 10];
118a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley#endif
119a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley
120af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  if (!property_get(DRIVER_PROP_NAME, driver_status, NULL) ||
121af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley      strcmp(driver_status, "ok") != 0) {
122af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley    return 0; /* driver not loaded */
123af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  }
124a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley#ifdef WIFI_DRIVER_MODULE_PATH
125af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  /*
126af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley   * If the property says the driver is loaded, check to
127af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley   * make sure that the property setting isn't just left
128af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley   * over from a previous manual shutdown or a runtime
129af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley   * crash.
130af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley   */
131af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  if ((proc = fopen(MODULE_FILE, "r")) == NULL) {
13286105fb24919eca17e71a5ec820d75ac57bbdc65Christopher Wiley    PLOG(WARNING) << "Could not open " << MODULE_FILE;
133a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley    property_set(DRIVER_PROP_NAME, "unloaded");
134a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley    return 0;
135af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  }
136af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  while ((fgets(line, sizeof(line), proc)) != NULL) {
137af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley    if (strncmp(line, DRIVER_MODULE_TAG, strlen(DRIVER_MODULE_TAG)) == 0) {
138af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley      fclose(proc);
139af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley      return 1;
140af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley    }
141af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  }
142af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  fclose(proc);
143af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  property_set(DRIVER_PROP_NAME, "unloaded");
144af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  return 0;
145a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley#else
146af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  return 1;
147a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley#endif
148a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley}
149a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley
150af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wileyint wifi_load_driver() {
151a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley#ifdef WIFI_DRIVER_MODULE_PATH
152af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  if (is_wifi_driver_loaded()) {
153af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley    return 0;
154af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  }
155a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley
156af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  if (insmod(DRIVER_MODULE_PATH, DRIVER_MODULE_ARG) < 0) return -1;
157278ed48124665c6285f9fae66649bfc3cc0a21c1Kumar Anand#endif
158a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley
159278ed48124665c6285f9fae66649bfc3cc0a21c1Kumar Anand#ifdef WIFI_DRIVER_STATE_CTRL_PARAM
160af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  if (is_wifi_driver_loaded()) {
161af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley    return 0;
162af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  }
163a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley
164af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  if (wifi_change_driver_state(WIFI_DRIVER_STATE_ON) < 0) return -1;
165a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley#endif
166af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  property_set(DRIVER_PROP_NAME, "ok");
167af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  return 0;
168a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley}
169a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley
170af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wileyint wifi_unload_driver() {
171823a774406c76128c549e026a808ff5ad0a63ebeWei Wang  if (!is_wifi_driver_loaded()) {
172823a774406c76128c549e026a808ff5ad0a63ebeWei Wang    return 0;
173823a774406c76128c549e026a808ff5ad0a63ebeWei Wang  }
174af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  usleep(200000); /* allow to finish interface down */
175a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley#ifdef WIFI_DRIVER_MODULE_PATH
176af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  if (rmmod(DRIVER_MODULE_NAME) == 0) {
177af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley    int count = 20; /* wait at most 10 seconds for completion */
178af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley    while (count-- > 0) {
179af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley      if (!is_wifi_driver_loaded()) break;
180af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley      usleep(500000);
181af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley    }
182af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley    usleep(500000); /* allow card removal */
183af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley    if (count) {
184af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley      return 0;
185af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley    }
186af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley    return -1;
187af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  } else
188af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley    return -1;
189a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley#else
190a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley#ifdef WIFI_DRIVER_STATE_CTRL_PARAM
191af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  if (is_wifi_driver_loaded()) {
192af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley    if (wifi_change_driver_state(WIFI_DRIVER_STATE_OFF) < 0) return -1;
193af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  }
194a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley#endif
195af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  property_set(DRIVER_PROP_NAME, "unloaded");
196af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  return 0;
197a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley#endif
198a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley}
199a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley
200af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wileyconst char *wifi_get_fw_path(int fw_type) {
201af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  switch (fw_type) {
202a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley    case WIFI_GET_FW_PATH_STA:
203af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley      return WIFI_DRIVER_FW_PATH_STA;
204a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley    case WIFI_GET_FW_PATH_AP:
205af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley      return WIFI_DRIVER_FW_PATH_AP;
206a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley    case WIFI_GET_FW_PATH_P2P:
207af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley      return WIFI_DRIVER_FW_PATH_P2P;
208af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  }
209af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  return NULL;
210a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley}
211a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley
212af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wileyint wifi_change_fw_path(const char *fwpath) {
213af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  int len;
214af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  int fd;
215af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  int ret = 0;
216af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley
217af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  if (!fwpath) return ret;
218af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  fd = TEMP_FAILURE_RETRY(open(WIFI_DRIVER_FW_PATH_PARAM, O_WRONLY));
219af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  if (fd < 0) {
22086105fb24919eca17e71a5ec820d75ac57bbdc65Christopher Wiley    PLOG(ERROR) << "Failed to open wlan fw path param";
221af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley    return -1;
222af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  }
223af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  len = strlen(fwpath) + 1;
224af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  if (TEMP_FAILURE_RETRY(write(fd, fwpath, len)) != len) {
22586105fb24919eca17e71a5ec820d75ac57bbdc65Christopher Wiley    PLOG(ERROR) << "Failed to write wlan fw path param";
226af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley    ret = -1;
227af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  }
228af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  close(fd);
229af52902e4746aab2bd667ac9bdeb1bbb3e46b539Christopher Wiley  return ret;
230a591506fbf1445877fc2f97bca1e00b51ccc3a85Christopher Wiley}
231