1433d6423SLionel Sambuc #include "common.h"
2433d6423SLionel Sambuc #include <ddekit/interrupt.h>
3433d6423SLionel Sambuc #include <ddekit/memory.h>
4187bd3cdSWojciech Zajac #include <ddekit/panic.h>
5433d6423SLionel Sambuc #include <ddekit/semaphore.h>
6433d6423SLionel Sambuc #include <ddekit/thread.h>
7433d6423SLionel Sambuc
8433d6423SLionel Sambuc #ifdef DDEBUG_LEVEL_IRQ
9433d6423SLionel Sambuc #undef DDEBUG
10433d6423SLionel Sambuc #define DDEBUG DDEBUG_LEVEL_IRQ
11433d6423SLionel Sambuc #endif
12433d6423SLionel Sambuc
13433d6423SLionel Sambuc #include "debug.h"
14433d6423SLionel Sambuc
15433d6423SLionel Sambuc struct ddekit_irq_s {
16433d6423SLionel Sambuc int irq;
17187bd3cdSWojciech Zajac int notify_id;
18433d6423SLionel Sambuc int irq_hook;
19433d6423SLionel Sambuc int shared;
20433d6423SLionel Sambuc void(*thread_init)(void *);
21433d6423SLionel Sambuc void(*handler)(void *);
22433d6423SLionel Sambuc void *priv;
23433d6423SLionel Sambuc int enabled;
24433d6423SLionel Sambuc ddekit_thread_t *th;
25433d6423SLionel Sambuc ddekit_sem_t *sem;
26433d6423SLionel Sambuc struct ddekit_irq_s *next;
27433d6423SLionel Sambuc };
28433d6423SLionel Sambuc
29433d6423SLionel Sambuc static struct ddekit_irq_s *irqs = 0;
30433d6423SLionel Sambuc static ddekit_lock_t lock;
31187bd3cdSWojciech Zajac static int next_notify_id = 0; /* TODO: This is only incremented and after
32187bd3cdSWojciech Zajac * enough interrupt attachments/detachments
33187bd3cdSWojciech Zajac * we can run out of legal IDs (this is however
34187bd3cdSWojciech Zajac * very atypical use case) */
35433d6423SLionel Sambuc
36433d6423SLionel Sambuc /******************************************************************************
37433d6423SLionel Sambuc * Local helpers *
38433d6423SLionel Sambuc *****************************************************************************/
39433d6423SLionel Sambuc
40433d6423SLionel Sambuc
41433d6423SLionel Sambuc static void ddekit_irq_lock(void);
42433d6423SLionel Sambuc static void ddekit_irq_unlock(void);
43433d6423SLionel Sambuc static struct ddekit_irq_s* find_by_irq(int irq);
44187bd3cdSWojciech Zajac static struct ddekit_irq_s* find_by_irq_id(int irq_id);
45433d6423SLionel Sambuc static void ddekit_irq_remove(struct ddekit_irq_s *irq_s);
46433d6423SLionel Sambuc static void ddekit_irq_thread(void *data);
47433d6423SLionel Sambuc
48433d6423SLionel Sambuc /******************************************************************************
49433d6423SLionel Sambuc * ddekit_irq_lock *
50433d6423SLionel Sambuc *****************************************************************************/
ddekit_irq_lock(void)51433d6423SLionel Sambuc static void ddekit_irq_lock(void)
52433d6423SLionel Sambuc {
53433d6423SLionel Sambuc ddekit_lock_lock(&lock);
54433d6423SLionel Sambuc }
55433d6423SLionel Sambuc
56433d6423SLionel Sambuc /******************************************************************************
57433d6423SLionel Sambuc * ddekit_irq_unlock *
58433d6423SLionel Sambuc *****************************************************************************/
ddekit_irq_unlock(void)59433d6423SLionel Sambuc static void ddekit_irq_unlock(void)
60433d6423SLionel Sambuc {
61433d6423SLionel Sambuc ddekit_lock_unlock(&lock);
62433d6423SLionel Sambuc }
63433d6423SLionel Sambuc
64433d6423SLionel Sambuc /******************************************************************************
65433d6423SLionel Sambuc * find_by_irq *
66433d6423SLionel Sambuc *****************************************************************************/
find_by_irq(int irq)67433d6423SLionel Sambuc static struct ddekit_irq_s * find_by_irq(int irq)
68433d6423SLionel Sambuc {
69433d6423SLionel Sambuc struct ddekit_irq_s * irq_s;
70433d6423SLionel Sambuc ddekit_irq_lock();
71433d6423SLionel Sambuc if (!irqs) {
72433d6423SLionel Sambuc return 0;
73433d6423SLionel Sambuc }
74433d6423SLionel Sambuc
75433d6423SLionel Sambuc irq_s = irqs;
76433d6423SLionel Sambuc
77433d6423SLionel Sambuc while(irq_s) {
78433d6423SLionel Sambuc if(irq_s->irq==irq)
79433d6423SLionel Sambuc break;
80433d6423SLionel Sambuc irq_s = irq_s->next;
81433d6423SLionel Sambuc }
82433d6423SLionel Sambuc
83433d6423SLionel Sambuc ddekit_irq_unlock();
84433d6423SLionel Sambuc return irq_s;
85433d6423SLionel Sambuc }
86433d6423SLionel Sambuc
87433d6423SLionel Sambuc /******************************************************************************
88187bd3cdSWojciech Zajac * find_by_irq_id *
89187bd3cdSWojciech Zajac *****************************************************************************/
find_by_irq_id(int irq_id)90187bd3cdSWojciech Zajac static struct ddekit_irq_s * find_by_irq_id(int irq_id)
91187bd3cdSWojciech Zajac {
92187bd3cdSWojciech Zajac struct ddekit_irq_s * irq_s;
93187bd3cdSWojciech Zajac ddekit_irq_lock();
94187bd3cdSWojciech Zajac if (!irqs) {
95187bd3cdSWojciech Zajac return 0;
96187bd3cdSWojciech Zajac }
97187bd3cdSWojciech Zajac
98187bd3cdSWojciech Zajac irq_s = irqs;
99187bd3cdSWojciech Zajac
100187bd3cdSWojciech Zajac while(irq_s) {
101187bd3cdSWojciech Zajac if(irq_s->notify_id==irq_id)
102187bd3cdSWojciech Zajac break;
103187bd3cdSWojciech Zajac irq_s = irq_s->next;
104187bd3cdSWojciech Zajac }
105187bd3cdSWojciech Zajac
106187bd3cdSWojciech Zajac ddekit_irq_unlock();
107187bd3cdSWojciech Zajac return irq_s;
108187bd3cdSWojciech Zajac }
109187bd3cdSWojciech Zajac
110187bd3cdSWojciech Zajac /******************************************************************************
111433d6423SLionel Sambuc * ddekit_irq_remove *
112433d6423SLionel Sambuc *****************************************************************************/
ddekit_irq_remove(struct ddekit_irq_s * irq_s)113433d6423SLionel Sambuc static void ddekit_irq_remove(struct ddekit_irq_s *irq_s)
114433d6423SLionel Sambuc {
115433d6423SLionel Sambuc struct ddekit_irq_s *i;
116433d6423SLionel Sambuc
117433d6423SLionel Sambuc ddekit_irq_lock();
118433d6423SLionel Sambuc
119433d6423SLionel Sambuc if(!irqs) {
120433d6423SLionel Sambuc ddekit_irq_unlock();
121433d6423SLionel Sambuc return;
122433d6423SLionel Sambuc }
123433d6423SLionel Sambuc
124433d6423SLionel Sambuc if(irqs==irq_s) {
125433d6423SLionel Sambuc irqs=irq_s->next;
126433d6423SLionel Sambuc ddekit_irq_unlock();
127433d6423SLionel Sambuc return;
128433d6423SLionel Sambuc }
129433d6423SLionel Sambuc
130433d6423SLionel Sambuc i = irqs;
131433d6423SLionel Sambuc
132433d6423SLionel Sambuc while(i) {
133433d6423SLionel Sambuc if (i->next == irq_s) {
134433d6423SLionel Sambuc i->next = irq_s->next;
135433d6423SLionel Sambuc ddekit_irq_unlock();
136433d6423SLionel Sambuc return;
137433d6423SLionel Sambuc }
138433d6423SLionel Sambuc i = i->next;
139433d6423SLionel Sambuc }
140433d6423SLionel Sambuc
141433d6423SLionel Sambuc ddekit_irq_unlock();
142433d6423SLionel Sambuc }
143433d6423SLionel Sambuc
144433d6423SLionel Sambuc /******************************************************************************
145433d6423SLionel Sambuc * ddekit_irq_thread *
146433d6423SLionel Sambuc *****************************************************************************/
ddekit_irq_thread(void * data)147433d6423SLionel Sambuc static void ddekit_irq_thread(void *data)
148433d6423SLionel Sambuc {
149433d6423SLionel Sambuc /* For each IRQ line an own thread is started */
150433d6423SLionel Sambuc
151433d6423SLionel Sambuc struct ddekit_irq_s *irq_s = (struct ddekit_irq_s *) data;
152433d6423SLionel Sambuc
153433d6423SLionel Sambuc /* call IRQ thread init function */
154433d6423SLionel Sambuc irq_s->thread_init(irq_s->priv);
155433d6423SLionel Sambuc
156433d6423SLionel Sambuc while(1) {
157433d6423SLionel Sambuc
158433d6423SLionel Sambuc /* Wait for IRQs */
159433d6423SLionel Sambuc DDEBUG_MSG_VERBOSE("wating for IRQ %d to occur", irq_s->irq);
160433d6423SLionel Sambuc ddekit_sem_down(irq_s->sem);
161433d6423SLionel Sambuc DDEBUG_MSG_VERBOSE("executing handler for IRQ %d", irq_s->irq);
162433d6423SLionel Sambuc irq_s->handler(irq_s->priv);
163433d6423SLionel Sambuc
164433d6423SLionel Sambuc }
165433d6423SLionel Sambuc }
166433d6423SLionel Sambuc
167433d6423SLionel Sambuc
168433d6423SLionel Sambuc /******************************************************************************
169433d6423SLionel Sambuc * DDEKIT public API (include/dde/ddekit) *
170433d6423SLionel Sambuc *****************************************************************************/
171433d6423SLionel Sambuc
172433d6423SLionel Sambuc /******************************************************************************
173433d6423SLionel Sambuc * ddekit_interrupt_attach *
174433d6423SLionel Sambuc *****************************************************************************/
ddekit_interrupt_attach(int irq,int shared,void (* thread_init)(void *),void (* handler)(void *),void * priv)175433d6423SLionel Sambuc ddekit_thread_t *ddekit_interrupt_attach(int irq,
176433d6423SLionel Sambuc int shared,
177433d6423SLionel Sambuc void(*thread_init)(void *),
178433d6423SLionel Sambuc void(*handler)(void *),
179433d6423SLionel Sambuc void *priv)
180433d6423SLionel Sambuc {
181433d6423SLionel Sambuc struct ddekit_irq_s *irq_s;
182187bd3cdSWojciech Zajac int err_code;
183433d6423SLionel Sambuc char name[32];
184433d6423SLionel Sambuc irq_s = (struct ddekit_irq_s *)
185433d6423SLionel Sambuc ddekit_simple_malloc(sizeof(struct ddekit_irq_s));
186433d6423SLionel Sambuc
187433d6423SLionel Sambuc irq_s->sem = ddekit_sem_init(0);
188187bd3cdSWojciech Zajac irq_s->irq = irq; /* represents real IRQ number */
189187bd3cdSWojciech Zajac ddekit_irq_lock();
190187bd3cdSWojciech Zajac irq_s->notify_id = next_notify_id; /* represents kernel's IRQ ID */
191187bd3cdSWojciech Zajac irq_s->irq_hook = next_notify_id; /* after given ID is passed to
192187bd3cdSWojciech Zajac * kernel, this field will be
193187bd3cdSWojciech Zajac * set to real irq_hook */
194187bd3cdSWojciech Zajac next_notify_id++; /* next time, assign different
195187bd3cdSWojciech Zajac * ID so we can distinguish
196187bd3cdSWojciech Zajac * interrupts */
197187bd3cdSWojciech Zajac ddekit_irq_unlock();
198433d6423SLionel Sambuc irq_s->shared = shared;
199433d6423SLionel Sambuc irq_s->thread_init = thread_init;
200433d6423SLionel Sambuc irq_s->handler = handler;
201433d6423SLionel Sambuc irq_s->priv = priv;
202433d6423SLionel Sambuc irq_s->next = 0;
203433d6423SLionel Sambuc irq_s->enabled = 1;
204433d6423SLionel Sambuc
205433d6423SLionel Sambuc /* create interrupt thread */
206433d6423SLionel Sambuc snprintf(name, 32, "ddekit_irq_%d",irq);
207433d6423SLionel Sambuc irq_s->th = ddekit_thread_create(ddekit_irq_thread, irq_s, name);
208433d6423SLionel Sambuc
209187bd3cdSWojciech Zajac /* try attaching to IRQ */
210187bd3cdSWojciech Zajac /* do not automatically re-enable interupts */
211187bd3cdSWojciech Zajac if (0 != (err_code = sys_irqsetpolicy(irq, 0, &irq_s->irq_hook)))
212187bd3cdSWojciech Zajac ddekit_panic("Failed to attach interrupt (ERROR %d)", err_code);
213433d6423SLionel Sambuc
214433d6423SLionel Sambuc /* add to IRQ list */
215433d6423SLionel Sambuc ddekit_irq_lock();
216433d6423SLionel Sambuc irq_s->next = irqs;
217433d6423SLionel Sambuc irqs=irq_s;
218433d6423SLionel Sambuc ddekit_irq_unlock();
219433d6423SLionel Sambuc
220433d6423SLionel Sambuc DDEBUG_MSG_INFO("Attached to irq %d (hook: %d)", irq, irq_s->irq_hook);
221433d6423SLionel Sambuc
222433d6423SLionel Sambuc return irq_s->th;
223433d6423SLionel Sambuc }
224433d6423SLionel Sambuc
225433d6423SLionel Sambuc /******************************************************************************
226433d6423SLionel Sambuc * ddekit_interrupt_detach *
227433d6423SLionel Sambuc *****************************************************************************/
ddekit_interrupt_detach(int irq)228433d6423SLionel Sambuc void ddekit_interrupt_detach(int irq)
229433d6423SLionel Sambuc {
230433d6423SLionel Sambuc struct ddekit_irq_s *irq_s;
231187bd3cdSWojciech Zajac int err_code;
232433d6423SLionel Sambuc
233433d6423SLionel Sambuc irq_s = find_by_irq(irq);
234433d6423SLionel Sambuc
235187bd3cdSWojciech Zajac if (0 != (err_code = sys_irqrmpolicy(&irq_s->irq_hook)))
236187bd3cdSWojciech Zajac ddekit_panic("Failed to detach interrupt (ERROR %d)", err_code);
237433d6423SLionel Sambuc
238433d6423SLionel Sambuc ddekit_thread_terminate(irq_s->th);
239433d6423SLionel Sambuc ddekit_irq_remove(irq_s);
240433d6423SLionel Sambuc ddekit_simple_free(irq_s);
241433d6423SLionel Sambuc DDEBUG_MSG_VERBOSE(" IRQ %d", irq);
242433d6423SLionel Sambuc }
243433d6423SLionel Sambuc
244433d6423SLionel Sambuc /******************************************************************************
245433d6423SLionel Sambuc * ddekit_interrupt_disable *
246433d6423SLionel Sambuc *****************************************************************************/
ddekit_interrupt_disable(int irq)247433d6423SLionel Sambuc void ddekit_interrupt_disable(int irq)
248433d6423SLionel Sambuc {
249433d6423SLionel Sambuc struct ddekit_irq_s *irq_s;
250433d6423SLionel Sambuc irq_s = find_by_irq(irq);
251433d6423SLionel Sambuc irq_s->enabled=0;
252433d6423SLionel Sambuc //sys_irqdisable(&irq_s->irq_hook);
253433d6423SLionel Sambuc DDEBUG_MSG_VERBOSE(" IRQ %d", irq);
254433d6423SLionel Sambuc }
255433d6423SLionel Sambuc
256433d6423SLionel Sambuc /******************************************************************************
257433d6423SLionel Sambuc * ddekit_interrupt_enable *
258433d6423SLionel Sambuc *****************************************************************************/
ddekit_interrupt_enable(int irq)259433d6423SLionel Sambuc void ddekit_interrupt_enable(int irq)
260433d6423SLionel Sambuc {
261433d6423SLionel Sambuc struct ddekit_irq_s *irq_s;
262433d6423SLionel Sambuc irq_s = find_by_irq(irq);
263433d6423SLionel Sambuc irq_s->enabled=1;
264433d6423SLionel Sambuc //sys_irqenable(&irq_s->irq_hook);
265433d6423SLionel Sambuc DDEBUG_MSG_VERBOSE(" IRQ %d", irq);
266433d6423SLionel Sambuc }
267433d6423SLionel Sambuc
268433d6423SLionel Sambuc /******************************************************************************
269433d6423SLionel Sambuc * ddekit_init_irqs *
270433d6423SLionel Sambuc *****************************************************************************/
ddekit_init_irqs()271433d6423SLionel Sambuc void ddekit_init_irqs()
272433d6423SLionel Sambuc {
273433d6423SLionel Sambuc ddekit_lock_init(&lock);
274433d6423SLionel Sambuc }
275433d6423SLionel Sambuc
276433d6423SLionel Sambuc /******************************************************************************
277433d6423SLionel Sambuc * DDEKIT internals (src/irq.h) *
278433d6423SLionel Sambuc *****************************************************************************/
279433d6423SLionel Sambuc
280433d6423SLionel Sambuc /******************************************************************************
281433d6423SLionel Sambuc * _ddekit_interrupt_trigger *
282433d6423SLionel Sambuc *****************************************************************************/
_ddekit_interrupt_trigger(int irq_id)283187bd3cdSWojciech Zajac void _ddekit_interrupt_trigger(int irq_id)
284433d6423SLionel Sambuc {
285433d6423SLionel Sambuc struct ddekit_irq_s *irq_s;
286187bd3cdSWojciech Zajac int err_code;
287433d6423SLionel Sambuc
288187bd3cdSWojciech Zajac irq_s = find_by_irq_id(irq_id);
289433d6423SLionel Sambuc
290433d6423SLionel Sambuc if (irq_s) {
291*2d64210cSWojciech Zajac DDEBUG_MSG_VERBOSE("Triggering IRQ %d", irq_s->irq);
292433d6423SLionel Sambuc ddekit_sem_up(irq_s->sem);
293187bd3cdSWojciech Zajac if (0 != (err_code = sys_irqenable(&irq_s->irq_hook)))
294187bd3cdSWojciech Zajac ddekit_panic("Failed to enable interrupt "
295187bd3cdSWojciech Zajac "(ERROR %d)", err_code);
296433d6423SLionel Sambuc } else {
297*2d64210cSWojciech Zajac DDEBUG_MSG_WARN("no handler for IRQ %d", irq_s->irq);
298433d6423SLionel Sambuc }
299433d6423SLionel Sambuc }
300433d6423SLionel Sambuc
301433d6423SLionel Sambuc
302