summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/genirq.h47
-rw-r--r--c/src/lib/libbsp/sparc/shared/irq/genirq.c58
2 files changed, 63 insertions, 42 deletions
diff --git a/c/src/lib/libbsp/sparc/shared/include/genirq.h b/c/src/lib/libbsp/sparc/shared/include/genirq.h
index d03b812437..673be173b1 100644
--- a/c/src/lib/libbsp/sparc/shared/include/genirq.h
+++ b/c/src/lib/libbsp/sparc/shared/include/genirq.h
@@ -35,7 +35,7 @@ struct genirq_stats {
extern genirq_t genirq_init(int number_of_irqs);
/* Free the dynamically allocated memory that the genirq interface has
- * allocated.
+ * allocated. Also the handlers will be freed.
*
* Returns zero on success, otherwise failure.
*/
@@ -47,33 +47,54 @@ extern void genirq_destroy(genirq_t d);
*/
extern int genirq_check(genirq_t d, int irq);
-/* Register shared interrupt handler.
+/* Allocate one ISR handler and initialize it. Input to genirq_register().
*
- * \param irq The interrupt number to register ISR on
* \param isr The interrupt service routine called upon IRQ
* \param arg The argument given to isr() when called.
*
+ * Returns a pointer on success, on failure NULL is returned.
+ */
+extern void *genirq_alloc_handler(genirq_handler isr, void *arg);
+
+/* Free handler memory */
+#define genirq_free_handler(handler) free(handler)
+
+/* Register shared interrupt handler previously initialized with
+ * genirq_alloc_handler().
+ *
+ * NOTE: internal list structures are accessed and needs to be protected by
+ * spin-locks/IRQ disable by the user to guarantee a correct behaviour.
+ *
+ * \param irq The interrupt number to register ISR on
+ * \param handler Install the pre- allocated and initialized handler.
+ *
* Return Values
* -1 = Failed
* 0 = Handler registered Successfully, first handler on this IRQ
* 1 = Handler registered Successfully, _not_ first handler on this IRQ
*/
-extern int genirq_register(genirq_t d, int irq, genirq_handler isr, void *arg);
+extern int genirq_register(genirq_t d, int irq, void *handler);
-/* Unregister an previous registered interrupt handler
+/* Unregister an previous registered interrupt handler. It is the user's
+ * responsibility to free the handler returned by genirq_unregister().
+ *
+ * NOTE: internal list structures are accessed and needs to be protected by
+ * spin-locks/IRQ disable by the user to guarantee a correct behaviour.
*
* Return Values
- * -1 = ISR not registered before
- * 0 = ISR unregistered
- * 1 = Unable to unregister enabled ISR
+ * NULL = ISR not registered before or unable to unregister enabled ISR
+ * Pointer = ISR sucessfully unregistered. Returned is the handler pointer
+ * previously allocated with genirq_alloc_handler().
*/
-extern int genirq_unregister(genirq_t d, int irq, genirq_handler isr, void *arg);
+extern void *genirq_unregister(genirq_t d, int irq,
+ genirq_handler isr, void *arg);
/* Enables IRQ only for this isr[arg] combination. Records if this
* is the first interrupt enable, only then must interrupts be enabled
* on the interrupt controller.
*
- * IRQs must be disabled before entering this function.
+ * NOTE: internal list structures are accessed and needs to be protected by
+ * spin-locks/IRQ disable by the user to guarantee a correct behaviour.
*
* Return values
* -1 = Failure, for example isr[arg] not registered on this irq
@@ -86,7 +107,8 @@ extern int genirq_enable(genirq_t d, int irq, genirq_handler isr, void *arg);
* is the only interrupt handler that is enabled on this IRQ, only then
* must interrupts be disabled on the interrupt controller.
*
- * IRQs must be disabled before entering this function.
+ * NOTE: internal list structures are accessed and needs to be protected by
+ * spin-locks/IRQ disable by the user to guarantee a correct behaviour.
*
* Return values
* -1 = Failure, for example isr[arg] not registered on this irq
@@ -97,6 +119,9 @@ extern int genirq_disable(genirq_t d, int irq, genirq_handler isr, void *arg);
/* Must be called by user when an IRQ has fired, the argument 'irq'
* is the IRQ number of the IRQ which was fired.
+ *
+ * NOTE: internal list structures are accessed and needs to be protected by
+ * spin-locks/IRQ disable by the user to guarantee a correct behaviour.
*/
extern void genirq_doirq(genirq_t d, int irq);
diff --git a/c/src/lib/libbsp/sparc/shared/irq/genirq.c b/c/src/lib/libbsp/sparc/shared/irq/genirq.c
index ef6272ce41..bba642e701 100644
--- a/c/src/lib/libbsp/sparc/shared/irq/genirq.c
+++ b/c/src/lib/libbsp/sparc/shared/irq/genirq.c
@@ -1,6 +1,6 @@
/*
* Generic interrupt helpers mainly for GRLIB PCI peripherals
- *
+ *
* COPYRIGHT (c) 2008.
* Cobham Gaisler AB.
*
@@ -47,6 +47,7 @@ genirq_t genirq_init(int number_of_irqs)
return NULL;
memset(priv, 0, size);
priv->genirq_max = number_of_irqs - 1;
+
return priv;
}
@@ -64,7 +65,7 @@ void genirq_destroy(genirq_t d)
while ( isrentry ) {
tmp = isrentry;
isrentry = isrentry->next;
- free(tmp);
+ genirq_free_handler(tmp);
}
}
@@ -81,56 +82,53 @@ int genirq_check(genirq_t d, int irq)
return 0;
}
-int genirq_register(genirq_t d, int irq, genirq_handler isr, void *arg)
+void *genirq_alloc_handler(genirq_handler isr, void *arg)
+{
+ struct genirq_handler_entry *newentry;
+
+ newentry = malloc(sizeof(struct genirq_handler_entry));
+ if ( newentry ) {
+ /* Initialize ISR entry */
+ newentry->isr = isr;
+ newentry->arg = arg;
+ newentry->enabled = 0;
+ }
+ return newentry;
+}
+
+int genirq_register(genirq_t d, int irq, void *handler)
{
struct genirq_priv *priv = d;
struct genirq_irq_entry *irqentry;
- struct genirq_handler_entry *isrentry, *newentry;
- rtems_interrupt_level level;
-
- if ( genirq_check(d, irq) )
- return -1;
+ struct genirq_handler_entry *isrentry, *newentry = handler;
- newentry = malloc(sizeof(*newentry));
- if ( !newentry )
+ if ( genirq_check(d, irq) )
return -1;
- /* Initialize ISR entry */
- newentry->isr = isr;
- newentry->arg = arg;
- newentry->enabled = 0;
-
- rtems_interrupt_disable(level);
-
/* Insert new ISR entry first into table */
irqentry = &priv->genirq_table[irq];
isrentry = irqentry->head;
irqentry->head = newentry;
newentry->next = isrentry;
- rtems_interrupt_enable(level);
-
if ( isrentry )
return 1; /* This is the first handler on this IRQ */
return 0;
}
-int genirq_unregister(genirq_t d, int irq, genirq_handler isr, void *arg)
+void *genirq_unregister(genirq_t d, int irq, genirq_handler isr, void *arg)
{
struct genirq_priv *priv = d;
struct genirq_irq_entry *irqentry;
struct genirq_handler_entry *isrentry, **prev;
- rtems_interrupt_level level;
- int ret;
+ void *ret;
if ( genirq_check(d, irq) )
- return -1;
+ return NULL;
/* Remove isr[arg] from ISR list */
irqentry = &priv->genirq_table[irq];
- ret = -1;
-
- rtems_interrupt_disable(level);
+ ret = NULL;
prev = &irqentry->head;
isrentry = irqentry->head;
@@ -139,19 +137,17 @@ int genirq_unregister(genirq_t d, int irq, genirq_handler isr, void *arg)
/* Found ISR, remove it from list */
if ( isrentry->enabled ) {
/* Can not remove enabled ISRs, disable first */
- ret = 1;
+ ret = NULL;
break;
}
*prev = isrentry->next;
- ret = 0;
+ ret = isrentry;
break;
}
prev = &isrentry->next;
isrentry = isrentry->next;
}
- rtems_interrupt_enable(level);
-
return ret;
}
@@ -226,7 +222,7 @@ void genirq_doirq(genirq_t d, int irq)
irqentry = &priv->genirq_table[irq];
irqentry->stats.irq_cnt++;
-
+
enabled = 0;
isrentry = irqentry->head;