xref: /minix/minix/lib/libddekit/src/irq.c (revision 9f988b79)
1 #include "common.h"
2 #include <ddekit/interrupt.h>
3 #include <ddekit/memory.h>
4 #include <ddekit/panic.h>
5 #include <ddekit/semaphore.h>
6 #include <ddekit/thread.h>
7 
8 #ifdef DDEBUG_LEVEL_IRQ
9 #undef DDEBUG
10 #define DDEBUG DDEBUG_LEVEL_IRQ
11 #endif
12 
13 #include "debug.h"
14 
15 struct ddekit_irq_s {
16 	int irq;
17 	int notify_id;
18 	int irq_hook;
19 	int shared;
20 	void(*thread_init)(void *);
21 	void(*handler)(void *);
22 	void *priv;
23 	int enabled;
24 	ddekit_thread_t *th;
25 	ddekit_sem_t *sem;
26 	struct ddekit_irq_s *next;
27 };
28 
29 static struct ddekit_irq_s *irqs = 0;
30 static ddekit_lock_t lock;
31 static int next_notify_id = 0; /* TODO: This is only incremented and after
32 				* enough interrupt attachments/detachments
33 				* we can run out of legal IDs (this is however
34 				* very atypical use case) */
35 
36 /******************************************************************************
37  *    Local helpers                                                           *
38  *****************************************************************************/
39 
40 
41 static void ddekit_irq_lock(void);
42 static void ddekit_irq_unlock(void);
43 static struct ddekit_irq_s* find_by_irq(int irq);
44 static struct ddekit_irq_s* find_by_irq_id(int irq_id);
45 static void ddekit_irq_remove(struct ddekit_irq_s *irq_s);
46 static void ddekit_irq_thread(void *data);
47 
48 /******************************************************************************
49  *       ddekit_irq_lock                                                      *
50  *****************************************************************************/
51 static void  ddekit_irq_lock(void)
52 {
53 	ddekit_lock_lock(&lock);
54 }
55 
56 /******************************************************************************
57  *       ddekit_irq_unlock                                                    *
58  *****************************************************************************/
59 static void ddekit_irq_unlock(void)
60 {
61 	ddekit_lock_unlock(&lock);
62 }
63 
64 /******************************************************************************
65  *       find_by_irq                                                          *
66  *****************************************************************************/
67 static struct ddekit_irq_s * find_by_irq(int irq)
68 {
69 	struct ddekit_irq_s * irq_s;
70 	ddekit_irq_lock();
71 	if (!irqs) {
72 		return 0;
73 	}
74 
75 	irq_s = irqs;
76 
77 	while(irq_s) {
78 		if(irq_s->irq==irq)
79 			break;
80 		irq_s = irq_s->next;
81 	}
82 
83 	ddekit_irq_unlock();
84 	return irq_s;
85 }
86 
87 /******************************************************************************
88  *       find_by_irq_id                                                       *
89  *****************************************************************************/
90 static struct ddekit_irq_s * find_by_irq_id(int irq_id)
91 {
92 	struct ddekit_irq_s * irq_s;
93 	ddekit_irq_lock();
94 	if (!irqs) {
95 		return 0;
96 	}
97 
98 	irq_s = irqs;
99 
100 	while(irq_s) {
101 		if(irq_s->notify_id==irq_id)
102 			break;
103 		irq_s = irq_s->next;
104 	}
105 
106 	ddekit_irq_unlock();
107 	return irq_s;
108 }
109 
110 /******************************************************************************
111  *       ddekit_irq_remove                                                    *
112  *****************************************************************************/
113 static void ddekit_irq_remove(struct ddekit_irq_s *irq_s)
114 {
115 	struct ddekit_irq_s *i;
116 
117 	ddekit_irq_lock();
118 
119 	if(!irqs) {
120 		ddekit_irq_unlock();
121 		return;
122 	}
123 
124 	if(irqs==irq_s) {
125 		irqs=irq_s->next;
126 		ddekit_irq_unlock();
127 		return;
128 	}
129 
130 	i = irqs;
131 
132 	while(i) {
133 		if (i->next == irq_s)  {
134 			i->next = irq_s->next;
135 			ddekit_irq_unlock();
136 			return;
137 		}
138 		i = i->next;
139 	}
140 
141 	ddekit_irq_unlock();
142 }
143 
144 /******************************************************************************
145  *       ddekit_irq_thread                                                    *
146  *****************************************************************************/
147 static void ddekit_irq_thread(void *data)
148 {
149 	/* For each IRQ line an own thread is started */
150 
151 	struct ddekit_irq_s *irq_s = (struct ddekit_irq_s *) data;
152 
153 	/* call IRQ thread init function */
154 	irq_s->thread_init(irq_s->priv);
155 
156 	while(1) {
157 
158 		/* Wait for IRQs */
159 		DDEBUG_MSG_VERBOSE("wating for IRQ %d to occur", irq_s->irq);
160 		ddekit_sem_down(irq_s->sem);
161 		DDEBUG_MSG_VERBOSE("executing handler for IRQ %d", irq_s->irq);
162 		irq_s->handler(irq_s->priv);
163 
164 	}
165 }
166 
167 
168 /******************************************************************************
169  *   DDEKIT public API (include/dde/ddekit)                                   *
170  *****************************************************************************/
171 
172 /******************************************************************************
173  *       ddekit_interrupt_attach                                              *
174  *****************************************************************************/
175 ddekit_thread_t *ddekit_interrupt_attach(int irq,
176                                          int shared,
177                                          void(*thread_init)(void *),
178                                          void(*handler)(void *),
179                                          void *priv)
180 {
181 	struct ddekit_irq_s *irq_s;
182 	int err_code;
183 	char name[32];
184 	irq_s = (struct ddekit_irq_s *)
185 	                ddekit_simple_malloc(sizeof(struct ddekit_irq_s));
186 
187 	irq_s->sem         = ddekit_sem_init(0);
188 	irq_s->irq         = irq;		/* represents real IRQ number */
189 	ddekit_irq_lock();
190 	irq_s->notify_id   = next_notify_id;	/* represents kernel's IRQ ID */
191 	irq_s->irq_hook    = next_notify_id;	/* after given ID is passed to
192 						 * kernel, this field will be
193 						 * set to real irq_hook */
194 	next_notify_id++;			/* next time, assign different
195 						 * ID so we can distinguish
196 						 * interrupts */
197 	ddekit_irq_unlock();
198 	irq_s->shared      = shared;
199 	irq_s->thread_init = thread_init;
200 	irq_s->handler     = handler;
201 	irq_s->priv        = priv;
202 	irq_s->next        = 0;
203 	irq_s->enabled     = 1;
204 
205 	/* create interrupt thread */
206 	snprintf(name, 32, "ddekit_irq_%d",irq);
207 	irq_s->th = ddekit_thread_create(ddekit_irq_thread, irq_s, name);
208 
209 	/* try attaching to IRQ */
210 	/* do not automatically re-enable interupts */
211 	if (0 != (err_code = sys_irqsetpolicy(irq, 0, &irq_s->irq_hook)))
212 		ddekit_panic("Failed to attach interrupt (ERROR %d)", err_code);
213 
214 	/* add to IRQ list */
215 	ddekit_irq_lock();
216 	irq_s->next = irqs;
217 	irqs=irq_s;
218 	ddekit_irq_unlock();
219 
220 	DDEBUG_MSG_INFO("Attached to irq %d (hook: %d)", irq, irq_s->irq_hook);
221 
222 	return irq_s->th;
223 }
224 
225 /******************************************************************************
226  *       ddekit_interrupt_detach                                              *
227  *****************************************************************************/
228 void ddekit_interrupt_detach(int irq)
229 {
230 	struct ddekit_irq_s *irq_s;
231 	int err_code;
232 
233 	irq_s = find_by_irq(irq);
234 
235 	if (0 != (err_code = sys_irqrmpolicy(&irq_s->irq_hook)))
236 		ddekit_panic("Failed to detach interrupt (ERROR %d)", err_code);
237 
238 	ddekit_thread_terminate(irq_s->th);
239 	ddekit_irq_remove(irq_s);
240 	ddekit_simple_free(irq_s);
241 	DDEBUG_MSG_VERBOSE(" IRQ %d", irq);
242 }
243 
244 /******************************************************************************
245  *       ddekit_interrupt_disable                                             *
246  *****************************************************************************/
247 void ddekit_interrupt_disable(int irq)
248 {
249 	struct ddekit_irq_s *irq_s;
250 	irq_s = find_by_irq(irq);
251 	irq_s->enabled=0;
252 	//sys_irqdisable(&irq_s->irq_hook);
253 	DDEBUG_MSG_VERBOSE(" IRQ %d", irq);
254 }
255 
256 /******************************************************************************
257  *       ddekit_interrupt_enable                                              *
258  *****************************************************************************/
259 void ddekit_interrupt_enable(int irq)
260 {
261 	struct ddekit_irq_s *irq_s;
262 	irq_s = find_by_irq(irq);
263 	irq_s->enabled=1;
264 	//sys_irqenable(&irq_s->irq_hook);
265 	DDEBUG_MSG_VERBOSE(" IRQ %d", irq);
266 }
267 
268 /******************************************************************************
269  *       ddekit_init_irqs                                                     *
270  *****************************************************************************/
271 void ddekit_init_irqs()
272 {
273 	ddekit_lock_init(&lock);
274 }
275 
276 /******************************************************************************
277  *   DDEKIT internals (src/irq.h)                                             *
278  *****************************************************************************/
279 
280 /******************************************************************************
281  *       _ddekit_interrupt_trigger                                            *
282  *****************************************************************************/
283 void _ddekit_interrupt_trigger(int irq_id)
284 {
285 	struct ddekit_irq_s *irq_s;
286 	int err_code;
287 
288 	irq_s = find_by_irq_id(irq_id);
289 
290 	if (irq_s)	{
291 		DDEBUG_MSG_VERBOSE("Triggering IRQ %d", irq_s->irq);
292 		ddekit_sem_up(irq_s->sem);
293 		if (0 != (err_code = sys_irqenable(&irq_s->irq_hook)))
294 			ddekit_panic("Failed to enable interrupt "
295 					"(ERROR %d)", err_code);
296 	} else {
297 		DDEBUG_MSG_WARN("no handler for IRQ %d", irq_s->irq);
298 	}
299 }
300 
301 
302