| #include <string.h> |
| #include <stdio.h> |
| #include "ml_sysfs_helper.h" |
| #include <dirent.h> |
| #include <ctype.h> |
| #define MPU_SYSFS_ABS_PATH "/sys/class/invensense/mpu" |
| |
| enum PROC_SYSFS_CMD { |
| CMD_GET_SYSFS_PATH, |
| CMD_GET_DMP_PATH, |
| CMD_GET_CHIP_NAME, |
| CMD_GET_SYSFS_KEY, |
| CMD_GET_TRIGGER_PATH, |
| CMD_GET_DEVICE_NODE |
| }; |
| static char sysfs_path[100]; |
| static char *chip_name[] = { |
| "ITG3500", |
| "MPU6050", |
| "MPU9150", |
| "MPU3050", |
| "MPU6500" |
| }; |
| static int chip_ind; |
| static int initialized =0; |
| static int status = 0; |
| static int iio_initialized = 0; |
| static int iio_dev_num = 0; |
| |
| #define IIO_MAX_NAME_LENGTH 30 |
| |
| #define FORMAT_SCAN_ELEMENTS_DIR "%s/scan_elements" |
| #define FORMAT_TYPE_FILE "%s_type" |
| |
| #define CHIP_NUM ARRAY_SIZE(chip_name) |
| |
| static const char *iio_dir = "/sys/bus/iio/devices/"; |
| |
| /** |
| * find_type_by_name() - function to match top level types by name |
| * @name: top level type instance name |
| * @type: the type of top level instance being sort |
| * |
| * Typical types this is used for are device and trigger. |
| **/ |
| int find_type_by_name(const char *name, const char *type) |
| { |
| const struct dirent *ent; |
| int number, numstrlen; |
| |
| FILE *nameFile; |
| DIR *dp; |
| char thisname[IIO_MAX_NAME_LENGTH]; |
| char *filename; |
| |
| dp = opendir(iio_dir); |
| if (dp == NULL) { |
| printf("No industrialio devices available"); |
| return -ENODEV; |
| } |
| |
| while (ent = readdir(dp), ent != NULL) { |
| if (strcmp(ent->d_name, ".") != 0 && |
| strcmp(ent->d_name, "..") != 0 && |
| strlen(ent->d_name) > strlen(type) && |
| strncmp(ent->d_name, type, strlen(type)) == 0) { |
| numstrlen = sscanf(ent->d_name + strlen(type), |
| "%d", |
| &number); |
| /* verify the next character is not a colon */ |
| if (strncmp(ent->d_name + strlen(type) + numstrlen, |
| ":", |
| 1) != 0) { |
| filename = malloc(strlen(iio_dir) |
| + strlen(type) |
| + numstrlen |
| + 6); |
| if (filename == NULL) |
| return -ENOMEM; |
| sprintf(filename, "%s%s%d/name", |
| iio_dir, |
| type, |
| number); |
| nameFile = fopen(filename, "r"); |
| if (!nameFile) |
| continue; |
| free(filename); |
| fscanf(nameFile, "%s", thisname); |
| if (strcmp(name, thisname) == 0) |
| return number; |
| fclose(nameFile); |
| } |
| } |
| } |
| return -ENODEV; |
| } |
| |
| /* mode 0: search for which chip in the system and fill sysfs path |
| mode 1: return event number |
| */ |
| static int parsing_proc_input(int mode, char *name){ |
| const char input[] = "/proc/bus/input/devices"; |
| char line[4096], d; |
| char tmp[100]; |
| FILE *fp; |
| int i, j, result, find_flag; |
| int event_number = -1; |
| int input_number = -1; |
| |
| if(NULL == (fp = fopen(input, "rt")) ){ |
| return -1; |
| } |
| result = 1; |
| find_flag = 0; |
| while(result != 0 && find_flag < 2){ |
| i = 0; |
| d = 0; |
| memset(line, 0, 100); |
| while(d != '\n'){ |
| result = fread(&d, 1, 1, fp); |
| if(result == 0){ |
| line[0] = 0; |
| break; |
| } |
| sprintf(&line[i], "%c", d); |
| i ++; |
| } |
| if(line[0] == 'N'){ |
| i = 1; |
| while(line[i] != '"'){ |
| i++; |
| } |
| i++; |
| j = 0; |
| find_flag = 0; |
| if (mode == 0){ |
| while(j < CHIP_NUM){ |
| if(!memcmp(&line[i], chip_name[j], strlen(chip_name[j]))){ |
| find_flag = 1; |
| chip_ind = j; |
| } |
| j++; |
| } |
| } else if (mode != 0){ |
| if(!memcmp(&line[i], name, strlen(name))){ |
| find_flag = 1; |
| } |
| } |
| } |
| if(find_flag){ |
| if(mode == 0){ |
| if(line[0] == 'S'){ |
| memset(tmp, 0, 100); |
| i =1; |
| while(line[i] != '=') i++; |
| i++; |
| j = 0; |
| while(line[i] != '\n'){ |
| tmp[j] = line[i]; |
| i ++; j++; |
| } |
| sprintf(sysfs_path, "%s%s", "/sys", tmp); |
| find_flag++; |
| } |
| } else if(mode == 1){ |
| if(line[0] == 'H') { |
| i = 2; |
| while(line[i] != '=') i++; |
| while(line[i] != 't') i++; |
| i++; |
| event_number = 0; |
| while(line[i] != '\n'){ |
| if(line[i] >= '0' && line[i] <= '9') |
| event_number = event_number*10 + line[i]-0x30; |
| i ++; |
| } |
| find_flag ++; |
| } |
| } else if (mode == 2) { |
| if(line[0] == 'S'){ |
| memset(tmp, 0, 100); |
| i =1; |
| while(line[i] != '=') i++; |
| i++; |
| j = 0; |
| while(line[i] != '\n'){ |
| tmp[j] = line[i]; |
| i ++; j++; |
| } |
| input_number = 0; |
| if(tmp[j-2] >= '0' && tmp[j-2] <= '9') |
| input_number += (tmp[j-2]-0x30)*10; |
| if(tmp[j-1] >= '0' && tmp[j-1] <= '9') |
| input_number += (tmp[j-1]-0x30); |
| find_flag++; |
| } |
| } |
| } |
| } |
| fclose(fp); |
| if(find_flag == 0){ |
| return -1; |
| } |
| if(0 == mode) |
| status = 1; |
| if (mode == 1) |
| return event_number; |
| if (mode == 2) |
| return input_number; |
| return 0; |
| |
| } |
| static void init_iio() { |
| int i, j; |
| char iio_chip[10]; |
| int dev_num; |
| for(j=0; j< CHIP_NUM; j++) { |
| for (i=0; i<strlen(chip_name[j]); i++) { |
| iio_chip[i] = tolower(chip_name[j][i]); |
| } |
| iio_chip[strlen(chip_name[0])] = '\0'; |
| dev_num = find_type_by_name(iio_chip, "iio:device"); |
| if(dev_num >= 0) { |
| iio_initialized = 1; |
| iio_dev_num = dev_num; |
| chip_ind = j; |
| } |
| } |
| } |
| |
| static int process_sysfs_request(enum PROC_SYSFS_CMD cmd, char *data) |
| { |
| char key_path[100]; |
| FILE *fp; |
| int i, result; |
| if(initialized == 0){ |
| parsing_proc_input(0, NULL); |
| initialized = 1; |
| } |
| if(initialized && status == 0) { |
| init_iio(); |
| if (iio_initialized == 0) |
| return -1; |
| } |
| |
| memset(key_path, 0, 100); |
| switch(cmd){ |
| case CMD_GET_SYSFS_PATH: |
| if (iio_initialized == 1) |
| sprintf(data, "/sys/bus/iio/devices/iio:device%d", iio_dev_num); |
| else |
| sprintf(data, "%s%s", sysfs_path, "/device/invensense/mpu"); |
| break; |
| case CMD_GET_DMP_PATH: |
| if (iio_initialized == 1) |
| sprintf(data, "/sys/bus/iio/devices/iio:device%d/dmp_firmware", iio_dev_num); |
| else |
| sprintf(data, "%s%s", sysfs_path, "/device/invensense/mpu/dmp_firmware"); |
| break; |
| case CMD_GET_CHIP_NAME: |
| sprintf(data, "%s", chip_name[chip_ind]); |
| break; |
| case CMD_GET_TRIGGER_PATH: |
| sprintf(data, "/sys/bus/iio/devices/trigger%d", iio_dev_num); |
| break; |
| case CMD_GET_DEVICE_NODE: |
| sprintf(data, "/dev/iio:device%d", iio_dev_num); |
| break; |
| case CMD_GET_SYSFS_KEY: |
| memset(key_path, 0, 100); |
| if (iio_initialized == 1) |
| sprintf(key_path, "/sys/bus/iio/devices/iio:device%d/key", iio_dev_num); |
| else |
| sprintf(key_path, "%s%s", sysfs_path, "/device/invensense/mpu/key"); |
| |
| if((fp = fopen(key_path, "rt")) == NULL) |
| return -1; |
| for(i=0;i<16;i++){ |
| fscanf(fp, "%02x", &result); |
| data[i] = (char)result; |
| } |
| |
| fclose(fp); |
| break; |
| default: |
| break; |
| } |
| return 0; |
| } |
| /** |
| * @brief return sysfs key. if the key is not available |
| * return false. So the return value must be checked |
| * to make sure the path is valid. |
| * @unsigned char *name: This should be array big enough to hold the key |
| * It should be zeroed before calling this function. |
| * Or it could have unpredicable result. |
| */ |
| inv_error_t inv_get_sysfs_key(unsigned char *key) |
| { |
| if (process_sysfs_request(CMD_GET_SYSFS_KEY, (char*)key) < 0) |
| return INV_ERROR_NOT_OPENED; |
| else |
| return INV_SUCCESS; |
| } |
| |
| /** |
| * @brief return the sysfs path. If the path is not |
| * found yet. return false. So the return value must be checked |
| * to make sure the path is valid. |
| * @unsigned char *name: This should be array big enough to hold the sysfs |
| * path. It should be zeroed before calling this function. |
| * Or it could have unpredicable result. |
| */ |
| inv_error_t inv_get_sysfs_path(char *name) |
| { |
| if (process_sysfs_request(CMD_GET_SYSFS_PATH, name) < 0) |
| return INV_ERROR_NOT_OPENED; |
| else |
| return INV_SUCCESS; |
| } |
| |
| inv_error_t inv_get_sysfs_abs_path(char *name) |
| { |
| strcpy(name, MPU_SYSFS_ABS_PATH); |
| return INV_SUCCESS; |
| } |
| |
| /** |
| * @brief return the dmp file path. If the path is not |
| * found yet. return false. So the return value must be checked |
| * to make sure the path is valid. |
| * @unsigned char *name: This should be array big enough to hold the dmp file |
| * path. It should be zeroed before calling this function. |
| * Or it could have unpredicable result. |
| */ |
| inv_error_t inv_get_dmpfile(char *name) |
| { |
| if (process_sysfs_request(CMD_GET_DMP_PATH, name) < 0) |
| return INV_ERROR_NOT_OPENED; |
| else |
| return INV_SUCCESS; |
| } |
| /** |
| * @brief return the chip name. If the chip is not |
| * found yet. return false. So the return value must be checked |
| * to make sure the path is valid. |
| * @unsigned char *name: This should be array big enough to hold the chip name |
| * path(8 bytes). It should be zeroed before calling this function. |
| * Or it could have unpredicable result. |
| */ |
| inv_error_t inv_get_chip_name(char *name) |
| { |
| if (process_sysfs_request(CMD_GET_CHIP_NAME, name) < 0) |
| return INV_ERROR_NOT_OPENED; |
| else |
| return INV_SUCCESS; |
| } |
| /** |
| * @brief return event handler number. If the handler number is not found |
| * return false. the return value must be checked |
| * to make sure the path is valid. |
| * @unsigned char *name: This should be array big enough to hold the chip name |
| * path(8 bytes). It should be zeroed before calling this function. |
| * Or it could have unpredicable result. |
| * @int *num: event number store |
| */ |
| inv_error_t inv_get_handler_number(const char *name, int *num) |
| { |
| initialized = 0; |
| if ((*num = parsing_proc_input(1, (char *)name)) < 0) |
| return INV_ERROR_NOT_OPENED; |
| else |
| return INV_SUCCESS; |
| } |
| |
| /** |
| * @brief return input number. If the handler number is not found |
| * return false. the return value must be checked |
| * to make sure the path is valid. |
| * @unsigned char *name: This should be array big enough to hold the chip name |
| * path(8 bytes). It should be zeroed before calling this function. |
| * Or it could have unpredicable result. |
| * @int *num: input number store |
| */ |
| inv_error_t inv_get_input_number(const char *name, int *num) |
| { |
| initialized = 0; |
| if ((*num = parsing_proc_input(2, (char *)name)) < 0) |
| return INV_ERROR_NOT_OPENED; |
| else { |
| return INV_SUCCESS; |
| } |
| } |
| |
| /** |
| * @brief return iio trigger name. If iio is not initialized, return false. |
| * So the return must be checked to make sure the numeber is valid. |
| * @unsigned char *name: This should be array big enough to hold the trigger |
| * name. It should be zeroed before calling this function. |
| * Or it could have unpredicable result. |
| */ |
| inv_error_t inv_get_iio_trigger_path(char *name) |
| { |
| if (process_sysfs_request(CMD_GET_TRIGGER_PATH, (char *)name) < 0) |
| return INV_ERROR_NOT_OPENED; |
| else |
| return INV_SUCCESS; |
| } |
| |
| /** |
| * @brief return iio device node. If iio is not initialized, return false. |
| * So the return must be checked to make sure the numeber is valid. |
| * @unsigned char *name: This should be array big enough to hold the device |
| * node. It should be zeroed before calling this function. |
| * Or it could have unpredicable result. |
| */ |
| inv_error_t inv_get_iio_device_node(char *name) |
| { |
| if (process_sysfs_request(CMD_GET_DEVICE_NODE, (char *)name) < 0) |
| return INV_ERROR_NOT_OPENED; |
| else |
| return INV_SUCCESS; |
| } |