1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "../port/error.h"
7 #include "io.h"
8
9 enum{
10 Qdir,
11 Qgpioset,
12 Qgpioclear,
13 Qgpioedge,
14 Qgpioctl,
15 Qgpiostatus,
16 };
17
18 Dirtab gpiodir[]={
19 ".", {Qdir,0}, 0, 0555,
20 "gpioset", {Qgpioset, 0}, 0, 0664,
21 "gpioclear", {Qgpioclear, 0}, 0, 0664,
22 "gpioedge", {Qgpioedge, 0}, 0, 0664,
23 "gpioctl", {Qgpioctl,0}, 0, 0664,
24 "gpiostatus", {Qgpiostatus,0}, 0, 0444,
25 };
26
27 static Chan*
gpioattach(char * spec)28 gpioattach(char* spec)
29 {
30 return devattach('G', spec);
31 }
32
33 static Walkqid*
gpiowalk(Chan * c,Chan * nc,char ** name,int nname)34 gpiowalk(Chan* c, Chan *nc, char **name, int nname)
35 {
36 return devwalk(c, nc, name, nname, gpiodir, nelem(gpiodir), devgen);
37 }
38
39 static int
gpiostat(Chan * c,uchar * dp,int n)40 gpiostat(Chan* c, uchar *dp, int n)
41 {
42 return devstat(c, dp, n, gpiodir, nelem(gpiodir), devgen);
43 }
44
45 static Chan*
gpioopen(Chan * c,int omode)46 gpioopen(Chan* c, int omode)
47 {
48 return devopen(c, omode, gpiodir, nelem(gpiodir), devgen);
49 }
50
51 static void
gpioclose(Chan *)52 gpioclose(Chan*)
53 {
54 }
55
56 static long
gpioread(Chan * c,void * buf,long n,vlong offset)57 gpioread(Chan* c, void *buf, long n, vlong offset)
58 {
59 char str[128];
60 GpioReg *g;
61
62 if(c->qid.type & QTDIR)
63 return devdirread(c, buf, n, gpiodir, nelem(gpiodir), devgen);
64
65 g = GPIOREG;
66 switch((ulong)c->qid.path){
67 case Qgpioset:
68 case Qgpioclear:
69 sprint(str, "%8.8lux", g->gplr);
70 break;
71 case Qgpioedge:
72 sprint(str, "%8.8lux", g->gedr);
73 break;
74 case Qgpioctl:
75 /* return 0; */
76 case Qgpiostatus:
77 snprint(str, sizeof(str), "GPDR:%8.8lux\nGRER:%8.8lux\nGFER:%8.8lux\nGAFR:%8.8lux\nGPLR:%8.8lux\n", g->gpdr, g->grer, g->gfer, g->gafr, g->gplr);
78 break;
79 default:
80 error(Ebadarg);
81 return 0;
82 }
83 return readstr(offset, buf, n, str);
84 }
85
86 static long
gpiowrite(Chan * c,void * a,long n,vlong)87 gpiowrite(Chan *c, void *a, long n, vlong)
88 {
89 char buf[128], *field[3];
90 int pin, set;
91 ulong *r;
92 GpioReg *g;
93
94 if(n >= sizeof(buf))
95 n = sizeof(buf)-1;
96 memmove(buf, a, n);
97 buf[n] = 0;
98 g = GPIOREG;
99 switch((ulong)c->qid.path){
100 case Qgpioset:
101 g->gpsr = strtol(buf, 0, 16);
102 break;
103 case Qgpioclear:
104 g->gpcr = strtol(buf, 0, 16);
105 break;
106 case Qgpioedge:
107 g->gedr = strtol(buf, 0, 16);
108 break;
109 case Qgpioctl:
110 if(getfields(buf, field, 3, 1, " \n\t") == 3) {
111 pin = strtol(field[1], 0, 0);
112 if(pin < 0 || pin >= 32)
113 error(Ebadarg);
114 set = strtol(field[2], 0, 0);
115 switch(*field[0]) {
116 case 'd':
117 r = &g->gpdr;
118 break;
119 case 'r':
120 r = &g->grer;
121 break;
122 case 'f':
123 r = &g->gfer;
124 break;
125 case 'a':
126 r = &g->gafr;
127 break;
128 default:
129 error(Ebadarg);
130 return 0;
131 }
132 if(set)
133 *r |= 1 << pin;
134 else
135 *r &= ~(1 << pin);
136 } else
137 error(Ebadarg);
138 break;
139 default:
140 error(Ebadusefd);
141 return 0;
142 }
143 return n;
144 }
145
146 Dev gpiodevtab = {
147 'G',
148 "gpio",
149
150 devreset,
151 devinit,
152 devshutdown,
153 gpioattach,
154 gpiowalk,
155 gpiostat,
156 gpioopen,
157 devcreate,
158 gpioclose,
159 gpioread,
160 devbread,
161 gpiowrite,
162 devbwrite,
163 devremove,
164 devwstat,
165 };
166