Home | History | Annotate | Download | only in wcnss-service
      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 
     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 
    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 
    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 
    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 }
    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 
    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 
    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
    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 
    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