summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/arm/gba/irq/irq.c
blob: 6abc48f6e3bd2a65bec6287e5680a649317555e5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/**
 *  @file irq.c
 *
 *  This file contains the implementation of the function described in irq.h.
 */
/*
 *  RTEMS GBA BSP
 *
 *  Copyright (c) 2002 by Jay Monkman <jtm@smoothsmoothie.com>
 *
 *  Copyright (c) 2002 by Charlie Steader <charlies@poliac.com>
 *
 *  Copyright (c) 2004 by Markku Puro <markku.puro@kopteri.net>
 *
 *  The license and distribution terms for this file may be
 *  found in found in the file LICENSE in this distribution or at
 *  http://www.rtems.com/license/LICENSE.
 *
 *  $Id$
 */

#include <bsp.h>
#include <irq.h>
#include <gba_registers.h>
#include <rtems/score/thread.h>
#include <rtems/score/apiext.h>


/**
 *  @brief isValidInterrupt function check that the value given for the irq line is valid.
 *
 *  @param  irq irq number
 *  @return status code TRUE/FALSE (0/1)
 */
static int isValidInterrupt(int irq)
{
  if ( (irq < 0) || (irq > BSP_MAX_INT)) {
     return 0;
  }
  return 1;
}

/*
 * ------------------------ RTEMS Single Irq Handler Mngt Routines ----------------
 */


/**
 *  @brief BSP_install_rtems_irq_handler function install rtems irq handler.
 *
 *  @param  irq irq connect data
 *  @return status code TRUE/FALSE (0/1)
 */
int BSP_install_rtems_irq_handler  (const rtems_irq_connect_data* irq)
{
    rtems_irq_hdl *HdlTable;
    rtems_interrupt_level level;

    if (!isValidInterrupt(irq->name)) {
       return 0;
    }
    /*
     * Check if default handler is actually connected. If not issue an error.
     */
    HdlTable = (rtems_irq_hdl *) (uint32_t)VECTOR_TABLE;
    if (*(HdlTable + irq->name) != default_int_handler) {
       return 0;
    }

    rtems_interrupt_disable(level);

    /*
     * store the new handler
     */
    *(HdlTable + irq->name) = irq->hdl;

    /*
     * ack pending interrupt
     */
    GBA_REG_IF |= (1 << (irq->name));

    /*
     * initialize the control register for the concerned interrupt
     */
    GBA_REG_IE |= (1 << (irq->name));

    /*
     * Enable interrupt on device
     */
	if (irq->on)
    	irq->on(irq);

    rtems_interrupt_enable(level);

    return 1;
}

/**
 *  @brief BSP_remove_rtems_irq_handler function removes rtems irq handler.
 *
 *  @param  irq irq connect data
 *  @return status code TRUE/FALSE (0/1)
 */
int BSP_remove_rtems_irq_handler  (const rtems_irq_connect_data* irq)
{
    rtems_irq_hdl *HdlTable;
    rtems_interrupt_level level;

    if (!isValidInterrupt(irq->name)) {
       return 0;
    }
    /*
     * Check if the handler is actually connected. If not issue an error.
     */
    HdlTable = (rtems_irq_hdl *) (uint32_t)VECTOR_TABLE;
    if (*(HdlTable + irq->name) != irq->hdl) {
       return 0;
    }
    rtems_interrupt_disable(level);

    /*
     * mask at INT controller level
     */
    GBA_REG_IE &= ~(1 << irq->name);

    /*
     * Disable interrupt on device
     */
	if (irq->off)
    	irq->off(irq);

    /*
     * restore the default irq value
     */
    *(HdlTable + irq->name) = default_int_handler;

    rtems_interrupt_enable(level);

    return 1;
}


/**
 *  @brief _ThreadProcessSignalsFromIrq function check that the value given for the irq line is valid.
 *
 *  @param  cxt exeption frame
 *  @return None
 */
void _ThreadProcessSignalsFromIrq (CPU_Exception_frame* ctx)
{
  /*
   * Process pending signals that have not already been
   * processed by _Thread_Dispatch. This happens quite
   * unfrequently : the ISR must have posted an action
   * to the current running thread.
   */
  if ( _Thread_Do_post_task_switch_extension ||
       _Thread_Executing->do_post_task_switch_extension )
  {
     _Thread_Executing->do_post_task_switch_extension = false;
     _API_extensions_Run_postswitch();
  }
}