diff options
-rw-r--r-- | c/src/lib/libbsp/shared/src/irq-generic.c | 81 | ||||
-rw-r--r-- | cpukit/include/rtems/irq-extension.h | 35 |
2 files changed, 83 insertions, 33 deletions
diff --git a/c/src/lib/libbsp/shared/src/irq-generic.c b/c/src/lib/libbsp/shared/src/irq-generic.c index 0343ccb6cf..ad34b4a4be 100644 --- a/c/src/lib/libbsp/shared/src/irq-generic.c +++ b/c/src/lib/libbsp/shared/src/irq-generic.c @@ -211,10 +211,8 @@ static rtems_status_code bsp_interrupt_handler_install( rtems_interrupt_level level; rtems_vector_number index = 0; bsp_interrupt_handler_entry *head = NULL; - bsp_interrupt_handler_entry *tail = NULL; - bsp_interrupt_handler_entry *current = NULL; - bsp_interrupt_handler_entry *match = NULL; bool enable_vector = false; + bool replace = RTEMS_INTERRUPT_IS_REPLACE(options); /* Check parameters and system state */ if (!bsp_interrupt_is_initialized()) { @@ -237,6 +235,12 @@ static rtems_status_code bsp_interrupt_handler_install( head = &bsp_interrupt_handler_table [index]; if (bsp_interrupt_is_empty_handler_entry(head)) { + if (replace) { + /* No handler to replace exists */ + bsp_interrupt_unlock(); + return RTEMS_UNSATISFIED; + } + /* * No real handler installed yet. So allocate a new index in * the handler table and fill the entry with life. @@ -260,10 +264,15 @@ static rtems_status_code bsp_interrupt_handler_install( /* This is the first handler so enable the vector later */ enable_vector = true; } else { + bsp_interrupt_handler_entry *current = head; + bsp_interrupt_handler_entry *tail = NULL; + bsp_interrupt_handler_entry *match = NULL; + /* Ensure that a unique handler remains unique */ if ( - RTEMS_INTERRUPT_IS_UNIQUE(options) - || bsp_interrupt_is_handler_unique(index) + !replace + && (RTEMS_INTERRUPT_IS_UNIQUE(options) + || bsp_interrupt_is_handler_unique(index)) ) { /* * Tried to install a unique handler on a not empty @@ -277,41 +286,59 @@ static rtems_status_code bsp_interrupt_handler_install( * Search for the list tail and check if the handler is already * installed. */ - current = head; do { - if (current->handler == handler && current->arg == arg) { + if ( + match == NULL + && (current->handler == handler || replace) + && current->arg == arg + ) { match = current; } tail = current; current = current->next; } while (current != NULL); - /* Ensure the handler is not already installed */ - if (match != NULL) { - /* The handler is already installed */ - bsp_interrupt_unlock(); - return RTEMS_TOO_MANY; - } + if (replace) { + /* Ensure that a handler to replace exists */ + if (match == NULL) { + bsp_interrupt_unlock(); + return RTEMS_UNSATISFIED; + } - /* Allocate a new entry */ - current = bsp_interrupt_allocate_handler_entry(); - if (current == NULL) { - /* Not enough memory */ - bsp_interrupt_unlock(); - return RTEMS_NO_MEMORY; + /* Use existing entry */ + current = match; + } else { + /* Ensure the handler is not already installed */ + if (match != NULL) { + /* The handler is already installed */ + bsp_interrupt_unlock(); + return RTEMS_TOO_MANY; + } + + /* Allocate a new entry */ + current = bsp_interrupt_allocate_handler_entry(); + if (current == NULL) { + /* Not enough memory */ + bsp_interrupt_unlock(); + return RTEMS_NO_MEMORY; + } } - /* Set entry */ + /* Update existing entry or set new entry */ current->handler = handler; - current->arg = arg; current->info = info; - current->next = NULL; - /* Link to list tail */ - bsp_interrupt_disable(level); - bsp_interrupt_fence(ATOMIC_ORDER_RELEASE); - tail->next = current; - bsp_interrupt_enable(level); + if (!replace) { + /* Set new entry */ + current->arg = arg; + current->next = NULL; + + /* Link to list tail */ + bsp_interrupt_disable(level); + bsp_interrupt_fence(ATOMIC_ORDER_RELEASE); + tail->next = current; + bsp_interrupt_enable(level); + } } /* Make the handler unique if necessary */ diff --git a/cpukit/include/rtems/irq-extension.h b/cpukit/include/rtems/irq-extension.h index ff2c6daff4..35eaf1e635 100644 --- a/cpukit/include/rtems/irq-extension.h +++ b/cpukit/include/rtems/irq-extension.h @@ -9,12 +9,13 @@ /* * Based on concepts of Pavel Pisa, Till Straumann and Eric Valette. * - * Copyright (c) 2008 - * Embedded Brains GmbH - * Obere Lagerstr. 30 - * D-82178 Puchheim - * Germany - * rtems@embedded-brains.de + * Copyright (c) 2008-2014 embedded brains GmbH. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at @@ -54,6 +55,12 @@ extern "C" { #define RTEMS_INTERRUPT_SHARED ((rtems_option) 0x00000000) /** + * @brief Forces that this interrupt handler replaces the first handler with + * the same argument. + */ +#define RTEMS_INTERRUPT_REPLACE ((rtems_option) 0x00000002) + +/** * @brief Returns true if the interrupt handler unique option is set. */ #define RTEMS_INTERRUPT_IS_UNIQUE( options) \ @@ -66,6 +73,12 @@ extern "C" { (!RTEMS_INTERRUPT_IS_UNIQUE( options)) /** + * @brief Returns true if the interrupt handler replace option is set. + */ +#define RTEMS_INTERRUPT_IS_REPLACE( options) \ + ((options) & RTEMS_INTERRUPT_REPLACE) + +/** * @brief Interrupt handler routine type. */ typedef void (*rtems_interrupt_handler)(void *); @@ -78,6 +91,7 @@ typedef void (*rtems_interrupt_handler)(void *); * * - @ref RTEMS_INTERRUPT_UNIQUE * - @ref RTEMS_INTERRUPT_SHARED + * - @ref RTEMS_INTERRUPT_REPLACE * * with the @a options parameter for the interrupt handler. * @@ -88,6 +102,13 @@ typedef void (*rtems_interrupt_handler)(void *); * If the option @ref RTEMS_INTERRUPT_UNIQUE is set then it shall be ensured * that this handler will be the only one for this vector. * + * If the option @ref RTEMS_INTERRUPT_REPLACE is set then it shall be ensured + * that this handler will replace the first handler with the same argument for + * this vector if it exists, otherwise an error status shall be returned. A + * second handler with the same argument for this vector shall remain + * unchanged. The new handler will inherit the unique or shared option from + * the replaced handler. + * * You can provide an informative description @a info. This may be used for * system debugging and status tools. The string has to be persistent during * the handler life time. @@ -108,6 +129,8 @@ typedef void (*rtems_interrupt_handler)(void *); * installed and there is already a handler installed this shall be returned. * @retval RTEMS_TOO_MANY If a handler with this argument is already installed * for the vector this shall be returned. + * @retval RTEMS_UNSATISFIED If no handler exists to replace with the specified + * argument and vector this shall be returned. * @retval RTEMS_IO_ERROR Reserved for board support package specific error * conditions. */ |