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

[tyndur-devel] [PATCH v2 02/24] cdi/misc: Erlaube IRQ-Sharing



* Dass Treiber mehrere Geräte verwalten, ist nicht selten. Dass mehrere
  Geräte denselben IRQ verwenden, ebenfalls nicht (zumindest, wenn man
  die IRQs nicht neu zuweist). Damit sollte die CDI-Bibliothek es auf
  jeden Fall erlauben, dass mehrere Handler für denselben IRQ angelegt
  werden.

Signed-off-by: Max Reitz <max@xxxxxxxxxx>
---
 src/modules/cdi/lib/misc.c | 37 +++++++++++++++++++++++--------------
 1 file changed, 23 insertions(+), 14 deletions(-)

diff --git a/src/modules/cdi/lib/misc.c b/src/modules/cdi/lib/misc.c
index 11661b4..1b965af 100644
--- a/src/modules/cdi/lib/misc.c
+++ b/src/modules/cdi/lib/misc.c
@@ -9,6 +9,7 @@
  */  
 
 #include <stdint.h>
+#include <stdlib.h>
 #include <syscall.h>
 #include <rpc.h>
 #include <sleep.h>
@@ -22,10 +23,16 @@
 /** Anzahl der verfuegbaren IRQs */
 #define IRQ_COUNT           0x10
 
+struct irq_handler {
+    struct irq_handler* next;
+
+    void (*handler)(struct cdi_device* dev);
+    struct cdi_device* dev;
+};
+
 /** 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 };
+static struct irq_handler* driver_irq_handlers[IRQ_COUNT];
+
 /**
  * Array, das die jeweilige Anzahl an aufgerufenen Interrupts seit dem
  * cdi_reset_wait_irq speichert.
@@ -44,8 +51,8 @@ static void irq_handler(uint8_t irq)
 
     irq -= TYNDUR_IRQ_OFFSET;
     driver_irq_count[irq]++;
-    if (driver_irq_handler[irq]) {
-        driver_irq_handler[irq](driver_irq_device[irq]);
+    for (struct irq_handler* h = driver_irq_handlers[irq]; h; h = h->next) {
+        h->handler(h->dev);
     }
 }
 
@@ -65,16 +72,18 @@ void cdi_register_irq(uint8_t irq, void (*handler)(struct cdi_device*),
         return;
     }
 
-    // Der Interrupt wurde schon mal registriert
-    if (driver_irq_handler[irq]) {
-        fprintf(stderr, "cdi: Versuch IRQ %d mehrfach zu registrieren\n", irq);
-        return;
-    }
+    struct irq_handler* h = malloc(sizeof(*h));
+    *h = (struct irq_handler){
+        .next    = driver_irq_handlers[irq],
+        .handler = handler,
+        .dev     = device
+    };
 
-    driver_irq_handler[irq] = handler;
-    driver_irq_device[irq] = device;
+    driver_irq_handlers[irq] = h;
 
-    register_intr_handler(TYNDUR_IRQ_OFFSET + irq, irq_handler);
+    if (!h->next) {
+        register_intr_handler(TYNDUR_IRQ_OFFSET + irq, irq_handler);
+    }
 }
 
 /**
@@ -118,7 +127,7 @@ int cdi_wait_irq(uint8_t irq, uint32_t timeout)
         return -1;
     }
 
-    if (!driver_irq_handler[irq]) {
+    if (!driver_irq_handlers[irq]) {
         return -2;
     }
 
-- 
2.6.3