Checked in anndl.
[utils.git] / gpio.c
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
9 static 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 };
14 static 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 };
18 static const int *umap = bmap;
19 static int mapn = sizeof(bmap) / sizeof(*bmap);
20 static int preserve = 0;
21
22 static int mappin(int num)
23 {
24     if((num < 0) || (num >= mapn))
25         return(-1);
26     return(umap[num]);
27 }
28
29 static 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
54 static 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
81 static 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
99 static 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
123 static void usage(FILE *out)
124 {
125     fprintf(out, "usage: gpio [-hip] {PORT=VAL|PORT==VAL|PORT?}...\n");
126 }
127
128 int 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  */