c/src/lib/libbsp/shared/src/irq-generic.c

Go to the documentation of this file.
00001 
00009 /*
00010  * Copyright (c) 2008
00011  * Embedded Brains GmbH
00012  * Obere Lagerstr. 30
00013  * D-82178 Puchheim
00014  * Germany
00015  * rtems@embedded-brains.de
00016  *
00017  * The license and distribution terms for this file may be found in the file
00018  * LICENSE in this distribution or at http://www.rtems.com/license/LICENSE.
00019  */
00020 
00021 #include <bsp/irq-generic.h>
00022 
00023 #ifdef BSP_INTERRUPT_USE_INDEX_TABLE
00024 bsp_interrupt_handler_index_type bsp_interrupt_handler_index_table [BSP_INTERRUPT_VECTOR_NUMBER];
00025 #endif /* BSP_INTERRUPT_USE_INDEX_TABLE */
00026 
00027 bsp_interrupt_handler_entry bsp_interrupt_handler_table [BSP_INTERRUPT_HANDLER_TABLE_SIZE];
00028 
00029 /* The last entry indicates if everything is initialized */
00030 static uint8_t bsp_interrupt_handler_unique_table [(BSP_INTERRUPT_HANDLER_TABLE_SIZE + 7 + 1) / 8];
00031 
00032 static rtems_id bsp_interrupt_mutex = 0;
00033 
00034 static inline int bsp_interrupt_is_handler_unique( rtems_vector_number index)
00035 {
00036         rtems_vector_number i = index / 8;
00037         rtems_vector_number s = index % 8;
00038         return (bsp_interrupt_handler_unique_table [i] >> s) & 0x1;
00039 }
00040 
00041 static inline void bsp_interrupt_set_handler_unique( rtems_vector_number index, int unique)
00042 {
00043         rtems_vector_number i = index / 8;
00044         rtems_vector_number s = index % 8;
00045         if (unique) {
00046                 bsp_interrupt_handler_unique_table [i] |= 0x1 << s;
00047         } else {
00048                 bsp_interrupt_handler_unique_table [i] &= ~((uint8_t) 0x1 << s);
00049         }
00050 }
00051 
00052 static inline int bsp_interrupt_is_initialized()
00053 {
00054         return bsp_interrupt_is_handler_unique( BSP_INTERRUPT_HANDLER_TABLE_SIZE);
00055 }
00056 
00057 static inline void bsp_interrupt_set_initialized()
00058 {
00059         bsp_interrupt_set_handler_unique( BSP_INTERRUPT_HANDLER_TABLE_SIZE, 1);
00060 }
00061 
00062 void bsp_interrupt_handler_empty()
00063 {
00064         /* Do nothing */
00065 }
00066 
00067 static inline void bsp_interrupt_clear_handler_entry( rtems_vector_number index)
00068 {
00069         bsp_interrupt_handler_table [index].handler = bsp_interrupt_handler_empty;
00070         bsp_interrupt_handler_table [index].arg = NULL;
00071         bsp_interrupt_handler_table [index].next = NULL;
00072         bsp_interrupt_set_handler_unique( index, 0);
00073 }
00074 
00075 static inline int bsp_interrupt_allocate_handler_index( rtems_vector_number vector, rtems_vector_number *index)
00076 {
00077 #ifdef BSP_INTERRUPT_USE_INDEX_TABLE
00078         rtems_vector_number i = 0;
00079 
00080         /* The first entry will remain empty */
00081         for (i = 1; i < BSP_INTERRUPT_HANDLER_TABLE_SIZE; ++i) {
00082                 if (bsp_interrupt_is_empty_handler_entry( &bsp_interrupt_handler_table [i])) {
00083                         *index = i;
00084                         return 1;
00085                 }
00086         }
00087 
00088         return 0;
00089 #else /* BSP_INTERRUPT_USE_INDEX_TABLE */
00090         *index = vector;
00091         return 1;
00092 #endif /* BSP_INTERRUPT_USE_INDEX_TABLE */
00093 }
00094 
00095 static bsp_interrupt_handler_entry *bsp_interrupt_allocate_handler_entry()
00096 {
00097 #ifdef BSP_INTERRUPT_NO_HEAP_USAGE
00098         rtems_vector_number index = 0;
00099         if (bsp_interrupt_allocate_handler_index( 0, &index)) {
00100                 return &bsp_interrupt_handler_table [index];
00101         } else {
00102                 return NULL;
00103         }
00104 #else /* BSP_INTERRUPT_NO_HEAP_USAGE */
00105         return malloc( sizeof( bsp_interrupt_handler_entry));
00106 #endif /* BSP_INTERRUPT_NO_HEAP_USAGE */
00107 }
00108 
00109 static void bsp_interrupt_free_handler_entry( bsp_interrupt_handler_entry *e)
00110 {
00111 #ifdef BSP_INTERRUPT_NO_HEAP_USAGE
00112         bsp_interrupt_clear_handler_entry( e);
00113 #else /* BSP_INTERRUPT_NO_HEAP_USAGE */
00114         free( e);
00115 #endif /* BSP_INTERRUPT_NO_HEAP_USAGE */
00116 }
00117 
00118 static rtems_status_code bsp_interrupt_lock()
00119 {
00120         rtems_status_code sc = RTEMS_SUCCESSFUL;
00121         if (_System_state_Is_up( _System_state_Get())) {
00122                 if (bsp_interrupt_mutex == 0) {
00123                         sc = rtems_semaphore_create (
00124                                 rtems_build_name ( 'I', 'N', 'T', 'R'),
00125                                 1,
00126                                 RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY,
00127                                 RTEMS_NO_PRIORITY,
00128                                 &bsp_interrupt_mutex
00129                         );
00130                         if (sc != RTEMS_SUCCESSFUL) {
00131                                 return sc;
00132                         }
00133                 }
00134                 return rtems_semaphore_obtain( bsp_interrupt_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
00135         } else {
00136                 return RTEMS_SUCCESSFUL;
00137         }
00138 }
00139 
00140 static rtems_status_code bsp_interrupt_unlock()
00141 {
00142         if (bsp_interrupt_mutex != 0) {
00143                 return rtems_semaphore_release( bsp_interrupt_mutex);
00144         } else {
00145                 return RTEMS_SUCCESSFUL;
00146         }
00147 }
00148 
00149 rtems_status_code bsp_interrupt_initialize()
00150 {
00151         rtems_status_code sc = RTEMS_SUCCESSFUL;
00152         rtems_vector_number index = 0;
00153 
00154         /* Lock */
00155         sc = bsp_interrupt_lock();
00156         if (sc != RTEMS_SUCCESSFUL) {
00157                 return sc;
00158         }
00159 
00160         /* Check if already initialized */
00161         if (bsp_interrupt_is_initialized()) {
00162                 bsp_interrupt_unlock();
00163                 return RTEMS_INTERNAL_ERROR;
00164         }
00165 
00166         /* Initialize the handler and unique table with default entries */
00167         for (index = 0; index < BSP_INTERRUPT_HANDLER_TABLE_SIZE; ++index) {
00168                 bsp_interrupt_clear_handler_entry( index);
00169         }
00170 
00171         /* BSP specific initialization */
00172         sc = bsp_interrupt_facility_initialize();
00173         if (sc != RTEMS_SUCCESSFUL) {
00174                 bsp_interrupt_unlock();
00175                 return sc;
00176         }
00177 
00178         /* Now we are initialized */
00179         bsp_interrupt_set_initialized();
00180 
00181         /* Unlock */
00182         sc = bsp_interrupt_unlock();
00183         if (sc != RTEMS_SUCCESSFUL) {
00184                 return sc;
00185         }
00186 
00187         return RTEMS_SUCCESSFUL;
00188 }
00189 
00202 rtems_status_code bsp_interrupt_handler_install( rtems_vector_number vector, rtems_interrupt_handler handler, void *arg, rtems_boolean shared)
00203 {
00204         rtems_status_code sc = RTEMS_SUCCESSFUL;
00205         rtems_interrupt_level level;
00206         rtems_vector_number index = 0;
00207         bsp_interrupt_handler_entry *head = NULL;
00208         bsp_interrupt_handler_entry *tail = NULL;
00209         bsp_interrupt_handler_entry *current = NULL;
00210         bsp_interrupt_handler_entry *match = NULL;
00211 
00212         /* Check parameters and system state */
00213         if (!bsp_interrupt_is_initialized()) {
00214                 return RTEMS_INTERNAL_ERROR;
00215         } else if (!bsp_interrupt_is_valid_vector( vector)) {
00216                 return RTEMS_INVALID_NUMBER;
00217         } else if (handler == NULL) {
00218                 return RTEMS_INVALID_ADDRESS;
00219         } else if (_ISR_Nest_level > 0) {
00220                 return RTEMS_CALLED_FROM_ISR;
00221         }
00222 
00223         /* Lock */
00224         sc = bsp_interrupt_lock();
00225         if (sc != RTEMS_SUCCESSFUL) {
00226                 return sc;
00227         }
00228 
00229         /* Get handler table index */
00230         index = bsp_interrupt_handler_index( vector);
00231 
00232         /* Get head entry of the handler list for current vector */
00233         head = &bsp_interrupt_handler_table [index];
00234 
00235         if (bsp_interrupt_is_empty_handler_entry( head)) {
00236                 /*
00237                  * No real handler installed yet.  So allocate a new index in
00238                  * the handler table and fill the entry with life.
00239                  */
00240                 if (bsp_interrupt_allocate_handler_index( vector, &index)) {
00241                         rtems_interrupt_disable( level);
00242                         bsp_interrupt_handler_table [index].handler = handler;
00243                         bsp_interrupt_handler_table [index].arg = arg;
00244 #ifdef BSP_INTERRUPT_USE_INDEX_TABLE
00245                         bsp_interrupt_handler_index_table [vector] = index;
00246 #endif /* BSP_INTERRUPT_USE_INDEX_TABLE */
00247                         rtems_interrupt_enable( level);
00248                 } else {
00249                         /* Handler table is full */
00250                         bsp_interrupt_unlock();
00251                         return RTEMS_NO_MEMORY;
00252                 }
00253 
00254                 /* This is the first handler so enable the vector */
00255                 sc = bsp_interrupt_vector_enable( vector);
00256                 if (sc != RTEMS_SUCCESSFUL) {
00257                         bsp_interrupt_unlock();
00258                         return sc;
00259                 }
00260         } else {
00261                 /* Ensures that a unique handler remains unique */
00262                 if (!shared || bsp_interrupt_is_handler_unique( index)) {
00263                         /*
00264                          * Tried to install a unique handler on a not empty
00265                          * list or there is already a unique handler installed.
00266                          */
00267                         bsp_interrupt_unlock();
00268                         return RTEMS_RESOURCE_IN_USE;
00269                 }
00270 
00271                 /*
00272                  * Search for the list tail and check if the handler is already
00273                  * installed.
00274                  */
00275                 current = head;
00276                 do {
00277                         if (current->handler == handler) {
00278                                 match = current;
00279                         }
00280                         tail = current;
00281                         current = current->next;
00282                 } while (current != NULL);
00283 
00284                 /* Ensure the handler is not already installed */
00285                 if (match != NULL) {
00286                         /* The handler is already installed */
00287                         bsp_interrupt_unlock();
00288                         return RTEMS_TOO_MANY;
00289                 }
00290 
00291                 /* Allocate a new entry */
00292                 current = bsp_interrupt_allocate_handler_entry();
00293                 if (current == NULL) {
00294                         /* Not enough memory */
00295                         bsp_interrupt_unlock();
00296                         return RTEMS_NO_MEMORY;
00297                 }
00298 
00299                 /* Set entry */
00300                 current->handler = handler;
00301                 current->arg = arg;
00302                 current->next = NULL;
00303 
00304                 /* Link to list tail */
00305                 rtems_interrupt_disable( level);
00306                 tail->next = current;
00307                 rtems_interrupt_enable( level);
00308         }
00309 
00310         /* Make the handler unique if necessary */
00311         if (!shared) {
00312                 bsp_interrupt_set_handler_unique( index, 1);
00313         }
00314 
00315         /* Unlock */
00316         sc = bsp_interrupt_unlock();
00317         if (sc != RTEMS_SUCCESSFUL) {
00318                 return sc;
00319         }
00320 
00321         return RTEMS_SUCCESSFUL;
00322 }
00323 
00332 rtems_status_code bsp_interrupt_handler_remove( rtems_vector_number vector, rtems_interrupt_handler handler)
00333 {
00334         rtems_status_code sc = RTEMS_SUCCESSFUL;
00335         rtems_interrupt_level level;
00336         rtems_vector_number index = 0;
00337         bsp_interrupt_handler_entry *head = NULL;
00338         bsp_interrupt_handler_entry *current = NULL;
00339         bsp_interrupt_handler_entry *previous = NULL;
00340         bsp_interrupt_handler_entry *match = NULL;
00341 
00342         /* Check parameters and system state */
00343         if (!bsp_interrupt_is_initialized()) {
00344                 return RTEMS_INTERNAL_ERROR;
00345         } else if (!bsp_interrupt_is_valid_vector( vector)) {
00346                 return RTEMS_INVALID_NUMBER;
00347         } else if (handler == NULL) {
00348                 return RTEMS_INVALID_ADDRESS;
00349         } else if (_ISR_Nest_level > 0) {
00350                 return RTEMS_CALLED_FROM_ISR;
00351         }
00352 
00353         /* Lock */
00354         sc = bsp_interrupt_lock();
00355         if (sc != RTEMS_SUCCESSFUL) {
00356                 return sc;
00357         }
00358 
00359         /* Get handler table index */
00360         index = bsp_interrupt_handler_index( vector);
00361 
00362         /* Get head entry of the handler list for current vector */
00363         head = &bsp_interrupt_handler_table [index];
00364 
00365         /* Search for a matching entry */
00366         current = head;
00367         do {
00368                 if (current->handler == handler) {
00369                         match = current;
00370                         break;
00371                 }
00372                 previous = current;
00373                 current = current->next;
00374         } while (current != NULL);
00375 
00376         /* Remove the matching entry */
00377         if (match != NULL) {
00378                 if (match->next != NULL) {
00379                         /*
00380                          * The match has a successor.  A successor is always
00381                          * allocated.  So replace the match with its successor
00382                          * and free the successor entry.
00383                          */
00384                         current = match->next;
00385 
00386                         rtems_interrupt_disable( level);
00387                         *match = *current;
00388                         rtems_interrupt_enable( level);
00389 
00390                         bsp_interrupt_free_handler_entry( current);
00391                 } else if (match == head) {
00392                         /*
00393                          * The match is the list head and has no successor.
00394                          * The list head is stored in a static table so clear
00395                          * this entry.  Since now the list is empty disable the
00396                          * vector.
00397                          */
00398 
00399                         /* Disable the vector */
00400                         sc = bsp_interrupt_vector_disable( vector);
00401 
00402                         /* Clear entry */
00403                         rtems_interrupt_disable( level);
00404                         bsp_interrupt_clear_handler_entry( index);
00405 #ifdef BSP_INTERRUPT_USE_INDEX_TABLE
00406                         bsp_interrupt_handler_index_table [vector] = 0;
00407 #endif /* BSP_INTERRUPT_USE_INDEX_TABLE */
00408                         rtems_interrupt_enable( level);
00409 
00410                         /* Check status code */
00411                         if (sc != RTEMS_SUCCESSFUL) {
00412                                 bsp_interrupt_unlock();
00413                                 return sc;
00414                         }
00415                 } else {
00416                         /*
00417                          * The match is the list tail and has a predecessor.
00418                          * So terminate the predecessor and free the match.
00419                          */
00420                         rtems_interrupt_disable( level);
00421                         previous->next = NULL;
00422                         rtems_interrupt_enable( level);
00423 
00424                         bsp_interrupt_free_handler_entry( match);
00425                 }
00426         } else {
00427                 /* No matching entry found.  */
00428                 bsp_interrupt_unlock();
00429                 return RTEMS_UNSATISFIED;
00430         }
00431 
00432         /* Unlock */
00433         sc = bsp_interrupt_unlock();
00434         if (sc != RTEMS_SUCCESSFUL) {
00435                 return sc;
00436         }
00437 
00438         return RTEMS_SUCCESSFUL;
00439 }
00440 
00444 int BSP_get_current_rtems_irq_handler( rtems_irq_connect_data *cd)
00445 {
00446         cd->hdl = NULL;
00447         cd->handle = NULL;
00448         cd->on = NULL;
00449         cd->off = NULL;
00450         cd->isOn = NULL;
00451 }
00452 
00456 int BSP_install_rtems_irq_handler( const rtems_irq_connect_data *cd)
00457 {
00458         rtems_status_code sc = RTEMS_SUCCESSFUL;
00459         sc = rtems_interrupt_handler_unique_install( cd->name, cd->hdl, cd->handle);
00460         if (sc != RTEMS_SUCCESSFUL) {
00461                 return 0;
00462         }
00463         if (cd->on) {
00464                 cd->on( cd);
00465         }
00466         return 1;
00467 }
00468 
00472 int BSP_install_rtems_shared_irq_handler( const rtems_irq_connect_data *cd)
00473 {
00474         rtems_status_code sc = RTEMS_SUCCESSFUL;
00475         sc = rtems_interrupt_handler_install( cd->name, cd->hdl, cd->handle);
00476         if (sc != RTEMS_SUCCESSFUL) {
00477                 return 0;
00478         }
00479         if (cd->on) {
00480                 cd->on( cd);
00481         }
00482         return 1;
00483 }
00484 
00488 int BSP_remove_rtems_irq_handler( const rtems_irq_connect_data *cd)
00489 {
00490         rtems_status_code sc = RTEMS_SUCCESSFUL;
00491         sc = rtems_interrupt_handler_remove( cd->name, cd->hdl);
00492         if (sc != RTEMS_SUCCESSFUL) {
00493                 return 0;
00494         }
00495         if (cd->off) {
00496                 cd->off( cd);
00497         }
00498         return 1;
00499 }
00500 
00504 int BSP_rtems_irq_mngt_set( rtems_irq_global_settings *config)
00505 {
00506         return 0;
00507 }
00508 
00512 int BSP_rtems_irq_mngt_get( rtems_irq_global_settings **config)
00513 {
00514         *config = NULL;
00515         return 0;
00516 }

Generated on Mon May 19 15:42:10 2008 for RTEMS by  doxygen 1.5.3