diff options
author | Thomas Doerfler <Thomas.Doerfler@embedded-brains.de> | 2008-07-10 06:19:03 +0000 |
---|---|---|
committer | Thomas Doerfler <Thomas.Doerfler@embedded-brains.de> | 2008-07-10 06:19:03 +0000 |
commit | 780428fb9da5a77c10a132b350a869678a790840 (patch) | |
tree | 9a1babf6df02bb949d9bfbaf11f8f31f4c0442ff | |
parent | - Simple timing functions based on a time base reference. (diff) | |
download | rtems-780428fb9da5a77c10a132b350a869678a790840.tar.bz2 |
Extension of the RTEMS Interrupt Manager
(shared handler and handler with a handle).
Diffstat (limited to '')
-rw-r--r-- | c/src/ChangeLog | 5 | ||||
-rw-r--r-- | c/src/lib/libbsp/ChangeLog | 6 | ||||
-rw-r--r-- | c/src/lib/libbsp/m68k/acinclude.m4 | 4 | ||||
-rw-r--r-- | c/src/lib/libbsp/shared/include/irq-config.h | 78 | ||||
-rw-r--r-- | c/src/lib/libbsp/shared/include/irq-generic.h | 246 | ||||
-rw-r--r-- | c/src/lib/libbsp/shared/src/irq-generic.c | 565 | ||||
-rw-r--r-- | c/src/lib/libbsp/shared/src/irq-legacy.c | 180 | ||||
-rw-r--r-- | cpukit/ChangeLog | 22 | ||||
-rw-r--r-- | cpukit/libcsupport/include/rtems/libcsupport.h | 9 | ||||
-rw-r--r-- | cpukit/rtems/include/rtems/rtems/intr.h | 85 |
10 files changed, 1151 insertions, 49 deletions
diff --git a/c/src/ChangeLog b/c/src/ChangeLog index 9cd3c760c1..0af1c5b13d 100644 --- a/c/src/ChangeLog +++ b/c/src/ChangeLog @@ -1,3 +1,8 @@ +2008-07-09 Sebastian Huber <sebastian.huber@embedded-brains.de> + + * libchip/i2c/spi-sd-card.h, libchip/i2c/spi-sd-card.c: SD Card driver + via SPI. + 2008-06-29 Ralf Corsépius <ralf.corsepius@rtems.org> * aclocal/rtems-top.m4: Require AC_DISABLE_OPTION_CHECKING. diff --git a/c/src/lib/libbsp/ChangeLog b/c/src/lib/libbsp/ChangeLog index 7ddebbb32f..61d088bdc4 100644 --- a/c/src/lib/libbsp/ChangeLog +++ b/c/src/lib/libbsp/ChangeLog @@ -1,3 +1,9 @@ +2008-07-09 Sebastian Huber <sebastian.huber@embedded-brains.de> + + * shared/include/irq-config.h, shared/include/irq-generic.h, + shared/src/irq-generic.c, shared/src/irq-legacy.c: Generic BSP + interrupt handler support. + 2008-01-16 Ralf Corsepius <ralf.corsepius@rtems.org> * Makefile.am: Fix indentation. diff --git a/c/src/lib/libbsp/m68k/acinclude.m4 b/c/src/lib/libbsp/m68k/acinclude.m4 index f2f7eec275..d171d30047 100644 --- a/c/src/lib/libbsp/m68k/acinclude.m4 +++ b/c/src/lib/libbsp/m68k/acinclude.m4 @@ -16,12 +16,8 @@ AC_DEFUN([RTEMS_CHECK_BSPDIR], AC_CONFIG_SUBDIRS([idp]);; mcf5206elite ) AC_CONFIG_SUBDIRS([mcf5206elite]);; - mcf52235 ) - AC_CONFIG_SUBDIRS([mcf52235]);; mcf5235 ) AC_CONFIG_SUBDIRS([mcf5235]);; - mcf5329 ) - AC_CONFIG_SUBDIRS([mcf5329]);; mrm332 ) AC_CONFIG_SUBDIRS([mrm332]);; mvme136 ) diff --git a/c/src/lib/libbsp/shared/include/irq-config.h b/c/src/lib/libbsp/shared/include/irq-config.h new file mode 100644 index 0000000000..3fffc779a1 --- /dev/null +++ b/c/src/lib/libbsp/shared/include/irq-config.h @@ -0,0 +1,78 @@ +/** + * @file + * + * @ingroup bsp_interrupt + * + * @brief BSP interrupt support configuration template. + */ + +/* + * 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 + * + * The license and distribution terms for this file may be found in the file + * LICENSE in this distribution or at http://www.rtems.com/license/LICENSE. + */ + +#ifndef LIBBSP_SHARED_IRQ_CONFIG_H +#define LIBBSP_SHARED_IRQ_CONFIG_H + +#include <stdint.h> + +/** + * @addtogroup bsp_interrupt + * + * @{ + */ + +/** + * @brief Minimum vector number. + */ +#define BSP_INTERRUPT_VECTOR_MIN 0 + +/** + * @brief Maximum vector number. + */ +#define BSP_INTERRUPT_VECTOR_MAX 0 + +/** + * @brief Enables the index table. + * + * If you enable the index table, you have to define a size for the handler + * table (@ref BSP_INTERRUPT_HANDLER_TABLE_SIZE) and must provide an integer + * type capable to index the complete handler table (@ref + * bsp_interrupt_handler_index_type). + */ +#undef BSP_INTERRUPT_USE_INDEX_TABLE + +/** + * @brief Disables usage of the heap. + * + * If you define this, you have to define @ref BSP_INTERRUPT_USE_INDEX_TABLE as + * well. + */ +#undef BSP_INTERRUPT_NO_HEAP_USAGE + +#ifdef BSP_INTERRUPT_USE_INDEX_TABLE + +/** + * @brief Size of the handler table. + */ +#define BSP_INTERRUPT_HANDLER_TABLE_SIZE 0 + +/** + * @brief Integer type capable to index the complete handler table. + */ +typedef uint8_t bsp_interrupt_handler_index_type; + +#endif /* BSP_INTERRUPT_USE_INDEX_TABLE */ + +/** @} */ + +#endif /* LIBBSP_SHARED_IRQ_CONFIG_H */ diff --git a/c/src/lib/libbsp/shared/include/irq-generic.h b/c/src/lib/libbsp/shared/include/irq-generic.h new file mode 100644 index 0000000000..cd56251bb9 --- /dev/null +++ b/c/src/lib/libbsp/shared/include/irq-generic.h @@ -0,0 +1,246 @@ +/** + * @file + * + * @ingroup bsp_interrupt + * + * @brief Header file for generic BSP interrupt support. + */ + +/* + * 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 + * + * The license and distribution terms for this file may be found in the file + * LICENSE in this distribution or at http://www.rtems.com/license/LICENSE. + */ + +#ifndef LIBBSP_SHARED_IRQ_GENERIC_H +#define LIBBSP_SHARED_IRQ_GENERIC_H + +#include <stdbool.h> + +#include <rtems/irq-extension.h> + +#include <bsp/irq-config.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#if !defined( BSP_INTERRUPT_VECTOR_MIN) || !defined( BSP_INTERRUPT_VECTOR_MAX) || (BSP_INTERRUPT_VECTOR_MAX + 1) < BSP_INTERRUPT_VECTOR_MIN +#error Invalid BSP_INTERRUPT_VECTOR_MIN or BSP_INTERRUPT_VECTOR_MAX. +#endif /* !defined( BSP_INTERRUPT_VECTOR_MIN) ... */ + +#if defined( BSP_INTERRUPT_USE_INDEX_TABLE) && !defined( BSP_INTERRUPT_HANDLER_TABLE_SIZE) +#error If you define BSP_INTERRUPT_USE_INDEX_TABLE, you have to define BSP_INTERRUPT_HANDLER_TABLE_SIZE etc. as well. +#endif /* defined( BSP_INTERRUPT_USE_INDEX_TABLE) ... */ + +#if defined( BSP_INTERRUPT_NO_HEAP_USAGE) && !defined( BSP_INTERRUPT_USE_INDEX_TABLE) +#error If you define BSP_INTERRUPT_NO_HEAP_USAGE, you have to define BSP_INTERRUPT_USE_INDEX_TABLE etc. as well. +#endif /* defined( BSP_INTERRUPT_NO_HEAP_USAGE) ... */ + +#define BSP_INTERRUPT_VECTOR_NUMBER (BSP_INTERRUPT_VECTOR_MAX - BSP_INTERRUPT_VECTOR_MIN + 1) + +#ifndef BSP_INTERRUPT_HANDLER_TABLE_SIZE +#define BSP_INTERRUPT_HANDLER_TABLE_SIZE BSP_INTERRUPT_VECTOR_NUMBER +#endif /* BSP_INTERRUPT_HANDLER_TABLE_SIZE */ + +struct bsp_interrupt_handler_entry { + rtems_interrupt_handler handler; + void *arg; + const char *info; + struct bsp_interrupt_handler_entry *next; +}; + +typedef struct bsp_interrupt_handler_entry bsp_interrupt_handler_entry; + +extern bsp_interrupt_handler_entry bsp_interrupt_handler_table []; + +#ifdef BSP_INTERRUPT_USE_INDEX_TABLE +extern bsp_interrupt_handler_index_type bsp_interrupt_handler_index_table []; +#endif /* BSP_INTERRUPT_USE_INDEX_TABLE */ + +static inline rtems_vector_number bsp_interrupt_handler_index( rtems_vector_number vector) +{ +#ifdef BSP_INTERRUPT_USE_INDEX_TABLE + return bsp_interrupt_handler_index_table [vector - BSP_INTERRUPT_VECTOR_MIN]; +#else /* BSP_INTERRUPT_USE_INDEX_TABLE */ + return vector - BSP_INTERRUPT_VECTOR_MIN; +#endif /* BSP_INTERRUPT_USE_INDEX_TABLE */ +} + +void bsp_interrupt_handler_empty( rtems_vector_number vector, void *arg); + +static inline bool bsp_interrupt_is_empty_handler_entry( bsp_interrupt_handler_entry *e) +{ + return e->handler == bsp_interrupt_handler_empty; +} + +/** + * @defgroup bsp_interrupt BSP Interrupt Support + * + * @ingroup rtems_interrupt_extension + * + * The BSP interrupt support manages a sequence of interrupt vector numbers + * ranging from @ref BSP_INTERRUPT_VECTOR_MIN to @ref BSP_INTERRUPT_VECTOR_MAX + * including the end points. It provides methods to @ref + * bsp_interrupt_handler_install() "install", @ref + * bsp_interrupt_handler_remove() "remove" and @ref + * bsp_interrupt_handler_dispatch() "dispatch" interrupt handlers for each + * vector number. It implements parts of the RTEMS interrupt manager. + * + * The entry points to a list of interrupt handlers are stored in a table + * (= handler table). + * + * You have to configure the BSP interrupt support in the bsp/irq-config.h file + * for each BSP. For a minimum configuration you have to provide @ref + * BSP_INTERRUPT_VECTOR_MIN and @ref BSP_INTERRUPT_VECTOR_MAX. + * + * For boards with small memory requirements you can define @ref + * BSP_INTERRUPT_USE_INDEX_TABLE. With an enabled index table the handler + * table will be accessed via a small index table. You can define the size of + * the handler table with @ref BSP_INTERRUPT_HANDLER_TABLE_SIZE. You must + * provide a data type for the index table (@ref + * bsp_interrupt_handler_index_type). It must be an integer type big enough to + * index the complete handler table. + * + * Normally new list entries are allocated from the heap. You may define @ref + * BSP_INTERRUPT_NO_HEAP_USAGE, if you do not want to use the heap. For this + * option you have to define @ref BSP_INTERRUPT_USE_INDEX_TABLE as well. + * + * You have to provide some special routines in your BSP (follow the links for + * the details): + * - bsp_interrupt_facility_initialize() + * - bsp_interrupt_vector_enable() + * - bsp_interrupt_vector_disable() + * - bsp_interrupt_handler_default() + * + * The following now deprecated functions are provided for backward + * compatibility: + * - BSP_get_current_rtems_irq_handler() + * - BSP_install_rtems_irq_handler() + * - BSP_install_rtems_shared_irq_handler() + * - BSP_remove_rtems_irq_handler() + * - BSP_rtems_irq_mngt_set() + * - BSP_rtems_irq_mngt_get() + * + * @{ + */ + +/** + * @brief Returns true if the interrupt vector with number @a vector is valid. + */ +static inline bool bsp_interrupt_is_valid_vector( rtems_vector_number vector) +{ + return (rtems_vector_number) BSP_INTERRUPT_VECTOR_MIN <= vector + && vector <= (rtems_vector_number) BSP_INTERRUPT_VECTOR_MAX; +} + +/** + * @brief Default interrupt handler. + * + * This routine will be called from bsp_interrupt_handler_dispatch() with the + * current vector number @a vector when the handler list for this vector is + * empty or the vector number is out of range. + * + * @note This function must cope with arbitrary vector numbers @a vector. + */ +void bsp_interrupt_handler_default( rtems_vector_number vector); + +rtems_status_code bsp_interrupt_initialize(); + +/** + * @brief BSP specific initialization. + * + * This routine will be called form bsp_interrupt_initialize() and shall do the + * following: + * - Initialize the facilities that call bsp_interrupt_handler_dispatch(). For + * example on PowerPC the external exception handler. + * - Initialize the interrupt controller. You shall set the interrupt + * controller in a state such that interrupts are disabled for all vectors. + * The vectors will be enabled with your bsp_interrupt_vector_enable() function + * and disabled via your bsp_interrupt_vector_disable() function. These + * functions have to work afterwards. + * + * @return On success RTEMS_SUCCESSFUL shall be returned. + */ +rtems_status_code bsp_interrupt_facility_initialize(); + +/** + * @brief Enables the interrupt vector with number @a vector. + * + * This function shall enable the vector at the corresponding facility (in most + * cases the interrupt controller). It will be called then the first handler + * is installed for the vector in bsp_interrupt_handler_install(). For a + * vector out of range this function shall do nothing except returning + * RTEMS_SUCCESSFUL. + * + * @note You must not install or remove an interrupt handler in this function. + * This may result in a deadlock. + * + * @return On success RTEMS_SUCCESSFUL shall be returned. + */ +rtems_status_code bsp_interrupt_vector_enable( rtems_vector_number vector); + +/** + * @brief Disables the interrupt vector with number @a vector. + * + * This function shall disable the vector at the corresponding facility (in + * most cases the interrupt controller). It will be called then the last + * handler is removed for the vector in bsp_interrupt_handler_remove(). For a + * vector out of range this function shall do nothing except returning + * RTEMS_SUCCESSFUL. + * + * @note You must not install or remove an interrupt handler in this function. + * This may result in a deadlock. + * + * @return On success RTEMS_SUCCESSFUL shall be returned. + */ +rtems_status_code bsp_interrupt_vector_disable( rtems_vector_number vector); + +/** + * @brief Sequencially calls all interrupt handlers for the vector number @a + * vector. + * + * If the vector number is out of range or the handler list is empty + * bsp_interrupt_handler_default() will be called with argument @a vector. + * + * You can call this function within every context which can be disabled via + * rtems_interrupt_disable(). + */ +static inline void bsp_interrupt_handler_dispatch( rtems_vector_number vector) +{ + if (bsp_interrupt_is_valid_vector( vector)) { + bsp_interrupt_handler_entry *head = &bsp_interrupt_handler_table [bsp_interrupt_handler_index( vector)]; + bsp_interrupt_handler_entry *current = head; + + do { + current->handler( vector, current->arg); + current = current->next; + } while (current != NULL); + + if (bsp_interrupt_is_empty_handler_entry( head)) { + bsp_interrupt_handler_default( vector); + } + } else { + bsp_interrupt_handler_default( vector); + } +} + +/** @} */ + +rtems_status_code bsp_interrupt_handler_query( rtems_vector_number vector, bsp_interrupt_handler_entry *head); + +rtems_status_code bsp_interrupt_handler_query_free( bsp_interrupt_handler_entry *head); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* LIBBSP_SHARED_IRQ_GENERIC_H */ diff --git a/c/src/lib/libbsp/shared/src/irq-generic.c b/c/src/lib/libbsp/shared/src/irq-generic.c new file mode 100644 index 0000000000..0428359d86 --- /dev/null +++ b/c/src/lib/libbsp/shared/src/irq-generic.c @@ -0,0 +1,565 @@ +/** + * @file + * + * @ingroup bsp_interrupt + * + * @brief Source file for generic BSP interrupt support. + */ + +/* + * 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 + * + * The license and distribution terms for this file may be found in the file + * LICENSE in this distribution or at http://www.rtems.com/license/LICENSE. + */ + +#include <bsp/irq-generic.h> + +#ifdef BSP_INTERRUPT_USE_INDEX_TABLE +bsp_interrupt_handler_index_type bsp_interrupt_handler_index_table [BSP_INTERRUPT_VECTOR_NUMBER]; +#endif /* BSP_INTERRUPT_USE_INDEX_TABLE */ + +bsp_interrupt_handler_entry bsp_interrupt_handler_table [BSP_INTERRUPT_HANDLER_TABLE_SIZE] = { + [0 ... BSP_INTERRUPT_HANDLER_TABLE_SIZE - 1] = { + .handler = bsp_interrupt_handler_empty, + .arg = NULL, + .info = NULL, + .next = NULL + } +}; + +/* The last entry indicates if everything is initialized */ +static uint8_t bsp_interrupt_handler_unique_table [(BSP_INTERRUPT_HANDLER_TABLE_SIZE + 7 + 1) / 8]; + +static rtems_id bsp_interrupt_mutex = RTEMS_ID_NONE; + +static inline bool bsp_interrupt_is_handler_unique( rtems_vector_number index) +{ + rtems_vector_number i = index / 8; + rtems_vector_number s = index % 8; + return (bsp_interrupt_handler_unique_table [i] >> s) & 0x1; +} + +static inline void bsp_interrupt_set_handler_unique( rtems_vector_number index, bool unique) +{ + rtems_vector_number i = index / 8; + rtems_vector_number s = index % 8; + if (unique) { + bsp_interrupt_handler_unique_table [i] |= 0x1 << s; + } else { + bsp_interrupt_handler_unique_table [i] &= ~((uint8_t) 0x1 << s); + } +} + +static inline bool bsp_interrupt_is_initialized() +{ + return bsp_interrupt_is_handler_unique( BSP_INTERRUPT_HANDLER_TABLE_SIZE); +} + +static inline void bsp_interrupt_set_initialized() +{ + bsp_interrupt_set_handler_unique( BSP_INTERRUPT_HANDLER_TABLE_SIZE, true); +} + +void bsp_interrupt_handler_empty( rtems_vector_number vector, void *arg) +{ + /* Do nothing */ +} + +static inline void bsp_interrupt_clear_handler_entry( bsp_interrupt_handler_entry *e) +{ + e->handler = bsp_interrupt_handler_empty; + e->arg = NULL; + e->info = NULL; + e->next = NULL; +} + +static inline bool bsp_interrupt_allocate_handler_index( rtems_vector_number vector, rtems_vector_number *index) +{ +#ifdef BSP_INTERRUPT_USE_INDEX_TABLE + rtems_vector_number i = 0; + + /* The first entry will remain empty */ + for (i = 1; i < BSP_INTERRUPT_HANDLER_TABLE_SIZE; ++i) { + if (bsp_interrupt_is_empty_handler_entry( &bsp_interrupt_handler_table [i])) { + *index = i; + return 1; + } + } + + return 0; +#else /* BSP_INTERRUPT_USE_INDEX_TABLE */ + *index = vector; + return 1; +#endif /* BSP_INTERRUPT_USE_INDEX_TABLE */ +} + +static bsp_interrupt_handler_entry *bsp_interrupt_allocate_handler_entry() +{ +#ifdef BSP_INTERRUPT_NO_HEAP_USAGE + rtems_vector_number index = 0; + if (bsp_interrupt_allocate_handler_index( 0, &index)) { + return &bsp_interrupt_handler_table [index]; + } else { + return NULL; + } +#else /* BSP_INTERRUPT_NO_HEAP_USAGE */ + return malloc( sizeof( bsp_interrupt_handler_entry)); +#endif /* BSP_INTERRUPT_NO_HEAP_USAGE */ +} + +static void bsp_interrupt_free_handler_entry( bsp_interrupt_handler_entry *e) +{ +#ifdef BSP_INTERRUPT_NO_HEAP_USAGE + bsp_interrupt_clear_handler_entry( e); +#else /* BSP_INTERRUPT_NO_HEAP_USAGE */ + free( e); +#endif /* BSP_INTERRUPT_NO_HEAP_USAGE */ +} + +static rtems_status_code bsp_interrupt_lock() +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + if (_System_state_Is_up( _System_state_Get())) { + if (bsp_interrupt_mutex == RTEMS_ID_NONE) { + rtems_id mutex = RTEMS_ID_NONE; + rtems_interrupt_level level; + + /* Create a mutex */ + sc = rtems_semaphore_create ( + rtems_build_name( 'I', 'N', 'T', 'R'), + 1, + RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY, + RTEMS_NO_PRIORITY, + &mutex + ); + if (sc != RTEMS_SUCCESSFUL) { + return sc; + } + + /* Assign the mutex */ + rtems_interrupt_disable( level); + if (bsp_interrupt_mutex == RTEMS_ID_NONE) { + /* Nobody else assigned the mutex in the meantime */ + + bsp_interrupt_mutex = mutex; + rtems_interrupt_enable( level); + } else { + /* Somebody else won */ + + rtems_interrupt_enable( level); + sc = rtems_semaphore_delete( mutex); + if (sc != RTEMS_SUCCESSFUL) { + return sc; + } + } + } + return rtems_semaphore_obtain( bsp_interrupt_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + } else { + return RTEMS_SUCCESSFUL; + } +} + +static rtems_status_code bsp_interrupt_unlock() +{ + if (bsp_interrupt_mutex != RTEMS_ID_NONE) { + return rtems_semaphore_release( bsp_interrupt_mutex); + } else { + return RTEMS_SUCCESSFUL; + } +} + +/** + * @brief Initialize BSP interrupt support. + * + * You must call this function before you can install, remove and dispatch + * interrupt handlers. The BSP specific bsp_interrupt_facility_initialize() + * function will be called after all internals are initialized. Initialization + * is complete if everything was successful. + */ +rtems_status_code bsp_interrupt_initialize() +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + rtems_vector_number index = 0; + + /* Lock */ + sc = bsp_interrupt_lock(); + if (sc != RTEMS_SUCCESSFUL) { + return sc; + } + + /* Check if already initialized */ + if (bsp_interrupt_is_initialized()) { + bsp_interrupt_unlock(); + return RTEMS_INTERNAL_ERROR; + } + + /* BSP specific initialization */ + sc = bsp_interrupt_facility_initialize(); + if (sc != RTEMS_SUCCESSFUL) { + bsp_interrupt_unlock(); + return sc; + } + + /* Now we are initialized */ + bsp_interrupt_set_initialized(); + + /* Unlock */ + sc = bsp_interrupt_unlock(); + if (sc != RTEMS_SUCCESSFUL) { + return sc; + } + + return RTEMS_SUCCESSFUL; +} + +/** + * @brief Installs an interrupt handler. + * + * @ingroup bsp_interrupt + * + * @return In addition to the standard status codes this function returns: + * - If the BSP interrupt support is not initialized RTEMS_INTERNAL_ERROR will + * be returned. + * - If not enough memory for a new handler is available RTEMS_NO_MEMORY will + * be returned + * + * @see rtems_interrupt_handler_install() + */ +static rtems_status_code bsp_interrupt_handler_install( rtems_vector_number vector, const char *info, rtems_option options, rtems_interrupt_handler handler, void *arg) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + 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; + + /* Check parameters and system state */ + if (!bsp_interrupt_is_initialized()) { + return RTEMS_INTERNAL_ERROR; + } else if (!bsp_interrupt_is_valid_vector( vector)) { + return RTEMS_INVALID_NUMBER; + } else if (handler == NULL) { + return RTEMS_INVALID_ADDRESS; + } else if (rtems_interrupt_is_in_progress()) { + return RTEMS_CALLED_FROM_ISR; + } + + /* Lock */ + sc = bsp_interrupt_lock(); + if (sc != RTEMS_SUCCESSFUL) { + return sc; + } + + /* Get handler table index */ + index = bsp_interrupt_handler_index( vector); + + /* Get head entry of the handler list for current vector */ + head = &bsp_interrupt_handler_table [index]; + + if (bsp_interrupt_is_empty_handler_entry( head)) { + /* + * No real handler installed yet. So allocate a new index in + * the handler table and fill the entry with life. + */ + if (bsp_interrupt_allocate_handler_index( vector, &index)) { + rtems_interrupt_disable( level); + bsp_interrupt_handler_table [index].handler = handler; + bsp_interrupt_handler_table [index].arg = arg; +#ifdef BSP_INTERRUPT_USE_INDEX_TABLE + bsp_interrupt_handler_index_table [vector] = index; +#endif /* BSP_INTERRUPT_USE_INDEX_TABLE */ + rtems_interrupt_enable( level); + bsp_interrupt_handler_table [index].info = info; + } else { + /* Handler table is full */ + bsp_interrupt_unlock(); + return RTEMS_NO_MEMORY; + } + + /* This is the first handler so enable the vector later */ + enable_vector = true; + } else { + /* Ensure that a unique handler remains unique */ + if (RTEMS_INTERRUPT_IS_UNIQUE( options) || bsp_interrupt_is_handler_unique( index)) { + /* + * Tried to install a unique handler on a not empty + * list or there is already a unique handler installed. + */ + bsp_interrupt_unlock(); + return RTEMS_RESOURCE_IN_USE; + } + + /* + * Search for the list tail and check if the handler is already + * installed. + */ + current = head; + do { + if (current->handler == handler && 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; + } + + /* 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 */ + current->handler = handler; + current->arg = arg; + current->info = info; + current->next = NULL; + + /* Link to list tail */ + rtems_interrupt_disable( level); + tail->next = current; + rtems_interrupt_enable( level); + } + + /* Make the handler unique if necessary */ + bsp_interrupt_set_handler_unique( index, RTEMS_INTERRUPT_IS_UNIQUE( options)); + + /* Enable the vector if necessary */ + if (enable_vector) { + sc = bsp_interrupt_vector_enable( vector); + if (sc != RTEMS_SUCCESSFUL) { + bsp_interrupt_unlock(); + return sc; + } + } + + /* Unlock */ + sc = bsp_interrupt_unlock(); + if (sc != RTEMS_SUCCESSFUL) { + return sc; + } + + return RTEMS_SUCCESSFUL; +} + +/** + * @brief Removes an interrupt handler. + * + * @ingroup bsp_interrupt + * + * @return In addition to the standard status codes this function returns + * RTEMS_INTERNAL_ERROR if the BSP interrupt support is not initialized. + * + * @see rtems_interrupt_handler_remove(). + */ +static rtems_status_code bsp_interrupt_handler_remove( rtems_vector_number vector, rtems_interrupt_handler handler, void *arg) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + rtems_interrupt_level level; + rtems_vector_number index = 0; + bsp_interrupt_handler_entry *head = NULL; + bsp_interrupt_handler_entry *current = NULL; + bsp_interrupt_handler_entry *previous = NULL; + bsp_interrupt_handler_entry *match = NULL; + + /* Check parameters and system state */ + if (!bsp_interrupt_is_initialized()) { + return RTEMS_INTERNAL_ERROR; + } else if (!bsp_interrupt_is_valid_vector( vector)) { + return RTEMS_INVALID_NUMBER; + } else if (handler == NULL) { + return RTEMS_INVALID_ADDRESS; + } else if (rtems_interrupt_is_in_progress()) { + return RTEMS_CALLED_FROM_ISR; + } + + /* Lock */ + sc = bsp_interrupt_lock(); + if (sc != RTEMS_SUCCESSFUL) { + return sc; + } + + /* Get handler table index */ + index = bsp_interrupt_handler_index( vector); + + /* Get head entry of the handler list for current vector */ + head = &bsp_interrupt_handler_table [index]; + + /* Search for a matching entry */ + current = head; + do { + if (current->handler == handler && current->arg == arg) { + match = current; + break; + } + previous = current; + current = current->next; + } while (current != NULL); + + /* Remove the matching entry */ + if (match != NULL) { + if (match->next != NULL) { + /* + * The match has a successor. A successor is always + * allocated. So replace the match with its successor + * and free the successor entry. + */ + current = match->next; + + rtems_interrupt_disable( level); + *match = *current; + rtems_interrupt_enable( level); + + bsp_interrupt_free_handler_entry( current); + } else if (match == head) { + /* + * The match is the list head and has no successor. + * The list head is stored in a static table so clear + * this entry. Since now the list is empty disable the + * vector. + */ + + /* Disable the vector */ + sc = bsp_interrupt_vector_disable( vector); + + /* Clear entry */ + rtems_interrupt_disable( level); + bsp_interrupt_clear_handler_entry( head); +#ifdef BSP_INTERRUPT_USE_INDEX_TABLE + bsp_interrupt_handler_index_table [vector] = 0; +#endif /* BSP_INTERRUPT_USE_INDEX_TABLE */ + rtems_interrupt_enable( level); + + /* Allow shared handlers */ + bsp_interrupt_set_handler_unique( index, false); + + /* Check status code */ + if (sc != RTEMS_SUCCESSFUL) { + bsp_interrupt_unlock(); + return sc; + } + } else { + /* + * The match is the list tail and has a predecessor. + * So terminate the predecessor and free the match. + */ + rtems_interrupt_disable( level); + previous->next = NULL; + rtems_interrupt_enable( level); + + bsp_interrupt_free_handler_entry( match); + } + } else { + /* No matching entry found */ + bsp_interrupt_unlock(); + return RTEMS_UNSATISFIED; + } + + /* Unlock */ + sc = bsp_interrupt_unlock(); + if (sc != RTEMS_SUCCESSFUL) { + return sc; + } + + return RTEMS_SUCCESSFUL; +} + +rtems_status_code rtems_interrupt_handler_install( rtems_vector_number vector, const char *info, rtems_option options, rtems_interrupt_handler handler, void *arg) +{ + return bsp_interrupt_handler_install( vector, info, options, handler, arg); +} + +rtems_status_code rtems_interrupt_handler_remove( rtems_vector_number vector, rtems_interrupt_handler handler, void *arg) +{ + return bsp_interrupt_handler_remove( vector, handler, arg); +} + +rtems_status_code bsp_interrupt_handler_query( rtems_vector_number vector, bsp_interrupt_handler_entry *head) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + bsp_interrupt_handler_entry *current_input = NULL; + bsp_interrupt_handler_entry *current_output = NULL; + + /* Terminate list */ + head = NULL; + + /* Check parameters and system state */ + if (!bsp_interrupt_is_initialized()) { + return RTEMS_INTERNAL_ERROR; + } else if (!bsp_interrupt_is_valid_vector( vector)) { + return RTEMS_INVALID_NUMBER; + } else if (rtems_interrupt_is_in_progress()) { + return RTEMS_CALLED_FROM_ISR; + } + + /* Lock */ + sc = bsp_interrupt_lock(); + if (sc != RTEMS_SUCCESSFUL) { + return sc; + } + + /* Fill output list */ + current_input = &bsp_interrupt_handler_table [bsp_interrupt_handler_index( vector)]; + if (!bsp_interrupt_is_empty_handler_entry( current_input)) { + do { + bsp_interrupt_handler_entry *e = malloc( sizeof( bsp_interrupt_handler_entry)); + if (e == NULL) { + bsp_interrupt_handler_query_free( head); + bsp_interrupt_unlock(); + return RTEMS_NO_MEMORY; + } + *e = *current_input; + e->next = NULL; + if (head == NULL) { + head = e; + current_output = head; + } else { + current_output->next = e; + current_output = current_output->next; + } + current_input = current_input->next; + } while (current_input != NULL); + } + + /* Unlock */ + sc = bsp_interrupt_unlock(); + if (sc != RTEMS_SUCCESSFUL) { + return sc; + } + + return RTEMS_SUCCESSFUL; +} + +rtems_status_code bsp_interrupt_handler_query_free( bsp_interrupt_handler_entry *head) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + bsp_interrupt_handler_entry *next = NULL; + + /* Free list */ + while (head != NULL) { + next = head->next; + free( head); + head = next; + } + + return RTEMS_SUCCESSFUL; +} diff --git a/c/src/lib/libbsp/shared/src/irq-legacy.c b/c/src/lib/libbsp/shared/src/irq-legacy.c new file mode 100644 index 0000000000..d71a55a0e7 --- /dev/null +++ b/c/src/lib/libbsp/shared/src/irq-legacy.c @@ -0,0 +1,180 @@ +/** + * @file + * + * @ingroup bsp_interrupt + * + * @brief Source file for generic BSP interrupt support legacy code. + */ + +/* + * Copyright (c) 2008 + * Embedded Brains GmbH + * Obere Lagerstr. 30 + * D-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 http://www.rtems.com/license/LICENSE. + */ + +#include <stdlib.h> + +#include <rtems/irq.h> + +#include <bsp/irq-generic.h> + +typedef struct { + rtems_irq_hdl handler; + void *arg; +} bsp_interrupt_legacy_entry; + +static void bsp_interrupt_legacy_dispatch( rtems_vector_number vector, void *arg) +{ + bsp_interrupt_legacy_entry *e = arg; + e->handler( e->arg); +} + +/** + * @deprecated Obsolete. + */ +int BSP_get_current_rtems_irq_handler( rtems_irq_connect_data *cd) +{ + cd->hdl = NULL; + cd->handle = NULL; + cd->on = NULL; + cd->off = NULL; + cd->isOn = NULL; +} + +/** + * @deprecated Use rtems_interrupt_handler_install() instead. + */ +int BSP_install_rtems_irq_handler( const rtems_irq_connect_data *cd) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + bsp_interrupt_legacy_entry *e = malloc( sizeof( bsp_interrupt_legacy_entry)); + + if (e == NULL) { + return 0; + } + + e->handler = cd->hdl; + e->arg = cd->handle; + + sc = rtems_interrupt_handler_install( + cd->name, + "Unique interrupt handler (installed with obsolete BSP_install_rtems_irq_handler())", + RTEMS_INTERRUPT_UNIQUE, + bsp_interrupt_legacy_dispatch, + e + ); + if (sc != RTEMS_SUCCESSFUL) { + free( e); + return 0; + } + + if (cd->on) { + cd->on( cd); + } + + return 1; +} + +/** + * @deprecated Use rtems_interrupt_handler_install() instead. + */ +int BSP_install_rtems_shared_irq_handler( const rtems_irq_connect_data *cd) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + bsp_interrupt_legacy_entry *e = malloc( sizeof( bsp_interrupt_legacy_entry)); + + if (e == NULL) { + return 0; + } + + e->handler = cd->hdl; + e->arg = cd->handle; + + sc = rtems_interrupt_handler_install( + cd->name, + "Shared interrupt handler (installed with obsolete BSP_install_rtems_shared_irq_handler())", + RTEMS_INTERRUPT_SHARED, + bsp_interrupt_legacy_dispatch, + e + ); + if (sc != RTEMS_SUCCESSFUL) { + free( e); + return 0; + } + + if (cd->on) { + cd->on( cd); + } + + return 1; +} + +/** + * @deprecated Use rtems_interrupt_handler_remove() instead. + */ +int BSP_remove_rtems_irq_handler( const rtems_irq_connect_data *cd) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + bsp_interrupt_handler_entry *head = NULL; + bsp_interrupt_handler_entry *current = NULL; + bsp_interrupt_legacy_entry *e = NULL; + + sc = bsp_interrupt_handler_query( cd->name, head); + if (sc != RTEMS_SUCCESSFUL) { + return 0; + } + + current = head; + while (current != NULL) { + if (current->handler == bsp_interrupt_legacy_dispatch) { + e = current->arg; + if (e->arg == cd->handle) { + break; + } else { + e = NULL; + } + } + current = current->next; + } + + sc = bsp_interrupt_handler_query_free( head); + if (sc != RTEMS_SUCCESSFUL) { + return 0; + } + + if (e == NULL) { + return 0; + } + + if (cd->off) { + cd->off( cd); + } + sc = rtems_interrupt_handler_remove( cd->name, bsp_interrupt_legacy_dispatch, e); + if (sc != RTEMS_SUCCESSFUL) { + return 0; + } + return 1; +} + +/** + * @deprecated Use bsp_interrupt_initialize() instead. + */ +int BSP_rtems_irq_mngt_set( rtems_irq_global_settings *config) +{ + return 0; +} + +/** + * @deprecated Obsolete. + */ +int BSP_rtems_irq_mngt_get( rtems_irq_global_settings **config) +{ + *config = NULL; + return 0; +} diff --git a/cpukit/ChangeLog b/cpukit/ChangeLog index 04afa3ad0e..c5941fabe4 100644 --- a/cpukit/ChangeLog +++ b/cpukit/ChangeLog @@ -1,3 +1,25 @@ +2008-07-09 Sebastian Huber <sebastian.huber@embedded-brains.de> + + * cpukit/include/rtems/status-checks.h: Macros for status code and + return value checks. + +2008-07-03 Sebastian Huber <sebastian.huber@embedded-brains.de> + + * cpukit/libmisc/shell/shell.c: Restore terminal settings on exit. + +2008-07-03 Sebastian Huber <sebastian.huber@embedded-brains.de> + + * cpukit/libfs/src/dosfs/msdos_dir.c, + cpukit/libfs/src/dosfs/msdos_file.c: Added S_IRWXU, S_IRWXG and S_IRWXO + to file mode. + +2008-07-03 Sebastian Huber <sebastian.huber@embedded-brains.de> + + * cpukit/libi2c/libi2c.h, cpukit/libi2c/libi2c.c: Modified error + messages. Driver operations table is now constant. New entry in the + rtems_libi2c_tfr_mode_t structure: idle_char. This character will be + continuously transmitted in read only functions. + 2008-07-03 Chris Johns <chrisj@rtems.org> * cpukit/libcsupport/include/chain.h: Removed. Use the SAPI diff --git a/cpukit/libcsupport/include/rtems/libcsupport.h b/cpukit/libcsupport/include/rtems/libcsupport.h index 817e9d8a5b..e6db490670 100644 --- a/cpukit/libcsupport/include/rtems/libcsupport.h +++ b/cpukit/libcsupport/include/rtems/libcsupport.h @@ -24,6 +24,8 @@ extern "C" { #endif +#include <stdint.h> + #include <sys/types.h> void RTEMS_Malloc_Initialize( @@ -71,6 +73,13 @@ rtems_extension libc_delete_hook( 0 /* fatal */ \ } +/* + * FIXME: Nearly every BSP declares this function in the BSP startup file + * separately and uses the implementation in c/src/lib/libbsp/shared/bsplibc.c. + * Why differ the parameter types from RTEMS_Malloc_Initialize()? + */ +void bsp_libc_init( void *heap_start, uint32_t heap_size, int use_sbrk); + #ifdef __cplusplus } #endif diff --git a/cpukit/rtems/include/rtems/rtems/intr.h b/cpukit/rtems/include/rtems/rtems/intr.h index d824960252..5482193b04 100644 --- a/cpukit/rtems/include/rtems/rtems/intr.h +++ b/cpukit/rtems/include/rtems/rtems/intr.h @@ -1,8 +1,10 @@ /** - * @file rtems/rtems/intr.h + * @file rtems/rtems/intr.h * - * This include file contains all the constants and structures associated - * with the Interrupt Manager. + * @brief Header file for the Interrupt Manager. + * + * This include file contains all the constants and structures associated with + * the Interrupt Manager. */ /* COPYRIGHT (c) 1989-2008. @@ -32,43 +34,40 @@ extern "C" { /**@{*/ /** - * Interrupt level type + * @brief Interrupt level type. */ typedef ISR_Level rtems_interrupt_level; /** - * The following type defines the control block used to manage - * the vectors. + * @brief Control block type used to manage the vectors. */ typedef ISR_Vector_number rtems_vector_number; /** - * Return type for ISR Handler + * @brief Return type for interrupt handler. */ typedef void rtems_isr; /** - * Pointer to an ISR Handler + * @brief Interrupt handler type. + * + * @see rtems_interrupt_catch() */ typedef rtems_isr ( *rtems_isr_entry )( rtems_vector_number ); /** - * @brief Interrupt_Manager_initialization - * - * This routine initializes the interrupt manager. - * + * @brief Initializes the Interrupt Manager. */ void _Interrupt_Manager_initialization( void ); /** - * @brief rtems_interrupt_catch - * - * This routine implements the rtems_interrupt_catch directive. This - * directive installs new_isr_handler as the RTEMS interrupt service - * routine for vector. The previous RTEMS interrupt service - * routine is returned in old_isr_handler. + * @brief Implementation of the rtems_interrupt_catch directive. + * + * This directive installs @a new_isr_handler as the RTEMS interrupt service + * routine for the interrupt vector with number @a vector. The previous RTEMS + * interrupt service routine is returned in @a old_isr_handler. */ rtems_status_code rtems_interrupt_catch( rtems_isr_entry new_isr_handler, @@ -77,58 +76,54 @@ rtems_status_code rtems_interrupt_catch( ); /** - * @brief rtems_interrupt_disable - * - * This routine disables all maskable interrupts and returns the - * previous level in _isr_cookie. + * @brief Disables all maskable interrupts and returns the previous level in + * @a _isr_cookie. + * + * @note The interrupt level shall be of type @ref rtems_interrupt_level. */ #define rtems_interrupt_disable( _isr_cookie ) \ _ISR_Disable(_isr_cookie) /** - * @brief rtems_interrupt_enable - * - * This routine enables maskable interrupts to the level indicated + * @brief Enables maskable interrupts to the level indicated by @a * _isr_cookie. + * + * @note The interrupt level shall be of type @ref rtems_interrupt_level. */ #define rtems_interrupt_enable( _isr_cookie ) \ _ISR_Enable(_isr_cookie) /** - * @brief rtems_interrupt_flash - * - * This routine temporarily enables maskable interrupts to the - * level in _isr_cookie before redisabling them. + * @brief Temporarily enables maskable interrupts to the level in @a + * _isr_cookie before redisabling them. + * + * @note The interrupt level shall be of type @ref rtems_interrupt_level. */ #define rtems_interrupt_flash( _isr_cookie ) \ _ISR_Flash(_isr_cookie) /** - * @brief rtems_interrupt_is_in_progress - * - * This function returns TRUE if the processor is currently servicing - * an interrupt and FALSE otherwise. A return value of TRUE indicates - * that the caller is an interrupt service routine, NOT a thread. The - * directives available to an interrupt service routine are restricted. + * @brief Returns TRUE if the processor is currently servicing an interrupt + * and FALSE otherwise. + * + * A return value of TRUE indicates that the caller is an interrupt service + * routine and @b not a thread. The directives available to an interrupt + * service routine are restricted. */ #define rtems_interrupt_is_in_progress() \ _ISR_Is_in_progress() /** - * @brief rtems_interrupt_cause - * - * This routine generates an interrupt. - * - * NOTE: No implementation. + * @brief This routine generates an interrupt. + * + * @note No implementation. */ #define rtems_interrupt_cause( _interrupt_to_cause ) /** - * @brief rtems_interrupt_clear - * - * This routine clears the specified interrupt. - * - * NOTE: No implementation. + * @brief This routine clears the specified interrupt. + * + * @note No implementation. */ #define rtems_interrupt_clear( _interrupt_to_clear ) |