From 81af714949dce41253de521495225f4840b358cd Mon Sep 17 00:00:00 2001 From: Christian Prochaska Date: Wed, 1 Oct 2014 16:00:52 +0200 Subject: [PATCH] Input merger This component merges the input events of multiple sources. Example configuration: For each 'input' config node, the component opens an 'Input' session with the configured label. This label is then evaluated by 'init' to route the session request to a specific input source component. Fixes #1259. --- repos/os/src/server/input_merger/README | 27 ++++ repos/os/src/server/input_merger/main.cc | 169 +++++++++++++++++++++ repos/os/src/server/input_merger/target.mk | 3 + 3 files changed, 199 insertions(+) create mode 100644 repos/os/src/server/input_merger/README create mode 100644 repos/os/src/server/input_merger/main.cc create mode 100644 repos/os/src/server/input_merger/target.mk diff --git a/repos/os/src/server/input_merger/README b/repos/os/src/server/input_merger/README new file mode 100644 index 0000000000..d2fedcdefa --- /dev/null +++ b/repos/os/src/server/input_merger/README @@ -0,0 +1,27 @@ +This component merges the input events of multiple sources. + +Example configuration: + + + + + + + + + + + + + + + + + + + + + +For each 'input' config node, the component opens an 'Input' session with the +configured label. This label is then evaluated by 'init' to route the session +request to a specific input source component. diff --git a/repos/os/src/server/input_merger/main.cc b/repos/os/src/server/input_merger/main.cc new file mode 100644 index 0000000000..58558527fb --- /dev/null +++ b/repos/os/src/server/input_merger/main.cc @@ -0,0 +1,169 @@ +/* + * \brief Input event merger + * \author Christian Prochaska + * \date 2014-09-29 + */ + +/* + * Copyright (C) 2014 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* Genode includes */ +#include +#include +#include +#include +#include +#include +#include + + +namespace Input_merger +{ + using namespace Genode; + + class Input_source : public List::Element + { + private: + + Input::Session_capability _create_session(const char *label) + { + char session_args[sizeof(Parent::Session_args)]; + + Arg_string::set_arg(session_args, sizeof(Parent::Session_args), + "ram_quota", "16K"); + Arg_string::set_arg(session_args, sizeof(Parent::Session_args), + "label", label); + + return env()->parent()->session(session_args); + } + + public: + + Input::Session_client session_client; + Attached_dataspace dataspace; + + Input_source(const char *label) + : session_client(_create_session(label)), + dataspace(session_client.dataspace()) { } + + ~Input_source() + { + env()->parent()->close(session_client); + } + }; + + struct Main; +} + + +/****************** + ** Main program ** + ******************/ + +struct Input_merger::Main +{ + Server::Entrypoint &ep; + List input_source_list; + + /* + * Input session provided to our client + */ + Input::Session_component input_session_component; + + /* + * Attach root interface to the entry point + */ + Static_root input_root { ep.manage(input_session_component) }; + + void handle_input(unsigned) + { + for (Input_source *input_source = input_source_list.first(); + input_source; + input_source = input_source->next()) { + + Input::Event const * const events = + input_source->dataspace.local_addr(); + + unsigned const num = input_source->session_client.flush(); + for (unsigned i = 0; i < num; i++) + input_session_component.submit(events[i]); + } + } + + Signal_rpc_member
input_dispatcher = + { ep, *this, &Main::handle_input}; + + + void handle_config_update(unsigned) + { + Genode::config()->reload(); + + for (Input_source *input_source; + (input_source = input_source_list.first()); ) { + input_source_list.remove(input_source); + destroy(env()->heap(), input_source); + } + + try { + for (Xml_node input_node = config()->xml_node().sub_node("input"); + ; + input_node = input_node.next("input")) { + + char label_buf[128]; + input_node.attribute("label").value(label_buf, sizeof(label_buf)); + + Input_source *input_source(new (env()->heap()) Input_source(label_buf)); + + input_source_list.insert(input_source); + + input_source->session_client.sigh(input_dispatcher); + } + } catch (Xml_node::Nonexistent_sub_node) { } + + } + + Signal_rpc_member
config_update_dispatcher = + { ep, *this, &Main::handle_config_update}; + + /** + * Constructor + */ + Main(Server::Entrypoint &ep) : ep(ep) + { + input_session_component.event_queue().enabled(true); + + /* + * Apply initial configuration + */ + handle_config_update(0); + + /* + * Register signal handler + */ + Genode::config()->sigh(config_update_dispatcher); + + /* + * Announce service + */ + Genode::env()->parent()->announce(ep.manage(input_root)); + } + +}; + + +/************ + ** Server ** + ************/ + +namespace Server { + + char const *name() { return "input_merger_ep"; } + + size_t stack_size() { return 4*1024*sizeof(addr_t); } + + void construct(Entrypoint &ep) { static Input_merger::Main inst(ep); } +} diff --git a/repos/os/src/server/input_merger/target.mk b/repos/os/src/server/input_merger/target.mk new file mode 100644 index 0000000000..636922a886 --- /dev/null +++ b/repos/os/src/server/input_merger/target.mk @@ -0,0 +1,3 @@ +TARGET = input_merger +SRC_CC = main.cc +LIBS = base config server