[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[tyndur-devel] [PATCH 2/3] cdi/core: Mehrere IRQ-Handler pro Treiber



! cdi/core: Jetzt funktioniert das mit den IRQs auch, wenn man mal auf
            absurde Idee kommt, mehrere IRQs in einem Treiber benutzen
            zu wollen. ;-)
---
 src/modules/cdi/lib/misc.c |   43 +++++++++++++++++++++++++++++++++++--------
 1 files changed, 35 insertions(+), 8 deletions(-)

diff --git a/src/modules/cdi/lib/misc.c b/src/modules/cdi/lib/misc.c
index d30d1b4..39047d7 100644
--- a/src/modules/cdi/lib/misc.c
+++ b/src/modules/cdi/lib/misc.c
@@ -12,20 +12,35 @@
 #include <syscall.h>
 #include <rpc.h>
 #include <sleep.h>
+#include <stdio.h>
 
 #include "cdi.h"
 #include "cdi/misc.h"
 
-// TODO Bei mehr als einem registrierten IRQ geht das so nicht mehr
-static void (*driver_irq_handler)(struct cdi_device*) = NULL;
-static struct cdi_device* driver_irq_device = NULL;
+/** Ab diesem Interrupt fangen bei tyndur die IRQs an */
+#define TYNDUR_IRQ_OFFSET   0x20
+/** Anzahl der verfuegbaren IRQs */
+#define IRQ_COUNT           0x10
+
+/** Array mit allen IRQ-Handlern; Als index wird die Nummer benutzt */
+static void (*driver_irq_handler[IRQ_COUNT])(struct cdi_device*) = { NULL };
+/** Array mit den passenden Geraeten zu den registrierten IRQs */
+static struct cdi_device* driver_irq_device[IRQ_COUNT] = { NULL };
 
 /**
  * Interner IRQ-Handler, der den IRQ-Handler des Treibers aufruft
  */
 static void irq_handler(uint8_t irq)
 {
-    driver_irq_handler(driver_irq_device);
+    // Ups, das war wohl kein IRQ, den wollen wir nicht.
+    if ((irq < TYNDUR_IRQ_OFFSET) || (irq >= TYNDUR_IRQ_OFFSET + IRQ_COUNT)) {
+        return;
+    }
+
+    irq -= TYNDUR_IRQ_OFFSET;
+    if (driver_irq_handler[irq]) {
+        driver_irq_handler[irq](driver_irq_device[irq]);
+    }
 }
 
 /**
@@ -35,13 +50,25 @@ static void irq_handler(uint8_t irq)
  * @param handler Handlerfunktion
  * @param device Geraet, das dem Handler als Parameter uebergeben werden soll
  */
-void cdi_register_irq(uint8_t irq, void (*handler)(struct cdi_device*), 
+void cdi_register_irq(uint8_t irq, void (*handler)(struct cdi_device*),
     struct cdi_device* device)
 {
-    driver_irq_handler = handler;
-    driver_irq_device = device;
+    if (irq > IRQ_COUNT) {
+        // FIXME: Eigentlich sollte diese Funktion etwas weniger optimistisch
+        // sein, und einen Rueckgabewert haben.
+        return;
+    }
+
+    // Der Interrupt wurde schon mal registriert
+    if (driver_irq_handler[irq]) {
+        fprintf(stderr, "cdi: Versuch IRQ %d mehrfach zu registrieren\n", irq);
+        return;
+    }
+
+    driver_irq_handler[irq] = handler;
+    driver_irq_device[irq] = device;
 
-    register_intr_handler(0x20 + irq, irq_handler);
+    register_intr_handler(TYNDUR_IRQ_OFFSET + irq, irq_handler);
 }
     
 /**
-- 
1.6.0.6