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

4.10
Last change on this file since d1d4e017 was d1d4e017, checked in by Sebastian Huber <sebastian.huber@…>, on Jan 3, 2013 at 2:41:16 PM

bsps: Fix rtems_interrupt_server_handler_remove()

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