blob: e70006306743208ae0e42702a79b36e17617a8fa [file] [log] [blame]
R. Andrew Ohana81c2e052012-10-03 19:52:52 -07001/*
2 * Copyright (C) 2012, The CyanogenMod Project
3 * Daniel Hillenbrand <codeworkx@cyanogenmod.com>
4 * Marco Hillenbrand <marco.hillenbrand@googlemail.com>
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
Andreas Schneider2b601792015-01-26 23:14:17 +010019#define LOG_TAG "macloader"
20#define LOG_NDEBUG 0
R. Andrew Ohana81c2e052012-10-03 19:52:52 -070021
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
Andreas Schneider3ff947b2015-01-26 22:56:30 +010025#include <sys/types.h>
R. Andrew Ohana81c2e052012-10-03 19:52:52 -070026#include <sys/stat.h>
Andreas Schneider3ff947b2015-01-26 22:56:30 +010027#include <fcntl.h>
Andreas Schneider7f517d72015-01-26 23:19:03 +010028#include <unistd.h>
Andreas Schneider7558b9d2015-01-26 23:29:18 +010029#include <pwd.h>
Caio Schnepper02c9c712015-10-10 02:14:28 -030030#include <errno.h>
R. Andrew Ohana81c2e052012-10-03 19:52:52 -070031
Andreas Schneider2b601792015-01-26 23:14:17 +010032#include <cutils/log.h>
R. Andrew Ohana81c2e052012-10-03 19:52:52 -070033
Andreas Schneider3ff947b2015-01-26 22:56:30 +010034#ifndef WIFI_DRIVER_NVRAM_PATH
35#define WIFI_DRIVER_NVRAM_PATH NULL
36#endif
37
38#ifndef WIFI_DRIVER_NVRAM_PATH_PARAM
39#define WIFI_DRIVER_NVRAM_PATH_PARAM "/sys/module/wlan/parameters/nvram_path"
40#endif
41
R. Andrew Ohana81c2e052012-10-03 19:52:52 -070042#define MACADDR_PATH "/efs/wifi/.mac.info"
43#define CID_PATH "/data/.cid.info"
44
45enum Type {
46 NONE,
47 MURATA,
48 SEMCOSH,
Andreas Schneiderf3ba7202015-01-03 19:29:28 +010049 SEMCOVE,
50 SEMCO3RD,
Christopher N. Hesse0ed56702015-01-25 17:38:23 +010051 SEMCO,
Andreas Schneiderf3ba7202015-01-03 19:29:28 +010052 WISOL
R. Andrew Ohana81c2e052012-10-03 19:52:52 -070053};
54
Andreas Schneider3ff947b2015-01-26 22:56:30 +010055static int wifi_change_nvram_calibration(const char *nvram_file,
56 const char *type)
57{
58 int len;
59 int fd = -1;
60 int ret = 0;
61 struct stat sb;
62 char nvram_str[1024] = { 0 };
63
64 if (nvram_file == NULL || type == NULL) {
65 return -1;
66 }
67
68 ret = stat(nvram_file, &sb);
69 if (ret != 0) {
70 ALOGE("Failed to check for NVRAM calibration file '%s' - error: %s",
71 nvram_file,
72 strerror(errno));
73 return -1;
74 }
75
76 ALOGD("Using NVRAM calibration file: %s\n", nvram_file);
77
78 fd = TEMP_FAILURE_RETRY(open(WIFI_DRIVER_NVRAM_PATH_PARAM, O_WRONLY));
79 if (fd < 0) {
80 ALOGE("Failed to open wifi nvram config path %s - error: %s",
81 WIFI_DRIVER_NVRAM_PATH_PARAM, strerror(errno));
82 return -1;
83 }
84
85 len = strlen(nvram_file) + 1;
86 if (TEMP_FAILURE_RETRY(write(fd, nvram_file, len)) != len) {
87 ALOGE("Failed to write to wifi config path %s - error: %s",
88 WIFI_DRIVER_NVRAM_PATH_PARAM, strerror(errno));
89 ret = -1;
90 goto out;
91 }
92
93 snprintf(nvram_str, sizeof(nvram_str), "%s_%s",
94 nvram_file, type);
95
96 ALOGD("Changing NVRAM calibration file for %s chipset\n", type);
97
98 ret = stat(nvram_str, &sb);
99 if (ret != 0) {
100 ALOGW("NVRAM calibration file '%s' doesn't exist", nvram_str);
101 /*
102 * We were able to write the default calibration file. So
103 * continue here without returning an error.
104 */
105 ret = 0;
106 goto out;
107 }
108
109 len = strlen(nvram_str) + 1;
110 if (TEMP_FAILURE_RETRY(write(fd, nvram_str, len)) != len) {
111 ALOGW("Failed to write to wifi config path %s - error: %s",
112 WIFI_DRIVER_NVRAM_PATH_PARAM, strerror(errno));
113 /*
114 * We were able to write the default calibration file. So
115 * continue here without returning an error.
116 */
117 ret = 0;
118 goto out;
119 }
120
121 ALOGD("NVRAM calibration file set to '%s'\n", nvram_str);
122
123 ret = 0;
124out:
125 if (fd != -1) {
126 close(fd);
127 }
128 return ret;
129}
130
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700131int main() {
132 FILE* file;
133 FILE* cidfile;
134 char* str;
135 char mac_addr_half[9];
136 int ret = -1;
137 int amode;
138 enum Type type = NONE;
139
140 /* open mac addr file */
141 file = fopen(MACADDR_PATH, "r");
codeworkx84f8d1d2012-12-13 17:23:45 +0100142 if (file == 0) {
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700143 fprintf(stderr, "open(%s) failed\n", MACADDR_PATH);
144 ALOGE("Can't open %s\n", MACADDR_PATH);
145 return -1;
146 }
147
148 /* get and compare mac addr */
149 str = fgets(mac_addr_half, 9, file);
Andreas Schneider3a73bd32015-01-26 23:30:13 +0100150 fclose(file);
codeworkx84f8d1d2012-12-13 17:23:45 +0100151 if (str == 0) {
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700152 fprintf(stderr, "fgets() from file %s failed\n", MACADDR_PATH);
153 ALOGE("Can't read from %s\n", MACADDR_PATH);
154 return -1;
155 }
156
Liam Alford2fccbdf2013-11-21 13:55:42 +0000157 /* murata
158 ref: http://hwaddress.com/?q=ACT */
159 if (strncasecmp(mac_addr_half, "00:0e:6d", 9) == 0 ||
160 strncasecmp(mac_addr_half, "00:13:e0", 9) == 0 ||
161 strncasecmp(mac_addr_half, "00:21:e8", 9) == 0 ||
162 strncasecmp(mac_addr_half, "00:26:e8", 9) == 0 ||
163 strncasecmp(mac_addr_half, "00:37:6d", 9) == 0 ||
164 strncasecmp(mac_addr_half, "00:60:57", 9) == 0 ||
165 strncasecmp(mac_addr_half, "04:46:65", 9) == 0 ||
166 strncasecmp(mac_addr_half, "10:5f:06", 9) == 0 ||
JustArchi300ecd32014-09-28 23:55:36 +0200167 strncasecmp(mac_addr_half, "10:a5:d0", 9) == 0 ||
golcheck5b418172013-12-30 13:22:55 +0000168 strncasecmp(mac_addr_half, "1c:99:4c", 9) == 0 ||
Liam Alford2fccbdf2013-11-21 13:55:42 +0000169 strncasecmp(mac_addr_half, "14:7d:c5", 9) == 0 ||
170 strncasecmp(mac_addr_half, "20:02:af", 9) == 0 ||
171 strncasecmp(mac_addr_half, "40:f3:08", 9) == 0 ||
172 strncasecmp(mac_addr_half, "44:a7:cf", 9) == 0 ||
173 strncasecmp(mac_addr_half, "5c:da:d4", 9) == 0 ||
174 strncasecmp(mac_addr_half, "5c:f8:a1", 9) == 0 ||
JustArchi300ecd32014-09-28 23:55:36 +0200175 strncasecmp(mac_addr_half, "78:4b:87", 9) == 0 ||
Liam Alford2fccbdf2013-11-21 13:55:42 +0000176 strncasecmp(mac_addr_half, "60:21:c0", 9) == 0 ||
177 strncasecmp(mac_addr_half, "88:30:8a", 9) == 0 ||
MarcKed973a7b2014-12-30 17:52:55 +0100178 strncasecmp(mac_addr_half, "f0:27:65", 9) == 0 ||
179 strncasecmp(mac_addr_half, "fc:c2:de", 9) == 0) {
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700180 type = MURATA;
181 }
182
183 /* semcosh */
MarcKea81d58b2014-12-10 19:12:54 +0100184 if (strncasecmp(mac_addr_half, "34:23:ba", 9) == 0 ||
185 strncasecmp(mac_addr_half, "38:aa:3c", 9) == 0 ||
186 strncasecmp(mac_addr_half, "5c:0a:5b", 9) == 0 ||
187 strncasecmp(mac_addr_half, "88:32:9b", 9) == 0 ||
188 strncasecmp(mac_addr_half, "90:18:7c", 9) == 0 ||
Ethan Chen727dea72013-07-31 13:18:51 -0700189 strncasecmp(mac_addr_half, "cc:3a:61", 9) == 0) {
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700190 type = SEMCOSH;
191 }
192
Andreas Schneiderf3ba7202015-01-03 19:29:28 +0100193 /* semco3rd */
194 if (strncasecmp(mac_addr_half, "f4:09:d8", 9) == 0) {
195 type = SEMCO3RD;
196 }
197
Christopher N. Hesse0ed56702015-01-25 17:38:23 +0100198 /* semco */
199 if (strncasecmp(mac_addr_half, "c0:bd:d1", 9) == 0 ||
200 strncasecmp(mac_addr_half, "51:f6:6b", 9) == 0) {
201 type = SEMCO;
202 }
203
Andreas Schneiderf3ba7202015-01-03 19:29:28 +0100204 /* wisol */
205 if (strncasecmp(mac_addr_half, "48:5A:3F", 9) == 0) {
206 type = WISOL;
207 }
208
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700209 if (type != NONE) {
Andreas Schneider3ff947b2015-01-26 22:56:30 +0100210 const char *nvram_file;
Andreas Schneiderc7212d02015-01-26 22:45:26 +0100211 const char *type_str;
Andreas Schneider7558b9d2015-01-26 23:29:18 +0100212 struct passwd *pwd;
213 int fd;
214
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700215 /* open cid file */
216 cidfile = fopen(CID_PATH, "w");
217 if(cidfile == 0) {
218 fprintf(stderr, "open(%s) failed\n", CID_PATH);
219 ALOGE("Can't open %s\n", CID_PATH);
220 return -1;
221 }
222
223 switch(type) {
224 case NONE:
225 return -1;
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700226 case MURATA:
Andreas Schneiderc7212d02015-01-26 22:45:26 +0100227 type_str = "murata";
228 break;
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700229 case SEMCOSH:
Andreas Schneiderc7212d02015-01-26 22:45:26 +0100230 type_str = "semcosh";
231 break;
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700232 case SEMCOVE:
Andreas Schneiderc7212d02015-01-26 22:45:26 +0100233 type_str = "semcove";
234 break;
Andreas Schneiderf3ba7202015-01-03 19:29:28 +0100235 case SEMCO3RD:
Andreas Schneiderc7212d02015-01-26 22:45:26 +0100236 type_str = "semco3rd";
Andreas Schneiderf3ba7202015-01-03 19:29:28 +0100237 break;
Christopher N. Hesse0ed56702015-01-25 17:38:23 +0100238 case SEMCO:
Andreas Schneiderc7212d02015-01-26 22:45:26 +0100239 type_str = "semco";
240 break;
Andreas Schneiderf3ba7202015-01-03 19:29:28 +0100241 case WISOL:
Andreas Schneiderc7212d02015-01-26 22:45:26 +0100242 type_str = "wisol";
Andreas Schneiderf3ba7202015-01-03 19:29:28 +0100243 break;
Andreas Schneiderc7212d02015-01-26 22:45:26 +0100244 }
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700245
Andreas Schneiderc7212d02015-01-26 22:45:26 +0100246 ALOGI("Settting wifi type to %s in %s\n", type_str, CID_PATH);
247
248 ret = fputs(type_str, cidfile);
codeworkx84f8d1d2012-12-13 17:23:45 +0100249 if (ret != 0) {
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700250 ALOGE("Can't write to %s\n", CID_PATH);
Andreas Schneiderca1a0ee2015-01-26 22:49:49 +0100251 return 1;
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700252 }
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700253
Andreas Schneider7f517d72015-01-26 23:19:03 +0100254 /* Change permissions of cid file */
255 ALOGD("Change permissions of %s\n", CID_PATH);
256
257 fd = fileno(cidfile);
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700258 amode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
Andreas Schneider7f517d72015-01-26 23:19:03 +0100259 ret = fchmod(fd, amode);
Andreas Schneider7f517d72015-01-26 23:19:03 +0100260 if (ret != 0) {
Andreas Schneider7558b9d2015-01-26 23:29:18 +0100261 fclose(cidfile);
Andreas Schneider7f517d72015-01-26 23:19:03 +0100262 ALOGE("Can't set permissions on %s - %s\n",
263 CID_PATH, strerror(errno));
264 return 1;
265 }
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700266
Andreas Schneider7558b9d2015-01-26 23:29:18 +0100267 pwd = getpwnam("system");
268 if (pwd == NULL) {
269 fclose(cidfile);
270 ALOGE("Failed to find 'system' user - %s\n",
271 strerror(errno));
272 return 1;
273 }
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700274
Andreas Schneider7558b9d2015-01-26 23:29:18 +0100275 ret = fchown(fd, pwd->pw_uid, pwd->pw_gid);
276 fclose(cidfile);
277 if (ret != 0) {
278 ALOGE("Failed to change owner of %s - %s\n",
279 CID_PATH, strerror(errno));
280 return 1;
281 }
Andreas Schneider3ff947b2015-01-26 22:56:30 +0100282
283 nvram_file = WIFI_DRIVER_NVRAM_PATH;
284 if (nvram_file != NULL) {
285 ret = wifi_change_nvram_calibration(nvram_file, type_str);
286 if (ret != 0) {
287 return 1;
288 }
289 }
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700290 } else {
291 /* delete cid file if no specific type */
292 ALOGD("Deleting file %s\n", CID_PATH);
293 remove(CID_PATH);
294 }
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700295 return 0;
296}