acmecert: Reorganized a bit.
[utils.git] / gpio.c
... / ...
CommitLineData
1#include <unistd.h>
2#include <stdlib.h>
3#include <stdio.h>
4#include <string.h>
5#include <fcntl.h>
6#include <errno.h>
7#include <err.h>
8
9static const int bmap[] = {
10 -1,
11 -1, -1, 2, -1, 3, -1, 4, 14, -1, 15, 17, 18, 27, -1, 22, 23, -1, 24, 10, -1,
12 9, 25, 11, 8, -1, 7, -1, -1, 5, -1, 6, 12, 13, -1, 19, 16, 21, 20, -1, 21,
13};
14static const int imap[] = {
15 -1, -1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
16 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, 27,
17};
18static const int *umap = bmap;
19static int mapn = sizeof(bmap) / sizeof(*bmap);
20static int preserve = 0;
21
22static int mappin(int num)
23{
24 if((num < 0) || (num >= mapn))
25 return(-1);
26 return(umap[num]);
27}
28
29static void export(int p)
30{
31 char path[256];
32 FILE *fp;
33 int rp;
34
35 if((rp = mappin(p)) < 0)
36 errx(1, "%i: no such port", p);
37 sprintf(path, "/sys/class/gpio/gpio%i", rp);
38 if(!access(path, R_OK | X_OK))
39 return;
40 if(preserve)
41 errx(2, "gpio%i: not exported", rp);
42 sprintf(path, "/sys/class/gpio/export");
43 if((fp = fopen(path, "w")) == NULL)
44 err(1, "%s", path);
45 fprintf(fp, "%i\n", rp); fflush(fp);
46 if(ferror(fp))
47 errx(1, "gpio%i: could not export", rp);
48 fclose(fp);
49 sprintf(path, "/sys/class/gpio/gpio%i", rp);
50 if(access(path, R_OK | X_OK))
51 errx(1, "gpio%i: still not available after export", rp);
52}
53
54static void checkdir(int rp, char *dir)
55{
56 char path[256], line[256];
57 FILE *fp;
58 int rv;
59 size_t ln;
60
61 sprintf(path, "/sys/class/gpio/gpio%i/direction", rp);
62 if((fp = fopen(path, "r")) == NULL)
63 err(1, "%s", path);
64 rv = !!fgets(line, sizeof(line), fp);
65 fclose(fp);
66 if(!rv || ((ln = strlen(line)) < 1) || (line[ln - 1] != '\n'))
67 errx(1, "gpio%i: could not read direction", rp);
68 line[ln - 1] = 0;
69 if(strcmp(line, dir)) {
70 if(preserve)
71 errx(2, "gpio%i: direction not set to %s", rp, dir);
72 if((fp = fopen(path, "w")) == NULL)
73 err(1, "%s", path);
74 fprintf(fp, "%s\n", dir); fflush(fp);
75 if(ferror(fp))
76 errx(1, "gpio%i: could not set to direction to %s", rp, dir);
77 fclose(fp);
78 }
79}
80
81static void setport(int p, int v)
82{
83 char path[256];
84 FILE *fp;
85 int rp;
86
87 if((rp = mappin(p)) < 0)
88 errx(1, "%i: no such port", p);
89 checkdir(rp, "out");
90 sprintf(path, "/sys/class/gpio/gpio%i/value", rp);
91 if((fp = fopen(path, "w")) == NULL)
92 err(1, "%s", path);
93 fprintf(fp, "%i\n", v); fflush(fp);
94 if(ferror(fp))
95 errx(1, "gpio%i: could not set value", rp);
96 fclose(fp);
97}
98
99static int getport(int p)
100{
101 char path[256], line[256], *ep;
102 FILE *fp;
103 int rv, rp;
104 size_t ln;
105
106 if((rp = mappin(p)) < 0)
107 errx(1, "%i: no such port", p);
108 checkdir(rp, "in");
109 sprintf(path, "/sys/class/gpio/gpio%i/value", rp);
110 if((fp = fopen(path, "r")) == NULL)
111 err(1, "%s", path);
112 rv = !!fgets(line, sizeof(line), fp);
113 fclose(fp);
114 if(!rv || ((ln = strlen(line)) < 1) || (line[ln - 1] != '\n'))
115 errx(1, "gpio%i: could not read direction", rp);
116 line[ln - 1] = 0;
117 rv = (int)strtol(line, &ep, 10);
118 if(*ep)
119 errx(1, "gpio%i: unexpected contents: %s", rp, line);
120 return(rv);
121}
122
123static void usage(FILE *out)
124{
125 fprintf(out, "usage: gpio [-hip] {PORT=VAL|PORT==VAL|PORT?}...\n");
126}
127
128int main(int argc, char **argv)
129{
130 int c, i, port, val;
131 char *e;
132
133 while((c = getopt(argc, argv, "hip")) >= 0) {
134 switch(c) {
135 case 'h':
136 usage(stdout);
137 return(0);
138 case 'i':
139 umap = imap;
140 mapn = sizeof(imap) / sizeof(*imap);
141 break;
142 case 'p':
143 preserve = 1;
144 break;
145 default:
146 usage(stderr);
147 return(1);
148 }
149 }
150 if(optind >= argc) {
151 usage(stderr);
152 return(1);
153 }
154 for(i = optind; i < argc; i++) {
155 port = strtol(argv[i], &e, 10);
156 if((e > argv[i]) && (e[0] == '=') && (e[1] == '=')) {
157 val = strtol(e + 2, &e, 10);
158 if(*e)
159 errx(1, "gpio: %s: not of the form PORT==VAL", argv[i]);
160 export(port);
161 return(getport(port) != val);
162 } else if((e > argv[i]) && (e[0] == '=')) {
163 val = strtol(e + 1, &e, 10);
164 if(*e)
165 errx(1, "gpio: %s: not of the form PORT=VAL", argv[i]);
166 export(port);
167 setport(port, val);
168 } else if((e > argv[i]) && (e[0] == '?') && !e[1]) {
169 export(port);
170 printf("%i\n", getport(port));
171 } else {
172 errx(1, "gpio: %s: not a valid argument", argv[i]);
173 }
174 }
175 return(0);
176}
177
178/*
179 * Local Variables:
180 * compile-command: "gcc -Wall -g -O2 -march=native -c -o gpio.o gpio.c && gcc -o gpio gpio.o"
181 * End:
182 */