source: rtems/c/src/lib/libbsp/shared/src/irq-generic.c @ 76cb5e4

4.104.114.95
Last change on this file since 76cb5e4 was 76cb5e4, checked in by Joel Sherrill <joel.sherrill@…>, on 08/20/08 at 17:28:59

2008-08-20 Sebastian Huber <sebastian.huber@…>

  • src/irq-generic.c: Fixed integer conversion warnings.
  • Property mode set to 100644
File size: 14.7 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup bsp_interrupt
5 *
6 * @brief Source file for generic BSP interrupt support.
7 */
8
9/*
10 * Based on concepts of Pavel Pisa, Till Straumann and Eric Valette.
11 *
12 * Copyright (c) 2008
13 * Embedded Brains GmbH
14 * Obere Lagerstr. 30
15 * D-82178 Puchheim
16 * Germany
17 * rtems@embedded-brains.de
18 *
19 * The license and distribution terms for this file may be found in the file
20 * LICENSE in this distribution or at http://www.rtems.com/license/LICENSE.
21 */
22
23#include <bsp/irq-generic.h>
24
25#ifdef BSP_INTERRUPT_USE_INDEX_TABLE
26bsp_interrupt_handler_index_type bsp_interrupt_handler_index_table [BSP_INTERRUPT_VECTOR_NUMBER];
27#endif /* BSP_INTERRUPT_USE_INDEX_TABLE */
28
29bsp_interrupt_handler_entry bsp_interrupt_handler_table [BSP_INTERRUPT_HANDLER_TABLE_SIZE] = {
30        [0 ... BSP_INTERRUPT_HANDLER_TABLE_SIZE - 1] = {
31                .handler = bsp_interrupt_handler_empty,
32                .arg = NULL,
33                .info = NULL,
34                .next = NULL
35        }
36};
37
38/* The last entry indicates if everything is initialized */
39static uint8_t bsp_interrupt_handler_unique_table [(BSP_INTERRUPT_HANDLER_TABLE_SIZE + 7 + 1) / 8];
40
41static rtems_id bsp_interrupt_mutex = RTEMS_ID_NONE;
42
43static inline bool bsp_interrupt_is_handler_unique( rtems_vector_number index)
44{
45        rtems_vector_number i = index / 8;
46        rtems_vector_number s = index % 8;
47        return (bsp_interrupt_handler_unique_table [i] >> s) & 0x1;
48}
49
50static inline void bsp_interrupt_set_handler_unique( rtems_vector_number index, bool unique)
51{
52        rtems_vector_number i = index / 8;
53        rtems_vector_number s = index % 8;
54        if (unique) {
55                bsp_interrupt_handler_unique_table [i] |= (uint8_t) (0x1U << s);
56        } else {
57                bsp_interrupt_handler_unique_table [i] &= (uint8_t) ~(0x1U << s);
58        }
59}
60
61static inline bool bsp_interrupt_is_initialized(void)
62{
63        return bsp_interrupt_is_handler_unique( BSP_INTERRUPT_HANDLER_TABLE_SIZE);
64}
65
66static inline void bsp_interrupt_set_initialized(void)
67{
68        bsp_interrupt_set_handler_unique( BSP_INTERRUPT_HANDLER_TABLE_SIZE, true);
69}
70
71void bsp_interrupt_handler_empty( rtems_vector_number vector, void *arg)
72{
73        /* Do nothing */
74}
75
76static inline void bsp_interrupt_clear_handler_entry( bsp_interrupt_handler_entry *e)
77{
78        e->handler = bsp_interrupt_handler_empty;
79        e->arg = NULL;
80        e->info = NULL;
81        e->next = NULL;
82}
83
84static inline bool bsp_interrupt_allocate_handler_index( rtems_vector_number vector, rtems_vector_number *index)
85{
86#ifdef BSP_INTERRUPT_USE_INDEX_TABLE
87        rtems_vector_number i = 0;
88
89        /* The first entry will remain empty */
90        for (i = 1; i < BSP_INTERRUPT_HANDLER_TABLE_SIZE; ++i) {
91                if (bsp_interrupt_is_empty_handler_entry( &bsp_interrupt_handler_table [i])) {
92                        *index = i;
93                        return 1;
94                }
95        }
96
97        return 0;
98#else /* BSP_INTERRUPT_USE_INDEX_TABLE */
99        *index = vector;
100        return 1;
101#endif /* BSP_INTERRUPT_USE_INDEX_TABLE */
102}
103
104static bsp_interrupt_handler_entry *bsp_interrupt_allocate_handler_entry()
105{
106#ifdef BSP_INTERRUPT_NO_HEAP_USAGE
107        rtems_vector_number index = 0;
108        if (bsp_interrupt_allocate_handler_index( 0, &index)) {
109                return &bsp_interrupt_handler_table [index];
110        } else {
111                return NULL;
112        }
113#else /* BSP_INTERRUPT_NO_HEAP_USAGE */
114        return malloc( sizeof( bsp_interrupt_handler_entry));
115#endif /* BSP_INTERRUPT_NO_HEAP_USAGE */
116}
117
118static void bsp_interrupt_free_handler_entry( bsp_interrupt_handler_entry *e)
119{
120#ifdef BSP_INTERRUPT_NO_HEAP_USAGE
121        bsp_interrupt_clear_handler_entry( e);
122#else /* BSP_INTERRUPT_NO_HEAP_USAGE */
123        free( e);
124#endif /* BSP_INTERRUPT_NO_HEAP_USAGE */
125}
126
127static rtems_status_code bsp_interrupt_lock()
128{
129        rtems_status_code sc = RTEMS_SUCCESSFUL;
130        if (_System_state_Is_up( _System_state_Get())) {
131                if (bsp_interrupt_mutex == RTEMS_ID_NONE) {
132                        rtems_id mutex = RTEMS_ID_NONE;
133                        rtems_interrupt_level level;
134
135                        /* Create a mutex */
136                        sc = rtems_semaphore_create (
137                                rtems_build_name( 'I', 'N', 'T', 'R'),
138                                1,
139                                RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY,
140                                RTEMS_NO_PRIORITY,
141                                &mutex
142                        );
143                        if (sc != RTEMS_SUCCESSFUL) {
144                                return sc;
145                        }
146
147                        /* Assign the mutex */
148                        rtems_interrupt_disable( level);
149                        if (bsp_interrupt_mutex == RTEMS_ID_NONE) {
150                                /* Nobody else assigned the mutex in the meantime */
151
152                                bsp_interrupt_mutex = mutex;
153                                rtems_interrupt_enable( level);
154                        } else {
155                                /* Somebody else won */
156
157                                rtems_interrupt_enable( level);
158                                sc = rtems_semaphore_delete( mutex);
159                                if (sc != RTEMS_SUCCESSFUL) {
160                                        return sc;
161                                }
162                        }
163                }
164                return rtems_semaphore_obtain( bsp_interrupt_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
165        } else {
166                return RTEMS_SUCCESSFUL;
167        }
168}
169
170static rtems_status_code bsp_interrupt_unlock()
171{
172        if (bsp_interrupt_mutex != RTEMS_ID_NONE) {
173                return rtems_semaphore_release( bsp_interrupt_mutex);
174        } else {
175                return RTEMS_SUCCESSFUL;
176        }
177}
178
179/**
180 * @brief Initialize BSP interrupt support.
181 *
182 * You must call this function before you can install, remove and dispatch
183 * interrupt handlers.  The BSP specific bsp_interrupt_facility_initialize()
184 * function will be called after all internals are initialized.  Initialization
185 * is complete if everything was successful.
186 */
187rtems_status_code bsp_interrupt_initialize()
188{
189        rtems_status_code sc = RTEMS_SUCCESSFUL;
190        rtems_vector_number index = 0;
191
192        /* Lock */
193        sc = bsp_interrupt_lock();
194        if (sc != RTEMS_SUCCESSFUL) {
195                return sc;
196        }
197
198        /* Check if already initialized */
199        if (bsp_interrupt_is_initialized()) {
200                bsp_interrupt_unlock();
201                return RTEMS_INTERNAL_ERROR;
202        }
203
204        /* BSP specific initialization */
205        sc = bsp_interrupt_facility_initialize();
206        if (sc != RTEMS_SUCCESSFUL) {
207                bsp_interrupt_unlock();
208                return sc;
209        }
210
211        /* Now we are initialized */
212        bsp_interrupt_set_initialized();
213
214        /* Unlock */
215        sc = bsp_interrupt_unlock();
216        if (sc != RTEMS_SUCCESSFUL) {
217                return sc;
218        }
219
220        return RTEMS_SUCCESSFUL;
221}
222
223/**
224 * @brief Installs an interrupt handler.
225 *
226 * @ingroup bsp_interrupt
227 *
228 * @return In addition to the standard status codes this function returns:
229 * - If the BSP interrupt support is not initialized RTEMS_INTERNAL_ERROR will
230 * be returned.
231 * - If not enough memory for a new handler is available RTEMS_NO_MEMORY will
232 * be returned
233 *
234 * @see rtems_interrupt_handler_install()
235 */
236static rtems_status_code bsp_interrupt_handler_install( rtems_vector_number vector, const char *info, rtems_option options, rtems_interrupt_handler handler, void *arg)
237{
238        rtems_status_code sc = RTEMS_SUCCESSFUL;
239        rtems_interrupt_level level;
240        rtems_vector_number index = 0;
241        bsp_interrupt_handler_entry *head = NULL;
242        bsp_interrupt_handler_entry *tail = NULL;
243        bsp_interrupt_handler_entry *current = NULL;
244        bsp_interrupt_handler_entry *match = NULL;
245        bool enable_vector = false;
246
247        /* Check parameters and system state */
248        if (!bsp_interrupt_is_initialized()) {
249                return RTEMS_INTERNAL_ERROR;
250        } else if (!bsp_interrupt_is_valid_vector( vector)) {
251                return RTEMS_INVALID_NUMBER;
252        } else if (handler == NULL) {
253                return RTEMS_INVALID_ADDRESS;
254        } else if (rtems_interrupt_is_in_progress()) {
255                return RTEMS_CALLED_FROM_ISR;
256        }
257
258        /* Lock */
259        sc = bsp_interrupt_lock();
260        if (sc != RTEMS_SUCCESSFUL) {
261                return sc;
262        }
263
264        /* Get handler table index */
265        index = bsp_interrupt_handler_index( vector);
266
267        /* Get head entry of the handler list for current vector */
268        head = &bsp_interrupt_handler_table [index];
269
270        if (bsp_interrupt_is_empty_handler_entry( head)) {
271                /*
272                 * No real handler installed yet.  So allocate a new index in
273                 * the handler table and fill the entry with life.
274                 */
275                if (bsp_interrupt_allocate_handler_index( vector, &index)) {
276                        rtems_interrupt_disable( level);
277                        bsp_interrupt_handler_table [index].handler = handler;
278                        bsp_interrupt_handler_table [index].arg = arg;
279#ifdef BSP_INTERRUPT_USE_INDEX_TABLE
280                        bsp_interrupt_handler_index_table [vector] = index;
281#endif /* BSP_INTERRUPT_USE_INDEX_TABLE */
282                        rtems_interrupt_enable( level);
283                        bsp_interrupt_handler_table [index].info = info;
284                } else {
285                        /* Handler table is full */
286                        bsp_interrupt_unlock();
287                        return RTEMS_NO_MEMORY;
288                }
289
290                /* This is the first handler so enable the vector later */
291                enable_vector = true;
292        } else {
293                /* Ensure that a unique handler remains unique */
294                if (RTEMS_INTERRUPT_IS_UNIQUE( options) || bsp_interrupt_is_handler_unique( index)) {
295                        /*
296                         * Tried to install a unique handler on a not empty
297                         * list or there is already a unique handler installed.
298                         */
299                        bsp_interrupt_unlock();
300                        return RTEMS_RESOURCE_IN_USE;
301                }
302
303                /*
304                 * Search for the list tail and check if the handler is already
305                 * installed.
306                 */
307                current = head;
308                do {
309                        if (current->handler == handler && current->arg == arg) {
310                                match = current;
311                        }
312                        tail = current;
313                        current = current->next;
314                } while (current != NULL);
315
316                /* Ensure the handler is not already installed */
317                if (match != NULL) {
318                        /* The handler is already installed */
319                        bsp_interrupt_unlock();
320                        return RTEMS_TOO_MANY;
321                }
322
323                /* Allocate a new entry */
324                current = bsp_interrupt_allocate_handler_entry();
325                if (current == NULL) {
326                        /* Not enough memory */
327                        bsp_interrupt_unlock();
328                        return RTEMS_NO_MEMORY;
329                }
330
331                /* Set entry */
332                current->handler = handler;
333                current->arg = arg;
334                current->info = info;
335                current->next = NULL;
336
337                /* Link to list tail */
338                rtems_interrupt_disable( level);
339                tail->next = current;
340                rtems_interrupt_enable( level);
341        }
342
343        /* Make the handler unique if necessary */
344        bsp_interrupt_set_handler_unique( index, RTEMS_INTERRUPT_IS_UNIQUE( options));
345
346        /* Enable the vector if necessary */
347        if (enable_vector) {
348                sc = bsp_interrupt_vector_enable( vector);
349                if (sc != RTEMS_SUCCESSFUL) {
350                        bsp_interrupt_unlock();
351                        return sc;
352                }
353        }
354
355        /* Unlock */
356        sc = bsp_interrupt_unlock();
357        if (sc != RTEMS_SUCCESSFUL) {
358                return sc;
359        }
360
361        return RTEMS_SUCCESSFUL;
362}
363
364/**
365 * @brief Removes an interrupt handler.
366 *
367 * @ingroup bsp_interrupt
368 *
369 * @return In addition to the standard status codes this function returns
370 * RTEMS_INTERNAL_ERROR if the BSP interrupt support is not initialized.
371 *
372 * @see rtems_interrupt_handler_remove().
373 */
374static rtems_status_code bsp_interrupt_handler_remove( rtems_vector_number vector, rtems_interrupt_handler handler, void *arg)
375{
376        rtems_status_code sc = RTEMS_SUCCESSFUL;
377        rtems_interrupt_level level;
378        rtems_vector_number index = 0;
379        bsp_interrupt_handler_entry *head = NULL;
380        bsp_interrupt_handler_entry *current = NULL;
381        bsp_interrupt_handler_entry *previous = NULL;
382        bsp_interrupt_handler_entry *match = NULL;
383
384        /* Check parameters and system state */
385        if (!bsp_interrupt_is_initialized()) {
386                return RTEMS_INTERNAL_ERROR;
387        } else if (!bsp_interrupt_is_valid_vector( vector)) {
388                return RTEMS_INVALID_NUMBER;
389        } else if (handler == NULL) {
390                return RTEMS_INVALID_ADDRESS;
391        } else if (rtems_interrupt_is_in_progress()) {
392                return RTEMS_CALLED_FROM_ISR;
393        }
394
395        /* Lock */
396        sc = bsp_interrupt_lock();
397        if (sc != RTEMS_SUCCESSFUL) {
398                return sc;
399        }
400
401        /* Get handler table index */
402        index = bsp_interrupt_handler_index( vector);
403
404        /* Get head entry of the handler list for current vector */
405        head = &bsp_interrupt_handler_table [index];
406
407        /* Search for a matching entry */
408        current = head;
409        do {
410                if (current->handler == handler && current->arg == arg) {
411                        match = current;
412                        break;
413                }
414                previous = current;
415                current = current->next;
416        } while (current != NULL);
417
418        /* Remove the matching entry */
419        if (match != NULL) {
420                if (match->next != NULL) {
421                        /*
422                         * The match has a successor.  A successor is always
423                         * allocated.  So replace the match with its successor
424                         * and free the successor entry.
425                         */
426                        current = match->next;
427
428                        rtems_interrupt_disable( level);
429                        *match = *current;
430                        rtems_interrupt_enable( level);
431
432                        bsp_interrupt_free_handler_entry( current);
433                } else if (match == head) {
434                        /*
435                         * The match is the list head and has no successor.
436                         * The list head is stored in a static table so clear
437                         * this entry.  Since now the list is empty disable the
438                         * vector.
439                         */
440
441                        /* Disable the vector */
442                        sc = bsp_interrupt_vector_disable( vector);
443
444                        /* Clear entry */
445                        rtems_interrupt_disable( level);
446                        bsp_interrupt_clear_handler_entry( head);
447#ifdef BSP_INTERRUPT_USE_INDEX_TABLE
448                        bsp_interrupt_handler_index_table [vector] = 0;
449#endif /* BSP_INTERRUPT_USE_INDEX_TABLE */
450                        rtems_interrupt_enable( level);
451
452                        /* Allow shared handlers */
453                        bsp_interrupt_set_handler_unique( index, false);
454
455                        /* Check status code */
456                        if (sc != RTEMS_SUCCESSFUL) {
457                                bsp_interrupt_unlock();
458                                return sc;
459                        }
460                } else {
461                        /*
462                         * The match is the list tail and has a predecessor.
463                         * So terminate the predecessor and free the match.
464                         */
465                        rtems_interrupt_disable( level);
466                        previous->next = NULL;
467                        rtems_interrupt_enable( level);
468
469                        bsp_interrupt_free_handler_entry( match);
470                }
471        } else {
472                /* No matching entry found */
473                bsp_interrupt_unlock();
474                return RTEMS_UNSATISFIED;
475        }
476
477        /* Unlock */
478        sc = bsp_interrupt_unlock();
479        if (sc != RTEMS_SUCCESSFUL) {
480                return sc;
481        }
482
483        return RTEMS_SUCCESSFUL;
484}
485
486/**
487 * @brief Iterates over all installed interrupt handler of a vector.
488 *
489 * @ingroup bsp_interrupt
490 *
491 * @return In addition to the standard status codes this function returns
492 * RTEMS_INTERNAL_ERROR if the BSP interrupt support is not initialized.
493 *
494 * @see rtems_interrupt_handler_iterate().
495 */
496static rtems_status_code bsp_interrupt_handler_iterate( rtems_vector_number vector, rtems_interrupt_per_handler_routine routine, void *arg)
497{
498        rtems_status_code sc = RTEMS_SUCCESSFUL;
499        bsp_interrupt_handler_entry *current = NULL;
500        rtems_option options = 0;
501        rtems_vector_number index = 0;
502
503        /* Check parameters and system state */
504        if (!bsp_interrupt_is_initialized()) {
505                return RTEMS_INTERNAL_ERROR;
506        } else if (!bsp_interrupt_is_valid_vector( vector)) {
507                return RTEMS_INVALID_NUMBER;
508        } else if (rtems_interrupt_is_in_progress()) {
509                return RTEMS_CALLED_FROM_ISR;
510        }
511
512        /* Lock */
513        sc = bsp_interrupt_lock();
514        if (sc != RTEMS_SUCCESSFUL) {
515                return sc;
516        }
517
518        /* Interate */
519        index = bsp_interrupt_handler_index( vector);
520        current = &bsp_interrupt_handler_table [index];
521        if (!bsp_interrupt_is_empty_handler_entry( current)) {
522                do {
523                        options = bsp_interrupt_is_handler_unique( index) ? RTEMS_INTERRUPT_UNIQUE : RTEMS_INTERRUPT_SHARED;
524                        routine( arg, current->info, options, current->handler, current->arg);
525                        current = current->next;
526                } while (current != NULL);
527        }
528
529        /* Unlock */
530        sc = bsp_interrupt_unlock();
531        if (sc != RTEMS_SUCCESSFUL) {
532                return sc;
533        }
534
535        return RTEMS_SUCCESSFUL;
536}
537
538rtems_status_code rtems_interrupt_handler_install( rtems_vector_number vector, const char *info, rtems_option options, rtems_interrupt_handler handler, void *arg)
539{
540        return bsp_interrupt_handler_install( vector, info, options, handler, arg);
541}
542
543rtems_status_code rtems_interrupt_handler_remove( rtems_vector_number vector, rtems_interrupt_handler handler, void *arg)
544{
545        return bsp_interrupt_handler_remove( vector, handler, arg);
546}
547
548rtems_status_code rtems_interrupt_handler_iterate( rtems_vector_number vector, rtems_interrupt_per_handler_routine routine, void *arg)
549{
550        return bsp_interrupt_handler_iterate( vector, routine, arg);
551}
Note: See TracBrowser for help on using the repository browser.