1 /*--------------------------------------------------------------------------
2 Copyright (c) 2013, The Linux Foundation. All rights reserved.
3
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions are met:
6 * Redistributions of source code must retain the above copyright
7 notice, this list of conditions and the following disclaimer.
8 * Redistributions in binary form must reproduce the above copyright
9 notice, this list of conditions and the following disclaimer in the
10 documentation and/or other materials provided with the distribution.
11 * Neither the name of The Linux Foundation nor
12 the names of its contributors may be used to endorse or promote
13 products derived from this software without specific prior written
14 permission.
15
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 --------------------------------------------------------------------------*/
28
29 #include <stdio.h>
30 #include <fcntl.h>
31 #include <errno.h>
32 #include <dirent.h>
33 #include <ctype.h>
34 #include <grp.h>
35 #include <utime.h>
36 #include <sys/stat.h>
37 #include <sys/sendfile.h>
38 #define LOG_TAG "wcnss_service"
39 #include <cutils/log.h>
40 #include <cutils/properties.h>
41 #ifdef WCNSS_QMI
42 #include "wcnss_qmi_client.h"
43 #include "mdm_detect.h"
44 #endif
45
46 #define SUCCESS 0
47 #define FAILED -1
48 #define BYTE_0 0
49 #define BYTE_1 8
50 #define BYTE_2 16
51 #define BYTE_3 24
52
53 #define MAX_FILE_LENGTH (1024)
54 #define WCNSS_MAX_CMD_LEN (128)
55
56 /* control messages to wcnss driver */
57 #define WCNSS_USR_CTRL_MSG_START 0x00000000
58 #define WCNSS_USR_SERIAL_NUM (WCNSS_USR_CTRL_MSG_START + 1)
59 #define WCNSS_USR_HAS_CAL_DATA (WCNSS_USR_CTRL_MSG_START + 2)
60 #define WCNSS_USR_WLAN_MAC_ADDR (WCNSS_USR_CTRL_MSG_START + 3)
61
62
63 #define WCNSS_CAL_CHUNK (3*1024)
64 #define WCNSS_CAL_FILE "/data/vendor/wifi/WCNSS_qcom_wlan_cal.bin"
65 #define WCNSS_FACT_FILE "/data/vendor/wifi/WCN_FACTORY"
66 #define WCNSS_DEVICE "/dev/wcnss_wlan"
67 #define WCNSS_CTRL "/dev/wcnss_ctrl"
68 #define WLAN_INI_FILE_DEST "/data/vendor/wifi/WCNSS_qcom_cfg.ini"
69 #define WLAN_INI_FILE_SOURCE "/vendor/etc/wifi/WCNSS_qcom_cfg.ini"
70 #define WCNSS_HAS_CAL_DATA\
71 "/sys/module/wcnsscore/parameters/has_calibrated_data"
72 #define WLAN_DRIVER_ATH_DEFAULT_VAL "0"
73
74 #define ASCII_A 65
75 #define ASCII_a 97
76 #define ASCII_0 48
77 #define HEXA_A 10
78 #define HEX_BASE 16
79
80 #ifdef WCNSS_QMI
81 #define WLAN_ADDR_SIZE 6
82 unsigned char wlan_nv_mac_addr[WLAN_ADDR_SIZE];
83 #define MAC_ADDR_ARRAY(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
84 #define MAC_ADDRESS_STR "%02x:%02x:%02x:%02x:%02x:%02x"
85
86 /* As we Want to write in 00:0a:f5:11:22:33 format in sysfs file
87 so taking mac length as 12 char + 5 for ":" + NULL
88 */
89 #define WLAN_MAC_ADDR_STRING 18
90 #endif
91
wcnss_write_cal_data(int fd_dev)92 int wcnss_write_cal_data(int fd_dev)
93 {
94 int rcount = 0;
95 int size = 0;
96 int rc = 0;
97 int wcount = 0;
98 int fd_file;
99 struct stat st;
100
101 char buf[WCNSS_CAL_CHUNK];
102
103 ALOGI("wcnss_write_cal_data trying to write cal");
104
105 rc = stat(WCNSS_CAL_FILE, &st);
106 if (rc < 0) {
107 ALOGE("Failed to stat cal file : %s",
108 strerror(errno));
109 goto exit;
110 }
111
112 size = st.st_size;
113
114 fd_file = open(WCNSS_CAL_FILE, O_RDONLY);
115 if (fd_file < 0) {
116 ALOGE("cal file doesn't exist: %s",
117 strerror(errno));
118 rc = fd_file;
119 goto exit;
120 }
121
122 /* write the file size first, so that platform driver knows
123 * when it recieves the full data */
124 wcount = write(fd_dev, (void *)&size, 4);
125 if (wcount != 4) {
126 ALOGE("Failed to write to wcnss device : %s",
127 strerror(errno));
128 rc = wcount;
129 goto exit_close;
130 }
131
132 do {
133 rcount = read(fd_file, (void *)buf, sizeof(buf));
134 if (rcount < 0) {
135 ALOGE("Failed to read from cal file ; %s",
136 strerror(errno));
137 rc = rcount;
138 goto exit_remove;
139 }
140
141 if (!rcount)
142 break;
143
144 wcount = write(fd_dev, buf, rcount);
145 if (wcount < 0) {
146 ALOGE("Failed to write to wcnss device : %s",
147 strerror(errno));
148 rc = wcount;
149 goto exit_close;
150 }
151
152 } while (rcount);
153 close(fd_file);
154
155 return SUCCESS;
156
157 exit_remove:
158 close(fd_file);
159 remove("WCNSS_CAL_FILE");
160 return rc;
161
162 exit_close:
163 close(fd_file);
164
165 exit:
166 return rc;
167 }
168
169
wcnss_read_and_store_cal_data(int fd_dev)170 int wcnss_read_and_store_cal_data(int fd_dev)
171 {
172 int rcount = 0;
173 int wcount = 0;
174 int fd_file = -1;
175 int rc = 0;
176
177 char buf[WCNSS_CAL_CHUNK];
178
179 ALOGI("wcnss_read_and_store_cal_data trying to read cal");
180
181 do {
182 /* wait on this read until data comes from fw */
183 rcount = read(fd_dev, (void *)buf, sizeof(buf));
184 if (rcount < 0) {
185 ALOGE("Failed to read from wcnss device : %s",
186 strerror(errno));
187 rc = rcount;
188 goto exit;
189 }
190
191 /* truncate the file only if there is fw data, this read
192 * may never return if the fw decides that no more cal is
193 * required; and the data we have now is good enough.
194 */
195 if (fd_file < 0) {
196 fd_file = open(WCNSS_CAL_FILE, O_WRONLY
197 | O_CREAT | O_TRUNC, 0664);
198 if (fd_file < 0) {
199 ALOGE("Failed to open cal file : %s",
200 strerror(errno));
201 rc = fd_file;
202 goto exit;
203 }
204 }
205
206 if (!rcount)
207 break;
208
209 wcount = write(fd_file, buf, rcount);
210 if (wcount < 0) {
211 ALOGE("Failed to write to cal file : %s",
212 strerror(errno));
213 rc = wcount;
214 goto exit_remove;
215 }
216
217 } while (rcount);
218
219 close(fd_file);
220
221 return SUCCESS;
222
223 exit_remove:
224 close(fd_file);
225 remove(WCNSS_CAL_FILE);
226
227 exit:
228 return rc;
229 }
230
231
find_full_path(char * cur_dir,char * file_to_find,char * full_path)232 void find_full_path(char *cur_dir, char *file_to_find, char *full_path)
233 {
234 DIR *dir;
235 struct stat st;
236 struct dirent *dr;
237 char cwd[1024];
238 int rc;
239
240 chdir(cur_dir);
241
242 dir = opendir(".");
243
244 if (dir != NULL) {
245 while ((dr = readdir(dir))) {
246
247 rc = lstat(dr->d_name, &st);
248 if (rc < 0) {
249 ALOGE("lstat failed %s", strerror(errno));
250 return;
251 }
252 if (S_ISDIR(st.st_mode)) {
253 if ((strcmp(dr->d_name, ".")) &&
254 (strcmp(dr->d_name, ".."))) {
255 find_full_path(dr->d_name,
256 file_to_find, full_path);
257 }
258 } else if (!strcmp(file_to_find, dr->d_name)) {
259 getcwd(cwd, sizeof(cwd));
260 snprintf(full_path, MAX_FILE_LENGTH, "%s/%s",
261 cwd, file_to_find);
262 }
263 }
264 closedir(dir);
265 }
266
267 chdir("..");
268 }
269
setup_wlan_config_file()270 void setup_wlan_config_file()
271 {
272 int rfd;
273 int wfd;
274 struct stat st_dest, st_src;
275 int rc_dest;
276 int rc;
277 struct group *grp;
278 struct utimbuf new_time;
279
280 rc = stat(WLAN_INI_FILE_SOURCE, &st_src);
281 if (rc != 0) {
282 ALOGE("source file do not exist %s", WLAN_INI_FILE_SOURCE);
283 return;
284 }
285
286 rc_dest = stat(WLAN_INI_FILE_DEST, &st_dest);
287 if (rc_dest == 0 && st_dest.st_size &&
288 (st_dest.st_mtime > st_src.st_mtime)) {
289 ALOGE("wlan ini file exists %s and is newer than %s",
290 WLAN_INI_FILE_DEST, WLAN_INI_FILE_SOURCE);
291 goto out_nocopy;
292 }
293
294 rfd = open(WLAN_INI_FILE_SOURCE, O_RDONLY);
295 if (rfd < 0) {
296 ALOGE("Failed to open ini source file: %s", strerror(errno));
297 return;
298 }
299
300 wfd = open(WLAN_INI_FILE_DEST, O_WRONLY | O_CREAT | O_TRUNC, 0660);
301 if (wfd < 0) {
302 ALOGE("Failed to open ini dest file: %s", strerror(errno));
303 close(rfd);
304 return;
305 }
306
307 rc = sendfile(wfd, rfd, 0, st_src.st_size);
308 if (rc != st_src.st_size) {
309 ALOGE("Failed to copy ini file: %s", strerror(errno));
310 goto out;
311 }
312
313 new_time.actime = st_src.st_atime;
314 new_time.modtime = st_src.st_mtime;
315
316 rc = utime(WLAN_INI_FILE_DEST, &new_time);
317 if (rc != 0)
318 ALOGE("could not preserve the timestamp %s", strerror(errno));
319
320 grp = getgrnam("wifi");
321 if (grp != NULL) {
322 rc = chown(WLAN_INI_FILE_DEST, -1, grp->gr_gid);
323 if (rc != 0)
324 ALOGE("Failed change group of ini file %s", strerror(errno));
325 } else {
326 ALOGE("Failed to get group wifi %s", strerror(errno));
327 }
328
329 property_set("wlan.driver.config", WLAN_INI_FILE_DEST);
330
331 out:
332 close(rfd);
333 close(wfd);
334 return;
335
336 out_nocopy:
337 property_set("wlan.driver.config", WLAN_INI_FILE_DEST);
338 return;
339 }
convert_string_to_hex(char * string)340 unsigned int convert_string_to_hex(char* string)
341 {
342 int idx = 0;
343 unsigned long int hex_num = 0;
344 for(idx; string[idx] != '\0'; idx++){
345 if(isalpha(string[idx])) {
346 if(string[idx] >='a' && string[idx] <='f') {
347 hex_num = hex_num * HEX_BASE + ((int)string[idx]
348 - ASCII_a + HEXA_A);
349 } else if ( string[idx] >='A' && string[idx] <='F') {
350 hex_num = hex_num * HEX_BASE + ((int)string[idx]
351 - ASCII_A + HEXA_A);
352 } else
353 hex_num = hex_num * HEX_BASE + (int)string[idx];
354 } else {
355 hex_num = hex_num * HEX_BASE + (string[idx]- ASCII_0);
356 }
357 }
358 hex_num = hex_num & 0xFFFFFFFF;
359 return hex_num;
360 }
361
362
setup_wcnss_parameters(int * cal,int nv_mac_addr)363 void setup_wcnss_parameters(int *cal, int nv_mac_addr)
364 {
365 char msg[WCNSS_MAX_CMD_LEN];
366 char serial[PROPERTY_VALUE_MAX];
367 int fd, rc, pos = 0;
368 struct stat st;
369 unsigned int serial_num = 0;
370
371 fd = open(WCNSS_CTRL, O_WRONLY);
372 if (fd < 0) {
373 ALOGE("Failed to open %s : %s", WCNSS_CTRL, strerror(errno));
374 return;
375 }
376
377 #ifdef WCNSS_QMI
378 if (SUCCESS == nv_mac_addr)
379 {
380 pos = 0;
381 msg[pos++] = WCNSS_USR_WLAN_MAC_ADDR >> BYTE_1;
382 msg[pos++] = WCNSS_USR_WLAN_MAC_ADDR >> BYTE_0;
383 msg[pos++] = wlan_nv_mac_addr[0];
384 msg[pos++] = wlan_nv_mac_addr[1];
385 msg[pos++] = wlan_nv_mac_addr[2];
386 msg[pos++] = wlan_nv_mac_addr[3];
387 msg[pos++] = wlan_nv_mac_addr[4];
388 msg[pos++] = wlan_nv_mac_addr[5];
389
390 ALOGI("WLAN MAC Addr:" MAC_ADDRESS_STR,
391 MAC_ADDR_ARRAY(wlan_nv_mac_addr));
392
393 if (write(fd, msg, pos) < 0) {
394 ALOGE("Failed to write to %s : %s", WCNSS_CTRL,
395 strerror(errno));
396 goto fail;
397 }
398 }
399 #endif
400
401 pos = 0;
402 msg[pos++] = WCNSS_USR_HAS_CAL_DATA >> BYTE_1;
403 msg[pos++] = WCNSS_USR_HAS_CAL_DATA >> BYTE_0;
404
405 rc = stat(WCNSS_FACT_FILE, &st);
406 if (rc == 0) {
407 ALOGE("Factory file found, deleting cal file");
408 unlink(WCNSS_CAL_FILE);
409 goto fail_resp;
410 }
411
412 rc = stat(WCNSS_CAL_FILE, &st);
413 if (rc != 0) {
414 ALOGE("CAL file not found");
415 goto fail_resp;
416 }
417
418 /* has cal data */
419 msg[pos++] = 1;
420
421 if (write(fd, msg, pos) < 0) {
422 ALOGE("Failed to write to %s : %s", WCNSS_CTRL,
423 strerror(errno));
424 goto fail;
425 }
426
427 ALOGI("Correctly triggered cal file");
428 *cal = SUCCESS;
429 close(fd);
430 return;
431
432 fail_resp:
433 msg[pos++] = 0;
434 if (write(fd, msg, pos) < 0)
435 ALOGE("Failed to write to %s : %s", WCNSS_CTRL,
436 strerror(errno));
437
438 fail:
439 *cal = FAILED;
440 close(fd);
441 return;
442 }
443
setup_wlan_driver_ath_prop()444 void setup_wlan_driver_ath_prop()
445 {
446 property_set("wlan.driver.ath", WLAN_DRIVER_ATH_DEFAULT_VAL);
447 }
448
449 #ifdef WCNSS_QMI
check_modem_compatability(struct dev_info * mdm_detect_info)450 int check_modem_compatability(struct dev_info *mdm_detect_info)
451 {
452 char args[MODEM_BASEBAND_PROPERTY_SIZE] = {0};
453 int ret = 0;
454 /* Get the hardware property */
455 ret = property_get(MODEM_BASEBAND_PROPERTY, args, "");
456 if (ret > MODEM_BASEBAND_PROPERTY_SIZE) {
457 ALOGE("property [%s] has size [%d] that exceeds max [%d]",
458 MODEM_BASEBAND_PROPERTY, ret, MODEM_BASEBAND_PROPERTY_SIZE);
459 return 0;
460 }
461 /* This will check for the type of hardware, and if the
462 hardware type needs external modem, it will check if the
463 modem type is external*/
464 if(!strncmp(MODEM_BASEBAND_VALUE_APQ, args, 3)) {
465
466 for (ret = 0; ret < mdm_detect_info->num_modems; ret++) {
467 if (mdm_detect_info->mdm_list[ret].type == MDM_TYPE_EXTERNAL) {
468 ALOGE("Hardware supports external modem");
469 return 1;
470 }
471 }
472 ALOGE("Hardware does not support external modem");
473 return 0;
474 }
475 return 1;
476 }
477 #endif
478
main(int argc,char * argv[])479 int main(int argc, char *argv[])
480 {
481 int rc;
482 int fd_dev, ret_cal;
483 int nv_mac_addr = FAILED;
484 #ifdef WCNSS_QMI
485 struct dev_info mdm_detect_info;
486 int nom = 0;
487 #endif
488
489 setup_wlan_config_file();
490
491 #ifdef WCNSS_QMI
492 /* Call ESOC API to get the number of modems.
493 If the number of modems is not zero, only then proceed
494 with the eap_proxy intialization.*/
495
496 nom = get_system_info(&mdm_detect_info);
497
498 if (nom > 0)
499 ALOGE("Failed to get system info, ret %d", nom);
500
501 if (mdm_detect_info.num_modems == 0) {
502 ALOGE("wcnss_service: No Modem support for this target"
503 " number of modems is %d", mdm_detect_info.num_modems);
504 goto nomodem;
505 }
506
507 ALOGE("wcnss_service: num_modems = %d", mdm_detect_info.num_modems);
508
509 if(!check_modem_compatability(&mdm_detect_info)) {
510 ALOGE("wcnss_service: Target does not have external modem");
511 goto nomodem;
512 }
513
514 /* initialize the DMS client and request the wlan mac address */
515
516 if (SUCCESS == wcnss_init_qmi()) {
517
518 rc = wcnss_qmi_get_wlan_address(wlan_nv_mac_addr);
519
520 if (rc == SUCCESS) {
521 nv_mac_addr = SUCCESS;
522 ALOGE("WLAN MAC Addr:" MAC_ADDRESS_STR,
523 MAC_ADDR_ARRAY(wlan_nv_mac_addr));
524 } else
525 ALOGE("Failed to Get MAC addr from modem");
526
527 wcnss_qmi_deinit();
528 }
529 else
530 ALOGE("Failed to Initialize wcnss QMI Interface");
531
532 nomodem:
533 #endif
534 setup_wcnss_parameters(&ret_cal, nv_mac_addr);
535
536 fd_dev = open(WCNSS_DEVICE, O_RDWR);
537 if (fd_dev < 0) {
538 ALOGE("Failed to open wcnss device : %s",
539 strerror(errno));
540 return fd_dev;
541 }
542
543 if (ret_cal != FAILED) {
544 rc = wcnss_write_cal_data(fd_dev);
545 if (rc != SUCCESS)
546 ALOGE("No cal data is written to WCNSS %d", rc);
547 else
548 ALOGE("Cal data is successfully written to WCNSS");
549 }
550
551 setup_wlan_driver_ath_prop();
552
553 rc = wcnss_read_and_store_cal_data(fd_dev);
554 if (rc != SUCCESS)
555 ALOGE("Failed to read and save cal data %d", rc);
556 else
557 ALOGI("Calibration data was successfull written to %s",
558 WCNSS_CAL_FILE);
559
560 close(fd_dev);
561
562 return rc;
563 }
564