blob: 4006a5a91ba9b5989b9479dc2d58218cea75f2cd [file] [log] [blame]
Daniel Lezcano03fc66b2011-08-25 15:46:13 +02001/*******************************************************************************
2 * Copyright (C) 2010, Linaro Limited.
3 *
4 * This file is part of PowerDebug.
5 *
6 * All rights reserved. This program and the accompanying materials
7 * are made available under the terms of the Eclipse Public License v1.0
8 * which accompanies this distribution, and is available at
9 * http://www.eclipse.org/legal/epl-v10.html
10 *
11 * Contributors:
12 * Daniel Lezcano <daniel.lezcano@linaro.org> (IBM Corporation)
13 * - initial API and implementation
14 *******************************************************************************/
15
16#ifndef _GNU_SOURCE
17#define _GNU_SOURCE
18#include <stdio.h>
19#undef _GNU_SOURCE
20#endif
21#include <mntent.h>
22#include <string.h>
23#include <stdbool.h>
24#include <stdlib.h>
25#include <unistd.h>
26#include <sys/param.h>
27#include <sys/stat.h>
28
29#include "powerdebug.h"
30#include "display.h"
31#include "tree.h"
32#include "utils.h"
33
34#define SYSFS_GPIO "/sys/class/gpio"
35
Shaojie Sun564a1fe2013-07-25 19:02:08 +080036#define MAX_VALUE_BYTE 10
37
Daniel Lezcano9d8475b2011-08-25 15:46:13 +020038struct gpio_info {
39 bool expanded;
40 int active_low;
41 int value;
Shaojie Sun564a1fe2013-07-25 19:02:08 +080042 char direction[MAX_VALUE_BYTE];
43 char edge[MAX_VALUE_BYTE];
Daniel Lezcano5e267282011-08-25 15:46:13 +020044 char *prefix;
Daniel Lezcano9d8475b2011-08-25 15:46:13 +020045} *gpios_info;
46
Daniel Lezcano03fc66b2011-08-25 15:46:13 +020047static struct tree *gpio_tree = NULL;
48
Daniel Lezcano9d8475b2011-08-25 15:46:13 +020049static struct gpio_info *gpio_alloc(void)
50{
51 struct gpio_info *gi;
52
53 gi = malloc(sizeof(*gi));
Daniel Lezcano5e267282011-08-25 15:46:13 +020054 if (gi) {
55 memset(gi, -1, sizeof(*gi));
Shaojie Sun564a1fe2013-07-25 19:02:08 +080056 memset(gi->direction, 0, MAX_VALUE_BYTE);
57 memset(gi->edge, 0, MAX_VALUE_BYTE);
Daniel Lezcano5e267282011-08-25 15:46:13 +020058 gi->prefix = NULL;
59 }
Daniel Lezcano9d8475b2011-08-25 15:46:13 +020060
61 return gi;
62}
63
Daniel Lezcano9d8475b2011-08-25 15:46:13 +020064static int gpio_filter_cb(const char *name)
65{
66 /* let's ignore some directories in order to avoid to be
67 * pulled inside the sysfs circular symlinks mess/hell
68 * (choose the word which fit better)
69 */
70 if (!strcmp(name, "device"))
71 return 1;
72
73 if (!strcmp(name, "subsystem"))
74 return 1;
75
76 if (!strcmp(name, "driver"))
77 return 1;
78
79 /* we want to ignore the gpio chips */
80 if (strstr(name, "chip"))
81 return 1;
82
83 /* we are not interested by the power value */
84 if (!strcmp(name, "power"))
85 return 1;
86
87 return 0;
88}
89
Daniel Lezcano03fc66b2011-08-25 15:46:13 +020090static inline int read_gpio_cb(struct tree *t, void *data)
91{
Daniel Lezcano9d8475b2011-08-25 15:46:13 +020092 struct gpio_info *gpio = t->private;
93
94 file_read_value(t->path, "active_low", "%d", &gpio->active_low);
95 file_read_value(t->path, "value", "%d", &gpio->value);
Shaojie Sun564a1fe2013-07-25 19:02:08 +080096 file_read_value(t->path, "edge", "%8s", &gpio->edge);
97 file_read_value(t->path, "direction", "%4s", &gpio->direction);
Daniel Lezcano9d8475b2011-08-25 15:46:13 +020098
Daniel Lezcano03fc66b2011-08-25 15:46:13 +020099 return 0;
100}
101
102static int read_gpio_info(struct tree *tree)
103{
Daniel Lezcano9d8475b2011-08-25 15:46:13 +0200104 return tree_for_each(tree, read_gpio_cb, NULL);
Daniel Lezcano03fc66b2011-08-25 15:46:13 +0200105}
106
107static int fill_gpio_cb(struct tree *t, void *data)
108{
Daniel Lezcano9d8475b2011-08-25 15:46:13 +0200109 struct gpio_info *gpio;
110
111 gpio = gpio_alloc();
112 if (!gpio)
113 return -1;
114 t->private = gpio;
115
116 /* we skip the root node but we set it expanded for its children */
117 if (!t->parent) {
118 gpio->expanded = true;
119 return 0;
120 }
121
122 return read_gpio_cb(t, data);
123
Daniel Lezcano03fc66b2011-08-25 15:46:13 +0200124}
125
126static int fill_gpio_tree(void)
127{
Daniel Lezcano9d8475b2011-08-25 15:46:13 +0200128 return tree_for_each(gpio_tree, fill_gpio_cb, NULL);
Daniel Lezcano03fc66b2011-08-25 15:46:13 +0200129}
130
Daniel Lezcano5e267282011-08-25 15:46:13 +0200131static int dump_gpio_cb(struct tree *t, void *data)
132{
133 struct gpio_info *gpio = t->private;
134 struct gpio_info *pgpio;
135
136 if (!t->parent) {
137 printf("/\n");
138 gpio->prefix = "";
139 return 0;
140 }
141
142 pgpio = t->parent->private;
143
144 if (!gpio->prefix)
145 if (asprintf(&gpio->prefix, "%s%s%s", pgpio->prefix,
146 t->depth > 1 ? " ": "", t->next ? "|" : " ") < 0)
147 return -1;
148
Daniel Lezcano960b4e92011-08-25 15:46:13 +0200149 printf("%s%s-- %s (", gpio->prefix, !t->next ? "`" : "", t->name);
150
151 if (gpio->active_low != -1)
152 printf(" active_low:%d", gpio->active_low);
153
154 if (gpio->value != -1)
155 printf(", value:%d", gpio->value);
156
Shaojie Sun564a1fe2013-07-25 19:02:08 +0800157 if (gpio->edge[0] != 0)
158 printf(", edge:%s", gpio->edge);
Daniel Lezcano960b4e92011-08-25 15:46:13 +0200159
Shaojie Sun564a1fe2013-07-25 19:02:08 +0800160 if (gpio->direction[0] != 0)
161 printf(", direction:%s", gpio->direction);
Daniel Lezcano960b4e92011-08-25 15:46:13 +0200162
163 printf(" )\n");
Daniel Lezcano5e267282011-08-25 15:46:13 +0200164
165 return 0;
166}
167
168int dump_gpio_info(void)
169{
170 return tree_for_each(gpio_tree, dump_gpio_cb, NULL);
171}
172
Daniel Lezcano03fc66b2011-08-25 15:46:13 +0200173int gpio_dump(void)
174{
Daniel Lezcano5e267282011-08-25 15:46:13 +0200175 int ret;
176
177 printf("\nGpio Tree :\n");
178 printf("***********\n");
179 ret = dump_gpio_info();
180 printf("\n\n");
181
182 return ret;
Daniel Lezcano03fc66b2011-08-25 15:46:13 +0200183}
184
Daniel Lezcano960b4e92011-08-25 15:46:13 +0200185static char *gpio_line(struct tree *t)
186{
187 struct gpio_info *gpio = t->private;
188 char *gpioline;
189
Shaojie Sun564a1fe2013-07-25 19:02:08 +0800190 if (asprintf(&gpioline, "%-20s %-10d %-10d %-10s %-10s", t->name,
Daniel Lezcano960b4e92011-08-25 15:46:13 +0200191 gpio->value, gpio->active_low, gpio->edge, gpio->direction) < 0)
192 return NULL;
193
194 return gpioline;
195}
196
197static int _gpio_print_info_cb(struct tree *t, void *data)
198{
199 int *line = data;
200 char *buffer;
201
202 /* we skip the root node of the tree */
203 if (!t->parent)
204 return 0;
205
206 buffer = gpio_line(t);
207 if (!buffer)
208 return -1;
209
210 display_print_line(GPIO, *line, buffer, 0, t);
211
212 (*line)++;
213
214 free(buffer);
215
216 return 0;
217}
218
219static int gpio_print_info_cb(struct tree *t, void *data)
220{
221 /* we skip the root node of the tree */
222 if (!t->parent)
223 return 0;
224
225 return _gpio_print_info_cb(t, data);
226}
227
228static int gpio_print_header(void)
229{
230 char *buf;
231 int ret;
232
233 if (asprintf(&buf, "%-20s %-10s %-10s %-10s %-10s",
234 "Name", "Value", "Active_low", "Edge", "Direction") < 0)
235 return -1;
236
237 ret = display_column_name(buf);
238
239 free(buf);
240
241 return ret;
242}
243
244static int gpio_print_info(struct tree *tree)
245{
246 int ret, line = 0;
247
248 display_reset_cursor(GPIO);
249
250 gpio_print_header();
251
252 ret = tree_for_each(tree, gpio_print_info_cb, &line);
253
254 display_refresh_pad(GPIO);
255
256 return ret;
257}
258
259static int gpio_display(bool refresh)
260{
261 if (refresh && read_gpio_info(gpio_tree))
262 return -1;
263
264 return gpio_print_info(gpio_tree);
265}
266
Shaojie Sun8ac4a2e2013-07-29 20:11:46 +0800267static int gpio_change(int keyvalue)
268{
269 struct tree *t = display_get_row_data(GPIO);
270 struct gpio_info *gpio = t->private;
271
272 if (!t || !gpio)
273 return -1;
274
275 switch (keyvalue) {
276 case 'D':
277 /* Only change direction when gpio interrupt not set.*/
278 if (!strstr(gpio->edge, "none"))
279 return 0;
280
281 if (strstr(gpio->direction, "in"))
282 strcpy(gpio->direction, "out");
283 else if (strstr(gpio->direction, "out"))
284 strcpy(gpio->direction, "in");
285 file_write_value(t->path, "direction", "%s", &gpio->direction);
286 file_read_value(t->path, "direction", "%s", &gpio->direction);
Shaojie Suned973182013-09-17 14:15:19 +0800287 file_read_value(t->path, "value", "%d", &gpio->value);
Shaojie Sun8ac4a2e2013-07-29 20:11:46 +0800288
289 break;
290
291 case 'V':
292 /* Only change value when gpio direction is out. */
293 if (!strstr(gpio->edge, "none")
294 || !strstr(gpio->direction, "out"))
295 return 0;
296
297 if (gpio->value)
298 file_write_value(t->path, "direction", "%s", &"low");
299 else
300 file_write_value(t->path, "direction", "%s", &"high");
301 file_read_value(t->path, "value", "%d", &gpio->value);
302
303 break;
304
305 default:
306 return -1;
307 }
308
309 return 0;
310}
311
Daniel Lezcano960b4e92011-08-25 15:46:13 +0200312static struct display_ops gpio_ops = {
313 .display = gpio_display,
Shaojie Sun8ac4a2e2013-07-29 20:11:46 +0800314 .change = gpio_change,
Daniel Lezcano960b4e92011-08-25 15:46:13 +0200315};
316
Sanjay Singh Rawatb2120542014-05-16 10:58:47 +0530317void export_gpios(void)
318{
319 FILE *fgpio, *fgpio_export;
320 int ret = 0, gpio[256], num = 0;
321 char *line;
322 ssize_t read, len;
323
324 fgpio = fopen("/sys/kernel/debug/gpio", "r");
325 if (!fgpio) {
326 printf("failed to read debugfs gpio file\n");
327 ret = -1;
328 goto out;
329 }
330
331 fgpio_export = fopen("/sys/class/gpio/export", "w");
332 if (!fgpio_export) {
333 printf("failed to write open gpio-export file\n");
334 ret = -1;
335 goto out;
336 }
337
338 /* export the gpios */
339 while (read = getline(&line, &len, fgpio) != -1) {
340 char *str;
341
342 if (strstr(line, "gpio-")) {
343 str = strtok(line, " ");
344 sscanf(str, "gpio-%d", &gpio[num]);
345 fprintf(fgpio_export, "%d", gpio[num]);
346 num++;
347 }
348 }
349out:
350 return;
351}
352
Daniel Lezcano03fc66b2011-08-25 15:46:13 +0200353/*
354 * Initialize the gpio framework
355 */
356int gpio_init(void)
357{
Sanjay Singh Rawatb2120542014-05-16 10:58:47 +0530358 export_gpios();
359
Daniel Lezcano9d8475b2011-08-25 15:46:13 +0200360 gpio_tree = tree_load(SYSFS_GPIO, gpio_filter_cb, false);
Daniel Lezcano03fc66b2011-08-25 15:46:13 +0200361 if (!gpio_tree)
362 return -1;
363
364 if (fill_gpio_tree())
365 return -1;
366
367 return display_register(GPIO, &gpio_ops);
368}