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