gpio: Auto-export ports.
[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\n", 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 setport(int p, int v)
55 {
56     char path[256], line[256];
57     FILE *fp;
58     int rv, rp;
59     
60     if((rp = mappin(p)) < 0)
61         errx(1, "%i: no such port\n", p);
62     sprintf(path, "/sys/class/gpio/gpio%i/direction", rp);
63     if((fp = fopen(path, "r")) == NULL)
64         err(1, "%s", path);
65     rv = !!fgets(line, sizeof(line), fp);
66     fclose(fp);
67     if(!rv || strcmp(line, "out\n")) {
68         if(preserve)
69             errx(2, "gpio%i: not set to output", rp);
70         if((fp = fopen(path, "w")) == NULL)
71             err(1, "%s", path);
72         fprintf(fp, "out\n"); fflush(fp);
73         if(ferror(fp))
74             errx(1, "gpio%i: could not set to output", rp);
75         fclose(fp);
76     }
77     sprintf(path, "/sys/class/gpio/gpio%i/value", rp);
78     if((fp = fopen(path, "w")) == NULL)
79         err(1, "%s", path);
80     fprintf(fp, "%i\n", v); fflush(fp);
81     if(ferror(fp))
82         errx(1, "gpio%i: could not set value", rp);
83     fclose(fp);
84 }
85
86 static void usage(FILE *out)
87 {
88     fprintf(out, "usage: gpio [-hip] PORT=VAL...\n");
89 }
90
91 int main(int argc, char **argv)
92 {
93     int c, i, port, val;
94     char *p, *e;
95     
96     while((c = getopt(argc, argv, "hip")) >= 0) {
97         switch(c) {
98         case 'h':
99             usage(stdout);
100             return(0);
101         case 'i':
102             umap = imap;
103             mapn = sizeof(imap) / sizeof(*imap);
104             break;
105         case 'p':
106             preserve = 1;
107             break;
108         default:
109             usage(stderr);
110             return(1);
111         }
112     }
113     if(optind >= argc) {
114         usage(stderr);
115         return(1);
116     }
117     for(i = optind; i < argc; i++) {
118         if((p = strchr(argv[i], '=')) == NULL) {
119             fprintf(stderr, "gpio: %s: not of the form PORT=VAL\n", argv[i]);
120             exit(1);
121         }
122         port = strtol(argv[i], &e, 10);
123         if(e != p) {
124             fprintf(stderr, "gpio: %s: not of the form PORT=VAL\n", argv[i]);
125             exit(1);
126         }
127         val = strtol(p + 1, &e, 10);
128         if(*e) {
129             fprintf(stderr, "gpio: %s: not of the form PORT=VAL\n", argv[i]);
130             exit(1);
131         }
132         export(port);
133         setport(port, val);
134     }
135     return(0);
136 }
137
138 /*
139  * Local Variables:
140  * compile-command: "gcc -Wall -g -O2 -march=native -o gpio gpio.c"
141  * End:
142  */