1// vi:set ft=cpp: -*- Mode: C++ -*-
2/**
3 * \file
4 */
5/*
6 * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
7 *               Alexander Warg <warg@os.inf.tu-dresden.de>
8 *     economic rights: Technische Universität Dresden (Germany)
9 *
10 * This file is part of TUD:OS and distributed under the terms of the
11 * GNU General Public License 2.
12 * Please see the COPYING-GPL-2 file for details.
13 *
14 * As a special exception, you may use this file as part of a free software
15 * library without restriction.  Specifically, if other files instantiate
16 * templates or use macros or inline functions from this file, or you compile
17 * this file and link it with other files to produce an executable, this
18 * file does not by itself cause the resulting executable to be covered by
19 * the GNU General Public License.  This exception does not however
20 * invalidate any other reasons why the executable file might be covered by
21 * the GNU General Public License.
22 */
23#pragma once
24
25#include <l4/re/cap_alloc>
26#include <l4/re/util/cap_alloc>
27#include <l4/re/util/unique_cap>
28#include <l4/re/env>
29#include <l4/re/rm>
30#include <l4/re/util/event_buffer>
31#include <l4/sys/factory>
32#include <l4/cxx/type_traits>
33
34namespace L4Re { namespace Util {
35
36/**
37 * Convenience wrapper for getting access to an event object.
38 *
39 * After calling init() the class supplies the event-buffer and the
40 * associated IRQ object.
41 */
42template< typename PAYLOAD >
43class Event_t
44{
45public:
46  /**
47   * Modes of operation.
48   */
49  enum Mode
50  {
51    Mode_irq,      ///< Create an IRQ and attach, to get notifications.
52    Mode_polling,  ///< Do not use an IRQ.
53  };
54
55  /**
56   * Initialise an event object.
57   *
58   * \tparam IRQ_TYPE  Type used for handling notifications from the event
59   *                   provider. This must be derived from L4::Triggerable.
60   *
61   * \param event   Capability to event.
62   * \param env     Pointer to L4Re-Environment
63   * \param ca      Pointer to capability allocator.
64   *
65   * \retval 0           Success
66   * \retval -L4_ENOMEM  No memory to allocate required capabilities.
67   * \retval <0          Other IPC errors.
68   */
69  template<typename IRQ_TYPE>
70  int init(L4::Cap<L4Re::Event> event,
71           L4Re::Env const *env = L4Re::Env::env(),
72           L4Re::Cap_alloc *ca = L4Re::Cap_alloc::get_cap_alloc(L4Re::Util::cap_alloc))
73  {
74    Unique_cap<L4Re::Dataspace> ev_ds(ca->alloc<L4Re::Dataspace>());
75    if (!ev_ds.is_valid())
76      return -L4_ENOMEM;
77
78    int r;
79
80    Unique_del_cap<IRQ_TYPE> ev_irq(ca->alloc<IRQ_TYPE>());
81    if (!ev_irq.is_valid())
82      return -L4_ENOMEM;
83
84    if ((r = l4_error(env->factory()->create(ev_irq.get()))))
85      return r;
86
87    if ((r = l4_error(event->bind(0, ev_irq.get()))))
88      return r;
89
90    if ((r = event->get_buffer(ev_ds.get())))
91      return r;
92
93    long sz = ev_ds->size();
94    if (sz < 0)
95      return sz;
96
97    Rm::Unique_region<void*> buf;
98
99    if ((r = env->rm()->attach(&buf, sz,
100                               L4Re::Rm::F::Search_addr | L4Re::Rm::F::RW,
101                               L4::Ipc::make_cap_rw(ev_ds.get()))))
102      return r;
103
104    _ev_buffer = L4Re::Event_buffer_t<PAYLOAD>(buf.get(), sz);
105    _ev_ds     = cxx::move(ev_ds);
106    _ev_irq    = cxx::move(ev_irq);
107    _buf       = cxx::move(buf);
108
109    return 0;
110  }
111
112  /**
113   * Initialise an event object in polling mode.
114   *
115   * \param event   Capability to event.
116   * \param env     Pointer to L4Re-Environment
117   * \param ca      Pointer to capability allocator.
118   *
119   * \retval 0           Success
120   * \retval -L4_ENOMEM  No memory to allocate required capabilities.
121   * \retval <0          Other IPC errors.
122   */
123  int init_poll(L4::Cap<L4Re::Event> event,
124                L4Re::Env const *env = L4Re::Env::env(),
125                L4Re::Cap_alloc *ca = L4Re::Cap_alloc::get_cap_alloc(L4Re::Util::cap_alloc))
126  {
127    Unique_cap<L4Re::Dataspace> ev_ds(ca->alloc<L4Re::Dataspace>());
128    if (!ev_ds.is_valid())
129      return -L4_ENOMEM;
130
131    int r;
132
133    if ((r = event->get_buffer(ev_ds.get())))
134      return r;
135
136    long sz = ev_ds->size();
137    if (sz < 0)
138      return sz;
139
140    Rm::Unique_region<void*> buf;
141
142    if ((r = env->rm()->attach(&buf, sz,
143                               L4Re::Rm::F::Search_addr | L4Re::Rm::F::RW,
144                               L4::Ipc::make_cap_rw(ev_ds.get()))))
145      return r;
146
147    _ev_buffer = L4Re::Event_buffer_t<PAYLOAD>(buf.get(), sz);
148    _ev_ds     = cxx::move(ev_ds);
149    _buf       = cxx::move(buf);
150
151    return 0;
152  }
153
154  /**
155   * Get event buffer.
156   *
157   * \return Event buffer object.
158   */
159  L4Re::Event_buffer_t<PAYLOAD> &buffer() { return _ev_buffer; }
160
161  /**
162   * Get event IRQ.
163   *
164   * \return Event IRQ.
165   */
166  L4::Cap<L4::Triggerable> irq() const { return _ev_irq.get(); }
167
168private:
169  Unique_cap<L4Re::Dataspace> _ev_ds;
170  Unique_del_cap<L4::Triggerable> _ev_irq;
171  L4Re::Event_buffer_t<PAYLOAD> _ev_buffer;
172  Rm::Unique_region<void*> _buf;
173};
174
175typedef Event_t<Default_event_payload> Event;
176
177}}
178