forked from Imagelibrary/rtems
bsps/sparc: Move shared files to bsps
This patch is a part of the BSP source reorganization. Update #3285.
This commit is contained in:
243
bsps/sparc/shared/irq/genirq.c
Normal file
243
bsps/sparc/shared/irq/genirq.c
Normal file
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* 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 <bsp/genirq.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[1]; /* Length depends on */
|
||||
};
|
||||
|
||||
genirq_t genirq_init(int number_of_irqs)
|
||||
{
|
||||
int size;
|
||||
struct genirq_priv *priv;
|
||||
|
||||
size = sizeof(int) +
|
||||
number_of_irqs * sizeof(struct genirq_irq_entry);
|
||||
|
||||
priv = (struct genirq_priv *)malloc(size);
|
||||
if ( !priv )
|
||||
return NULL;
|
||||
memset(priv, 0, size);
|
||||
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 = 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 = 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user