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