337 lines
8.2 KiB
C++
337 lines
8.2 KiB
C++
// vi:set ft=cpp: -*- Mode: C++ -*-
|
|
/*
|
|
* (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
|
|
* Alexander Warg <warg@os.inf.tu-dresden.de>
|
|
* economic rights: Technische Universität Dresden (Germany)
|
|
*
|
|
* License: see LICENSE.spdx (in this directory or the directories above)
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <l4/sys/capability>
|
|
#include <l4/sys/irq>
|
|
#include <l4/sys/cxx/ipc_iface>
|
|
#include <l4/sys/cxx/ipc_array>
|
|
#include <l4/re/dataspace>
|
|
#include <l4/re/event.h>
|
|
|
|
namespace L4Re {
|
|
|
|
/**
|
|
* \defgroup api_l4re_event Event API
|
|
* \ingroup api_l4re
|
|
* Event API.
|
|
*
|
|
* On top of a shared L4Re::Dataspace (and optionally using L4::Triggerable),
|
|
* the event API implements asynchronous event transmission from an event
|
|
* provider (server) to an event receiver (client). Events are put into an
|
|
* Event_buffer_t residing on the shared L4Re::Dataspace.
|
|
*
|
|
* This interface is usually not used directly. Instead use
|
|
* L4Re::Util::Event_t for clients. An example server portion is implemented
|
|
* in L4Re::Util::Event_svr.
|
|
*
|
|
* This interface is usually used with L4Re::Default_event_payload which
|
|
* delivers HID events modeled on the Linux evdev API, and the interface's
|
|
* methods allow further querying of information about the HID event streams.
|
|
*/
|
|
|
|
typedef l4re_event_stream_id_t Event_stream_id;
|
|
typedef l4re_event_absinfo_t Event_absinfo;
|
|
|
|
class L4_EXPORT Event_stream_bitmap_h
|
|
{
|
|
protected:
|
|
static unsigned __get_idx(unsigned idx)
|
|
{ return idx / (sizeof(unsigned long)*8); }
|
|
|
|
static unsigned long __get_mask(unsigned idx)
|
|
{ return 1ul << (idx % (sizeof(unsigned long)*8)); }
|
|
|
|
static bool __get_bit(unsigned long const *bm, unsigned max, unsigned idx)
|
|
{
|
|
if (idx <= max)
|
|
return bm[__get_idx(idx)] & __get_mask(idx);
|
|
return false;
|
|
}
|
|
|
|
static void __set_bit(unsigned long *bm, unsigned max, unsigned idx, bool v)
|
|
{
|
|
if (idx > max)
|
|
return;
|
|
|
|
if (v)
|
|
bm[__get_idx(idx)] |= __get_mask(idx);
|
|
else
|
|
bm[__get_idx(idx)] &= ~__get_mask(idx);
|
|
}
|
|
};
|
|
|
|
class L4_EXPORT Event_stream_info
|
|
: public l4re_event_stream_info_t,
|
|
private Event_stream_bitmap_h
|
|
{
|
|
public:
|
|
bool get_propbit(unsigned idx) const
|
|
{ return __get_bit(propbits, L4RE_EVENT_PROP_MAX, idx); }
|
|
|
|
void set_propbit(unsigned idx, bool v)
|
|
{ __set_bit(propbits, L4RE_EVENT_PROP_MAX, idx, v); }
|
|
|
|
bool get_evbit(unsigned idx) const
|
|
{ return __get_bit(evbits, L4RE_EVENT_EV_MAX, idx); }
|
|
|
|
void set_evbit(unsigned idx, bool v)
|
|
{ __set_bit(evbits, L4RE_EVENT_EV_MAX, idx, v); }
|
|
|
|
bool get_keybit(unsigned idx) const
|
|
{ return __get_bit(keybits, L4RE_EVENT_KEY_MAX, idx); }
|
|
|
|
void set_keybit(unsigned idx, bool v)
|
|
{ __set_bit(keybits, L4RE_EVENT_KEY_MAX, idx, v); }
|
|
|
|
bool get_relbit(unsigned idx) const
|
|
{ return __get_bit(relbits, L4RE_EVENT_REL_MAX, idx); }
|
|
|
|
void set_relbit(unsigned idx, bool v)
|
|
{ __set_bit(relbits, L4RE_EVENT_REL_MAX, idx, v); }
|
|
|
|
bool get_absbit(unsigned idx) const
|
|
{ return __get_bit(absbits, L4RE_EVENT_ABS_MAX, idx); }
|
|
|
|
void set_absbit(unsigned idx, bool v)
|
|
{ __set_bit(absbits, L4RE_EVENT_ABS_MAX, idx, v); }
|
|
|
|
bool get_swbit(unsigned idx) const
|
|
{ return __get_bit(swbits, L4RE_EVENT_SW_MAX, idx); }
|
|
|
|
void set_swbit(unsigned idx, bool v)
|
|
{ __set_bit(swbits, L4RE_EVENT_SW_MAX, idx, v); }
|
|
};
|
|
|
|
class L4_EXPORT Event_stream_state
|
|
: public l4re_event_stream_state_t,
|
|
private Event_stream_bitmap_h
|
|
{
|
|
public:
|
|
bool get_keybit(unsigned idx) const
|
|
{ return __get_bit(keybits, L4RE_EVENT_KEY_MAX, idx); }
|
|
|
|
void set_keybit(unsigned idx, bool v)
|
|
{ __set_bit(keybits, L4RE_EVENT_KEY_MAX, idx, v); }
|
|
|
|
bool get_swbit(unsigned idx) const
|
|
{ return __get_bit(swbits, L4RE_EVENT_SW_MAX, idx); }
|
|
|
|
void set_swbit(unsigned idx, bool v)
|
|
{ __set_bit(swbits, L4RE_EVENT_SW_MAX, idx, v); }
|
|
};
|
|
|
|
/**
|
|
* \brief Event class.
|
|
* \ingroup api_l4re_event
|
|
*
|
|
* \see \link api_l4re_event L4Re Event API \endlink
|
|
*/
|
|
class L4_EXPORT Event :
|
|
public L4::Kobject_t<Event, L4::Icu, L4RE_PROTO_EVENT>
|
|
{
|
|
public:
|
|
/**
|
|
* Get event signal buffer.
|
|
*
|
|
* \param[out] ds Event buffer.
|
|
*
|
|
* \retval 0 Success
|
|
* \retval <0 Error
|
|
*/
|
|
L4_RPC(long, get_buffer, (L4::Ipc::Out<L4::Cap<Dataspace> > ds));
|
|
|
|
/**
|
|
* Get number of event streams.
|
|
*
|
|
* \retval >=0 Number of streams.
|
|
* \retval <0 Error code.
|
|
*/
|
|
L4_RPC(long, get_num_streams, ());
|
|
|
|
/**
|
|
* Get event stream infos.
|
|
*
|
|
* Deprecated. Use get_stream_info_for_id().
|
|
*
|
|
* \param idx ID of the event stream.
|
|
* \param[out] info Event stream info.
|
|
*
|
|
* \retval 0 Success
|
|
* \retval <0 Error
|
|
*/
|
|
L4_RPC(long, get_stream_info, (int idx, Event_stream_info *info));
|
|
|
|
/**
|
|
* Get event stream infos.
|
|
*
|
|
* \param stream_id ID of the event stream.
|
|
* \param[out] info Event stream info.
|
|
*
|
|
* \retval 0 Success
|
|
* \retval <0 Error
|
|
*/
|
|
L4_RPC(long, get_stream_info_for_id, (l4_umword_t stream_id, Event_stream_info *info));
|
|
|
|
/**
|
|
* Get event stream axis infos.
|
|
*
|
|
* \param stream_id ID of the event stream.
|
|
* \param[in] naxes Number of axis IDs and axis infos.
|
|
* \param[in] axis Array of axis IDs.
|
|
* \param[out] info Array of axis infos.
|
|
*
|
|
* \retval >=0 Number of returned axes infos.
|
|
* \retval <0 Error code.
|
|
*/
|
|
L4_RPC_NF(long, get_axis_info, (l4_umword_t stream_id,
|
|
L4::Ipc::Array<unsigned const, unsigned long> axes,
|
|
L4::Ipc::Array<Event_absinfo, unsigned long> &info));
|
|
|
|
long get_axis_info(l4_umword_t stream_id, unsigned naxes,
|
|
unsigned const *axis, Event_absinfo *info) const noexcept
|
|
{
|
|
L4::Ipc::Array<Event_absinfo, unsigned long> i(naxes, info);
|
|
return get_axis_info_t::call(c(), stream_id,
|
|
L4::Ipc::Array<unsigned const, unsigned long>(naxes, axis), i);
|
|
}
|
|
|
|
/**
|
|
* Get event stream state.
|
|
*
|
|
* \param stream_id ID of the event stream.
|
|
* \param[out] state Event stream state.
|
|
*
|
|
* \retval 0 Success
|
|
* \retval <0 Error
|
|
*/
|
|
L4_RPC(long, get_stream_state_for_id, (l4_umword_t stream_id,
|
|
Event_stream_state *state));
|
|
|
|
typedef L4::Typeid::Rpcs<
|
|
get_buffer_t,
|
|
get_num_streams_t,
|
|
get_stream_info_t,
|
|
get_stream_info_for_id_t,
|
|
get_axis_info_t,
|
|
get_stream_state_for_id_t
|
|
> Rpcs;
|
|
};
|
|
|
|
/**
|
|
* Default event stream payload.
|
|
* \ingroup api_l4re_event
|
|
*/
|
|
struct L4_EXPORT Default_event_payload
|
|
{
|
|
unsigned short type; /**< Type of event */
|
|
unsigned short code; /**< Code of event */
|
|
int value; /**< Value of event */
|
|
l4_umword_t stream_id; /**< Stream ID */
|
|
};
|
|
|
|
|
|
/**
|
|
* \brief Event buffer class.
|
|
* \ingroup api_l4re_event
|
|
*/
|
|
template< typename PAYLOAD = Default_event_payload >
|
|
class L4_EXPORT Event_buffer_t
|
|
{
|
|
public:
|
|
|
|
/**
|
|
* \brief Event structure used in buffer.
|
|
*/
|
|
struct Event
|
|
{
|
|
long long time; /**< Event time stamp */
|
|
PAYLOAD payload;
|
|
|
|
/**
|
|
* \brief Free the entry.
|
|
*/
|
|
void free() noexcept { l4_mb(); time = 0; }
|
|
};
|
|
|
|
private:
|
|
Event *_current;
|
|
Event *_begin;
|
|
Event const *_end;
|
|
|
|
void inc() noexcept
|
|
{
|
|
++_current;
|
|
if (_current == _end)
|
|
_current = _begin;
|
|
}
|
|
|
|
public:
|
|
|
|
Event_buffer_t() : _current(0), _begin(0), _end(0) {}
|
|
|
|
void reset()
|
|
{
|
|
for (Event *i = _begin; i != _end; ++i)
|
|
i->time = 0;
|
|
_current = _begin;
|
|
}
|
|
|
|
/**
|
|
* \brief Initialize event buffer.
|
|
*
|
|
* \param buffer Pointer to buffer.
|
|
* \param size Size of buffer in bytes.
|
|
*/
|
|
Event_buffer_t(void *buffer, l4_addr_t size)
|
|
: _current(static_cast<Event*>(buffer)), _begin(_current),
|
|
_end(_begin + size / sizeof(Event))
|
|
{ reset(); }
|
|
|
|
/**
|
|
* \brief Next event in buffer.
|
|
*
|
|
* \return 0 if no event available, event otherwise.
|
|
*/
|
|
Event *next() noexcept
|
|
{
|
|
Event *c = _current;
|
|
if (c->time)
|
|
{
|
|
inc();
|
|
return c;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* \brief Put event into buffer at current position.
|
|
*
|
|
* \param ev Event to put into the buffer.
|
|
* \return false if buffer is full and entry could not be added.
|
|
*/
|
|
bool put(Event const &ev) noexcept
|
|
{
|
|
Event *c = _current;
|
|
if (c->time)
|
|
return false;
|
|
|
|
inc();
|
|
c->payload = ev.payload;
|
|
l4_wmb();
|
|
c->time = ev.time;
|
|
return true;
|
|
}
|
|
};
|
|
|
|
typedef Event_buffer_t<Default_event_payload> Event_buffer;
|
|
|
|
}
|