blob: a71afb0569dbbb79e0e8f693da4ba38dd4b1bf25 [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>
R. Andrew Ohana81c2e052012-10-03 19:52:52 -070030
Andreas Schneider2b601792015-01-26 23:14:17 +010031#include <cutils/log.h>
R. Andrew Ohana81c2e052012-10-03 19:52:52 -070032
Andreas Schneider3ff947b2015-01-26 22:56:30 +010033#ifndef WIFI_DRIVER_NVRAM_PATH
34#define WIFI_DRIVER_NVRAM_PATH NULL
35#endif
36
37#ifndef WIFI_DRIVER_NVRAM_PATH_PARAM
38#define WIFI_DRIVER_NVRAM_PATH_PARAM "/sys/module/wlan/parameters/nvram_path"
39#endif
40
R. Andrew Ohana81c2e052012-10-03 19:52:52 -070041#define MACADDR_PATH "/efs/wifi/.mac.info"
42#define CID_PATH "/data/.cid.info"
43
44enum Type {
45 NONE,
46 MURATA,
47 SEMCOSH,
Andreas Schneiderf3ba7202015-01-03 19:29:28 +010048 SEMCOVE,
49 SEMCO3RD,
Christopher N. Hesse0ed56702015-01-25 17:38:23 +010050 SEMCO,
Andreas Schneiderf3ba7202015-01-03 19:29:28 +010051 WISOL
R. Andrew Ohana81c2e052012-10-03 19:52:52 -070052};
53
Andreas Schneider3ff947b2015-01-26 22:56:30 +010054static int wifi_change_nvram_calibration(const char *nvram_file,
55 const char *type)
56{
57 int len;
58 int fd = -1;
59 int ret = 0;
60 struct stat sb;
61 char nvram_str[1024] = { 0 };
62
63 if (nvram_file == NULL || type == NULL) {
64 return -1;
65 }
66
67 ret = stat(nvram_file, &sb);
68 if (ret != 0) {
69 ALOGE("Failed to check for NVRAM calibration file '%s' - error: %s",
70 nvram_file,
71 strerror(errno));
72 return -1;
73 }
74
75 ALOGD("Using NVRAM calibration file: %s\n", nvram_file);
76
77 fd = TEMP_FAILURE_RETRY(open(WIFI_DRIVER_NVRAM_PATH_PARAM, O_WRONLY));
78 if (fd < 0) {
79 ALOGE("Failed to open wifi nvram config path %s - error: %s",
80 WIFI_DRIVER_NVRAM_PATH_PARAM, strerror(errno));
81 return -1;
82 }
83
84 len = strlen(nvram_file) + 1;
85 if (TEMP_FAILURE_RETRY(write(fd, nvram_file, len)) != len) {
86 ALOGE("Failed to write to wifi config path %s - error: %s",
87 WIFI_DRIVER_NVRAM_PATH_PARAM, strerror(errno));
88 ret = -1;
89 goto out;
90 }
91
92 snprintf(nvram_str, sizeof(nvram_str), "%s_%s",
93 nvram_file, type);
94
95 ALOGD("Changing NVRAM calibration file for %s chipset\n", type);
96
97 ret = stat(nvram_str, &sb);
98 if (ret != 0) {
99 ALOGW("NVRAM calibration file '%s' doesn't exist", nvram_str);
100 /*
101 * We were able to write the default calibration file. So
102 * continue here without returning an error.
103 */
104 ret = 0;
105 goto out;
106 }
107
108 len = strlen(nvram_str) + 1;
109 if (TEMP_FAILURE_RETRY(write(fd, nvram_str, len)) != len) {
110 ALOGW("Failed to write to wifi config path %s - error: %s",
111 WIFI_DRIVER_NVRAM_PATH_PARAM, strerror(errno));
112 /*
113 * We were able to write the default calibration file. So
114 * continue here without returning an error.
115 */
116 ret = 0;
117 goto out;
118 }
119
120 ALOGD("NVRAM calibration file set to '%s'\n", nvram_str);
121
122 ret = 0;
123out:
124 if (fd != -1) {
125 close(fd);
126 }
127 return ret;
128}
129
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700130int main() {
131 FILE* file;
132 FILE* cidfile;
133 char* str;
134 char mac_addr_half[9];
135 int ret = -1;
136 int amode;
137 enum Type type = NONE;
138
139 /* open mac addr file */
140 file = fopen(MACADDR_PATH, "r");
codeworkx84f8d1d2012-12-13 17:23:45 +0100141 if (file == 0) {
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700142 fprintf(stderr, "open(%s) failed\n", MACADDR_PATH);
143 ALOGE("Can't open %s\n", MACADDR_PATH);
144 return -1;
145 }
146
147 /* get and compare mac addr */
148 str = fgets(mac_addr_half, 9, file);
Andreas Schneider3a73bd32015-01-26 23:30:13 +0100149 fclose(file);
codeworkx84f8d1d2012-12-13 17:23:45 +0100150 if (str == 0) {
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700151 fprintf(stderr, "fgets() from file %s failed\n", MACADDR_PATH);
152 ALOGE("Can't read from %s\n", MACADDR_PATH);
153 return -1;
154 }
155
Liam Alford2fccbdf2013-11-21 13:55:42 +0000156 /* murata
157 ref: http://hwaddress.com/?q=ACT */
158 if (strncasecmp(mac_addr_half, "00:0e:6d", 9) == 0 ||
159 strncasecmp(mac_addr_half, "00:13:e0", 9) == 0 ||
160 strncasecmp(mac_addr_half, "00:21:e8", 9) == 0 ||
161 strncasecmp(mac_addr_half, "00:26:e8", 9) == 0 ||
162 strncasecmp(mac_addr_half, "00:37:6d", 9) == 0 ||
163 strncasecmp(mac_addr_half, "00:60:57", 9) == 0 ||
164 strncasecmp(mac_addr_half, "04:46:65", 9) == 0 ||
165 strncasecmp(mac_addr_half, "10:5f:06", 9) == 0 ||
JustArchi300ecd32014-09-28 23:55:36 +0200166 strncasecmp(mac_addr_half, "10:a5:d0", 9) == 0 ||
golcheck5b418172013-12-30 13:22:55 +0000167 strncasecmp(mac_addr_half, "1c:99:4c", 9) == 0 ||
Liam Alford2fccbdf2013-11-21 13:55:42 +0000168 strncasecmp(mac_addr_half, "14:7d:c5", 9) == 0 ||
169 strncasecmp(mac_addr_half, "20:02:af", 9) == 0 ||
170 strncasecmp(mac_addr_half, "40:f3:08", 9) == 0 ||
171 strncasecmp(mac_addr_half, "44:a7:cf", 9) == 0 ||
172 strncasecmp(mac_addr_half, "5c:da:d4", 9) == 0 ||
173 strncasecmp(mac_addr_half, "5c:f8:a1", 9) == 0 ||
JustArchi300ecd32014-09-28 23:55:36 +0200174 strncasecmp(mac_addr_half, "78:4b:87", 9) == 0 ||
Liam Alford2fccbdf2013-11-21 13:55:42 +0000175 strncasecmp(mac_addr_half, "60:21:c0", 9) == 0 ||
176 strncasecmp(mac_addr_half, "88:30:8a", 9) == 0 ||
MarcKed973a7b2014-12-30 17:52:55 +0100177 strncasecmp(mac_addr_half, "f0:27:65", 9) == 0 ||
178 strncasecmp(mac_addr_half, "fc:c2:de", 9) == 0) {
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700179 type = MURATA;
180 }
181
182 /* semcosh */
MarcKea81d58b2014-12-10 19:12:54 +0100183 if (strncasecmp(mac_addr_half, "34:23:ba", 9) == 0 ||
184 strncasecmp(mac_addr_half, "38:aa:3c", 9) == 0 ||
185 strncasecmp(mac_addr_half, "5c:0a:5b", 9) == 0 ||
186 strncasecmp(mac_addr_half, "88:32:9b", 9) == 0 ||
187 strncasecmp(mac_addr_half, "90:18:7c", 9) == 0 ||
Ethan Chen727dea72013-07-31 13:18:51 -0700188 strncasecmp(mac_addr_half, "cc:3a:61", 9) == 0) {
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700189 type = SEMCOSH;
190 }
191
Andreas Schneiderf3ba7202015-01-03 19:29:28 +0100192 /* semco3rd */
193 if (strncasecmp(mac_addr_half, "f4:09:d8", 9) == 0) {
194 type = SEMCO3RD;
195 }
196
Christopher N. Hesse0ed56702015-01-25 17:38:23 +0100197 /* semco */
198 if (strncasecmp(mac_addr_half, "c0:bd:d1", 9) == 0 ||
199 strncasecmp(mac_addr_half, "51:f6:6b", 9) == 0) {
200 type = SEMCO;
201 }
202
Andreas Schneiderf3ba7202015-01-03 19:29:28 +0100203 /* wisol */
204 if (strncasecmp(mac_addr_half, "48:5A:3F", 9) == 0) {
205 type = WISOL;
206 }
207
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700208 if (type != NONE) {
Andreas Schneider3ff947b2015-01-26 22:56:30 +0100209 const char *nvram_file;
Andreas Schneiderc7212d02015-01-26 22:45:26 +0100210 const char *type_str;
Andreas Schneider7558b9d2015-01-26 23:29:18 +0100211 struct passwd *pwd;
212 int fd;
213
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700214 /* open cid file */
215 cidfile = fopen(CID_PATH, "w");
216 if(cidfile == 0) {
217 fprintf(stderr, "open(%s) failed\n", CID_PATH);
218 ALOGE("Can't open %s\n", CID_PATH);
219 return -1;
220 }
221
222 switch(type) {
223 case NONE:
224 return -1;
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700225 case MURATA:
Andreas Schneiderc7212d02015-01-26 22:45:26 +0100226 type_str = "murata";
227 break;
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700228 case SEMCOSH:
Andreas Schneiderc7212d02015-01-26 22:45:26 +0100229 type_str = "semcosh";
230 break;
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700231 case SEMCOVE:
Andreas Schneiderc7212d02015-01-26 22:45:26 +0100232 type_str = "semcove";
233 break;
Andreas Schneiderf3ba7202015-01-03 19:29:28 +0100234 case SEMCO3RD:
Andreas Schneiderc7212d02015-01-26 22:45:26 +0100235 type_str = "semco3rd";
Andreas Schneiderf3ba7202015-01-03 19:29:28 +0100236 break;
Christopher N. Hesse0ed56702015-01-25 17:38:23 +0100237 case SEMCO:
Andreas Schneiderc7212d02015-01-26 22:45:26 +0100238 type_str = "semco";
239 break;
Andreas Schneiderf3ba7202015-01-03 19:29:28 +0100240 case WISOL:
Andreas Schneiderc7212d02015-01-26 22:45:26 +0100241 type_str = "wisol";
Andreas Schneiderf3ba7202015-01-03 19:29:28 +0100242 break;
Andreas Schneiderc7212d02015-01-26 22:45:26 +0100243 }
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700244
Andreas Schneiderc7212d02015-01-26 22:45:26 +0100245 ALOGI("Settting wifi type to %s in %s\n", type_str, CID_PATH);
246
247 ret = fputs(type_str, cidfile);
codeworkx84f8d1d2012-12-13 17:23:45 +0100248 if (ret != 0) {
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700249 ALOGE("Can't write to %s\n", CID_PATH);
Andreas Schneiderca1a0ee2015-01-26 22:49:49 +0100250 return 1;
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700251 }
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700252
Andreas Schneider7f517d72015-01-26 23:19:03 +0100253 /* Change permissions of cid file */
254 ALOGD("Change permissions of %s\n", CID_PATH);
255
256 fd = fileno(cidfile);
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700257 amode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
Andreas Schneider7f517d72015-01-26 23:19:03 +0100258 ret = fchmod(fd, amode);
Andreas Schneider7f517d72015-01-26 23:19:03 +0100259 if (ret != 0) {
Andreas Schneider7558b9d2015-01-26 23:29:18 +0100260 fclose(cidfile);
Andreas Schneider7f517d72015-01-26 23:19:03 +0100261 ALOGE("Can't set permissions on %s - %s\n",
262 CID_PATH, strerror(errno));
263 return 1;
264 }
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700265
Andreas Schneider7558b9d2015-01-26 23:29:18 +0100266 pwd = getpwnam("system");
267 if (pwd == NULL) {
268 fclose(cidfile);
269 ALOGE("Failed to find 'system' user - %s\n",
270 strerror(errno));
271 return 1;
272 }
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700273
Andreas Schneider7558b9d2015-01-26 23:29:18 +0100274 ret = fchown(fd, pwd->pw_uid, pwd->pw_gid);
275 fclose(cidfile);
276 if (ret != 0) {
277 ALOGE("Failed to change owner of %s - %s\n",
278 CID_PATH, strerror(errno));
279 return 1;
280 }
Andreas Schneider3ff947b2015-01-26 22:56:30 +0100281
282 nvram_file = WIFI_DRIVER_NVRAM_PATH;
283 if (nvram_file != NULL) {
284 ret = wifi_change_nvram_calibration(nvram_file, type_str);
285 if (ret != 0) {
286 return 1;
287 }
288 }
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700289 } else {
290 /* delete cid file if no specific type */
291 ALOGD("Deleting file %s\n", CID_PATH);
292 remove(CID_PATH);
293 }
R. Andrew Ohana81c2e052012-10-03 19:52:52 -0700294 return 0;
295}