diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-12-22 18:31:04 +0100 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2019-01-22 12:46:33 +0100 |
commit | 7eb606d393306da25fd6e6aa7f8595ffb2e924fc (patch) | |
tree | 085befd6fe5e29d229fec9683735516d48e9d41e /bsps/shared/grlib/irq | |
parent | grlib: Move header files (diff) | |
download | rtems-7eb606d393306da25fd6e6aa7f8595ffb2e924fc.tar.bz2 |
grlib: Move source files
Update #3678.
Diffstat (limited to 'bsps/shared/grlib/irq')
-rw-r--r-- | bsps/shared/grlib/irq/genirq.c | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/bsps/shared/grlib/irq/genirq.c b/bsps/shared/grlib/irq/genirq.c new file mode 100644 index 0000000000..285416b0d3 --- /dev/null +++ b/bsps/shared/grlib/irq/genirq.c @@ -0,0 +1,244 @@ +/* + * Generic interrupt helpers mainly for GRLIB PCI peripherals + * + * COPYRIGHT (c) 2008. + * Cobham Gaisler AB. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <rtems.h> +#include <rtems/bspIo.h> +#include <stdlib.h> +#include <string.h> +#include <grlib/genirq.h> + +#include <grlib/grlib_impl.h> + +struct genirq_handler_entry { + struct genirq_handler_entry *next; /* Next ISR entry for this IRQ number */ + genirq_handler isr; /* ISR function called upon IRQ */ + void *arg; /* custom argument to ISR */ + int enabled; /* Inidicates if IRQ is enabled */ +}; + +struct genirq_irq_entry { + struct genirq_handler_entry *head; + struct genirq_stats stats; +}; + +struct genirq_priv { + /* Maximum number of interrupt */ + int genirq_max; + /* IRQ Table index N reflect IRQ number N */ + struct genirq_irq_entry genirq_table[0]; /* Length depends on */ +}; + +genirq_t genirq_init(int number_of_irqs) +{ + size_t size; + struct genirq_priv *priv; + + size = sizeof(*priv) + + number_of_irqs * sizeof(priv->genirq_table[0]); + + priv = grlib_calloc(1, size); + if ( !priv ) + return NULL; + priv->genirq_max = number_of_irqs - 1; + + return priv; +} + +void genirq_destroy(genirq_t d) +{ + struct genirq_priv *priv = d; + struct genirq_irq_entry *irqentry; + struct genirq_handler_entry *isrentry, *tmp; + int i; + + /* Free all registered interrupts */ + for ( i=0; i<priv->genirq_max; i++) { + irqentry = &priv->genirq_table[i]; + isrentry = irqentry->head; + while ( isrentry ) { + tmp = isrentry; + isrentry = isrentry->next; + genirq_free_handler(tmp); + } + } + + free(priv); +} + +int genirq_check(genirq_t d, int irq) +{ + struct genirq_priv *priv = d; + + if ( (irq <= 0) || (irq > priv->genirq_max) ) + return -1; + else + return 0; +} + +void *genirq_alloc_handler(genirq_handler isr, void *arg) +{ + struct genirq_handler_entry *newentry; + + newentry = grlib_malloc(sizeof(*newentry)); + 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 = handler; + + if ( genirq_check(d, irq) ) + return -1; + + /* Insert new ISR entry first into table */ + irqentry = &priv->genirq_table[irq]; + isrentry = irqentry->head; + irqentry->head = newentry; + newentry->next = isrentry; + + if ( isrentry ) + return 1; /* This is the first handler on this IRQ */ + return 0; +} + +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; + void *ret; + + if ( genirq_check(d, irq) ) + return NULL; + + /* Remove isr[arg] from ISR list */ + irqentry = &priv->genirq_table[irq]; + ret = NULL; + + prev = &irqentry->head; + isrentry = irqentry->head; + while ( isrentry ) { + if ( (isrentry->arg == arg) && (isrentry->isr == isr) ) { + /* Found ISR, remove it from list */ + if ( isrentry->enabled ) { + /* Can not remove enabled ISRs, disable first */ + ret = NULL; + break; + } + *prev = isrentry->next; + ret = isrentry; + break; + } + prev = &isrentry->next; + isrentry = isrentry->next; + } + + return ret; +} + +/* Enables or Disables ISR handler. Internal function to reduce footprint + * of enable/disable functions. + * + * \param action 1=enable, 0=disable ISR + */ +static int genirq_set_active( + struct genirq_priv *priv, + int irq, + genirq_handler isr, + void *arg, + int action) +{ + struct genirq_irq_entry *irqentry; + struct genirq_handler_entry *isrentry, *e = NULL; + int enabled; + + if ( genirq_check(priv, irq) ) + return -1; + + /* Find isr[arg] in ISR list */ + irqentry = &priv->genirq_table[irq]; + enabled = 0; + + isrentry = irqentry->head; + while ( isrentry ) { + if ( (isrentry->arg == arg) && (isrentry->isr == isr) ) { + /* Found ISR */ + if ( isrentry->enabled == action ) { + /* The ISR is already enabled or disabled + * depending on request, neccessary actions + * were taken last time the same action was + * requested. + */ + return 1; + } + e = isrentry; + } else { + enabled += isrentry->enabled; + } + isrentry = isrentry->next; + } + + if ( !e ) + return -1; + + e->enabled = action; + + return enabled; +} + +int genirq_enable(genirq_t d, int irq, genirq_handler isr, void *arg) +{ + struct genirq_priv *priv = d; + return genirq_set_active(priv, irq, isr, arg, 1); +} + +int genirq_disable(genirq_t d, int irq, genirq_handler isr, void *arg) +{ + struct genirq_priv *priv = d; + return genirq_set_active(priv, irq, isr, arg, 0); +} + +void genirq_doirq(genirq_t d, int irq) +{ + struct genirq_priv *priv = d; + struct genirq_irq_entry *irqentry; + struct genirq_handler_entry *isrentry; + int enabled; + + irqentry = &priv->genirq_table[irq]; + irqentry->stats.irq_cnt++; + + enabled = 0; + + isrentry = irqentry->head; + while ( isrentry ) { + if ( isrentry->enabled ) { + enabled = 1; + /* Call the ISR */ + isrentry->isr(isrentry->arg); + } + isrentry = isrentry->next; + } + + /* Was the IRQ an IRQ without source? */ + if ( enabled == 0 ) { + /* This should not happen */ + printk("Spurious IRQ happened on IRQ %d\n", irq); + } +} |