blob: 7b5bbb2e5f512767262430a0c6969718cadba9d6 [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;
Sanjay Singh Rawat96f6e052014-05-26 11:35:02 +053048static bool gpio_error = false;
Daniel Lezcano03fc66b2011-08-25 15:46:13 +020049
Daniel Lezcano9d8475b2011-08-25 15:46:13 +020050static struct gpio_info *gpio_alloc(void)
51{
52 struct gpio_info *gi;
53
54 gi = malloc(sizeof(*gi));
Daniel Lezcano5e267282011-08-25 15:46:13 +020055 if (gi) {
56 memset(gi, -1, sizeof(*gi));
Shaojie Sun564a1fe2013-07-25 19:02:08 +080057 memset(gi->direction, 0, MAX_VALUE_BYTE);
58 memset(gi->edge, 0, MAX_VALUE_BYTE);
Daniel Lezcano5e267282011-08-25 15:46:13 +020059 gi->prefix = NULL;
60 }
Daniel Lezcano9d8475b2011-08-25 15:46:13 +020061
62 return gi;
63}
64
Daniel Lezcano9d8475b2011-08-25 15:46:13 +020065static int gpio_filter_cb(const char *name)
66{
67 /* let's ignore some directories in order to avoid to be
68 * pulled inside the sysfs circular symlinks mess/hell
69 * (choose the word which fit better)
70 */
71 if (!strcmp(name, "device"))
72 return 1;
73
74 if (!strcmp(name, "subsystem"))
75 return 1;
76
77 if (!strcmp(name, "driver"))
78 return 1;
79
80 /* we want to ignore the gpio chips */
81 if (strstr(name, "chip"))
82 return 1;
83
84 /* we are not interested by the power value */
85 if (!strcmp(name, "power"))
86 return 1;
87
88 return 0;
89}
90
Daniel Lezcano03fc66b2011-08-25 15:46:13 +020091static inline int read_gpio_cb(struct tree *t, void *data)
92{
Daniel Lezcano9d8475b2011-08-25 15:46:13 +020093 struct gpio_info *gpio = t->private;
94
95 file_read_value(t->path, "active_low", "%d", &gpio->active_low);
96 file_read_value(t->path, "value", "%d", &gpio->value);
Shaojie Sun564a1fe2013-07-25 19:02:08 +080097 file_read_value(t->path, "edge", "%8s", &gpio->edge);
98 file_read_value(t->path, "direction", "%4s", &gpio->direction);
Daniel Lezcano9d8475b2011-08-25 15:46:13 +020099
Daniel Lezcano03fc66b2011-08-25 15:46:13 +0200100 return 0;
101}
102
103static int read_gpio_info(struct tree *tree)
104{
Daniel Lezcano9d8475b2011-08-25 15:46:13 +0200105 return tree_for_each(tree, read_gpio_cb, NULL);
Daniel Lezcano03fc66b2011-08-25 15:46:13 +0200106}
107
108static int fill_gpio_cb(struct tree *t, void *data)
109{
Daniel Lezcano9d8475b2011-08-25 15:46:13 +0200110 struct gpio_info *gpio;
111
112 gpio = gpio_alloc();
113 if (!gpio)
114 return -1;
115 t->private = gpio;
116
117 /* we skip the root node but we set it expanded for its children */
118 if (!t->parent) {
119 gpio->expanded = true;
120 return 0;
121 }
122
123 return read_gpio_cb(t, data);
124
Daniel Lezcano03fc66b2011-08-25 15:46:13 +0200125}
126
127static int fill_gpio_tree(void)
128{
Daniel Lezcano9d8475b2011-08-25 15:46:13 +0200129 return tree_for_each(gpio_tree, fill_gpio_cb, NULL);
Daniel Lezcano03fc66b2011-08-25 15:46:13 +0200130}
131
Daniel Lezcano5e267282011-08-25 15:46:13 +0200132static int dump_gpio_cb(struct tree *t, void *data)
133{
134 struct gpio_info *gpio = t->private;
135 struct gpio_info *pgpio;
136
137 if (!t->parent) {
138 printf("/\n");
139 gpio->prefix = "";
140 return 0;
141 }
142
143 pgpio = t->parent->private;
144
145 if (!gpio->prefix)
146 if (asprintf(&gpio->prefix, "%s%s%s", pgpio->prefix,
147 t->depth > 1 ? " ": "", t->next ? "|" : " ") < 0)
148 return -1;
149
Daniel Lezcano960b4e92011-08-25 15:46:13 +0200150 printf("%s%s-- %s (", gpio->prefix, !t->next ? "`" : "", t->name);
151
152 if (gpio->active_low != -1)
153 printf(" active_low:%d", gpio->active_low);
154
155 if (gpio->value != -1)
156 printf(", value:%d", gpio->value);
157
Shaojie Sun564a1fe2013-07-25 19:02:08 +0800158 if (gpio->edge[0] != 0)
159 printf(", edge:%s", gpio->edge);
Daniel Lezcano960b4e92011-08-25 15:46:13 +0200160
Shaojie Sun564a1fe2013-07-25 19:02:08 +0800161 if (gpio->direction[0] != 0)
162 printf(", direction:%s", gpio->direction);
Daniel Lezcano960b4e92011-08-25 15:46:13 +0200163
164 printf(" )\n");
Daniel Lezcano5e267282011-08-25 15:46:13 +0200165
166 return 0;
167}
168
169int dump_gpio_info(void)
170{
171 return tree_for_each(gpio_tree, dump_gpio_cb, NULL);
172}
173
Daniel Lezcano03fc66b2011-08-25 15:46:13 +0200174int gpio_dump(void)
175{
Daniel Lezcano5e267282011-08-25 15:46:13 +0200176 int ret;
177
178 printf("\nGpio Tree :\n");
179 printf("***********\n");
180 ret = dump_gpio_info();
181 printf("\n\n");
182
183 return ret;
Daniel Lezcano03fc66b2011-08-25 15:46:13 +0200184}
185
Daniel Lezcano960b4e92011-08-25 15:46:13 +0200186static char *gpio_line(struct tree *t)
187{
188 struct gpio_info *gpio = t->private;
189 char *gpioline;
190
Shaojie Sun564a1fe2013-07-25 19:02:08 +0800191 if (asprintf(&gpioline, "%-20s %-10d %-10d %-10s %-10s", t->name,
Daniel Lezcano960b4e92011-08-25 15:46:13 +0200192 gpio->value, gpio->active_low, gpio->edge, gpio->direction) < 0)
193 return NULL;
194
195 return gpioline;
196}
197
198static int _gpio_print_info_cb(struct tree *t, void *data)
199{
200 int *line = data;
201 char *buffer;
202
203 /* we skip the root node of the tree */
204 if (!t->parent)
205 return 0;
206
207 buffer = gpio_line(t);
208 if (!buffer)
209 return -1;
210
211 display_print_line(GPIO, *line, buffer, 0, t);
212
213 (*line)++;
214
215 free(buffer);
216
217 return 0;
218}
219
220static int gpio_print_info_cb(struct tree *t, void *data)
221{
222 /* we skip the root node of the tree */
223 if (!t->parent)
224 return 0;
225
226 return _gpio_print_info_cb(t, data);
227}
228
229static int gpio_print_header(void)
230{
231 char *buf;
232 int ret;
233
234 if (asprintf(&buf, "%-20s %-10s %-10s %-10s %-10s",
235 "Name", "Value", "Active_low", "Edge", "Direction") < 0)
236 return -1;
237
238 ret = display_column_name(buf);
239
240 free(buf);
241
242 return ret;
243}
244
245static int gpio_print_info(struct tree *tree)
246{
247 int ret, line = 0;
248
249 display_reset_cursor(GPIO);
250
251 gpio_print_header();
252
253 ret = tree_for_each(tree, gpio_print_info_cb, &line);
254
255 display_refresh_pad(GPIO);
256
257 return ret;
258}
259
260static int gpio_display(bool refresh)
261{
Sanjay Singh Rawat96f6e052014-05-26 11:35:02 +0530262 if (gpio_error) {
263 display_message(GPIO, "error: path " SYSFS_GPIO " not found");
264 return -2;
265 }
266
Daniel Lezcano960b4e92011-08-25 15:46:13 +0200267 if (refresh && read_gpio_info(gpio_tree))
268 return -1;
269
270 return gpio_print_info(gpio_tree);
271}
272
Shaojie Sun8ac4a2e2013-07-29 20:11:46 +0800273static int gpio_change(int keyvalue)
274{
275 struct tree *t = display_get_row_data(GPIO);
276 struct gpio_info *gpio = t->private;
277
278 if (!t || !gpio)
279 return -1;
280
281 switch (keyvalue) {
282 case 'D':
283 /* Only change direction when gpio interrupt not set.*/
284 if (!strstr(gpio->edge, "none"))
285 return 0;
286
287 if (strstr(gpio->direction, "in"))
288 strcpy(gpio->direction, "out");
289 else if (strstr(gpio->direction, "out"))
290 strcpy(gpio->direction, "in");
291 file_write_value(t->path, "direction", "%s", &gpio->direction);
292 file_read_value(t->path, "direction", "%s", &gpio->direction);
Shaojie Suned973182013-09-17 14:15:19 +0800293 file_read_value(t->path, "value", "%d", &gpio->value);
Shaojie Sun8ac4a2e2013-07-29 20:11:46 +0800294
295 break;
296
297 case 'V':
298 /* Only change value when gpio direction is out. */
299 if (!strstr(gpio->edge, "none")
300 || !strstr(gpio->direction, "out"))
301 return 0;
302
303 if (gpio->value)
304 file_write_value(t->path, "direction", "%s", &"low");
305 else
306 file_write_value(t->path, "direction", "%s", &"high");
307 file_read_value(t->path, "value", "%d", &gpio->value);
308
309 break;
310
311 default:
312 return -1;
313 }
314
315 return 0;
316}
317
Daniel Lezcano960b4e92011-08-25 15:46:13 +0200318static struct display_ops gpio_ops = {
319 .display = gpio_display,
Shaojie Sun8ac4a2e2013-07-29 20:11:46 +0800320 .change = gpio_change,
Daniel Lezcano960b4e92011-08-25 15:46:13 +0200321};
322
Sanjay Singh Rawat75eadf32014-06-19 17:55:09 +0530323void export_free_gpios(void)
Sanjay Singh Rawatb2120542014-05-16 10:58:47 +0530324{
325 FILE *fgpio, *fgpio_export;
Sanjay Singh Rawat75eadf32014-06-19 17:55:09 +0530326 int i, gpio_max = 0;
Sanjay Singh Rawat03fdbc02014-05-27 16:52:27 +0530327 char *line = NULL;
Daniel Lezcano83b28d02016-02-18 13:49:55 +0000328 ssize_t read;
329 size_t len = 0;
Sanjay Singh Rawatb2120542014-05-16 10:58:47 +0530330
331 fgpio = fopen("/sys/kernel/debug/gpio", "r");
332 if (!fgpio) {
333 printf("failed to read debugfs gpio file\n");
Daniel Lezcano83b28d02016-02-18 13:49:55 +0000334 return;
Sanjay Singh Rawatb2120542014-05-16 10:58:47 +0530335 }
336
337 fgpio_export = fopen("/sys/class/gpio/export", "w");
338 if (!fgpio_export) {
339 printf("failed to write open gpio-export file\n");
Sanjay Singh Rawatb2120542014-05-16 10:58:47 +0530340 goto out;
341 }
342
343 /* export the gpios */
Sanjay Singh Rawat75eadf32014-06-19 17:55:09 +0530344 while ((read = getline(&line, &len, fgpio)) != -1) {
345 if (strstr(line, "GPIOs"))
Daniel Lezcano83b28d02016-02-18 13:49:55 +0000346 sscanf(line, "%*[^-]-%d", &gpio_max);
Sanjay Singh Rawat75eadf32014-06-19 17:55:09 +0530347 }
Sanjay Singh Rawatb2120542014-05-16 10:58:47 +0530348
Sanjay Singh Rawat75eadf32014-06-19 17:55:09 +0530349 printf("log: total gpios = %d\n", gpio_max);
350 for (i = 0 ; i <= gpio_max ; i++) {
351 char command[50] = "";
352
353 sprintf(command, "echo %d > /sys/class/gpio/export", i);
354 if (system(command) < 0)
355 printf("error: failed to export gpio-%d\n", i);
Sanjay Singh Rawatb2120542014-05-16 10:58:47 +0530356 }
Meraje33055c2014-06-30 16:11:45 +0530357
358 free(line);
Daniel Lezcano83b28d02016-02-18 13:49:55 +0000359
Meraje33055c2014-06-30 16:11:45 +0530360 if (fgpio)
361 fclose(fgpio);
Daniel Lezcano83b28d02016-02-18 13:49:55 +0000362out:
Meraje33055c2014-06-30 16:11:45 +0530363 if (fgpio_export)
364 fclose(fgpio_export);
365
Sanjay Singh Rawatb2120542014-05-16 10:58:47 +0530366 return;
367}
368
Daniel Lezcano03fc66b2011-08-25 15:46:13 +0200369/*
370 * Initialize the gpio framework
371 */
372int gpio_init(void)
373{
Sanjay Singh Rawat96f6e052014-05-26 11:35:02 +0530374 int ret = 0;
375
376 ret = display_register(GPIO, &gpio_ops);
Sanjay Singh Rawat03fdbc02014-05-27 16:52:27 +0530377 if (ret)
Sanjay Singh Rawat96f6e052014-05-26 11:35:02 +0530378 printf("error: gpio display register failed");
379
380 if (access(SYSFS_GPIO, F_OK))
381 gpio_error = true; /* set the flag */
382
Sanjay Singh Rawat75eadf32014-06-19 17:55:09 +0530383 export_free_gpios();
Sanjay Singh Rawatb2120542014-05-16 10:58:47 +0530384
Daniel Lezcano9d8475b2011-08-25 15:46:13 +0200385 gpio_tree = tree_load(SYSFS_GPIO, gpio_filter_cb, false);
Daniel Lezcano03fc66b2011-08-25 15:46:13 +0200386 if (!gpio_tree)
387 return -1;
388
389 if (fill_gpio_tree())
390 return -1;
391
Sanjay Singh Rawat96f6e052014-05-26 11:35:02 +0530392 return ret;
Daniel Lezcano03fc66b2011-08-25 15:46:13 +0200393}