diff options
-rw-r--r-- | c/src/lib/libbsp/sparc/shared/include/genirq.h | 47 | ||||
-rw-r--r-- | c/src/lib/libbsp/sparc/shared/irq/genirq.c | 58 |
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; |