diff --git a/repos/os/run/input.run b/repos/os/run/input.run index 168602dfa5..0eb19c0e24 100644 --- a/repos/os/run/input.run +++ b/repos/os/run/input.run @@ -7,6 +7,7 @@ assert_spec x86 set build_components { core init drivers/timer + server/dynamic_rom test/input } @@ -59,8 +60,12 @@ append_if [have_spec ps2] config { - + + + + @@ -86,6 +91,39 @@ append_if [have_spec sdl] config { } append config { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -110,7 +148,7 @@ install_config $config # generic modules set boot_modules { core ld.lib.so init - timer + timer dynamic_rom test-input } diff --git a/repos/os/src/drivers/input/spec/ps2/README b/repos/os/src/drivers/input/spec/ps2/README new file mode 100644 index 0000000000..5167b466a2 --- /dev/null +++ b/repos/os/src/drivers/input/spec/ps2/README @@ -0,0 +1,20 @@ +The PS/2 driver makes PS/2 mouse and keyboard input available as an input +session. It accepts the following configuration attributes. The default +values are shown as attribute values. + +! + +The 'capslock_led', 'numlock_led', and 'scrlock_led' attributes can have the +values "no" (LED is turned off), "yes" (LED is turned on), or "rom". In the +latter case, the PS/2 driver reads the LED state from a dedicated ROM module +called "capslock", "numlock", or "scrlock" respectively. The ROM module is +expected to have a top-level XML node with the attribute 'enabled' set to +"yes" or "no". The PS/2 driver supports dynamic updates of its configuration +as well as the ROM modules for LED states. This mechanism enables other +components to control the indicator states by the means of providing and +updating those ROM modules. diff --git a/repos/os/src/drivers/input/spec/ps2/led_state.h b/repos/os/src/drivers/input/spec/ps2/led_state.h new file mode 100644 index 0000000000..20b4e1fec0 --- /dev/null +++ b/repos/os/src/drivers/input/spec/ps2/led_state.h @@ -0,0 +1,66 @@ +/* + * \brief Configuration of keyboard mode indicators + * \author Norman Feske + * \date 2017-10-25 + */ + +/* + * Copyright (C) 2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _DRIVERS__INPUT__SPEC__LED_STATE_H_ +#define _DRIVERS__INPUT__SPEC__LED_STATE_H_ + +#include +#include +#include + +namespace Ps2 { struct Led_state; } + + +struct Ps2::Led_state +{ + Genode::Env &_env; + + typedef Genode::String<32> Name; + + Name const _name; + + Genode::Constructible _rom; + + bool _enabled = false; + + Led_state(Genode::Env &env, Name const &name) : _env(env), _name(name) { } + + void update(Genode::Xml_node config, Genode::Signal_context_capability sigh) + { + typedef Genode::String<32> Attr; + typedef Genode::String<16> Value; + + Attr const attr(_name, "_led"); + Value const value = config.attribute_value(attr.string(), Value()); + + bool const rom_configured = (value == "rom"); + + if (rom_configured && !_rom.constructed()) { + _rom.construct(_env, _name.string()); + _rom->sigh(sigh); + } + + if (!rom_configured && _rom.constructed()) + _rom.destruct(); + + if (_rom.constructed()) + _rom->update(); + + _enabled = _rom.constructed() ? _rom->xml().attribute_value("enabled", false) + : config.attribute_value(attr.string(), false); + } + + bool enabled() const { return _enabled; } +}; + +#endif /* _DRIVERS__INPUT__SPEC__LED_STATE_H_ */ diff --git a/repos/os/src/drivers/input/spec/ps2/pbxa9/main.cc b/repos/os/src/drivers/input/spec/ps2/pbxa9/main.cc index 0fb41a1287..851f141e93 100644 --- a/repos/os/src/drivers/input/spec/ps2/pbxa9/main.cc +++ b/repos/os/src/drivers/input/spec/ps2/pbxa9/main.cc @@ -23,6 +23,7 @@ #include "ps2_mouse.h" #include "irq_handler.h" #include "pl050.h" +#include "led_state.h" namespace Ps2 { struct Main; } @@ -47,16 +48,42 @@ struct Ps2::Main Genode::Attached_rom_dataspace _config { _env, "config" }; - Verbose _verbose { _config.xml() }; + Genode::Reconstructible _verbose { _config.xml() }; - Mouse _mouse { _pl050.aux_interface(), _session.event_queue(), _verbose }; - Keyboard _keyboard { _pl050.kbd_interface(), _session.event_queue(), false, _verbose }; + Mouse _mouse { _pl050.aux_interface(), _session.event_queue(), *_verbose }; + Keyboard _keyboard { _pl050.kbd_interface(), _session.event_queue(), false, *_verbose }; Irq_handler _mouse_irq { _env, PL050_MOUSE_IRQ, _pl050.aux_interface(), _mouse }; Irq_handler _keyboard_irq { _env, PL050_KEYBD_IRQ, _pl050.kbd_interface(), _keyboard }; + Led_state _capslock { _env, "capslock" }, + _numlock { _env, "numlock" }, + _scrlock { _env, "scrlock" }; + + void _handle_config() + { + _config.update(); + + Genode::Xml_node config = _config.xml(); + + _verbose.construct(config); + + _capslock.update(config, _config_handler); + _numlock .update(config, _config_handler); + _scrlock .update(config, _config_handler); + + _keyboard.led_enabled(Keyboard::CAPSLOCK_LED, _capslock.enabled()); + _keyboard.led_enabled(Keyboard::NUMLOCK_LED, _numlock .enabled()); + _keyboard.led_enabled(Keyboard::SCRLOCK_LED, _scrlock .enabled()); + } + + Genode::Signal_handler
_config_handler { + _env.ep(), *this, &Main::_handle_config }; + Main(Genode::Env &env) : _env(env) { + _handle_config(); + env.parent().announce(env.ep().manage(_root)); } }; diff --git a/repos/os/src/drivers/input/spec/ps2/ps2_keyboard.h b/repos/os/src/drivers/input/spec/ps2/ps2_keyboard.h index 0ef6de085b..b34b658014 100644 --- a/repos/os/src/drivers/input/spec/ps2/ps2_keyboard.h +++ b/repos/os/src/drivers/input/spec/ps2/ps2_keyboard.h @@ -351,11 +351,33 @@ class Ps2::Keyboard : public Input_driver } _scan_code_set_2_state_machine; + /* acknowledge code from keyboard */ + enum { ACK = 0xfa }; + /** * Used keyboard-packet state machine */ Scan_code_state_machine *_state_machine; + bool _capslock = false; + bool _numlock = false; + bool _scrlock = false; + + void _update_leds() + { + _kbd.write(0xed); + if (_kbd.read() != ACK) { + Genode::warning("setting of mode indicators failed (0xed)"); + return; + } + + _kbd.write((_capslock ? 4:0) | (_numlock ? 2:0) | (_scrlock ? 1:0)); + if (_kbd.read() != ACK) { + Genode::warning("setting of mode indicators failed"); + return; + } + } + public: /** @@ -387,11 +409,20 @@ class Ps2::Keyboard : public Input_driver : "2"); } + enum Led { CAPSLOCK_LED, NUMLOCK_LED, SCRLOCK_LED }; + + void led_enabled(Led led, bool enabled) + { + switch (led) { + case CAPSLOCK_LED: _capslock = enabled; break; + case NUMLOCK_LED: _numlock = enabled; break; + case SCRLOCK_LED: _scrlock = enabled; break; + } + _update_leds(); + } + void reset() { - /* acknowledge code from keyboard */ - enum { ACK = 0xfa }; - /* scan-code request/config commands */ enum { SCAN_CODE_REQUEST = 0, SCAN_CODE_SET_1 = 1, SCAN_CODE_SET_2 = 2 }; diff --git a/repos/os/src/drivers/input/spec/ps2/x86/main.cc b/repos/os/src/drivers/input/spec/ps2/x86/main.cc index 8ce76ba71f..49e2bea279 100644 --- a/repos/os/src/drivers/input/spec/ps2/x86/main.cc +++ b/repos/os/src/drivers/input/spec/ps2/x86/main.cc @@ -27,6 +27,7 @@ #include "ps2_mouse.h" #include "irq_handler.h" #include "verbose.h" +#include "led_state.h" namespace Ps2 { struct Main; } @@ -55,18 +56,44 @@ struct Ps2::Main Genode::Attached_rom_dataspace _config { _env, "config" }; - Verbose _verbose { _config.xml() }; + Genode::Reconstructible _verbose { _config.xml() }; Keyboard _keyboard { _i8042.kbd_interface(), _session.event_queue(), - _i8042.kbd_xlate(), _verbose }; + _i8042.kbd_xlate(), *_verbose }; - Mouse _mouse { _i8042.aux_interface(), _session.event_queue(), _verbose }; + Mouse _mouse { _i8042.aux_interface(), _session.event_queue(), *_verbose }; Irq_handler _keyboard_irq { _env.ep(), _keyboard, _device_ps2.irq(0) }; Irq_handler _mouse_irq { _env.ep(), _mouse, _device_ps2.irq(1) }; + Led_state _capslock { _env, "capslock" }, + _numlock { _env, "numlock" }, + _scrlock { _env, "scrlock" }; + + void _handle_config() + { + _config.update(); + + Genode::Xml_node config = _config.xml(); + + _verbose.construct(config); + + _capslock.update(config, _config_handler); + _numlock .update(config, _config_handler); + _scrlock .update(config, _config_handler); + + _keyboard.led_enabled(Keyboard::CAPSLOCK_LED, _capslock.enabled()); + _keyboard.led_enabled(Keyboard::NUMLOCK_LED, _numlock .enabled()); + _keyboard.led_enabled(Keyboard::SCRLOCK_LED, _scrlock .enabled()); + } + + Genode::Signal_handler
_config_handler { + _env.ep(), *this, &Main::_handle_config }; + Main(Genode::Env &env) : _env(env) { + _handle_config(); + env.parent().announce(env.ep().manage(_root)); } };