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

5
Last change on this file since 5c7bfcf was 4fee129, checked in by Sebastian Huber <sebastian.huber@…>, on 11/11/15 at 09:47:52

Introduce general purpose system server event

Use this event for the interrupt server to avoid conflicts with
application events used by interrupt handlers.

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