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 #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 
    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
    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 
    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