1// vi:set ft=cpp: -*- Mode: C++ -*-
2/*
3 * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
4 *               Alexander Warg <warg@os.inf.tu-dresden.de>
5 *     economic rights: Technische Universität Dresden (Germany)
6 *
7 * This file is part of TUD:OS and distributed under the terms of the
8 * GNU General Public License 2.
9 * Please see the COPYING-GPL-2 file for details.
10 *
11 * As a special exception, you may use this file as part of a free software
12 * library without restriction.  Specifically, if other files instantiate
13 * templates or use macros or inline functions from this file, or you compile
14 * this file and link it with other files to produce an executable, this
15 * file does not by itself cause the resulting executable to be covered by
16 * the GNU General Public License.  This exception does not however
17 * invalidate any other reasons why the executable file might be covered by
18 * the GNU General Public License.
19 */
20
21#pragma once
22
23#include <l4/sys/capability>
24#include <l4/sys/irq>
25#include <l4/sys/cxx/ipc_iface>
26#include <l4/sys/cxx/ipc_array>
27#include <l4/re/dataspace>
28#include <l4/re/event.h>
29
30namespace L4Re {
31
32/**
33 * \defgroup api_l4re_event Event API
34 * \ingroup api_l4re
35 * Event API.
36 *
37 * On top of a shared L4Re::Dataspace (and optionally using L4::Triggerable),
38 * the event API implements asynchronous event transmission from an event
39 * provider (server) to an event receiver (client). Events are put into an
40 * Event_buffer_t residing on the shared L4Re::Dataspace.
41 *
42 * This interface is not usually used directly. Instead use
43 * L4Re::Util::Event_t for clients. An example server portion is implemented
44 * in L4Re::Util::Event_svr.
45 */
46
47typedef l4re_event_stream_id_t Event_stream_id;
48typedef l4re_event_absinfo_t Event_absinfo;
49
50class L4_EXPORT Event_stream_bitmap_h
51{
52protected:
53  static unsigned __get_idx(unsigned idx)
54  { return idx / (sizeof(unsigned long)*8); }
55
56  static unsigned long __get_mask(unsigned idx)
57  { return 1ul << (idx % (sizeof(unsigned long)*8)); }
58
59  static bool __get_bit(unsigned long const *bm, unsigned max, unsigned idx)
60  {
61    if (idx <= max)
62      return bm[__get_idx(idx)] & __get_mask(idx);
63    return false;
64  }
65
66  static void __set_bit(unsigned long *bm, unsigned max, unsigned idx, bool v)
67  {
68    if (idx > max)
69      return;
70
71    if (v)
72      bm[__get_idx(idx)] |= __get_mask(idx);
73    else
74      bm[__get_idx(idx)] &= ~__get_mask(idx);
75  }
76};
77
78class L4_EXPORT Event_stream_info
79: public l4re_event_stream_info_t,
80  private Event_stream_bitmap_h
81{
82public:
83  bool get_propbit(unsigned idx) const
84  { return __get_bit(propbits, L4RE_EVENT_PROP_MAX, idx); }
85
86  void set_propbit(unsigned idx, bool v)
87  { __set_bit(propbits, L4RE_EVENT_PROP_MAX, idx, v); }
88
89  bool get_evbit(unsigned idx) const
90  { return __get_bit(evbits, L4RE_EVENT_EV_MAX, idx); }
91
92  void set_evbit(unsigned idx, bool v)
93  { __set_bit(evbits, L4RE_EVENT_EV_MAX, idx, v); }
94
95  bool get_keybit(unsigned idx) const
96  { return __get_bit(keybits, L4RE_EVENT_KEY_MAX, idx); }
97
98  void set_keybit(unsigned idx, bool v)
99  { __set_bit(keybits, L4RE_EVENT_KEY_MAX, idx, v); }
100
101  bool get_relbit(unsigned idx) const
102  { return __get_bit(relbits, L4RE_EVENT_REL_MAX, idx); }
103
104  void set_relbit(unsigned idx, bool v)
105  { __set_bit(relbits, L4RE_EVENT_REL_MAX, idx, v); }
106
107  bool get_absbit(unsigned idx) const
108  { return __get_bit(absbits, L4RE_EVENT_ABS_MAX, idx); }
109
110  void set_absbit(unsigned idx, bool v)
111  { __set_bit(absbits, L4RE_EVENT_ABS_MAX, idx, v); }
112
113  bool get_swbit(unsigned idx) const
114  { return __get_bit(swbits, L4RE_EVENT_SW_MAX, idx); }
115
116  void set_swbit(unsigned idx, bool v)
117  { __set_bit(swbits, L4RE_EVENT_SW_MAX, idx, v); }
118};
119
120class L4_EXPORT Event_stream_state
121: public l4re_event_stream_state_t,
122  private Event_stream_bitmap_h
123{
124public:
125  bool get_keybit(unsigned idx) const
126  { return __get_bit(keybits, L4RE_EVENT_KEY_MAX, idx); }
127
128  void set_keybit(unsigned idx, bool v)
129  { __set_bit(keybits, L4RE_EVENT_KEY_MAX, idx, v); }
130
131  bool get_swbit(unsigned idx) const
132  { return __get_bit(swbits, L4RE_EVENT_SW_MAX, idx); }
133
134  void set_swbit(unsigned idx, bool v)
135  { __set_bit(swbits, L4RE_EVENT_SW_MAX, idx, v); }
136};
137
138/**
139 * \brief Event class.
140 * \ingroup api_l4re_event
141 *
142 * \see \link api_l4re_event L4Re Event API \endlink
143 */
144class L4_EXPORT Event :
145  public L4::Kobject_t<Event, L4::Icu, L4RE_PROTO_EVENT>
146{
147public:
148  /**
149   * \brief Get event signal buffer.
150   *
151   * \retval ds Event buffer.
152   *
153   * \return 0 on success, negative error code otherwise.
154   */
155  L4_RPC(long, get_buffer, (L4::Ipc::Out<L4::Cap<Dataspace> > ds));
156  L4_RPC(long, get_num_streams, ());
157  L4_RPC(long, get_stream_info, (int idx, Event_stream_info *info));
158  L4_RPC(long, get_stream_info_for_id, (l4_umword_t stream_id, Event_stream_info *info));
159  L4_RPC_NF(long, get_axis_info, (l4_umword_t stream_id,
160                                  L4::Ipc::Array<unsigned const, unsigned long> axes,
161                                  L4::Ipc::Array<Event_absinfo, unsigned long> &info));
162
163  long get_axis_info(l4_umword_t stream_id, unsigned naxes,
164                     unsigned const *axis, Event_absinfo *info) const noexcept
165  {
166    L4::Ipc::Array<Event_absinfo, unsigned long> i(naxes, info);
167    return get_axis_info_t::call(c(), stream_id,
168        L4::Ipc::Array<unsigned const, unsigned long>(naxes, axis), i);
169  }
170
171  L4_RPC(long, get_stream_state_for_id, (l4_umword_t stream_id,
172                                         Event_stream_state *state));
173
174  typedef L4::Typeid::Rpcs<
175    get_buffer_t,
176    get_num_streams_t,
177    get_stream_info_t,
178    get_stream_info_for_id_t,
179    get_axis_info_t,
180    get_stream_state_for_id_t
181  > Rpcs;
182};
183
184struct L4_EXPORT Default_event_payload
185{
186  unsigned short type;    /**< Type of event */
187  unsigned short code;    /**< Code of event */
188  int value;              /**< Value of event */
189  l4_umword_t stream_id;  /**< Stream ID */
190};
191
192
193/**
194 * \brief Event buffer class.
195 * \ingroup api_l4re_event
196 */
197template< typename PAYLOAD = Default_event_payload >
198class L4_EXPORT Event_buffer_t
199{
200public:
201
202  /**
203   * \brief Event structure used in buffer.
204   */
205  struct Event
206  {
207    long long time;         /**< Event time stamp */
208    PAYLOAD payload;
209
210    /**
211     * \brief Free the entry.
212     */
213    void free() noexcept { l4_mb(); time = 0; }
214  };
215
216private:
217  Event *_current;
218  Event *_begin;
219  Event const *_end;
220
221  void inc() noexcept
222  {
223    ++_current;
224    if (_current == _end)
225      _current = _begin;
226  }
227
228public:
229
230  Event_buffer_t() : _current(0), _begin(0), _end(0) {}
231
232  void reset()
233  {
234    for (Event *i = _begin; i != _end; ++i)
235      i->time = 0;
236    _current = _begin;
237  }
238
239  /**
240   * \brief Initialize event buffer.
241   *
242   * \param buffer   Pointer to buffer.
243   * \param size     Size of buffer in bytes.
244   */
245  Event_buffer_t(void *buffer, l4_addr_t size)
246    : _current((Event*)buffer), _begin(_current),
247      _end(_begin + size / sizeof(Event))
248  { reset(); }
249
250  /**
251   * \brief Next event in buffer.
252   *
253   * \return 0 if no event available, event otherwise.
254   */
255  Event *next() noexcept
256  {
257    Event *c = _current;
258    if (c->time)
259      {
260        inc();
261        return c;
262      }
263    return 0;
264  }
265
266  /**
267   * \brief Put event into buffer at current position.
268   *
269   * \param ev   Event to put into the buffer.
270   * \return false if buffer is full and entry could not be added.
271   */
272  bool put(Event const &ev) noexcept
273  {
274    Event *c = _current;
275    if (c->time)
276      return false;
277
278    inc();
279    c->payload = ev.payload;
280    l4_wmb();
281    c->time = ev.time;
282    return true;
283  }
284};
285
286typedef Event_buffer_t<Default_event_payload> Event_buffer;
287
288}
289
290
291