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