source: rtems/c/src/lib/libbsp/shared/src/irq-server.c @ 8dbb14d5

5
Last change on this file since 8dbb14d5 was 8dbb14d5, checked in by Sebastian Huber <sebastian.huber@…>, on 11/03/15 at 10:14:21

bsp/irq-server: Use proper chain API

  • Property mode set to 100644
File size: 6.1 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, 2015 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
28#include <bsp/irq-generic.h>
29
30#define BSP_INTERRUPT_EVENT RTEMS_EVENT_13
31
32RTEMS_INTERRUPT_LOCK_DEFINE(
33  static,
34  bsp_interrupt_server_lock,
35  "Interrupt Server"
36)
37
38typedef struct bsp_interrupt_server_entry {
39  rtems_chain_node node;
40  rtems_vector_number vector;
41  rtems_interrupt_handler handler;
42  void *arg;
43} bsp_interrupt_server_entry;
44
45static rtems_id bsp_interrupt_server_id = RTEMS_ID_NONE;
46
47static RTEMS_CHAIN_DEFINE_EMPTY(bsp_interrupt_server_chain);
48
49static rtems_status_code bsp_interrupt_server_is_initialized(void)
50{
51  if (bsp_interrupt_server_id != RTEMS_ID_NONE) {
52    return RTEMS_SUCCESSFUL;
53  } else {
54    return RTEMS_INCORRECT_STATE;
55  }
56}
57
58static unsigned bsp_interrupt_server_errors;
59
60static void bsp_interrupt_server_trigger(void *arg)
61{
62  bsp_interrupt_server_entry *e = arg;
63
64  bsp_interrupt_vector_disable(e->vector);
65
66  if (rtems_chain_is_node_off_chain(&e->node)) {
67    rtems_interrupt_lock_context lock_context;
68
69    rtems_interrupt_lock_acquire(&bsp_interrupt_server_lock, &lock_context);
70    rtems_chain_append_unprotected(&bsp_interrupt_server_chain, &e->node);
71    rtems_interrupt_lock_release(&bsp_interrupt_server_lock, &lock_context);
72  } else {
73    ++bsp_interrupt_server_errors;
74  }
75
76  rtems_event_send(bsp_interrupt_server_id, BSP_INTERRUPT_EVENT);
77}
78
79static bsp_interrupt_server_entry *bsp_interrupt_server_get_entry(void)
80{
81  rtems_interrupt_lock_context lock_context;
82  bsp_interrupt_server_entry *e;
83  rtems_chain_control *chain;
84
85  rtems_interrupt_lock_acquire(&bsp_interrupt_server_lock, &lock_context);
86  chain = &bsp_interrupt_server_chain;
87
88  if (!rtems_chain_is_empty(chain)) {
89    e = (bsp_interrupt_server_entry *)
90      rtems_chain_get_first_unprotected(chain);
91    rtems_chain_set_off_chain(&e->node);
92  } else {
93    e = NULL;
94  }
95
96  rtems_interrupt_lock_release(&bsp_interrupt_server_lock, &lock_context);
97
98  return e;
99}
100
101static void bsp_interrupt_server_task(rtems_task_argument arg)
102{
103  rtems_status_code sc = RTEMS_SUCCESSFUL;
104
105  while (true) {
106    rtems_event_set events = 0;
107    bsp_interrupt_server_entry *e = NULL;
108
109    sc = rtems_event_receive(
110      BSP_INTERRUPT_EVENT,
111      RTEMS_EVENT_ALL | RTEMS_WAIT,
112      RTEMS_NO_TIMEOUT,
113      &events
114    );
115    if (sc != RTEMS_SUCCESSFUL) {
116      break;
117    }
118
119    while ((e = bsp_interrupt_server_get_entry()) != NULL) {
120      (*e->handler)(e->arg);
121
122      bsp_interrupt_vector_enable(e->vector);
123    }
124  }
125
126  rtems_task_delete(RTEMS_SELF);
127}
128
129typedef struct {
130  rtems_interrupt_handler handler;
131  void *arg;
132  bsp_interrupt_server_entry *entry;
133} bsp_interrupt_server_iterate_entry;
134
135static void bsp_interrupt_server_per_handler_routine(
136  void *iterate_arg,
137  const char *info,
138  rtems_option options,
139  rtems_interrupt_handler handler,
140  void *handler_arg
141)
142{
143  bsp_interrupt_server_iterate_entry *ie = iterate_arg;
144  bsp_interrupt_server_entry *e = handler_arg;
145
146  if (handler == bsp_interrupt_server_trigger) {
147    if (e->handler == ie->handler && e->arg == ie->arg) {
148      ie->entry = e;
149    }
150  }
151}
152
153rtems_status_code rtems_interrupt_server_handler_install(
154  rtems_id server,
155  rtems_vector_number vector,
156  const char *info,
157  rtems_option options,
158  rtems_interrupt_handler handler,
159  void *arg
160)
161{
162  rtems_status_code sc = RTEMS_SUCCESSFUL;
163  bsp_interrupt_server_entry *e = NULL;
164
165  sc = bsp_interrupt_server_is_initialized();
166  if (sc != RTEMS_SUCCESSFUL) {
167    return sc;
168  }
169
170  if (server != RTEMS_ID_NONE) {
171    return RTEMS_NOT_IMPLEMENTED;
172  }
173
174  if (RTEMS_INTERRUPT_IS_SHARED(options)) {
175    return RTEMS_NOT_IMPLEMENTED;
176  }
177
178  e = calloc(1, sizeof(*e));
179  if (e == NULL) {
180    return RTEMS_NO_MEMORY;
181  }
182
183  e->vector = vector;
184  e->handler = handler;
185  e->arg = arg;
186
187  sc = rtems_interrupt_handler_install(
188    vector,
189    info,
190    options,
191    bsp_interrupt_server_trigger,
192    e
193  );
194  if (sc != RTEMS_SUCCESSFUL) {
195    free(e);
196
197    return sc;
198  }
199
200  return RTEMS_SUCCESSFUL;
201}
202
203rtems_status_code rtems_interrupt_server_handler_remove(
204  rtems_id server,
205  rtems_vector_number vector,
206  rtems_interrupt_handler handler,
207  void *arg
208)
209{
210  rtems_status_code sc = RTEMS_SUCCESSFUL;
211  bsp_interrupt_server_iterate_entry ie = {
212    .handler = handler,
213    .arg = arg,
214    .entry = NULL
215  };
216
217  sc = bsp_interrupt_server_is_initialized();
218  if (sc != RTEMS_SUCCESSFUL) {
219    return sc;
220  }
221
222  if (server != RTEMS_ID_NONE) {
223    return RTEMS_NOT_IMPLEMENTED;
224  }
225
226  /* Query corresponding interrupt server entry */
227  sc = rtems_interrupt_handler_iterate(
228    vector,
229    bsp_interrupt_server_per_handler_routine,
230    &ie
231  );
232  if (sc != RTEMS_SUCCESSFUL) {
233    return sc;
234  } else if (ie.entry == NULL) {
235    return RTEMS_INVALID_ID;
236  }
237
238  sc = rtems_interrupt_handler_remove(
239    vector,
240    bsp_interrupt_server_trigger,
241    ie.entry
242  );
243  if (sc != RTEMS_SUCCESSFUL) {
244    return sc;
245  }
246
247  free(ie.entry);
248
249  return RTEMS_SUCCESSFUL;
250}
251
252rtems_status_code rtems_interrupt_server_initialize(
253  rtems_task_priority priority,
254  size_t stack_size,
255  rtems_mode modes,
256  rtems_attribute attributes,
257  rtems_id *server
258)
259{
260  rtems_status_code sc = RTEMS_SUCCESSFUL;
261
262  if (server != NULL) {
263    return RTEMS_NOT_IMPLEMENTED;
264  }
265
266  sc = rtems_task_create(
267    rtems_build_name('I', 'R', 'Q', 'S'),
268    priority,
269    stack_size,
270    modes,
271    attributes,
272    &bsp_interrupt_server_id
273  );
274  if (sc != RTEMS_SUCCESSFUL) {
275    return RTEMS_TOO_MANY;
276  }
277
278  sc = rtems_task_start(
279    bsp_interrupt_server_id,
280    bsp_interrupt_server_task,
281    0
282  );
283  if (sc != RTEMS_SUCCESSFUL) {
284    /* In this case we could also panic */
285    rtems_task_delete(bsp_interrupt_server_id);
286    bsp_interrupt_server_id = RTEMS_ID_NONE;
287
288    return RTEMS_TOO_MANY;
289  }
290
291  return RTEMS_SUCCESSFUL;
292}
Note: See TracBrowser for help on using the repository browser.