[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[tyndur-devel] [PATCH 3/3] cdi/core: Funktionen um auf IRQs zu warten
+ cdi/core: Zwei neue Funktionen um effizient auf IRQs zu warten
---
src/modules/cdi/include/cdi/misc.h | 24 +++++++++++-
src/modules/cdi/lib/misc.c | 73 +++++++++++++++++++++++++++++++++++-
2 files changed, 95 insertions(+), 2 deletions(-)
diff --git a/src/modules/cdi/include/cdi/misc.h b/src/modules/cdi/include/cdi/misc.h
index dc9e277..2a130f6 100644
--- a/src/modules/cdi/include/cdi/misc.h
+++ b/src/modules/cdi/include/cdi/misc.h
@@ -24,7 +24,29 @@
*/
void cdi_register_irq(uint8_t irq, void (*handler)(struct cdi_device*),
struct cdi_device* device);
-
+
+/**
+ * Setzt den IRQ-Zaehler fuer cdi_wait_irq zurueck.
+ *
+ * @param irq Nummer des IRQ
+ *
+ * @return 0 bei Erfolg, -1 im Fehlerfall
+ */
+int cdi_reset_wait_irq(uint8_t irq);
+
+/**
+ * Wartet bis der IRQ aufgerufen wurde. Der interne Zaehler muss zuerst mit
+ * cdi_reset_wait_irq zurueckgesetzt werden, damit auch die IRQs abgefangen
+ * werden koennen, die kurz vor dem Aufruf von dieser Funktion aufgerufen
+ * werden.
+ *
+ * @param irq Nummer des IRQ auf den gewartet werden soll
+ * @param timeout Anzahl der Millisekunden, die maximal gewartet werden sollen
+ *
+ * @return 0 wenn der irq aufgerufen wurde, -1 sonst.
+ */
+int cdi_wait_irq(uint8_t irq, uint32_t timeout);
+
/**
* Reserviert physisch zusammenhaengenden Speicher.
*
diff --git a/src/modules/cdi/lib/misc.c b/src/modules/cdi/lib/misc.c
index ae66a9e..4f2c19d 100644
--- a/src/modules/cdi/lib/misc.c
+++ b/src/modules/cdi/lib/misc.c
@@ -21,6 +21,7 @@
static void (*driver_irq_handler[IRQ_COUNT])(struct cdi_device*) = { NULL };
static struct cdi_device* driver_irq_device[IRQ_COUNT] = { NULL };
+static uint8_t driver_irq_count[IRQ_COUNT] = { 0 };
/**
* Interner IRQ-Handler, der den IRQ-Handler des Treibers aufruft
@@ -33,6 +34,7 @@ static void irq_handler(uint8_t irq)
}
irq -= LOST_IRQ_OFFSET;
+ driver_irq_count[irq]++;
if (driver_irq_handler[irq]) {
driver_irq_handler[irq](driver_irq_device[irq]);
}
@@ -59,7 +61,76 @@ void cdi_register_irq(uint8_t irq, void (*handler)(struct cdi_device*),
register_intr_handler(LOST_IRQ_OFFSET + irq, irq_handler);
}
-
+
+/**
+ * Setzt den IRQ-Zaehler fuer cdi_wait_irq zurueck.
+ *
+ * @param irq Nummer des IRQ
+ *
+ * @return 0 bei Erfolg, -1 im Fehlerfall
+ */
+int cdi_reset_wait_irq(uint8_t irq)
+{
+ if (irq > IRQ_COUNT) {
+ return -1;
+ }
+
+ driver_irq_count[irq] = 0;
+ return 0;
+}
+
+// Dummy-Callback fuer den timer_register-Aufruf in cdi_wait_irq
+static void wait_irq_dummy_callback(void) { }
+
+/**
+ * Wartet bis der IRQ aufgerufen wurde. Der interne Zaehler muss zuerst mit
+ * cdi_reset_wait_irq zurueckgesetzt werden, damit auch die IRQs abgefangen
+ * werden koennen, die kurz vor dem Aufruf von dieser Funktion aufgerufen
+ * werden.
+ *
+ * @param irq Nummer des IRQ auf den gewartet werden soll
+ * @param timeout Anzahl der Millisekunden, die maximal gewartet werden sollen
+ *
+ * @return 0 wenn der irq aufgerufen wurde, -1 wenn eine ungueltige IRQ-Nummer
+ * angegeben wurde, -2 wenn eine nicht registrierte IRQ-Nummer angegeben wurde,
+ * und -3 im Falle eines Timeouts.
+ */
+int cdi_wait_irq(uint8_t irq, uint32_t timeout)
+{
+ uint64_t timeout_ticks;
+
+ if (irq > IRQ_COUNT) {
+ return -1;
+ }
+
+ if (!driver_irq_handler[irq]) {
+ return -2;
+ }
+
+ // Wenn der IRQ bereits gefeuert wurde, koennen wir uns ein paar Syscalls
+ // sparen
+ if (driver_irq_count [irq]) {
+ return 0;
+ }
+
+ timeout_ticks = get_tick_count() + (uint64_t) timeout * 1000;
+ timer_register(wait_irq_dummy_callback, timeout * 1000);
+
+ p();
+ while (!driver_irq_count [irq]) {
+ v_and_wait_for_rpc();
+
+ if (timeout_ticks < get_tick_count()) {
+ return -3;
+ }
+ p();
+ }
+ v();
+
+ return 0;
+}
+
+
/**
* Reserviert physisch zusammenhaengenden Speicher.
*
--
1.6.0.6