Home | History | Annotate | Download | only in linux
      1 /*
      2  $License:
      3     Copyright (C) 2014 InvenSense Corporation, All Rights Reserved.
      4  $
      5  */
      6 
      7 #undef MPL_LOG_NDEBUG
      8 #define MPL_LOG_NDEBUG 0 /* Use 0 to turn on MPL_LOGV output */
      9 #undef MPL_LOG_TAG
     10 #define MPL_LOG_TAG "MLLITE"
     11 
     12 #include <string.h>
     13 #include <stdio.h>
     14 #include "ml_sysfs_helper.h"
     15 #include <dirent.h>
     16 #include <ctype.h>
     17 #include "log.h"
     18 
     19 #define MPU_SYSFS_ABS_PATH "/sys/class/invensense/mpu"
     20 
     21 enum PROC_SYSFS_CMD {
     22 	CMD_GET_SYSFS_PATH,
     23 	CMD_GET_DMP_PATH,
     24 	CMD_GET_CHIP_NAME,
     25 	CMD_GET_SYSFS_KEY,
     26 	CMD_GET_TRIGGER_PATH,
     27 	CMD_GET_DEVICE_NODE
     28 };
     29 static char sysfs_path[100];
     30 static char *chip_name[] = {
     31     "ITG3500",
     32     "MPU6050",
     33     "MPU9150",
     34     "MPU3050",
     35     "MPU6500",
     36     "MPU9250",
     37     "MPU6XXX",
     38     "MPU9350",
     39     "MPU6515",
     40     "MPU6880",
     41 };
     42 static int chip_ind;
     43 static int initialized =0;
     44 static int status = 0;
     45 static int iio_initialized = 0;
     46 static int iio_dev_num = 0;
     47 
     48 #define IIO_MAX_NAME_LENGTH 30
     49 
     50 #define FORMAT_SCAN_ELEMENTS_DIR "%s/scan_elements"
     51 #define FORMAT_TYPE_FILE "%s_type"
     52 
     53 #define CHIP_NUM ARRAY_SIZE(chip_name)
     54 
     55 static const char *iio_dir = "/sys/bus/iio/devices/";
     56 
     57 /**
     58  * find_type_by_name() - function to match top level types by name
     59  * @name: top level type instance name
     60  * @type: the type of top level instance being sort
     61  *
     62  * Typical types this is used for are device and trigger.
     63  **/
     64 int find_type_by_name(const char *name, const char *type)
     65 {
     66 	const struct dirent *ent;
     67 	int number, numstrlen;
     68 
     69 	FILE *nameFile;
     70 	DIR *dp;
     71 	char thisname[IIO_MAX_NAME_LENGTH];
     72 	char *filename;
     73 
     74 	dp = opendir(iio_dir);
     75 	if (dp == NULL) {
     76 		MPL_LOGE("No industrialio devices available");
     77 		return -ENODEV;
     78 	}
     79 
     80 	while (ent = readdir(dp), ent != NULL) {
     81 		if (strcmp(ent->d_name, ".") != 0 &&
     82 			strcmp(ent->d_name, "..") != 0 &&
     83 			strlen(ent->d_name) > strlen(type) &&
     84 			strncmp(ent->d_name, type, strlen(type)) == 0) {
     85 			numstrlen = sscanf(ent->d_name + strlen(type),
     86 					   "%d",
     87 					   &number);
     88 			/* verify the next character is not a colon */
     89 			if (strncmp(ent->d_name + strlen(type) + numstrlen,
     90 					":",
     91 					1) != 0) {
     92 				filename = malloc(strlen(iio_dir)
     93 						+ strlen(type)
     94 						+ numstrlen
     95 						+ 6);
     96 				if (filename == NULL)
     97 					return -ENOMEM;
     98 				sprintf(filename, "%s%s%d/name",
     99 					iio_dir,
    100 					type,
    101 					number);
    102 				nameFile = fopen(filename, "r");
    103 				if (!nameFile)
    104 					continue;
    105 				free(filename);
    106 				fscanf(nameFile, "%s", thisname);
    107 				if (strcmp(name, thisname) == 0)
    108 					return number;
    109 				fclose(nameFile);
    110 			}
    111 		}
    112 	}
    113 	return -ENODEV;
    114 }
    115 
    116 /* mode 0: search for which chip in the system and fill sysfs path
    117    mode 1: return event number
    118  */
    119 static int parsing_proc_input(int mode, char *name){
    120 	const char input[] = "/proc/bus/input/devices";
    121 	char line[4096], d;
    122 	char tmp[100];
    123 	FILE *fp;
    124 	int i, j, result, find_flag;
    125 	int event_number = -1;
    126 	int input_number = -1;
    127 
    128 	if(NULL == (fp = fopen(input, "rt")) ){
    129 		return -1;
    130 	}
    131 	result = 1;
    132 	find_flag = 0;
    133 	while(result != 0 && find_flag < 2){
    134 		i = 0;
    135 		d = 0;
    136 		memset(line, 0, 100);
    137 		while(d != '\n'){
    138 			result = fread(&d, 1, 1, fp);
    139 			if(result == 0){
    140 				line[0] = 0;
    141 				break;
    142 			}
    143 			sprintf(&line[i], "%c", d);
    144 			i ++;
    145 		}
    146 		if(line[0] == 'N'){
    147 			i = 1;
    148 			while(line[i] != '"'){
    149 				i++;
    150 			}
    151 			i++;
    152 			j = 0;
    153 			find_flag = 0;
    154 			if (mode == 0){
    155 				while(j < CHIP_NUM){
    156 					if(!memcmp(&line[i], chip_name[j], strlen(chip_name[j]))){
    157 						find_flag = 1;
    158 						chip_ind = j;
    159 					}
    160 					j++;
    161 				}
    162 			} else if (mode  != 0){
    163 				if(!memcmp(&line[i], name, strlen(name))){
    164 					find_flag = 1;
    165 				}
    166 			}
    167 		}
    168 		if(find_flag){
    169 			if(mode == 0){
    170 				if(line[0] == 'S'){
    171 					memset(tmp, 0, 100);
    172 					i =1;
    173 					while(line[i] != '=') i++;
    174 					i++;
    175 					j = 0;
    176 					while(line[i] != '\n'){
    177 						tmp[j] = line[i];
    178 						i ++; j++;
    179 					}
    180 					sprintf(sysfs_path, "%s%s", "/sys", tmp);
    181 					find_flag++;
    182 				}
    183 			} else if(mode == 1){
    184 				if(line[0] == 'H') {
    185 					i = 2;
    186 					while(line[i] != '=') i++;
    187 					while(line[i] != 't') i++;
    188 					i++;
    189 					event_number = 0;
    190 					while(line[i] != '\n'){
    191 						if(line[i] >= '0' && line[i] <= '9')
    192 							event_number = event_number*10 + line[i]-0x30;
    193 						i ++;
    194 					}
    195 					find_flag ++;
    196 				}
    197 			} else if (mode == 2) {
    198 				if(line[0] == 'S'){
    199 					memset(tmp, 0, 100);
    200 					i =1;
    201 					while(line[i] != '=') i++;
    202 					i++;
    203 					j = 0;
    204 					while(line[i] != '\n'){
    205 						tmp[j] = line[i];
    206 						i ++; j++;
    207 					}
    208 					input_number = 0;
    209 					if(tmp[j-2] >= '0' && tmp[j-2] <= '9')
    210 						input_number += (tmp[j-2]-0x30)*10;
    211 					if(tmp[j-1] >= '0' && tmp[j-1] <= '9')
    212 						input_number += (tmp[j-1]-0x30);
    213 					find_flag++;
    214 				}
    215 			}
    216 		}
    217 	}
    218 	fclose(fp);
    219 	if(find_flag == 0){
    220 		return -1;
    221 	}
    222 	if(0 == mode)
    223 		status = 1;
    224 	if (mode == 1)
    225 		return event_number;
    226 	if (mode == 2)
    227 		return input_number;
    228 	return 0;
    229 
    230 }
    231 static void init_iio() {
    232 	int i, j;
    233 	char iio_chip[10];
    234 	int dev_num;
    235 	for(j=0; j< CHIP_NUM; j++) {
    236 		for (i=0; i<strlen(chip_name[j]); i++) {
    237 			iio_chip[i] = tolower(chip_name[j][i]);
    238 		}
    239 		iio_chip[strlen(chip_name[j])] = '\0';
    240 		dev_num = find_type_by_name(iio_chip, "iio:device");
    241 		if(dev_num >= 0) {
    242 			iio_initialized = 1;
    243 			iio_dev_num = dev_num;
    244 			chip_ind = j;
    245 		}
    246 	}
    247 }
    248 
    249 static int process_sysfs_request(enum PROC_SYSFS_CMD cmd, char *data)
    250 {
    251 	char key_path[100];
    252 	FILE *fp;
    253 	int i, result;
    254 	if(initialized == 0){
    255 		parsing_proc_input(0, NULL);
    256 		initialized = 1;
    257 	}
    258 	if(initialized && status == 0) {
    259 		init_iio();
    260 		if (iio_initialized == 0)
    261 			return -1;
    262 	}
    263 
    264 	memset(key_path, 0, 100);
    265 	switch(cmd){
    266 	case CMD_GET_SYSFS_PATH:
    267 		if (iio_initialized == 1)
    268 			sprintf(data, "/sys/bus/iio/devices/iio:device%d", iio_dev_num);
    269 		else
    270 			sprintf(data, "%s%s", sysfs_path, "/device/invensense/mpu");
    271 		break;
    272 	case CMD_GET_DMP_PATH:
    273 		if (iio_initialized == 1)
    274 			sprintf(data, "/sys/bus/iio/devices/iio:device%d/dmp_firmware", iio_dev_num);
    275 		else
    276 			sprintf(data, "%s%s", sysfs_path, "/device/invensense/mpu/dmp_firmware");
    277 		break;
    278 	case CMD_GET_CHIP_NAME:
    279 		sprintf(data, "%s", chip_name[chip_ind]);
    280 		break;
    281 	case CMD_GET_TRIGGER_PATH:
    282 		sprintf(data, "/sys/bus/iio/devices/trigger%d", iio_dev_num);
    283 		break;
    284 	case CMD_GET_DEVICE_NODE:
    285 		sprintf(data, "/dev/iio:device%d", iio_dev_num);
    286 		break;
    287 	case CMD_GET_SYSFS_KEY:
    288 		memset(key_path, 0, 100);
    289 		if (iio_initialized == 1)
    290 			sprintf(key_path, "/sys/bus/iio/devices/iio:device%d/key", iio_dev_num);
    291 		else
    292 			sprintf(key_path, "%s%s", sysfs_path, "/device/invensense/mpu/key");
    293 
    294 		if((fp = fopen(key_path, "rt")) == NULL)
    295 			return -1;
    296 		for(i=0;i<16;i++){
    297 			fscanf(fp, "%02x", &result);
    298 			data[i] = (char)result;
    299 		}
    300 
    301 		fclose(fp);
    302 		break;
    303 	default:
    304 		break;
    305 	}
    306 	return 0;
    307 }
    308 
    309 int find_name_by_sensor_type(const char *sensor_type, const char *type, char *sensor_name)
    310 {
    311     const struct dirent *ent;
    312     int number, numstrlen;
    313 
    314     FILE *nameFile;
    315     DIR *dp;
    316     char *filename;
    317 
    318     dp = opendir(iio_dir);
    319     if (dp == NULL) {
    320         MPL_LOGE("No industrialio devices available");
    321         return -ENODEV;
    322     }
    323 
    324     while (ent = readdir(dp), ent != NULL) {
    325         if (strcmp(ent->d_name, ".") != 0 &&
    326             strcmp(ent->d_name, "..") != 0 &&
    327             strlen(ent->d_name) > strlen(type) &&
    328             strncmp(ent->d_name, type, strlen(type)) == 0) {
    329             numstrlen = sscanf(ent->d_name + strlen(type),
    330                        "%d",
    331                        &number);
    332             /* verify the next character is not a colon */
    333             if (strncmp(ent->d_name + strlen(type) + numstrlen,
    334                     ":",
    335                     1) != 0) {
    336                 filename = malloc(strlen(iio_dir)
    337                         + strlen(type)
    338                         + numstrlen
    339                         + 6
    340                         + strlen(sensor_type));
    341                 if (filename == NULL)
    342                     return -ENOMEM;
    343                 sprintf(filename, "%s%s%d/%s",
    344                     iio_dir,
    345                     type,
    346                     number,
    347                     sensor_type);
    348                 nameFile = fopen(filename, "r");
    349                 MPL_LOGI("sensor type path: %s\n", filename);
    350                 free(filename);
    351                 //fscanf(nameFile, "%s", thisname);
    352                 //if (strcmp(name, thisname) == 0) {
    353                 if(nameFile == NULL) {
    354                     MPL_LOGI("keeps searching");
    355                     continue;
    356                 } else{
    357                     MPL_LOGI("found directory");
    358                 }
    359                 filename = malloc(strlen(iio_dir)
    360                         + strlen(type)
    361                         + numstrlen
    362                         + 6);
    363                 sprintf(filename, "%s%s%d/name",
    364                     iio_dir,
    365                     type,
    366                     number);
    367                     nameFile = fopen(filename, "r");
    368                     MPL_LOGI("name path: %s\n", filename);
    369                     free(filename);
    370                     if (!nameFile)
    371                         continue;
    372                     fscanf(nameFile, "%s", sensor_name);
    373                     MPL_LOGI("name found: %s now test for mpuxxxx", sensor_name);
    374                     if( !strncmp("mpu",sensor_name, 3) ) {
    375                         char secondaryFileName[200];
    376                     sprintf(secondaryFileName, "%s%s%d/secondary_name",
    377                         iio_dir,
    378                         type,
    379                         number);
    380                         nameFile = fopen(secondaryFileName, "r");
    381                         MPL_LOGI("name path: %s\n", secondaryFileName);
    382                         if(!nameFile)
    383                             continue;
    384                         fscanf(nameFile, "%s", sensor_name);
    385                         MPL_LOGI("secondary name found: %s\n", sensor_name);
    386                     }
    387                     else {
    388                         fscanf(nameFile, "%s", sensor_name);
    389                         MPL_LOGI("name found: %s\n", sensor_name);
    390                     }
    391                     return 0;
    392                 //}
    393                 fclose(nameFile);
    394             }
    395         }
    396     }
    397     return -ENODEV;
    398 }
    399 
    400 /**
    401  *  @brief  return sysfs key. if the key is not available
    402  *          return false. So the return value must be checked
    403  *          to make sure the path is valid.
    404  *  @unsigned char *name: This should be array big enough to hold the key
    405  *           It should be zeroed before calling this function.
    406  *           Or it could have unpredicable result.
    407  */
    408 inv_error_t inv_get_sysfs_key(unsigned char *key)
    409 {
    410 	if (process_sysfs_request(CMD_GET_SYSFS_KEY, (char*)key) < 0)
    411 		return INV_ERROR_NOT_OPENED;
    412 	else
    413 		return INV_SUCCESS;
    414 }
    415 
    416 /**
    417  *  @brief  return the sysfs path. If the path is not
    418  *          found yet. return false. So the return value must be checked
    419  *          to make sure the path is valid.
    420  *  @unsigned char *name: This should be array big enough to hold the sysfs
    421  *           path. It should be zeroed before calling this function.
    422  *           Or it could have unpredicable result.
    423  */
    424 inv_error_t inv_get_sysfs_path(char *name)
    425 {
    426 	if (process_sysfs_request(CMD_GET_SYSFS_PATH, name) < 0)
    427 		return INV_ERROR_NOT_OPENED;
    428 	else
    429 		return INV_SUCCESS;
    430 }
    431 
    432 inv_error_t inv_get_sysfs_abs_path(char *name)
    433 {
    434     strcpy(name, MPU_SYSFS_ABS_PATH);
    435     return INV_SUCCESS;
    436 }
    437 
    438 /**
    439  *  @brief  return the dmp file path. If the path is not
    440  *          found yet. return false. So the return value must be checked
    441  *          to make sure the path is valid.
    442  *  @unsigned char *name: This should be array big enough to hold the dmp file
    443  *           path. It should be zeroed before calling this function.
    444  *           Or it could have unpredicable result.
    445  */
    446 inv_error_t inv_get_dmpfile(char *name)
    447 {
    448    	if (process_sysfs_request(CMD_GET_DMP_PATH, name) < 0)
    449 		return INV_ERROR_NOT_OPENED;
    450 	else
    451 		return INV_SUCCESS;
    452 }
    453 /**
    454  *  @brief  return the chip name. If the chip is not
    455  *          found yet. return false. So the return value must be checked
    456  *          to make sure the path is valid.
    457  *  @unsigned char *name: This should be array big enough to hold the chip name
    458  *           path(8 bytes). It should be zeroed before calling this function.
    459  *           Or it could have unpredicable result.
    460  */
    461 inv_error_t inv_get_chip_name(char *name)
    462 {
    463    	if (process_sysfs_request(CMD_GET_CHIP_NAME, name) < 0)
    464 		return INV_ERROR_NOT_OPENED;
    465 	else
    466 		return INV_SUCCESS;
    467 }
    468 /**
    469  *  @brief  return event handler number. If the handler number is not found
    470  *          return false. the return value must be checked
    471  *          to make sure the path is valid.
    472  *  @unsigned char *name: This should be array big enough to hold the chip name
    473  *           path(8 bytes). It should be zeroed before calling this function.
    474  *           Or it could have unpredicable result.
    475  *  @int *num: event number store
    476  */
    477 inv_error_t  inv_get_handler_number(const char *name, int *num)
    478 {
    479 	initialized = 0;
    480 	if ((*num = parsing_proc_input(1, (char *)name)) < 0)
    481 		return INV_ERROR_NOT_OPENED;
    482 	else
    483 		return INV_SUCCESS;
    484 }
    485 
    486 /**
    487  *  @brief  return input number. If the handler number is not found
    488  *          return false. the return value must be checked
    489  *          to make sure the path is valid.
    490  *  @unsigned char *name: This should be array big enough to hold the chip name
    491  *           path(8 bytes). It should be zeroed before calling this function.
    492  *           Or it could have unpredicable result.
    493  *  @int *num: input number store
    494  */
    495 inv_error_t  inv_get_input_number(const char *name, int *num)
    496 {
    497 	initialized = 0;
    498 	if ((*num = parsing_proc_input(2, (char *)name)) < 0)
    499 		return INV_ERROR_NOT_OPENED;
    500 	else {
    501 		return INV_SUCCESS;
    502 	}
    503 }
    504 
    505 /**
    506  *  @brief  return iio trigger name. If iio is not initialized, return false.
    507  *          So the return must be checked to make sure the numeber is valid.
    508  *  @unsigned char *name: This should be array big enough to hold the trigger
    509  *           name. It should be zeroed before calling this function.
    510  *           Or it could have unpredicable result.
    511  */
    512 inv_error_t inv_get_iio_trigger_path(const char *name)
    513 {
    514 	if (process_sysfs_request(CMD_GET_TRIGGER_PATH, (char *)name) < 0)
    515 		return INV_ERROR_NOT_OPENED;
    516 	else
    517 		return INV_SUCCESS;
    518 }
    519 
    520 /**
    521  *  @brief  return iio device node. If iio is not initialized, return false.
    522  *          So the return must be checked to make sure the numeber is valid.
    523  *  @unsigned char *name: This should be array big enough to hold the device
    524  *           node. It should be zeroed before calling this function.
    525  *           Or it could have unpredicable result.
    526  */
    527 inv_error_t inv_get_iio_device_node(const char *name)
    528 {
    529 	if (process_sysfs_request(CMD_GET_DEVICE_NODE, (char *)name) < 0)
    530 		return INV_ERROR_NOT_OPENED;
    531 	else
    532 		return INV_SUCCESS;
    533 }
    534