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