• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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