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