2 #include "../port/lib.h"
7 #include "../port/error.h"
29 static Dirtab irqdir[]={
30 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
31 "irq1", {Qirq1}, 0, 0666,
32 "irq2", {Qirq2}, 0, 0666,
33 "irq3", {Qirq1}, 0, 0666,
34 "irq4", {Qirq1}, 0, 0666,
35 "irq5", {Qirq1}, 0, 0666,
36 "irq6", {Qirq1}, 0, 0666,
37 "irq7", {Qirq1}, 0, 0666,
38 "mstimer", {Qmstimer}, 0, 0666,
39 "fpgareset", {Qfpgareset}, 0, 0222,
53 CMinterrupt, "interrupt", 2,
60 typedef struct Irqconfig Irqconfig;
62 int intenable; /* Interrupts are enabled */
63 int mode; /* level == 0; edge == 1 */
64 ulong interrupts; /* Count interrupts */
65 ulong sleepints; /* interrupt count when waiting */
66 Rendez r; /* Rendez-vous point for interrupt waiting */
71 Irqconfig *irqconfig[NIRQ]; /* irqconfig[0] is not used */
74 static void interrupt(Ureg*, void*);
78 ticmstimer(Ureg*, Timer *t)
88 irqenable(Irqconfig *ic, int irq)
90 /* call with ilock(&irqlock) held */
96 ic->tns = MS2NS(ic->mode);
97 ic->tmode = Tperiodic;
101 ic->next = irqconfig[irq];
106 intrenable(IRQ0 + irq, interrupt, &irqconfig[irq], irqdir[irq].name);
113 irqdisable(Irqconfig *ic, int irq)
117 /* call with ilock(&irqlock) held */
119 if (ic->intenable == 0)
121 if (irq == Qmstimer){
122 timerdel(&ic->Timer);
124 for(pic = &irqconfig[irq]; *pic != ic; pic = &(*pic)->next)
127 if (irqconfig[irq] == nil)
128 intrdisable(IRQ0 + irq, interrupt, &irqconfig[irq], irqdir[irq].name);
134 irqattach(char *spec)
136 return devattach('b', spec);
140 irqwalk(Chan *c, Chan *nc, char **name, int nname)
142 return devwalk(c, nc, name,nname, irqdir, nelem(irqdir), devgen);
146 irqstat(Chan *c, uchar *dp, int n)
148 return devstat(c, dp, n, irqdir, nelem(irqdir), devgen);
152 irqopen(Chan *c, int omode)
157 irq = (ulong)c->qid.path;
159 ic = mallocz(sizeof(Irqconfig), 1);
166 return devopen(c, omode, irqdir, nelem(irqdir), devgen);
175 irq = (ulong)c->qid.path;
193 return ic->sleepints != ic->interrupts;
197 irqread(Chan *c, void *buf, long n, vlong)
205 irq = (ulong)c->qid.path;
207 return devdirread(c, buf, n, irqdir, nelem(irqdir), devgen);
209 print("irqread 0x%llux\n", c->qid.path);
213 if (ic->intenable == 0)
215 ic->sleepints = ic->interrupts;
216 sleep(&ic->r, irqtfn, ic);
218 snprint(tmp, sizeof tmp, "%11lud %d", ic->interrupts, ic->mode);
220 snprint(tmp, sizeof tmp, "%11lud %s", ic->interrupts, ic->mode ?"edge":"level");
221 n = readstr(0, buf, n, tmp);
226 irqwrite(Chan *c, void *a, long n, vlong)
236 irq = (ulong)c->qid.path;
237 if(irq <= 0 || irq >= nelem(irqdir)){
238 print("irqwrite 0x%llux\n", c->qid.path);
241 if (irq == Qfpgareset){
242 if (strncmp(a, "reset", 5) == 0)
256 ct = lookupcmd(cb, irqmsg, nelem(irqmsg));
259 /* Turn interrupts on or off */
260 if (strcmp(cb->f[1], "on") == 0){
263 iomem->siprr = 0x65009770;
265 }else if (strcmp(cb->f[1], "off") == 0){
274 if (irq == Qmstimer){
275 ic->mode = strtol(cb->f[1], nil, 0);
277 ic->tns = MS2NS(1000);
281 ic->tns = MS2NS(ic->mode);
282 }else if (strcmp(cb->f[1], "level") == 0){
284 iomem->siexr &= ~(0x8000 >> irq);
285 }else if (strcmp(cb->f[1], "edge") == 0){
287 iomem->siexr |= 0x8000 >> irq;
295 if (ic->intenable == 0)
296 error("interrupts are off");
297 ic->sleepints = ic->interrupts;
298 sleep(&ic->r, irqtfn, ic);
301 print("simr h/l 0x%lux/0x%lux, sipnr h/l 0x%lux/0x%lux, siexr 0x%lux, siprr 0x%lux\n",
302 iomem->simr_h, iomem->simr_l,
303 iomem->sipnr_h, iomem->sipnr_l,
304 iomem->siexr, iomem->siprr);
315 interrupt(Ureg*, void *arg)
317 Irqconfig **pic, *ic;
321 irq = pic - irqconfig;
322 if (irq <= 0 || irq > nelem(irqdir)){
323 print("Unexpected interrupt: %d\n", irq);
328 iomem->sipnr_h |= 0x8000 >> irq; /* Clear the interrupt */
329 for(ic = *pic; ic; ic = ic->next){