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 <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <fcntl.h>
33 #include <errno.h>
34 #include <dirent.h>
35 #include <ctype.h>
36 #include <grp.h>
37 #include <utime.h>
38 #include <sys/stat.h>
39 #include <sys/sendfile.h>
40 #define LOG_TAG "wcnss_service"
41 #include <cutils/log.h>
42 #include <cutils/properties.h>
43 #ifdef WCNSS_QMI
44 #include "wcnss_qmi_client.h"
45 #include "mdm_detect.h"
46 #endif
47 
48 #define SUCCESS 0
49 #define FAILED -1
50 #define BYTE_0  0
51 #define BYTE_1  8
52 #define BYTE_2  16
53 #define BYTE_3  24
54 #define UNUSED(x)	(void)(x)
55 
56 #define MAX_FILE_LENGTH    (1024)
57 #define WCNSS_MAX_CMD_LEN  (128)
58 
59 /* control messages to wcnss driver */
60 #define WCNSS_USR_CTRL_MSG_START    0x00000000
61 #define WCNSS_USR_SERIAL_NUM        (WCNSS_USR_CTRL_MSG_START + 1)
62 #define WCNSS_USR_HAS_CAL_DATA      (WCNSS_USR_CTRL_MSG_START + 2)
63 #define WCNSS_USR_WLAN_MAC_ADDR     (WCNSS_USR_CTRL_MSG_START + 3)
64 
65 
66 #define WCNSS_CAL_CHUNK (3*1024)
67 #define WCNSS_CAL_FILE  "/data/vendor/wifi/WCNSS_qcom_wlan_cal.bin"
68 #define WCNSS_FACT_FILE "/data/vendor/wifi/WCN_FACTORY"
69 #define WCNSS_DEVICE    "/dev/wcnss_wlan"
70 #define WCNSS_CTRL      "/dev/wcnss_ctrl"
71 #define WLAN_INI_FILE_DEST   "/data/vendor/wifi/WCNSS_qcom_cfg.ini"
72 #define WLAN_INI_FILE_SOURCE "/vendor/etc/wifi/WCNSS_qcom_cfg.ini"
73 #define WCNSS_HAS_CAL_DATA\
74 		"/sys/module/wcnsscore/parameters/has_calibrated_data"
75 #define WLAN_DRIVER_ATH_DEFAULT_VAL "0"
76 
77 #define ASCII_A		65
78 #define ASCII_a		97
79 #define ASCII_0		48
80 #define HEXA_A		10
81 #define HEX_BASE		16
82 
83 #ifdef WCNSS_QMI
84 #define WLAN_ADDR_SIZE   6
85 unsigned char wlan_nv_mac_addr[WLAN_ADDR_SIZE];
86 #define MAC_ADDR_ARRAY(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
87 #define MAC_ADDRESS_STR "%02x:%02x:%02x:%02x:%02x:%02x"
88 
89 /* As we Want to write in 00:0a:f5:11:22:33 format in sysfs file
90    so taking mac length as 12 char + 5 for ":" + NULL
91  */
92 #define WLAN_MAC_ADDR_STRING 18
93 #endif
94 
95 #define MAX_SOC_INFO_NAME_LEN (15)
96 #define MAX_DATA_NVBIN_PATH_LEN (64)
97 #define QRD_DYNAMIC_NV_PROP  "persist.sys.dynamic.nv"
98 #define QRD_HW_PLATFORM  "QRD"
99 #define QRD_PLATFORM_SUBTYPE_ID  0
100 #define PERSIST_NVFILE    "/persist/WCNSS_qcom_wlan_nv.bin"
101 #define DATA_NVFILE_DIR   "/data/misc/wifi/nvbin/"
102 #define SYSFS_SOCID_PATH1   "/sys/devices/soc0/soc_id"
103 #define SYSFS_SOCID_PATH2   "/sys/devices/system/soc/soc0/id"
104 #define SYSFS_HW_PLATFORM_PATH1  "/sys/devices/soc0/hw_platform"
105 #define SYSFS_HW_PLATFORM_PATH2   "/sys/devices/system/soc/soc0/hw_platform"
106 #define SYSFS_PLATFORM_SUBTYPE_PATH1   "/sys/devices/soc0/platform_subtype_id"
107 #define SYSFS_PLATFORM_SUBTYPE_PATH2    "/sys/devices/system/soc/soc0/platform_subtype_id"
108 #define SYSFS_PLATFORM_VERSION_PATH1  "/sys/devices/soc0/platform_version"
109 #define SYSFS_PLATFORM_VERSION_PATH2   "/sys/devices/system/soc/soc0/platform_version"
110 #define SOCINFO_HWVER_MAJOR(ver) (((ver) & 0x00ff0000) >> 16)
111 #define SOCINFO_HWVER_MINOR(ver) ((ver) & 0x000000ff)
112 #define GET_SOC_INFO(buf, soc_node_path1, soc_node_path2, info_got) \
113 		{  if (get_soc_info(buf, soc_node_path1, soc_node_path2) < 0) \
114 		    { \
115 		        ALOGE("get_soc_info failed!\n"); \
116 		        return FAILED; \
117 		    } \
118 		    info_got = atoi(buf); \
119 		}
120 
wcnss_write_cal_data(int fd_dev)121 int wcnss_write_cal_data(int fd_dev)
122 {
123 	int rcount = 0;
124 	int size = 0;
125 	int rc = 0;
126 	int wcount = 0;
127 	int fd_file;
128 	struct stat st;
129 
130 	char buf[WCNSS_CAL_CHUNK];
131 
132 	ALOGI("wcnss_write_cal_data trying to write cal");
133 
134 	rc = stat(WCNSS_CAL_FILE, &st);
135 	if (rc < 0) {
136 		ALOGE("Failed to stat cal file : %s",
137 				strerror(errno));
138 		goto exit;
139 	}
140 
141 	size = st.st_size;
142 
143 	fd_file = open(WCNSS_CAL_FILE, O_RDONLY);
144 	if (fd_file < 0) {
145 		ALOGE("cal file doesn't exist: %s",
146 				strerror(errno));
147 		rc = fd_file;
148 		goto exit;
149 	}
150 
151 	/* write the file size first, so that platform driver knows
152 	 * when it recieves the full data */
153 	wcount = write(fd_dev, (void *)&size, 4);
154 	if (wcount != 4) {
155 		ALOGE("Failed to write to wcnss device : %s",
156 				strerror(errno));
157 		rc = wcount;
158 		goto exit_close;
159 	}
160 
161 	do {
162 		rcount = read(fd_file, (void *)buf, sizeof(buf));
163 		if (rcount < 0) {
164 			ALOGE("Failed to read from cal file ; %s",
165 					strerror(errno));
166 			rc = rcount;
167 			goto exit_remove;
168 		}
169 
170 		if (!rcount)
171 			break;
172 
173 		wcount = write(fd_dev, buf, rcount);
174 		if (wcount < 0) {
175 			ALOGE("Failed to write to wcnss device : %s",
176 				strerror(errno));
177 			rc = wcount;
178 			goto exit_close;
179 		}
180 
181 	} while (rcount);
182 	close(fd_file);
183 
184 	return SUCCESS;
185 
186 exit_remove:
187 	close(fd_file);
188 	remove("WCNSS_CAL_FILE");
189 	return rc;
190 
191 exit_close:
192 	close(fd_file);
193 
194 exit:
195 	return rc;
196 }
197 
198 
wcnss_read_and_store_cal_data(int fd_dev)199 int wcnss_read_and_store_cal_data(int fd_dev)
200 {
201 	int rcount = 0;
202 	int wcount = 0;
203 	int fd_file = -1;
204 	int rc = 0;
205 
206 	char buf[WCNSS_CAL_CHUNK];
207 
208 	ALOGI("wcnss_read_and_store_cal_data trying to read cal");
209 
210 	do {
211 		/* wait on this read until data comes from fw */
212 		rcount = read(fd_dev, (void *)buf, sizeof(buf));
213 		if (rcount < 0) {
214 			ALOGE("Failed to read from wcnss device : %s",
215 					strerror(errno));
216 			rc = rcount;
217 			goto exit;
218 		}
219 
220 		/* truncate the file only if there is fw data, this read
221 		 * may never return if the fw decides that no more cal is
222 		 * required; and the data we have now is good enough.
223 		 */
224 		if (fd_file < 0) {
225 			fd_file = open(WCNSS_CAL_FILE, O_WRONLY
226 					| O_CREAT | O_TRUNC, 0664);
227 			if (fd_file < 0) {
228 				ALOGE("Failed to open cal file : %s",
229 						strerror(errno));
230 				rc = fd_file;
231 				goto exit;
232 			}
233 		}
234 
235 		if (!rcount)
236 			break;
237 
238 		wcount = write(fd_file, buf, rcount);
239 		if (wcount < 0) {
240 			ALOGE("Failed to write to cal file : %s",
241 				strerror(errno));
242 			rc = wcount;
243 			goto exit_remove;
244 		}
245 
246 	} while (rcount);
247 
248 	close(fd_file);
249 
250 	return SUCCESS;
251 
252 exit_remove:
253 	close(fd_file);
254 	remove(WCNSS_CAL_FILE);
255 
256 exit:
257 	return rc;
258 }
259 
260 
find_full_path(char * cur_dir,char * file_to_find,char * full_path)261 void find_full_path(char *cur_dir, char *file_to_find, char *full_path)
262 {
263 	DIR *dir;
264 	struct stat st;
265 	struct dirent *dr;
266 	char cwd[1024];
267 	int rc;
268 
269 	chdir(cur_dir);
270 
271 	dir = opendir(".");
272 
273 	if (dir != NULL) {
274 		while ((dr = readdir(dir))) {
275 
276 			rc = lstat(dr->d_name, &st);
277 			if (rc < 0) {
278 				ALOGE("lstat failed %s", strerror(errno));
279 				return;
280 			}
281 			if (S_ISDIR(st.st_mode)) {
282 				if ((strcmp(dr->d_name, ".")) &&
283 					(strcmp(dr->d_name, ".."))) {
284 				find_full_path(dr->d_name,
285 						file_to_find, full_path);
286 				}
287 			} else if (!strcmp(file_to_find, dr->d_name)) {
288 				getcwd(cwd, sizeof(cwd));
289 				snprintf(full_path, MAX_FILE_LENGTH, "%s/%s",
290 					cwd, file_to_find);
291 			}
292 		}
293 		closedir(dir);
294 	}
295 
296 	chdir("..");
297 }
298 
setup_wlan_config_file()299 void setup_wlan_config_file()
300 {
301 	int rfd;
302 	int wfd;
303 	struct stat st_dest, st_src;
304 	int rc_dest;
305 	int rc;
306 	struct group *grp;
307 	struct utimbuf new_time;
308 
309 	rc = stat(WLAN_INI_FILE_SOURCE, &st_src);
310 	if (rc != 0) {
311 		ALOGE("source file do not exist %s", WLAN_INI_FILE_SOURCE);
312 		return;
313 	}
314 
315 	rc_dest = stat(WLAN_INI_FILE_DEST, &st_dest);
316 	if (rc_dest == 0 && st_dest.st_size &&
317 			(st_dest.st_mtime > st_src.st_mtime)) {
318 		ALOGE("wlan ini file exists %s and is newer than %s",
319 				WLAN_INI_FILE_DEST, WLAN_INI_FILE_SOURCE);
320 		goto out_nocopy;
321 	}
322 
323 	rfd = open(WLAN_INI_FILE_SOURCE, O_RDONLY);
324 	if (rfd < 0) {
325 		ALOGE("Failed to open ini source file: %s", strerror(errno));
326 		return;
327 	}
328 
329 	wfd = open(WLAN_INI_FILE_DEST, O_WRONLY | O_CREAT | O_TRUNC, 0660);
330 	if (wfd < 0) {
331 		ALOGE("Failed to open ini dest file: %s", strerror(errno));
332 		close(rfd);
333 		return;
334 	}
335 
336 	rc = sendfile(wfd, rfd, 0, st_src.st_size);
337 	if (rc != st_src.st_size) {
338 		ALOGE("Failed to copy ini file: %s", strerror(errno));
339 		goto out;
340 	}
341 
342 	new_time.actime = st_src.st_atime;
343 	new_time.modtime = st_src.st_mtime;
344 
345 	rc = utime(WLAN_INI_FILE_DEST, &new_time);
346 	if (rc != 0)
347 		ALOGE("could not preserve the timestamp %s", strerror(errno));
348 
349 	grp = getgrnam("wifi");
350 	if (grp != NULL) {
351 		rc = chown(WLAN_INI_FILE_DEST, -1, grp->gr_gid);
352 		if (rc != 0)
353 			ALOGE("Failed change group of ini file %s", strerror(errno));
354 	} else {
355 			ALOGE("Failed to get group wifi %s", strerror(errno));
356 	}
357 
358 	property_set("vendor.wlan.driver.config", WLAN_INI_FILE_DEST);
359 
360 out:
361 	close(rfd);
362 	close(wfd);
363 	return;
364 
365 out_nocopy:
366 	property_set("vendor.wlan.driver.config", WLAN_INI_FILE_DEST);
367 	return;
368 }
convert_string_to_hex(char * string)369 unsigned int convert_string_to_hex(char* string)
370 {
371 	int idx;
372 	unsigned long int hex_num = 0;
373 	for(idx = 0; string[idx] != '\0'; idx++){
374 		if(isalpha(string[idx])) {
375 			if(string[idx] >='a' && string[idx] <='f') {
376 				hex_num = hex_num * HEX_BASE + ((int)string[idx]
377 					       - ASCII_a + HEXA_A);
378 			} else if ( string[idx] >='A' && string[idx] <='F') {
379 				hex_num = hex_num * HEX_BASE + ((int)string[idx]
380 						- ASCII_A + HEXA_A);
381 			} else
382 				hex_num = hex_num * HEX_BASE + (int)string[idx];
383 		} else {
384 			hex_num = hex_num * HEX_BASE + (string[idx]- ASCII_0);
385 		}
386 	}
387 	hex_num = hex_num & 0xFFFFFFFF;
388 	return hex_num;
389 }
390 
391 
392 #ifdef WCNSS_QMI
setup_wcnss_parameters(int * cal,int nv_mac_addr)393 void setup_wcnss_parameters(int *cal, int nv_mac_addr)
394 #else
395 void setup_wcnss_parameters(int *cal)
396 #endif
397 {
398 	char msg[WCNSS_MAX_CMD_LEN];
399 	char serial[PROPERTY_VALUE_MAX];
400 	int fd, rc, pos = 0;
401 	struct stat st;
402 	unsigned int serial_num = 0;
403 
404 	fd = open(WCNSS_CTRL, O_WRONLY);
405 	if (fd < 0) {
406 		ALOGE("Failed to open %s : %s", WCNSS_CTRL, strerror(errno));
407 		return;
408 	}
409 
410 	rc = property_get("ro.serialno", serial, "");
411 	if (rc) {
412 		serial_num = convert_string_to_hex(serial);
413 		ALOGE("Serial Number is  %x", serial_num);
414 
415 		msg[pos++] = WCNSS_USR_SERIAL_NUM >> BYTE_1;
416 		msg[pos++] = WCNSS_USR_SERIAL_NUM >> BYTE_0;
417 		msg[pos++] = serial_num >> BYTE_3;
418 		msg[pos++] = serial_num >> BYTE_2;
419 		msg[pos++] = serial_num >> BYTE_1;
420 		msg[pos++] = serial_num >> BYTE_0;
421 
422 		if (write(fd, msg, pos) < 0) {
423 			ALOGE("Failed to write to %s : %s", WCNSS_CTRL,
424 					strerror(errno));
425 			goto fail;
426 		}
427 	}
428 
429 #ifdef WCNSS_QMI
430 	if (SUCCESS == nv_mac_addr)
431 	{
432 		pos = 0;
433 		msg[pos++] = WCNSS_USR_WLAN_MAC_ADDR >> BYTE_1;
434 		msg[pos++] = WCNSS_USR_WLAN_MAC_ADDR >> BYTE_0;
435 		msg[pos++] = wlan_nv_mac_addr[0];
436 		msg[pos++] = wlan_nv_mac_addr[1];
437 		msg[pos++] = wlan_nv_mac_addr[2];
438 		msg[pos++] = wlan_nv_mac_addr[3];
439 		msg[pos++] = wlan_nv_mac_addr[4];
440 		msg[pos++] = wlan_nv_mac_addr[5];
441 
442 		ALOGI("WLAN MAC Addr:" MAC_ADDRESS_STR,
443 			MAC_ADDR_ARRAY(wlan_nv_mac_addr));
444 
445 		if (write(fd, msg, pos) < 0) {
446 			ALOGE("Failed to write to %s : %s", WCNSS_CTRL,
447 						strerror(errno));
448 			goto fail;
449 		}
450 	}
451 #endif
452 
453 	pos = 0;
454 	msg[pos++] = WCNSS_USR_HAS_CAL_DATA >> BYTE_1;
455 	msg[pos++] = WCNSS_USR_HAS_CAL_DATA >> BYTE_0;
456 
457 	rc = stat(WCNSS_FACT_FILE, &st);
458 	if (rc == 0) {
459 		ALOGE("Factory file found, deleting cal file");
460 		unlink(WCNSS_CAL_FILE);
461 		goto fail_resp;
462 	}
463 
464 	rc = stat(WCNSS_CAL_FILE, &st);
465 	if (rc != 0) {
466 		ALOGE("CAL file not found");
467 		goto fail_resp;
468 	}
469 
470 	/* has cal data */
471 	msg[pos++] = 1;
472 
473 	if (write(fd, msg, pos) < 0) {
474 		ALOGE("Failed to write to %s : %s", WCNSS_CTRL,
475 				strerror(errno));
476 		goto fail;
477 	}
478 
479 	ALOGI("Correctly triggered cal file");
480 	*cal = SUCCESS;
481 	close(fd);
482 	return;
483 
484 fail_resp:
485 	msg[pos++] = 0;
486 	if (write(fd, msg, pos) < 0)
487 		ALOGE("Failed to write to %s : %s", WCNSS_CTRL,
488 				strerror(errno));
489 
490 fail:
491 	*cal = FAILED;
492 	close(fd);
493 	return;
494 }
495 
setup_wlan_driver_ath_prop()496 void setup_wlan_driver_ath_prop()
497 {
498 	property_set("vendor.wlan.driver.ath", WLAN_DRIVER_ATH_DEFAULT_VAL);
499 }
500 
501 #ifdef WCNSS_QMI
check_modem_compatability(struct dev_info * mdm_detect_info)502 int check_modem_compatability(struct dev_info *mdm_detect_info)
503 {
504 	char args[MODEM_BASEBAND_PROPERTY_SIZE] = {0};
505 	int ret = 0;
506 	/* Get the hardware property */
507 	ret = property_get(MODEM_BASEBAND_PROPERTY, args, "");
508 	if (ret > MODEM_BASEBAND_PROPERTY_SIZE) {
509 		ALOGE("property [%s] has size [%d] that exceeds max [%d]",
510 				MODEM_BASEBAND_PROPERTY, ret, MODEM_BASEBAND_PROPERTY_SIZE);
511 		return 0;
512 	}
513 	/* This will check for the type of hardware, and if the
514 	   hardware type needs external modem, it will check if the
515 	   modem type is external*/
516 	if(!strncmp(MODEM_BASEBAND_VALUE_APQ, args, 3)) {
517 
518 		for (ret = 0; ret < mdm_detect_info->num_modems; ret++) {
519 			if (mdm_detect_info->mdm_list[ret].type == MDM_TYPE_EXTERNAL) {
520 				ALOGE("Hardware supports external modem");
521 				return 1;
522 			}
523 		}
524 		ALOGE("Hardware does not support external modem");
525 		return 0;
526 	}
527 	return 1;
528 }
529 #endif
530 
read_line_from_file(const char * path,char * buf,size_t count)531 static int read_line_from_file(const char *path, char *buf, size_t count)
532 {
533 	char * fgets_ret;
534 	FILE * fd;
535 	int rv;
536 
537 	fd = fopen(path, "r");
538 	if (fd == NULL)
539 	return -1;
540 
541 	fgets_ret = fgets(buf, (int)count, fd);
542 	if (NULL != fgets_ret) {
543 	    rv = (int)strlen(buf);
544 	} else {
545 	    rv = ferror(fd);
546 	}
547 
548 	fclose(fd);
549 
550 	return rv;
551 }
552 
get_soc_info(char * buf,char * soc_node_path1,char * soc_node_path2)553 static int get_soc_info(char *buf, char *soc_node_path1,
554 			char *soc_node_path2)
555 {
556 	int ret = 0;
557 
558 	ret = read_line_from_file(soc_node_path1, buf,
559 					MAX_SOC_INFO_NAME_LEN);
560 	if (ret < 0) {
561 		ret = read_line_from_file(soc_node_path2, buf,
562 					MAX_SOC_INFO_NAME_LEN);
563 		if (ret < 0) {
564 		    ALOGE("getting socinfo(%s, %d) failed.\n",
565 					soc_node_path1, ret);
566 		    return ret;
567 		}
568 	}
569 	if (ret && buf[ret - 1] == '\n')
570 		buf[ret - 1] = '\0';
571 
572 	return ret;
573 }
574 
get_data_nvfile_path(char * data_nvfile_path,struct stat * pdata_nvfile_stat)575 static int get_data_nvfile_path(char *data_nvfile_path,
576 	struct stat *pdata_nvfile_stat)
577 {
578 	char target_board_platform[PROP_VALUE_MAX] = {'\0'};
579 	char buf[MAX_SOC_INFO_NAME_LEN] = {'\0'};
580 	int  soc_id, platform_subtype_id, platform_version;
581 	int  major_hwver, minor_hwver;
582 	int  rc;
583 
584 	rc = property_get("ro.board.platform", target_board_platform, "");
585 	if (!rc)
586 	{
587 		ALOGE("get ro.board.platform fail, rc=%d(%s)\n",
588 				rc, strerror(errno));
589 		return FAILED;
590 	}
591 
592 	GET_SOC_INFO(buf, SYSFS_SOCID_PATH1, SYSFS_SOCID_PATH2, soc_id);
593 	GET_SOC_INFO(buf, SYSFS_PLATFORM_SUBTYPE_PATH1,
594 			SYSFS_PLATFORM_SUBTYPE_PATH2, platform_subtype_id);
595 	GET_SOC_INFO(buf, SYSFS_PLATFORM_VERSION_PATH1,
596 			SYSFS_PLATFORM_VERSION_PATH2, platform_version);
597 
598 	major_hwver = SOCINFO_HWVER_MAJOR(platform_version);
599 	minor_hwver = SOCINFO_HWVER_MINOR(platform_version);
600 
601 	snprintf(data_nvfile_path, MAX_DATA_NVBIN_PATH_LEN,
602 		"%s%s_%d_0x%02x_0x%02x_0x%02x_nv.bin", DATA_NVFILE_DIR,
603 		target_board_platform, soc_id, platform_subtype_id&0xff,
604 		major_hwver&0xff, minor_hwver&0xff);
605 	ALOGI("data_nvfile_path %s\n",
606 			data_nvfile_path);
607 
608 	if (stat(data_nvfile_path, pdata_nvfile_stat) != 0)
609 	{
610 		ALOGE("source file do not exist %s\n",
611 				data_nvfile_path);
612 		return FAILED;
613 	}
614 
615 	return SUCCESS;
616 }
617 
nvbin_sendfile(const char * dst,const char * src,struct stat * src_stat)618 static int nvbin_sendfile(const char *dst, const char *src,
619 	struct stat *src_stat)
620 {
621 	struct utimbuf new_time;
622 	int fp_src, fp_dst;
623 	int rc;
624 	if ((fp_src = open(src, O_RDONLY)) < 0)
625 	{
626 		ALOGE("open %s failed(%s).\n",
627 				src, strerror(errno));
628 		return FAILED;
629 	}
630 
631 	if ((fp_dst = open(dst, O_WRONLY |O_TRUNC)) < 0)
632 	{
633 		close(fp_src);
634 		ALOGE("open %s failed(%s).\n",
635 				dst, strerror(errno));
636 		return FAILED;
637 	}
638 
639 	if (sendfile(fp_dst, fp_src, 0, src_stat->st_size) == -1)
640 	{
641 		ALOGE("dynamic nv sendfile failed: (%s).\n",
642 				strerror(errno));
643 		rc = FAILED;
644 		goto exit;
645 	}
646 
647 	new_time.actime  = src_stat->st_atime;
648 	new_time.modtime = src_stat->st_mtime;
649 	if (utime(dst, &new_time) != 0)
650 	{
651 		ALOGE("could not preserve the timestamp %s",
652 				strerror(errno));
653 		rc = FAILED;
654 		goto exit;
655 	}
656 
657 	rc = SUCCESS;
658 exit:
659 	close(fp_dst);
660 	close(fp_src);
661 	return rc;
662 }
dynamic_nv_replace()663 void dynamic_nv_replace()
664 {
665 	char data_nvfile_path[MAX_DATA_NVBIN_PATH_LEN] = {'\0'};
666 	char property_nv_replaced_status [PROPERTY_VALUE_MAX] = { '\0' };
667 	char buf[MAX_SOC_INFO_NAME_LEN] = {'\0'};
668 	struct stat  data_nvfile_stat;
669 	int rc;
670 
671 	if (property_get(QRD_DYNAMIC_NV_PROP, property_nv_replaced_status, NULL)
672 		&& strcmp(property_nv_replaced_status, "done") == 0) {
673 		ALOGI("dynamic nv have been replaced. leave\n");
674 		return;
675 	}
676 
677 	rc = get_soc_info(buf, SYSFS_HW_PLATFORM_PATH1, SYSFS_HW_PLATFORM_PATH2);
678 	if (rc < 0)
679 	{
680 		ALOGE("get_soc_info(HW_PLATFORM) fail!\n");
681 		return;
682 	} else {
683 		if( 0 != strncmp(buf, QRD_HW_PLATFORM, MAX_SOC_INFO_NAME_LEN))
684 		{
685 			ALOGI("dynamic nv only for QRD platform, current platform:%s.\n",
686 					buf);
687 			return;
688 		}
689 	}
690 
691 	rc = get_data_nvfile_path(data_nvfile_path, &data_nvfile_stat);
692 	if (rc != SUCCESS)
693 	{
694 		ALOGE("Get source file path fail !\n");
695 		return;
696 	}
697 
698 	if (property_set(QRD_DYNAMIC_NV_PROP, "replacing") < 0)
699 	{
700 		ALOGE("set %s to replacing failed (%s).\n",
701 				QRD_DYNAMIC_NV_PROP, strerror(errno));
702 		return;
703 	}
704 
705 	rc = nvbin_sendfile(PERSIST_NVFILE, data_nvfile_path, &data_nvfile_stat);
706 	if ( rc != SUCCESS)
707 	{
708 		ALOGE("nvbin_sendfile failed.\n");
709 		return;
710 	}
711 
712 	if (property_set(QRD_DYNAMIC_NV_PROP, "done") < 0)
713 	{
714 		ALOGE("set %s to done failed(%s).\n",
715 				QRD_DYNAMIC_NV_PROP, strerror(errno));
716 		return;
717 	}
718 
719 	ALOGI("dynamic nv replace sucessfully!\n");
720 
721 }
722 
main(int argc,char * argv[])723 int main(int argc, char *argv[])
724 {
725 	UNUSED(argc), UNUSED(argv);
726 	int rc;
727 	int fd_dev, ret_cal;
728 #ifdef WCNSS_QMI
729 	int nv_mac_addr = FAILED;
730 	struct dev_info mdm_detect_info;
731 	int nom = 0;
732 #endif
733 
734 	setup_wlan_config_file();
735 
736 #ifdef WCNSS_QMI
737 	/* Call ESOC API to get the number of modems.
738 	   If the number of modems is not zero, only then proceed
739 	   with the eap_proxy intialization.*/
740 
741 	nom = get_system_info(&mdm_detect_info);
742 
743 	if (nom > 0)
744 		ALOGE("Failed to get system info, ret %d", nom);
745 
746 	if (mdm_detect_info.num_modems == 0) {
747 		ALOGE("wcnss_service: No Modem support for this target"
748 				" number of modems is %d", mdm_detect_info.num_modems);
749 		goto nomodem;
750 	}
751 
752 	ALOGE("wcnss_service: num_modems = %d", mdm_detect_info.num_modems);
753 
754 	if(!check_modem_compatability(&mdm_detect_info)) {
755 		ALOGE("wcnss_service: Target does not have external modem");
756 		goto nomodem;
757 	}
758 
759 	/* initialize the DMS client and request the wlan mac address */
760 
761 	if (SUCCESS == wcnss_init_qmi()) {
762 
763 		rc = wcnss_qmi_get_wlan_address(wlan_nv_mac_addr);
764 
765 		if (rc == SUCCESS) {
766 			nv_mac_addr = SUCCESS;
767 			ALOGE("WLAN MAC Addr:" MAC_ADDRESS_STR,
768 					MAC_ADDR_ARRAY(wlan_nv_mac_addr));
769 		} else
770 			ALOGE("Failed to Get MAC addr from modem");
771 
772 		wcnss_qmi_deinit();
773 	}
774 	else
775 		ALOGE("Failed to Initialize wcnss QMI Interface");
776 
777 nomodem:
778 #endif
779 
780 	dynamic_nv_replace();
781 
782 #ifdef WCNSS_QMI
783 	setup_wcnss_parameters(&ret_cal, nv_mac_addr);
784 #else
785 	setup_wcnss_parameters(&ret_cal);
786 #endif
787 
788 	fd_dev = open(WCNSS_DEVICE, O_RDWR);
789 	if (fd_dev < 0) {
790 		ALOGE("Failed to open wcnss device : %s",
791 				strerror(errno));
792 		return fd_dev;
793 	}
794 
795 	if (ret_cal != FAILED) {
796 		rc = wcnss_write_cal_data(fd_dev);
797 		if (rc != SUCCESS)
798 			ALOGE("No cal data is written to WCNSS %d", rc);
799 		else
800 			ALOGE("Cal data is successfully written to WCNSS");
801 	}
802 
803 	setup_wlan_driver_ath_prop();
804 
805 	rc = wcnss_read_and_store_cal_data(fd_dev);
806 	if (rc != SUCCESS)
807 		ALOGE("Failed to read and save cal data %d", rc);
808 	else
809 		ALOGI("Calibration data was successfull written to %s",
810 			WCNSS_CAL_FILE);
811 
812 	close(fd_dev);
813 
814 	return rc;
815 }
816