source: rtems/c/src/lib/libbsp/sparc/shared/irq/genirq.c @ d968826

5
Last change on this file since d968826 was d968826, checked in by Joel Sherrill <joel@…>, on Apr 23, 2017 at 4:48:32 PM

irq/genirq.c: Include <rtems/bspIo.h>

  • Property mode set to 100644
File size: 5.2 KB
Line 
1/*
2 * Generic interrupt helpers mainly for GRLIB PCI peripherals
3 *
4 * COPYRIGHT (c) 2008.
5 * Cobham Gaisler AB.
6 *
7 * The license and distribution terms for this file may be
8 * found in the file LICENSE in this distribution or at
9 * http://www.rtems.org/license/LICENSE.
10 */
11
12#include <rtems.h>
13#include <rtems/bspIo.h>
14#include <stdlib.h>
15#include <string.h>
16#include <bsp/genirq.h>
17
18struct genirq_handler_entry {
19        struct genirq_handler_entry     *next;          /* Next ISR entry for this IRQ number */
20        genirq_handler                  isr;            /* ISR function called upon IRQ */
21        void                            *arg;           /* custom argument to ISR */
22        int                             enabled;        /* Inidicates if IRQ is enabled */
23};
24
25struct genirq_irq_entry {
26        struct genirq_handler_entry     *head;
27        struct genirq_stats             stats;
28};
29
30struct genirq_priv {
31        /* Maximum number of interrupt */
32        int                             genirq_max;
33        /* IRQ Table index N reflect IRQ number N */
34        struct genirq_irq_entry         genirq_table[1]; /* Length depends on */
35};
36
37genirq_t genirq_init(int number_of_irqs)
38{
39        int size;
40        struct genirq_priv *priv;
41
42        size = sizeof(int) +
43               number_of_irqs * sizeof(struct genirq_irq_entry);
44
45        priv = (struct genirq_priv *)malloc(size);
46        if ( !priv )
47                return NULL;
48        memset(priv, 0, size);
49        priv->genirq_max = number_of_irqs - 1;
50        return priv;
51}
52
53void genirq_destroy(genirq_t d)
54{
55        struct genirq_priv *priv = d;
56        struct genirq_irq_entry *irqentry;
57        struct genirq_handler_entry *isrentry, *tmp;
58        int i;
59
60        /* Free all registered interrupts */
61        for ( i=0; i<priv->genirq_max; i++) {
62                irqentry = &priv->genirq_table[i];
63                isrentry = irqentry->head;
64                while ( isrentry ) {
65                        tmp = isrentry;
66                        isrentry = isrentry->next;
67                        free(tmp);
68                }
69        }
70
71        free(priv);
72}
73
74int genirq_check(genirq_t d, int irq)
75{
76        struct genirq_priv *priv = d;
77
78        if ( (irq <= 0) || (irq > priv->genirq_max) )
79                return -1;
80        else
81                return 0;
82}
83
84int genirq_register(genirq_t d, int irq, genirq_handler isr, void *arg)
85{
86        struct genirq_priv *priv = d;
87        struct genirq_irq_entry *irqentry;
88        struct genirq_handler_entry *isrentry, *newentry;
89        rtems_interrupt_level level;
90       
91        if ( genirq_check(d, irq) )
92                return -1;
93
94        newentry = malloc(sizeof(*newentry));
95        if ( !newentry )
96                return -1;
97
98        /* Initialize ISR entry */
99        newentry->isr     = isr;
100        newentry->arg     = arg;
101        newentry->enabled = 0;
102
103        rtems_interrupt_disable(level);
104
105        /* Insert new ISR entry first into table */
106        irqentry = &priv->genirq_table[irq];
107        isrentry = irqentry->head;
108        irqentry->head = newentry;
109        newentry->next = isrentry;
110
111        rtems_interrupt_enable(level);
112
113        if ( isrentry )
114                return 1; /* This is the first handler on this IRQ */
115        return 0;
116}
117
118int genirq_unregister(genirq_t d, int irq, genirq_handler isr, void *arg)
119{
120        struct genirq_priv *priv = d;
121        struct genirq_irq_entry *irqentry;
122        struct genirq_handler_entry *isrentry, **prev;
123        rtems_interrupt_level level;
124        int ret;
125
126        if ( genirq_check(d, irq) )
127                return -1;
128
129        /* Remove isr[arg] from ISR list */
130        irqentry = &priv->genirq_table[irq];
131        ret = -1;
132
133        rtems_interrupt_disable(level);
134
135        prev = &irqentry->head;
136        isrentry = irqentry->head;
137        while ( isrentry ) {
138                if ( (isrentry->arg == arg) && (isrentry->isr == isr) ) {
139                        /* Found ISR, remove it from list */
140                        if ( isrentry->enabled ) {
141                                /* Can not remove enabled ISRs, disable first */
142                                ret = 1;
143                                break;
144                        }
145                        *prev = isrentry->next;
146                        ret = 0;
147                        break;
148                }
149                prev = &isrentry->next;
150                isrentry = isrentry->next;
151        }
152
153        rtems_interrupt_enable(level);
154
155        return ret;
156}
157
158/* Enables or Disables ISR handler. Internal function to reduce footprint
159 * of enable/disable functions.
160 *
161 * \param action 1=enable, 0=disable ISR
162 */
163static int genirq_set_active(
164        struct genirq_priv *priv,
165        int irq,
166        genirq_handler isr,
167        void *arg,
168        int action)
169{
170        struct genirq_irq_entry *irqentry;
171        struct genirq_handler_entry *isrentry, *e = NULL;
172        int enabled;
173
174        if ( genirq_check(priv, irq) )
175                return -1;
176
177        /* Find isr[arg] in ISR list */
178        irqentry = &priv->genirq_table[irq];
179        enabled = 0;
180
181        isrentry = irqentry->head;
182        while ( isrentry ) {
183                if ( (isrentry->arg == arg) && (isrentry->isr == isr) ) {
184                        /* Found ISR */
185                        if ( isrentry->enabled == action ) {
186                                /* The ISR is already enabled or disabled
187                                 * depending on request, neccessary actions
188                                 * were taken last time the same action was
189                                 * requested.
190                                 */
191                                return 1;
192                        }
193                        e = isrentry;
194                } else {
195                        enabled += isrentry->enabled;
196                }
197                isrentry = isrentry->next;
198        }
199
200        if ( !e )
201                return -1;
202
203        e->enabled = action;
204
205        return enabled;
206}
207
208int genirq_enable(genirq_t d, int irq, genirq_handler isr, void *arg)
209{
210        struct genirq_priv *priv = d;
211        return genirq_set_active(priv, irq, isr, arg, 1);
212}
213
214int genirq_disable(genirq_t d, int irq, genirq_handler isr, void *arg)
215{
216        struct genirq_priv *priv = d;
217        return genirq_set_active(priv, irq, isr, arg, 0);
218}
219
220void genirq_doirq(genirq_t d, int irq)
221{
222        struct genirq_priv *priv = d;
223        struct genirq_irq_entry *irqentry;
224        struct genirq_handler_entry *isrentry;
225        int enabled;
226
227        irqentry = &priv->genirq_table[irq];
228        irqentry->stats.irq_cnt++;
229       
230        enabled = 0;
231
232        isrentry = irqentry->head;
233        while ( isrentry ) {
234                if ( isrentry->enabled ) {
235                        enabled = 1;
236                        /* Call the ISR */
237                        isrentry->isr(isrentry->arg);
238                }
239                isrentry = isrentry->next;
240        }
241
242        /* Was the IRQ an IRQ without source? */
243        if ( enabled == 0 ) {
244                /* This should not happen */
245                printk("Spurious IRQ happened on IRQ %d\n", irq);
246        }
247}
Note: See TracBrowser for help on using the repository browser.