2 * This file is part of DDE/Linux2.6.
4 * (c) 2006-2010 Bjoern Doebel <doebel@os.inf.tu-dresden.de>
5 * Christian Helmuth <ch12@os.inf.tu-dresden.de>
6 * economic rights: Technische Universitaet Dresden (Germany)
8 * This file is part of TUD:OS and distributed under the terms of the
9 * GNU General Public License 2.
10 * Please see the COPYING-GPL-2 file for details.
14 * \brief Hardware-interrupt support
16 * XXX Consider support for IRQ_HANDLED and friends (linux/irqreturn.h)
20 #include <linux/interrupt.h>
21 #include <linux/string.h> /* memset() */
24 #include <l4/dde/ddekit/interrupt.h>
25 #include <l4/dde/ddekit/memory.h>
32 irq_cpustat_t irq_stat[CONFIG_NR_CPUS];
39 unsigned irq; /* IRQ number */
40 unsigned count; /* usage count */
41 int shared; /* shared IRQ */
42 struct ddekit_thread *thread; /* DDEKit interrupt thread */
43 struct irqaction *action; /* Linux IRQ action */
45 struct dde_irq *next; /* next DDE IRQ */
49 static void irq_thread_init(void *p) {
50 l4dde26_process_add_worker(); }
53 extern ddekit_sem_t *dde_softirq_sem;
54 static void irq_handler(void *arg)
56 struct dde_irq *irq = arg;
57 struct irqaction *action;
60 DEBUG_MSG("irq 0x%x", irq->irq);
62 /* interrupt occurred - call all handlers */
63 for (action = irq->action; action; action = action->next) {
64 irqreturn_t r = action->handler(action->irq, action->dev_id);
66 DEBUG_MSG("return: %s", r == IRQ_HANDLED ? "IRQ_HANDLED" : r == IRQ_NONE ? "IRQ_NONE" : "??");
70 /* upon return we check for pending soft irqs */
71 if (local_softirq_pending())
72 ddekit_sem_up(dde_softirq_sem);
76 /*****************************
77 ** IRQ handler bookkeeping **
78 *****************************/
83 * \return usage counter or negative error code
85 * FIXME are there more races?
87 static int claim_irq(struct irqaction *action)
89 int shared = action->flags & IRQF_SHARED ? 1 : 0;
92 /* check if IRQ already used */
93 for (irq = used_irqs; irq; irq = irq->next)
94 if (irq->irq == action->irq) break;
96 /* we have to setup IRQ handling */
98 /* allocate and initalize new descriptor */
99 irq = ddekit_simple_malloc(sizeof(*irq));
100 if (!irq) return -ENOMEM;
101 memset(irq, 0, sizeof(*irq));
103 irq->irq = action->irq;
104 irq->shared = shared;
106 /* attach to interrupt */
107 irq->thread = ddekit_interrupt_attach(irq->irq,
113 DEBUG_MSG("failed to attach IRQ");
114 ddekit_simple_free(irq);
118 /* FIXME list locking */
119 irq->next = used_irqs;
123 /* does desciptor allow our new handler? */
124 if ((!irq->shared || !shared) && irq->action) return -EBUSY;
128 action->next = irq->action;
129 irq->action = action;
136 * Free previously claimed IRQ
138 * \return usage counter or negative error code
140 static struct irqaction *release_irq(unsigned irq_num, void *dev_id)
142 struct dde_irq *prev_irq, *irq;
144 /* check if IRQ already used */
145 for (prev_irq = 0, irq = used_irqs; irq;
146 prev_irq = irq, irq = irq->next)
147 if (irq->irq == irq_num) break;
151 struct irqaction *prev_action, *action;
153 for (prev_action = 0, action = irq->action; action;
154 prev_action = action, action = action->next)
155 if (action->dev_id == dev_id) break;
157 if (!action) return 0;
159 /* dequeue action from irq */
161 prev_action->next = action->next;
163 irq->action = action->next;
165 /* dequeue irq from used_irqs list and free structure,
166 if no more actions available */
169 prev_irq->next = irq->next;
171 used_irqs = irq->next;
173 /* detach from interrupt */
174 ddekit_interrupt_detach(irq->irq);
176 ddekit_simple_free(irq);
190 * \param irq interrupt number
191 * \param handler interrupt handler -> top half
192 * \param flags interrupt handling flags (SA_SHIRQ, ...)
193 * \param dev_name device name
194 * \param dev_id cookie passed back to handler
196 * \return 0 on success; error code otherwise
198 * \todo FIXME consider locking!
200 int request_irq(unsigned int irq, irq_handler_t handler,
201 unsigned long flags, const char *dev_name, void *dev_id)
203 if (!handler) return -EINVAL;
205 /* facilitate Linux irqaction for this handler */
206 struct irqaction *irq_action = ddekit_simple_malloc(sizeof(*irq_action));
207 if (!irq_action) return -ENOMEM;
208 memset(irq_action, 0, sizeof(*irq_action));
210 irq_action->handler = handler;
211 irq_action->flags = flags;
212 irq_action->name = dev_name;
213 irq_action->dev_id = dev_id;
214 irq_action->irq = irq;
217 int err = claim_irq(irq_action);
218 if (err < 0) return err;
223 /** Release Interrupt
226 * \param irq interrupt number
227 * \param dev_id cookie passed back to handler
230 void free_irq(unsigned int irq, void *dev_id)
232 struct irqaction *irq_action = release_irq(irq, dev_id);
235 ddekit_simple_free(irq_action);
238 void disable_irq(unsigned int irq)
240 ddekit_interrupt_disable(irq);
243 void disable_irq_nosync(unsigned int irq)
247 * In contrast to the _nosync semantics, DDEKit's
248 * disable definitely waits until a currently executed
249 * IRQ handler terminates.
251 ddekit_interrupt_disable(irq);
254 void enable_irq(unsigned int irq)
256 ddekit_interrupt_enable(irq);