summaryrefslogtreecommitdiffstats
path: root/cpukit/posix/src/intr.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--cpukit/posix/src/intr.c336
1 files changed, 336 insertions, 0 deletions
diff --git a/cpukit/posix/src/intr.c b/cpukit/posix/src/intr.c
new file mode 100644
index 0000000000..4011cf9a91
--- /dev/null
+++ b/cpukit/posix/src/intr.c
@@ -0,0 +1,336 @@
+/* intr.c
+ *
+ * NOTE: Each task has an interrupt semaphore associated with it.
+ * No matter which interrupt occurs that it has registered,
+ * the same semaphore is used.
+ */
+
+#include <errno.h>
+#include <intr.h>
+
+#include <pthread.h>
+#include <rtems/score/isr.h>
+#include <rtems/score/coresem.h>
+#include <rtems/score/thread.h>
+#include <rtems/score/watchdog.h>
+#include <rtems/posix/intr.h>
+#include <rtems/posix/time.h>
+#include <rtems/posix/threadsup.h>
+
+/*
+ * _POSIX_Interrupt_Manager_initialization
+ *
+ * DESCRIPTION:
+ *
+ * This routine performs the initialization necessary for this manager.
+ */
+
+void _POSIX_Interrupt_Manager_initialization(
+ unsigned32 maximum_interrupt_handlers
+)
+{
+ unsigned32 index;
+ POSIX_Interrupt_Control *the_vector;
+
+ _Objects_Initialize_information(
+ &_POSIX_Interrupt_Handlers_Information,
+ OBJECTS_POSIX_INTERRUPTS,
+ FALSE,
+ maximum_interrupt_handlers,
+ sizeof( POSIX_Interrupt_Handler_control ),
+ FALSE,
+ 0,
+ FALSE
+ );
+
+ for ( index=0 ; index < CPU_INTERRUPT_NUMBER_OF_VECTORS ; index++ ) {
+ the_vector = &_POSIX_Interrupt_Information[ index ];
+
+ the_vector->number_installed = 0;
+ the_vector->lock_count = 0;
+ the_vector->deferred_count = 0;
+ _Chain_Initialize_empty( &the_vector->Handlers );
+ }
+}
+
+/*PAGE
+ *
+ * 22.3.1 Associate a User-Written ISR with an Interrupt, P1003.4b/D8, p. 74
+ */
+
+int intr_capture(
+ intr_t intr,
+ int (*intr_handler)( void *area ),
+ volatile void *area,
+ size_t areasize
+)
+{
+ POSIX_Interrupt_Handler_control *the_intr;
+ POSIX_Interrupt_Control *the_vector;
+ POSIX_API_Thread_Support_Control *thread_support;
+ proc_ptr old_handler;
+
+ if ( !_ISR_Is_vector_number_valid( intr ) ||
+ !_ISR_Is_valid_user_handler( intr_handler ) )
+ return EINVAL;
+
+ _Thread_Disable_dispatch();
+
+ the_intr = _POSIX_Interrupt_Allocate();
+
+ if ( !the_intr ) {
+ _Thread_Enable_dispatch();
+ return ENOMEM;
+ }
+
+ the_vector = &_POSIX_Interrupt_Information[ intr ];
+
+ the_intr->vector = intr;
+ the_intr->handler = intr_handler;
+ the_intr->user_data_area = area;
+ the_intr->server = _Thread_Executing;
+ the_intr->is_active = TRUE;
+
+ thread_support = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ];
+ thread_support->interrupts_installed++;
+
+/* XXX should we malloc the semaphore on the fly??? if so we probably need to
+ release it when the thread has released all interrupts and keep
+ a count of how many it has installed. CURRENTLY NO.. ALLOCATED w/TCB
+*/
+
+ /*
+ * This is sufficient to have the handlers invoked in the opposite
+ * order of installation. The loop invoking them can then go from
+ * the front of the list to the end.
+ */
+
+ _Chain_Prepend( &the_vector->Handlers, &the_intr->Object.Node );
+
+ if ( !the_vector->number_installed++ )
+ _ISR_Install_vector(
+ intr,
+ (proc_ptr) _POSIX_Interrupt_Handler,
+ &old_handler
+ );
+
+ _Objects_Open( &_POSIX_Interrupt_Handlers_Information, &the_intr->Object, 0 );
+
+ /*
+ * Normally, an Id would be returned here.
+ */
+
+ _Thread_Enable_dispatch();
+
+ return 0;
+}
+
+/*PAGE
+ *
+ * 22.3.1 Associate a User-Written ISR with an Interrupt, P1003.4b/D8, p. 74
+ */
+
+int intr_release(
+ intr_t intr,
+ int (*intr_handler)( void *area )
+)
+{
+ boolean found;
+ POSIX_Interrupt_Handler_control *the_intr;
+ POSIX_Interrupt_Control *the_vector;
+ POSIX_API_Thread_Support_Control *thread_support;
+ Chain_Node *the_node;
+
+ if ( !_ISR_Is_valid_user_handler( intr_handler ) )
+ return EINVAL;
+
+ _Thread_Disable_dispatch();
+
+ /*
+ * Since interrupt handlers do not have a user visible id, there is
+ * no choice but to search the entire set of active interrupt handlers
+ * to find this one.
+ */
+
+ found = FALSE;
+
+ the_vector = &_POSIX_Interrupt_Information[ intr ];
+
+ the_node = _Chain_Head( &the_vector->Handlers );
+
+ for ( ; !_Chain_Is_tail( &the_vector->Handlers, the_node ) ; ) {
+ the_intr = (POSIX_Interrupt_Handler_control *) the_node;
+
+ if ( the_intr->handler == intr_handler ) {
+ found = TRUE;
+ break;
+ }
+ the_node = the_node->next;
+ }
+
+ if ( !found ) {
+ _Thread_Enable_dispatch();
+ return EINVAL;
+ }
+
+ if ( !_Thread_Is_executing( the_intr->server ) ) {
+ _Thread_Enable_dispatch();
+ return EINVAL; /* XXX should be ENOISR; */
+ }
+
+ /*
+ * OK now we have found the interrupt handler and can do some work.
+ */
+
+ _Chain_Extract( &the_intr->Object.Node );
+
+ the_intr->is_active = FALSE;
+
+ the_vector->number_installed -= 1;
+
+ thread_support = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ];
+ thread_support->interrupts_installed--;
+
+ /*
+ * It is unnecessary to flush the semaphore since the handler can only
+ * be "removed" by the thread which installed it. Thus it cannot be
+ * blocked on the semaphore or it would not be executing this routine.
+ */
+
+ _Objects_Close( &_POSIX_Interrupt_Handlers_Information, &the_intr->Object );
+
+ _POSIX_Interrupt_Free( the_intr );
+
+ _Thread_Enable_dispatch();
+
+ return 0;
+}
+
+/*PAGE
+ *
+ * 22.3.1 Associate a User-Written ISR with an Interrupt, P1003.4b/D8, p. 74
+ */
+
+int intr_lock(
+ intr_t intr
+)
+{
+ POSIX_Interrupt_Control *the_vector;
+
+ _Thread_Disable_dispatch();
+
+ the_vector = &_POSIX_Interrupt_Information[ intr ];
+
+ the_vector->lock_count++;
+
+ _Thread_Enable_dispatch();
+
+ return 0;
+}
+
+/*PAGE
+ *
+ * 22.3.1 Associate a User-Written ISR with an Interrupt, P1003.4b/D8, p. 74
+ */
+
+int intr_unlock(
+ intr_t intr
+)
+{
+ POSIX_Interrupt_Control *the_vector;
+
+ _Thread_Disable_dispatch();
+
+ the_vector = &_POSIX_Interrupt_Information[ intr ];
+
+ if ( !--the_vector->lock_count ) {
+ while ( --the_vector->deferred_count ) {
+ _POSIX_Interrupt_Handler( intr );
+ }
+ }
+
+ _Thread_Enable_dispatch();
+
+ return 0;
+}
+
+/*
+ * 22.3.2 Await Interrupt Notification, P1003.4b/D8, p. 76
+ */
+
+int intr_timed_wait(
+ int flags,
+ const struct timespec *timeout
+)
+{
+ Watchdog_Interval ticks;
+ POSIX_API_Thread_Support_Control *thread_support;
+
+ ticks = _POSIX_Time_Spec_to_interval( timeout );
+
+ thread_support = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ];
+
+ _Thread_Disable_dispatch();
+
+ _CORE_semaphore_Seize(
+ &thread_support->Interrupt_Semaphore,
+ 0, /* XXX does id=0 hurt in this case? */
+ TRUE,
+ ticks
+ );
+ _Thread_Enable_dispatch();
+
+ return _Thread_Executing->Wait.return_code; /* XXX should be POSIX */
+}
+
+/*PAGE
+ *
+ * _POSIX_Interrupt_Handler
+ *
+ */
+
+void _POSIX_Interrupt_Handler(
+ ISR_Vector_number vector
+)
+{
+ POSIX_Interrupt_Handler_control *the_intr;
+ POSIX_Interrupt_Control *the_vector;
+ POSIX_API_Thread_Support_Control *thread_support;
+ Chain_Node *the_node;
+ int status;
+
+ the_vector = &_POSIX_Interrupt_Information[ vector ];
+
+ the_node = _Chain_Head( &the_vector->Handlers );
+
+ for ( ; !_Chain_Is_tail( &the_vector->Handlers, the_node ) ; ) {
+ the_intr = (POSIX_Interrupt_Handler_control *) the_node;
+
+ status = (*the_intr->handler)( (void *) the_intr->user_data_area );
+
+ switch ( status ) {
+ case INTR_HANDLED_NOTIFY:
+ thread_support = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ];
+
+ _CORE_semaphore_Surrender(
+ &thread_support->Interrupt_Semaphore,
+ 0, /* XXX is id=0 a problem */
+ 0 /* XXX is this a problem (mp support)*/
+ );
+ return;
+
+ case INTR_HANDLED_DO_NOT_NOTIFY:
+ return;
+
+ case INTR_NOT_HANDLED:
+ default: /* this should not happen */
+ break;
+ }
+ the_node = the_node->next;
+ }
+
+ /* XXX
+ *
+ * This is an unhandled interrupt!!!
+ */
+}