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    "MPU6XXX",
38    "MPU9350",
39    "MPU6515",
40    "MPU6880",
41};
42static int chip_ind;
43static int initialized =0;
44static int status = 0;
45static int iio_initialized = 0;
46static 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
55static 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 **/
64int 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 */
119static 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}
231static 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
249static 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
309int 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 */
408inv_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 */
424inv_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
432inv_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 */
446inv_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 */
461inv_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 */
477inv_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 */
495inv_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 */
512inv_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 */
527inv_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