]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/input/lib/src/emul_irq.c
update
[l4.git] / l4 / pkg / input / lib / src / emul_irq.c
1 /*****************************************************************************/
2 /**
3  * \file   input/lib/src/emul_irq.c
4  * \brief  L4INPUT: Linux IRQ handling emulation
5  *
6  * \date   11/20/2003
7  * \author Christian Helmuth <ch12@os.inf.tu-dresden.de>
8  * \author Frank Mehnert <fm3@os.inf.tu-dresden.de>
9  *
10  */
11 /*
12  * (c) 2003-2009 Author(s)
13  *     economic rights: Technische Universität Dresden (Germany)
14  *
15  * This file is part of TUD:OS and distributed under the terms of the
16  * GNU General Public License 2.
17  * Please see the COPYING-GPL-2 file for details.
18  */
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <l4/sys/ipc.h>
23 #include <l4/sys/types.h>
24 //#include <l4/util/irq.h>
25 #include <l4/irq/irq.h>
26 #if !defined(ARCH_arm) && !defined(ARCH_ppc32) && !defined(ARCH_sparc)
27 #include <l4/util/port_io.h>
28 #endif
29 #include <l4/util/macros.h>
30
31 #include <pthread.h>
32
33 /* Linux */
34 #include <linux/interrupt.h>
35
36 #include "internal.h"
37
38 #define DEBUG_IRQ         0
39 #define DEBUG_IRQ_VERBOSE 0
40
41 /* return within 50ms even if there was no interrupt */
42 #define IRQ_TIMEOUT       l4_ipc_timeout(0,0,781,6)
43
44 /* INTERRUPT HANDLING EMULATION */
45
46 static struct irq_desc {
47         int active;
48         int num;
49         void *cookie;
50         pthread_t t;
51         pthread_mutex_t startup;
52         irqreturn_t (*handler)(int, void *, struct pt_regs *);
53 } handlers[NR_IRQS];
54
55 static int irq_prio   = -1;
56
57 /* OMEGA0 STUFF */
58
59 #define OM_MASK    0x00000001
60 #define OM_UNMASK  0x00000002
61 #define OM_CONSUME 0x00000004
62 #define OM_AGAIN   0x00000008
63
64 /** Attach IRQ line.
65  *
66  * \param  irq           IRQ number
67  * \retval handle        IRQ handle
68  *
69  * \return 0 on success (attached interrupt), -1 if attach failed.
70  */
71 static inline int __omega0_attach(unsigned int irq, l4irq_t **handle)
72 {
73   return (*handle = l4irq_attach(irq)) ? 0 : -1;
74 }
75
76 /** Wait for IRQ notification.
77  *
78  * \param  irq           IRQ number
79  * \param  handle        IRQ line handle
80  * \param  flags         Flags:
81  *                       - \c OM_MASK    request IRQ mask
82  *                       - \c OM_UNMASK  request IRQ unmask
83  *                       - \c OM_CONSUME IRQ consumed
84  * \return               0 for success
85  *                       L4_IPC_RETIMEOUT if no IRQ was received (timeout)
86  */
87 static inline int __omega0_wait(unsigned int irq, l4irq_t *handle,
88                                 unsigned int flags)
89 {
90   return l4irq_wait(handle);
91 }
92
93 /** IRQ HANDLER THREAD.
94  *
95  * \param irq_desc  IRQ handling descriptor (IRQ number and handler routine)
96  */
97 static void *__irq_handler(void *_data)
98 {
99         struct irq_desc *irq_desc = (struct irq_desc *)_data;
100         unsigned int irq = irq_desc->num; /* save irq number */
101         void *cookie = irq_desc->cookie;  /* save cookie/dev_id pointer */
102         long ret;
103         l4irq_t *irq_handle;
104         unsigned int om_flags;
105
106         /* get permission for attaching to IRQ */
107         ret = __omega0_attach(irq, &irq_handle);
108         if (ret < 0)
109           {
110             fprintf(stderr, "failed to attach IRQ %d!\n", irq);
111             return NULL;
112           }
113
114         /* we are up */
115         ret = pthread_mutex_unlock(&handlers[irq].startup);
116
117 #if DEBUG_IRQ
118         printf("emul_irq.c: __irq_handler %p for IRQ %d running\n",
119                irq_desc->handler, irq);
120 #endif
121
122         if (ret)
123           {
124             fprintf(stderr, "IRQ thread startup failed!\n");
125             return NULL;
126           }
127
128         om_flags = OM_UNMASK;
129         for (;;) {
130                 ret = __omega0_wait(irq, irq_handle, om_flags);
131
132                 switch (ret) {
133                 case 0:
134 #if DEBUG_IRQ_VERBOSE
135                         printf("emul_irq.c: got IRQ %d\n", irq);
136 #endif
137                         if (irq_desc->active)
138                                 irq_desc->handler(irq, cookie, NULL);
139                         om_flags = 0;
140                         break;
141
142 #if 0
143                 case L4_IPC_RETIMEOUT:
144                         if (irq_desc->active)
145                                 irq_desc->handler(irq, cookie, NULL);
146                         om_flags = OM_AGAIN;
147                         break;
148 #endif
149
150                 default:
151                         fprintf(stderr, "error receiving irq\n");
152                         return NULL;
153                 }
154         }
155 }
156
157 /** Request Interrupt.
158  * \ingroup grp_irq
159  *
160  * \param irq      interrupt number
161  * \param handler  interrupt handler -> top half
162  * \param ...
163  * \param cookie   cookie pointer passed back
164  *
165  * \return 0 on success; error code otherwise
166  */
167 int request_irq(unsigned int irq,
168                 irqreturn_t (*handler)(int, void *, struct pt_regs *),
169                 unsigned long flags, const char *devname, void *cookie)
170 {
171         pthread_t irq_tid;
172         char buf[7];
173
174         if (irq >= NR_IRQS)
175                 return -L4_EINVAL;
176         if (!handler)
177                 return -L4_EINVAL;
178
179         handlers[irq].num = irq;
180         handlers[irq].cookie = cookie;
181         handlers[irq].handler = handler;
182
183         handlers[irq].active = 1;
184
185         if(handlers[irq].t) {
186 #if DEBUG_IRQ
187                 printf("emul_irq.c: reattached to irq %d\n", irq);
188 #endif
189                 return 0;
190         }
191
192         sprintf(buf, ".irq%.2X", irq);
193         /* create IRQ handler thread */
194         pthread_mutex_init(&handlers[irq].startup, NULL);
195         pthread_mutex_lock(&handlers[irq].startup);
196
197         pthread_attr_t a;
198         pthread_attr_init(&a);
199         if (irq_prio != -1) {
200             struct sched_param sp;
201             sp.sched_priority = irq_prio;
202             pthread_attr_setschedpolicy(&a, SCHED_L4);
203             pthread_attr_setschedparam(&a, &sp);
204             pthread_attr_setinheritsched(&a, PTHREAD_EXPLICIT_SCHED);
205         }
206         if (pthread_create(&irq_tid, &a, __irq_handler, (void *)
207                            &handlers[irq]))
208           {
209             printf("emul_irq.c: Creating irq-thread failed\n");
210             pthread_mutex_unlock(&handlers[irq].startup);
211             return 0;
212           }
213
214         pthread_mutex_lock(&handlers[irq].startup);
215         pthread_mutex_unlock(&handlers[irq].startup);
216
217 #if DEBUG_IRQ
218         printf("emul_irq.c: attached to irq %d\n", irq);
219 #endif
220
221         handlers[irq].t = irq_tid;
222
223         return 0;
224 }
225
226 /** Release Interrupt.
227  *
228  * \param irq     interrupt number
229  * \param cookie  cookie pointer passed back
230  *
231  * \todo Implementation.
232  */
233 void free_irq(unsigned int irq, void *cookie)
234 {
235         handlers[irq].active = 0;
236
237 #if DEBUG_IRQ
238         printf("emul_irq.c: attempt to free irq %d\n", irq);
239 #endif
240 }
241
242 /* INTERRUPT EMULATION INITIALIZATION */
243 void l4input_internal_irq_init(int prio)
244 {
245         irq_prio   = prio;
246
247         memset(&handlers, 0, sizeof(handlers));
248 }