source: rtems/c/src/lib/libbsp/shared/src/irq-server.c @ 12bc6c5

5
Last change on this file since 12bc6c5 was d9bd59da, checked in by Sebastian Huber <sebastian.huber@…>, on 11/03/15 at 10:44:11

bsp/irq-server: Support shared interrupts

  • Property mode set to 100644
File size: 8.3 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup bsp_interrupt
5 *
6 * @brief Generic BSP interrupt server implementation.
7 */
8
9/*
10 * Copyright (c) 2009, 2016 embedded brains GmbH.  All rights reserved.
11 *
12 *  embedded brains GmbH
13 *  Dornierstr. 4
14 *  82178 Puchheim
15 *  Germany
16 *  <rtems@embedded-brains.de>
17 *
18 * The license and distribution terms for this file may be
19 * found in the file LICENSE in this distribution or at
20 * http://www.rtems.org/license/LICENSE.
21 */
22
23#include <stdlib.h>
24
25#include <rtems.h>
26#include <rtems/chain.h>
27#include <rtems/score/assert.h>
28
29#include <bsp/irq-generic.h>
30
31RTEMS_INTERRUPT_LOCK_DEFINE(
32  static,
33  bsp_interrupt_server_lock,
34  "Interrupt Server"
35)
36
37typedef struct bsp_interrupt_server_action {
38  struct bsp_interrupt_server_action *next;
39  rtems_interrupt_handler handler;
40  void *arg;
41} bsp_interrupt_server_action;
42
43typedef struct {
44  rtems_chain_node node;
45  rtems_vector_number vector;
46  bsp_interrupt_server_action *actions;
47} bsp_interrupt_server_entry;
48
49static rtems_id bsp_interrupt_server_id = RTEMS_ID_NONE;
50
51static RTEMS_CHAIN_DEFINE_EMPTY(bsp_interrupt_server_chain);
52
53static rtems_status_code bsp_interrupt_server_is_initialized(void)
54{
55  if (bsp_interrupt_server_id != RTEMS_ID_NONE) {
56    return RTEMS_SUCCESSFUL;
57  } else {
58    return RTEMS_INCORRECT_STATE;
59  }
60}
61
62static unsigned bsp_interrupt_server_errors;
63
64static void bsp_interrupt_server_trigger(void *arg)
65{
66  rtems_interrupt_lock_context lock_context;
67  bsp_interrupt_server_entry *e = arg;
68
69  bsp_interrupt_vector_disable(e->vector);
70
71  rtems_interrupt_lock_acquire(&bsp_interrupt_server_lock, &lock_context);
72
73  if (rtems_chain_is_node_off_chain(&e->node)) {
74    rtems_chain_append_unprotected(&bsp_interrupt_server_chain, &e->node);
75  } else {
76    ++bsp_interrupt_server_errors;
77  }
78
79  rtems_interrupt_lock_release(&bsp_interrupt_server_lock, &lock_context);
80
81  rtems_event_system_send(bsp_interrupt_server_id, RTEMS_EVENT_SYSTEM_SERVER);
82}
83
84typedef struct {
85  bsp_interrupt_server_action *action;
86  bsp_interrupt_server_action **link;
87  rtems_id task;
88} bsp_interrupt_server_helper_data;
89
90static void bsp_interrupt_server_helper(void *arg)
91{
92  bsp_interrupt_server_helper_data *hd = arg;
93
94  *hd->link = hd->action;
95  rtems_event_transient_send(hd->task);
96}
97
98static void bsp_interrupt_server_call_helper(
99  bsp_interrupt_server_action *action,
100  bsp_interrupt_server_action **link
101)
102{
103  bsp_interrupt_server_helper_data hd = {
104    .action = action,
105    .link = link,
106    .task = rtems_task_self()
107  };
108  bsp_interrupt_server_action a = {
109    .handler = bsp_interrupt_server_helper,
110    .arg = &hd
111  };
112  bsp_interrupt_server_entry e = {
113    .vector = BSP_INTERRUPT_VECTOR_MAX + 1,
114    .actions = &a
115  };
116
117  bsp_interrupt_server_trigger(&e);
118  rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
119}
120
121static bsp_interrupt_server_entry *bsp_interrupt_server_get_entry(void)
122{
123  rtems_interrupt_lock_context lock_context;
124  bsp_interrupt_server_entry *e;
125  rtems_chain_control *chain;
126
127  rtems_interrupt_lock_acquire(&bsp_interrupt_server_lock, &lock_context);
128  chain = &bsp_interrupt_server_chain;
129
130  if (!rtems_chain_is_empty(chain)) {
131    e = (bsp_interrupt_server_entry *)
132      rtems_chain_get_first_unprotected(chain);
133    rtems_chain_set_off_chain(&e->node);
134  } else {
135    e = NULL;
136  }
137
138  rtems_interrupt_lock_release(&bsp_interrupt_server_lock, &lock_context);
139
140  return e;
141}
142
143static void bsp_interrupt_server_task(rtems_task_argument arg)
144{
145  while (true) {
146    rtems_event_set events;
147    bsp_interrupt_server_entry *e;
148
149    rtems_event_system_receive(
150      RTEMS_EVENT_SYSTEM_SERVER,
151      RTEMS_EVENT_ALL | RTEMS_WAIT,
152      RTEMS_NO_TIMEOUT,
153      &events
154    );
155
156    while ((e = bsp_interrupt_server_get_entry()) != NULL) {
157      bsp_interrupt_server_action *action = e->actions;
158      rtems_vector_number vector = e->vector;
159
160      do {
161        bsp_interrupt_server_action *current = action;
162        action = action->next;
163        (*current->handler)(current->arg);
164      } while (action != NULL);
165
166      bsp_interrupt_vector_enable(vector);
167    }
168  }
169}
170
171typedef struct {
172  bsp_interrupt_server_entry *entry;
173  rtems_option *options;
174} bsp_interrupt_server_iterate_entry;
175
176static void bsp_interrupt_server_per_handler_routine(
177  void *iterate_arg,
178  const char *info,
179  rtems_option options,
180  rtems_interrupt_handler handler,
181  void *handler_arg
182)
183{
184  if (handler == bsp_interrupt_server_trigger) {
185    bsp_interrupt_server_iterate_entry *ie = iterate_arg;
186
187    ie->entry = handler_arg;
188    *ie->options = options;
189  }
190}
191
192static bsp_interrupt_server_entry *bsp_interrupt_server_query_entry(
193  rtems_vector_number vector,
194  rtems_option *trigger_options
195)
196{
197  bsp_interrupt_server_iterate_entry ie = {
198    .entry = NULL,
199    .options = trigger_options
200  };
201
202  rtems_interrupt_handler_iterate(
203    vector,
204    bsp_interrupt_server_per_handler_routine,
205    &ie
206  );
207
208  return ie.entry;
209}
210
211rtems_status_code rtems_interrupt_server_handler_install(
212  rtems_id server,
213  rtems_vector_number vector,
214  const char *info,
215  rtems_option options,
216  rtems_interrupt_handler handler,
217  void *arg
218)
219{
220  rtems_status_code sc;
221  bsp_interrupt_server_entry *e;
222  bsp_interrupt_server_action *a;
223  rtems_option trigger_options;
224
225  sc = bsp_interrupt_server_is_initialized();
226  if (sc != RTEMS_SUCCESSFUL) {
227    return sc;
228  }
229
230  if (server != RTEMS_ID_NONE) {
231    return RTEMS_NOT_IMPLEMENTED;
232  }
233
234  a = calloc(1, sizeof(*a));
235  if (a == NULL) {
236    return RTEMS_NO_MEMORY;
237  }
238
239  a->handler = handler;
240  a->arg = arg;
241
242  bsp_interrupt_lock();
243
244  e = bsp_interrupt_server_query_entry(vector, &trigger_options);
245  if (e == NULL) {
246    e = calloc(1, sizeof(*e));
247    if (e != NULL) {
248      e->vector = vector;
249      e->actions = a;
250
251      sc = rtems_interrupt_handler_install(
252        vector,
253        "IRQS",
254        options & RTEMS_INTERRUPT_UNIQUE,
255        bsp_interrupt_server_trigger,
256        e
257      );
258      if (sc != RTEMS_SUCCESSFUL) {
259        free(e);
260      }
261    } else {
262      sc = RTEMS_NO_MEMORY;
263    }
264  } else if (
265    RTEMS_INTERRUPT_IS_UNIQUE(options)
266      || RTEMS_INTERRUPT_IS_UNIQUE(trigger_options)
267  ) {
268    sc = RTEMS_RESOURCE_IN_USE;
269  } else {
270    bsp_interrupt_server_action **link = &e->actions;
271    bsp_interrupt_server_action *c;
272
273    while ((c = *link) != NULL) {
274      if (c->handler == handler && c->arg == arg) {
275        sc = RTEMS_TOO_MANY;
276        break;
277      }
278
279      link = &c->next;
280    }
281
282    if (sc == RTEMS_SUCCESSFUL) {
283      bsp_interrupt_server_call_helper(a, link);
284    }
285  }
286
287  bsp_interrupt_unlock();
288
289  if (sc != RTEMS_SUCCESSFUL) {
290    free(a);
291  }
292
293  return sc;
294}
295
296rtems_status_code rtems_interrupt_server_handler_remove(
297  rtems_id server,
298  rtems_vector_number vector,
299  rtems_interrupt_handler handler,
300  void *arg
301)
302{
303  rtems_status_code sc;
304  bsp_interrupt_server_entry *e;
305  rtems_option trigger_options;
306
307  sc = bsp_interrupt_server_is_initialized();
308  if (sc != RTEMS_SUCCESSFUL) {
309    return sc;
310  }
311
312  if (server != RTEMS_ID_NONE) {
313    return RTEMS_NOT_IMPLEMENTED;
314  }
315
316  bsp_interrupt_lock();
317
318  e = bsp_interrupt_server_query_entry(vector, &trigger_options);
319  if (e != NULL) {
320    bsp_interrupt_server_action **link = &e->actions;
321    bsp_interrupt_server_action *c;
322
323    while ((c = *link) != NULL) {
324      if (c->handler == handler && c->arg == arg) {
325        break;
326      }
327
328      link = &c->next;
329    }
330
331    if (c != NULL) {
332      bool remove_last = e->actions->next == NULL;
333
334      if (remove_last) {
335        rtems_interrupt_handler_remove(
336          vector,
337          bsp_interrupt_server_trigger,
338          e
339        );
340      }
341
342      bsp_interrupt_server_call_helper(c->next, link);
343      free(c);
344
345      if (remove_last) {
346        free(e);
347      }
348    } else {
349      sc = RTEMS_UNSATISFIED;
350    }
351  } else {
352    sc = RTEMS_INVALID_ID;
353  }
354
355  bsp_interrupt_unlock();
356
357  return sc;
358}
359
360rtems_status_code rtems_interrupt_server_initialize(
361  rtems_task_priority priority,
362  size_t stack_size,
363  rtems_mode modes,
364  rtems_attribute attributes,
365  rtems_id *server
366)
367{
368  rtems_status_code sc = RTEMS_SUCCESSFUL;
369
370  if (server != NULL) {
371    return RTEMS_NOT_IMPLEMENTED;
372  }
373
374  sc = rtems_task_create(
375    rtems_build_name('I', 'R', 'Q', 'S'),
376    priority,
377    stack_size,
378    modes,
379    attributes,
380    &bsp_interrupt_server_id
381  );
382  if (sc != RTEMS_SUCCESSFUL) {
383    return RTEMS_TOO_MANY;
384  }
385
386  sc = rtems_task_start(
387    bsp_interrupt_server_id,
388    bsp_interrupt_server_task,
389    0
390  );
391  _Assert(sc == RTEMS_SUCCESSFUL);
392
393  return RTEMS_SUCCESSFUL;
394}
Note: See TracBrowser for help on using the repository browser.