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
21enum 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};
29static char sysfs_path[100];
30static 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};
43static int chip_ind;
44static int initialized =0;
45static int status = 0;
46static int iio_initialized = 0;
47static 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
56static 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 **/
65int 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 */
120static 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}
232static 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
250static 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
310int 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 */
409inv_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 */
425inv_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
433inv_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 */
447inv_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 */
462inv_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 */
478inv_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 */
496inv_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 */
513inv_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 */
528inv_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