2 #include "../port/lib.h"
6 #include "../port/error.h"
10 // 3 bits - generic file type (Qinctl, Qindata)
11 // 3 bits - parent type
12 // 3 bits - chosen scheme type (Qgeneric, Qbcm, Qboard, Qwpi)
13 // 6 bits - input number
15 #define PIN_TABLE_SIZE 32
17 #define PIN_OFFSET SCHEME_OFFSET + SCHEME_BITS
19 #define PIN_MASK ((1 << PIN_BITS) - 1)
20 #define PIN_NUMBER(q) (((q).path >> PIN_OFFSET) & PIN_MASK)
22 #define SCHEME_OFFSET PARENT_OFFSET + PARENT_BITS
24 #define SCHEME_MASK ((1 << SCHEME_BITS) - 1)
25 #define SCHEME_TYPE(q) (((q).path >> SCHEME_OFFSET) & SCHEME_MASK)
27 #define PARENT_OFFSET FILE_OFFSET + FILE_BITS
29 #define PARENT_MASK ((1 << PARENT_BITS) - 1)
30 #define PARENT_TYPE(q) (((q).path >> PARENT_OFFSET) & PARENT_MASK)
34 #define FILE_MASK ((1 << FILE_BITS) - 1)
35 #define FILE_TYPE(q) (((q).path >> FILE_OFFSET) & FILE_MASK)
37 // pin is valid only when file is Qdata otherwise 0 is used
38 #define PATH(pin, scheme, parent, file) \
39 ((pin & PIN_MASK) << PIN_OFFSET) \
40 | ((scheme & SCHEME_MASK) << SCHEME_OFFSET) \
41 | ((parent & PARENT_MASK) << PARENT_OFFSET) \
42 | ((file & FILE_MASK) << FILE_OFFSET)
44 #define SET_BIT(f, offset, value) \
45 (*f = ((*f & ~(1 << (offset % 32))) | (value << (offset % 32))))
48 #define D(...) if(dflag) print(__VA_ARGS__)
80 Dirtab topdir = { "#G", {PATH(0, Qgeneric, Qtopdir, Qdir), 0, QTDIR}, 0, 0555 };
81 Dirtab gpiodir = { "gpio", {PATH(0, Qgeneric, Qgpiodir, Qdir), 0, QTDIR}, 0, 0555 };
84 "OK", { PATH(16, Qgeneric, Qgpiodir, Qdata), 0, QTFILE }, 0, 0666,
85 "ctl", { PATH(0, Qgeneric, Qgpiodir, Qctl), 0, QTFILE }, 0, 0666,
86 "event", { PATH(0, Qgeneric, Qgpiodir, Qevent), 0, QTFILE }, 0, 0444,
89 // commands definition
94 CMscheme, "scheme", 2,
95 CMfunc, "function", 3,
100 static int pinscheme;
104 static u32int eventvalue;
105 static long eventinuse;
106 static Lock eventlock;
122 static char *funcname[] = {
123 "in", "out", "5", "4", "0", "1", "2", "3",
132 static char *pudname[] = {
136 static char *evstatename[] = {
145 static char *evtypename[] = {
146 "edge-rising", "edge-falling",
149 static char *bcmtableR1[PIN_TABLE_SIZE] = {
150 "1", "2", 0, 0, // 0-3
151 "4", 0, 0, "7", // 4-7
152 "8", "9", "10", "11", // 8-11
153 0, 0, "14", "15", // 12-15
154 0, "17", "18", 0, // 16-19
155 0, "21", "22", "23", // 20-23
156 "24", "25", 0, 0, // 24-27
160 static char *bcmtableR2[PIN_TABLE_SIZE] = {
161 0, 0, "2", "3", // 0-3
162 "4", 0, 0, "7", // 4-7
163 "8", "9", "10", "11", // 8-11
164 0, 0, "14", "15", // 12-15
165 0, "17", "18", 0, // 16-19
166 0, 0, "22", "23", // 20-23
167 "24", "25", 0, "27", // 24-27
168 "28", "29", "30", "31", // 28-31
171 static char *boardtableR1[PIN_TABLE_SIZE] = {
172 "SDA", "SCL", 0, 0, // 0-3
173 "GPIO7", 0, 0, "CE1", // 4-7
174 "CE0", "MISO", "MOSI", "SCLK", // 8-11
175 0, 0, "TxD", "RxD", // 12-15
176 0, "GPIO0", "GPIO1", 0, // 16-19
177 0, "GPIO2", "GPIO3", "GPIO4", // 20-23
178 "GPIO5", "GPIO6", 0, 0, // 24-27
182 static char *boardtableR2[PIN_TABLE_SIZE] = {
183 0, 0, "SDA", "SCL", // 0-3
184 "GPIO7", 0, 0, "CE1", // 4-7
185 "CE0", "MISO", "MOSI", "SCLK", // 8-11
186 0, 0, "TxD", "RxD", // 12-15
187 0, "GPIO0", "GPIO1", 0, // 16-19
188 0, 0, "GPIO3", "GPIO4", // 20-23
189 "GPIO5", "GPIO6", 0, "GPIO2", // 24-27
190 "GPIO8", "GPIO9", "GPIO10", "GPIO11", // 28-31
193 static char *wpitableR1[PIN_TABLE_SIZE] = {
194 "8", "9", 0, 0, // 0-3
195 "7", 0, 0, "11", // 4-7
196 "10", "13", "12", "14", // 8-11
197 0, 0, "15", "16", // 12-15
198 0, "0", "1", 0, // 16-19
199 0, "2", "3", "4", // 20-23
200 "5", "6", 0, 0, // 24-27
204 static char *wpitableR2[PIN_TABLE_SIZE] = {
205 0, 0, "8", "9", // 0-3
206 "7", 0, 0, "11", // 4-7
207 "10", "13", "12", "14", // 8-11
208 0, 0, "15", "16", // 12-15
209 0, "0", "1", 0, // 16-19
210 0, 0, "3", "4", // 20-23
211 "5", "6", 0, "2", // 24-27
212 "17", "18", "19", "20", // 28-31
215 static char *schemename[] = {
216 "bcm", "board", "wpi",
225 return (boardrev>3)?bcmtableR2:bcmtableR1;
227 return (boardrev>3)?boardtableR2:boardtableR1;
229 return (boardrev>3)?wpitableR2:wpitableR1;
235 // stolen from uartmini.c
236 #define GPIOREGS (VIRTIO+0x200000)
257 gpiofuncset(uint pin, int func)
262 gp = (u32int*)GPIOREGS;
263 fsel = &gp[Fsel0 + pin/10];
264 off = (pin % 10) * 3;
265 *fsel = (*fsel & ~(FuncMask<<off)) | func<<off;
269 gpiofuncget(uint pin)
274 gp = (u32int*)GPIOREGS;
275 fsel = &gp[Fsel0 + pin/10];
276 off = (pin % 10) * 3;
277 return ((*fsel >> off) & FuncMask);
281 gpiopullset(uint pin, int state)
286 gp = (u32int*)GPIOREGS;
287 reg = &gp[PUDclk0 + pin/32];
288 mask = 1 << (pin % 32);
297 gpioout(uint pin, int set)
302 gp = (u32int*)GPIOREGS;
303 v = set? Set0 : Clr0;
304 gp[v + pin/32] = 1 << (pin % 32);
312 gp = (u32int*)GPIOREGS;
313 return (gp[Lev0 + pin/32] & (1 << (pin % 32))) != 0;
317 gpioevent(uint pin, int event, int enable)
331 panic("gpio: unknown event type");
333 gp = (u32int*)GPIOREGS;
334 field = &gp[reg + pin/32];
335 SET_BIT(field, pin, enable);
339 mkdeventry(Chan *c, Qid qid, Dirtab *tab, Dir *db)
341 mkqid(&qid, tab->qid.path, tab->qid.vers, tab->qid.type);
342 devdir(c, qid, tab->name, tab->length, eve, tab->perm, db);
346 gpiogen(Chan *c, char *, Dirtab *, int , int s, Dir *db)
349 int parent, scheme, l;
350 char **pintable = getpintable();
353 parent = PARENT_TYPE(c->qid);
354 scheme = SCHEME_TYPE(c->qid);
362 mkdeventry(c, qid, &topdir, db);
370 if(parent == Qtopdir)
375 mkdeventry(c, qid, &gpiodir, db);
383 if(scheme != Qgeneric && scheme != pinscheme)
388 if(parent == Qgpiodir)
393 mkdeventry(c, qid, &typedir[s], db);
394 } else if (s < l + PIN_TABLE_SIZE)
402 mkqid(&qid, PATH(s, pinscheme, Qgpiodir, Qdata), 0, QTFILE);
403 snprint(up->genbuf, sizeof up->genbuf, "%s", pintable[s]);
404 devdir(c, qid, up->genbuf, 0, eve, 0666, db);
417 interrupt(Ureg*, void *)
423 gp = (u32int*)GPIOREGS;
431 for(pin = 0; pin < PIN_TABLE_SIZE; pin++)
433 set = (gp[Evds0 + pin/32] & (1 << (pin % 32))) != 0;
437 field = &gp[Evds0 + pin/32];
438 SET_BIT(field, pin, 1);
439 SET_BIT(&eventvalue, pin, 1);
450 boardrev = getrevision() & 0xff;
452 intrenable(49, interrupt, nil, 0, "gpio1");
460 gpioattach(char *spec)
462 return devattach('G', spec);
466 gpiowalk(Chan *c, Chan *nc, char** name, int nname)
468 return devwalk(c, nc, name, nname, 0, 0, gpiogen);
472 gpiostat(Chan *c, uchar *db, int n)
474 return devstat(c, db, n, 0, 0, gpiogen);
478 gpioopen(Chan *c, int omode)
482 c = devopen(c, omode, 0, 0, gpiogen);
484 type = FILE_TYPE(c->qid);
513 type = FILE_TYPE(c->qid);
535 gpioread(Chan *c, void *va, long n, vlong off)
543 if(c->qid.type & QTDIR)
545 return devdirread(c, va, n, 0, 0, gpiogen);
548 type = FILE_TYPE(c->qid);
549 scheme = SCHEME_TYPE(c->qid);
551 if(scheme != Qgeneric && scheme != pinscheme)
559 pin = PIN_NUMBER(c->qid);
560 a[0] = (gpioin(pin))?'1':'0';
571 sleep(&rend, isset, 0);
577 memmove(a, &eventvalue + off, n);
584 getpin(char *pinname)
587 char **pintable = getpintable();
588 for(i = 0; i < PIN_TABLE_SIZE; i++)
594 if(strncmp(pintable[i], pinname, strlen(pintable[i])) == 0)
603 gpiowrite(Chan *c, void *va, long n, vlong)
612 if(c->qid.type & QTDIR)
617 type = FILE_TYPE(c->qid);
619 scheme = SCHEME_TYPE(c->qid);
621 if(scheme != Qgeneric && scheme != pinscheme)
626 cb = parsecmd(va, n);
632 ct = lookupcmd(cb, gpiocmd, nelem(gpiocmd));
641 pin = PIN_NUMBER(c->qid);
660 for(i = 0; i < nelem(schemename); i++)
662 if(strncmp(schemename[i], arg, strlen(schemename[i])) == 0)
670 pin = getpin(cb->f[2]);
675 for(i = 0; i < nelem(funcname); i++)
677 if(strncmp(funcname[i], arg, strlen(funcname[i])) == 0)
685 pin = getpin(cb->f[2]);
690 for(i = 0; i < nelem(pudname); i++)
692 if(strncmp(pudname[i], arg, strlen(pudname[i])) == 0)
700 pin = getpin(cb->f[3]);
706 for(i = 0; i < nelem(evtypename); i++)
708 if(strncmp(evtypename[i], arg, strlen(evtypename[i])) == 0)
710 gpioevent(pin, i, (cb->f[2][0] == 'e'));