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/misc/wifi/WCNSS_qcom_wlan_cal.bin"
65 #define WCNSS_FACT_FILE "/data/misc/wifi/WCN_FACTORY"
66 #define WCNSS_DEVICE "/dev/wcnss_wlan"
67 #define WCNSS_CTRL "/dev/wcnss_ctrl"
68 #define WLAN_INI_FILE_DEST "/data/misc/wifi/WCNSS_qcom_cfg.ini"
69 #define WLAN_INI_FILE_SOURCE "/system/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 rc = property_get("ro.serialno", serial, "");
378 if (rc) {
379 serial_num = convert_string_to_hex(serial);
380 ALOGE("Serial Number is %x", serial_num);
381
382 msg[pos++] = WCNSS_USR_SERIAL_NUM >> BYTE_1;
383 msg[pos++] = WCNSS_USR_SERIAL_NUM >> BYTE_0;
384 msg[pos++] = serial_num >> BYTE_3;
385 msg[pos++] = serial_num >> BYTE_2;
386 msg[pos++] = serial_num >> BYTE_1;
387 msg[pos++] = serial_num >> BYTE_0;
388
389 if (write(fd, msg, pos) < 0) {
390 ALOGE("Failed to write to %s : %s", WCNSS_CTRL,
391 strerror(errno));
392 goto fail;
393 }
394 }
395
396 #ifdef WCNSS_QMI
397 if (SUCCESS == nv_mac_addr)
398 {
399 pos = 0;
400 msg[pos++] = WCNSS_USR_WLAN_MAC_ADDR >> BYTE_1;
401 msg[pos++] = WCNSS_USR_WLAN_MAC_ADDR >> BYTE_0;
402 msg[pos++] = wlan_nv_mac_addr[0];
403 msg[pos++] = wlan_nv_mac_addr[1];
404 msg[pos++] = wlan_nv_mac_addr[2];
405 msg[pos++] = wlan_nv_mac_addr[3];
406 msg[pos++] = wlan_nv_mac_addr[4];
407 msg[pos++] = wlan_nv_mac_addr[5];
408
409 ALOGI("WLAN MAC Addr:" MAC_ADDRESS_STR,
410 MAC_ADDR_ARRAY(wlan_nv_mac_addr));
411
412 if (write(fd, msg, pos) < 0) {
413 ALOGE("Failed to write to %s : %s", WCNSS_CTRL,
414 strerror(errno));
415 goto fail;
416 }
417 }
418 #endif
419
420 pos = 0;
421 msg[pos++] = WCNSS_USR_HAS_CAL_DATA >> BYTE_1;
422 msg[pos++] = WCNSS_USR_HAS_CAL_DATA >> BYTE_0;
423
424 rc = stat(WCNSS_FACT_FILE, &st);
425 if (rc == 0) {
426 ALOGE("Factory file found, deleting cal file");
427 unlink(WCNSS_CAL_FILE);
428 goto fail_resp;
429 }
430
431 rc = stat(WCNSS_CAL_FILE, &st);
432 if (rc != 0) {
433 ALOGE("CAL file not found");
434 goto fail_resp;
435 }
436
437 /* has cal data */
438 msg[pos++] = 1;
439
440 if (write(fd, msg, pos) < 0) {
441 ALOGE("Failed to write to %s : %s", WCNSS_CTRL,
442 strerror(errno));
443 goto fail;
444 }
445
446 ALOGI("Correctly triggered cal file");
447 *cal = SUCCESS;
448 close(fd);
449 return;
450
451 fail_resp:
452 msg[pos++] = 0;
453 if (write(fd, msg, pos) < 0)
454 ALOGE("Failed to write to %s : %s", WCNSS_CTRL,
455 strerror(errno));
456
457 fail:
458 *cal = FAILED;
459 close(fd);
460 return;
461 }
462
setup_wlan_driver_ath_prop()463 void setup_wlan_driver_ath_prop()
464 {
465 property_set("wlan.driver.ath", WLAN_DRIVER_ATH_DEFAULT_VAL);
466 }
467
468 #ifdef WCNSS_QMI
check_modem_compatability(struct dev_info * mdm_detect_info)469 int check_modem_compatability(struct dev_info *mdm_detect_info)
470 {
471 char args[MODEM_BASEBAND_PROPERTY_SIZE] = {0};
472 int ret = 0;
473 /* Get the hardware property */
474 ret = property_get(MODEM_BASEBAND_PROPERTY, args, "");
475 if (ret > MODEM_BASEBAND_PROPERTY_SIZE) {
476 ALOGE("property [%s] has size [%d] that exceeds max [%d]",
477 MODEM_BASEBAND_PROPERTY, ret, MODEM_BASEBAND_PROPERTY_SIZE);
478 return 0;
479 }
480 /* This will check for the type of hardware, and if the
481 hardware type needs external modem, it will check if the
482 modem type is external*/
483 if(!strncmp(MODEM_BASEBAND_VALUE_APQ, args, 3)) {
484
485 for (ret = 0; ret < mdm_detect_info->num_modems; ret++) {
486 if (mdm_detect_info->mdm_list[ret].type == MDM_TYPE_EXTERNAL) {
487 ALOGE("Hardware supports external modem");
488 return 1;
489 }
490 }
491 ALOGE("Hardware does not support external modem");
492 return 0;
493 }
494 return 1;
495 }
496 #endif
497
main(int argc,char * argv[])498 int main(int argc, char *argv[])
499 {
500 int rc;
501 int fd_dev, ret_cal;
502 int nv_mac_addr = FAILED;
503 #ifdef WCNSS_QMI
504 struct dev_info mdm_detect_info;
505 int nom = 0;
506 #endif
507
508 setup_wlan_config_file();
509
510 #ifdef WCNSS_QMI
511 /* Call ESOC API to get the number of modems.
512 If the number of modems is not zero, only then proceed
513 with the eap_proxy intialization.*/
514
515 nom = get_system_info(&mdm_detect_info);
516
517 if (nom > 0)
518 ALOGE("Failed to get system info, ret %d", nom);
519
520 if (mdm_detect_info.num_modems == 0) {
521 ALOGE("wcnss_service: No Modem support for this target"
522 " number of modems is %d", mdm_detect_info.num_modems);
523 goto nomodem;
524 }
525
526 ALOGE("wcnss_service: num_modems = %d", mdm_detect_info.num_modems);
527
528 if(!check_modem_compatability(&mdm_detect_info)) {
529 ALOGE("wcnss_service: Target does not have external modem");
530 goto nomodem;
531 }
532
533 /* initialize the DMS client and request the wlan mac address */
534
535 if (SUCCESS == wcnss_init_qmi()) {
536
537 rc = wcnss_qmi_get_wlan_address(wlan_nv_mac_addr);
538
539 if (rc == SUCCESS) {
540 nv_mac_addr = SUCCESS;
541 ALOGE("WLAN MAC Addr:" MAC_ADDRESS_STR,
542 MAC_ADDR_ARRAY(wlan_nv_mac_addr));
543 } else
544 ALOGE("Failed to Get MAC addr from modem");
545
546 wcnss_qmi_deinit();
547 }
548 else
549 ALOGE("Failed to Initialize wcnss QMI Interface");
550
551 nomodem:
552 #endif
553 setup_wcnss_parameters(&ret_cal, nv_mac_addr);
554
555 fd_dev = open(WCNSS_DEVICE, O_RDWR);
556 if (fd_dev < 0) {
557 ALOGE("Failed to open wcnss device : %s",
558 strerror(errno));
559 return fd_dev;
560 }
561
562 if (ret_cal != FAILED) {
563 rc = wcnss_write_cal_data(fd_dev);
564 if (rc != SUCCESS)
565 ALOGE("No cal data is written to WCNSS %d", rc);
566 else
567 ALOGE("Cal data is successfully written to WCNSS");
568 }
569
570 setup_wlan_driver_ath_prop();
571
572 rc = wcnss_read_and_store_cal_data(fd_dev);
573 if (rc != SUCCESS)
574 ALOGE("Failed to read and save cal data %d", rc);
575 else
576 ALOGI("Calibration data was successfull written to %s",
577 WCNSS_CAL_FILE);
578
579 close(fd_dev);
580
581 return rc;
582 }
583