ps2_drv: drive mode indicator LEDs

The new feature is demonstrated by the input.run script. It uses a
dynamic ROM service to toggle the keyboard LEDs at different intervals.

Fixes #2546
This commit is contained in:
Norman Feske 2017-10-24 17:17:33 +02:00 committed by Christian Helmuth
parent d6a05245f2
commit a0a7d5d165
6 changed files with 220 additions and 11 deletions

View File

@ -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 {
<start name="ps2_drv">
<resource name="RAM" quantum="2M"/>
<provides><service name="Input"/></provides>
<config verbose_keyboard="no" verbose_mouse="no" verbose_scancodes="no"/>
<config verbose_keyboard="no" verbose_mouse="no" verbose_scancodes="no"
capslock_led="rom" numlock_led="rom" scrlock_led="rom"/>
<route>
<service name="ROM" label="capslock"> <child name="dynamic_rom"/> </service>
<service name="ROM" label="numlock"> <child name="dynamic_rom"/> </service>
<service name="ROM" label="scrlock"> <child name="dynamic_rom"/> </service>
<service name="ROM"> <parent/> </service>
<service name="CPU"> <parent/> </service>
<service name="PD"> <parent/> </service>
@ -86,6 +91,39 @@ append_if [have_spec sdl] config {
<alias name="input_drv" child="fb_sdl"/>}
append config {
<start name="dynamic_rom">
<resource name="RAM" quantum="4M"/>
<provides> <service name="ROM"/> </provides>
<config verbose="no">
<rom name="capslock">
<inline> <capslock enabled="no"/> </inline>
<sleep milliseconds="250" />
<inline> <capslock enabled="yes"/> </inline>
<sleep milliseconds="250" />
</rom>
<rom name="numlock">
<inline> <numlock enabled="no"/> </inline>
<sleep milliseconds="500" />
<inline> <numlock enabled="yes"/> </inline>
<sleep milliseconds="500" />
</rom>
<rom name="scrlock">
<inline> <scrlock enabled="no"/> </inline>
<sleep milliseconds="1000" />
<inline> <scrlock enabled="yes"/> </inline>
<sleep milliseconds="1000" />
</rom>
</config>
<route>
<service name="ROM"> <parent/> </service>
<service name="CPU"> <parent/> </service>
<service name="PD"> <parent/> </service>
<service name="LOG"> <parent/> </service>
<service name="Timer"> <child name="timer"/> </service>
</route>
</start>
<start name="test-input">
<resource name="RAM" quantum="1M"/>
<route>
@ -110,7 +148,7 @@ install_config $config
# generic modules
set boot_modules {
core ld.lib.so init
timer
timer dynamic_rom
test-input
}

View File

@ -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.
! <config verbose_keyboard="no"
! verbose_mouse="no"
! verbose_scancodes="no"
! capslock_led="no"
! numlock_led="no"
! scrlock_led="no"/>
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.

View File

@ -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 <util/xml_node.h>
#include <util/reconstructible.h>
#include <base/component.h>
namespace Ps2 { struct Led_state; }
struct Ps2::Led_state
{
Genode::Env &_env;
typedef Genode::String<32> Name;
Name const _name;
Genode::Constructible<Genode::Attached_rom_dataspace> _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_ */

View File

@ -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> _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<Main> _config_handler {
_env.ep(), *this, &Main::_handle_config };
Main(Genode::Env &env) : _env(env)
{
_handle_config();
env.parent().announce(env.ep().manage(_root));
}
};

View File

@ -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 };

View File

@ -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> _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<Main> _config_handler {
_env.ep(), *this, &Main::_handle_config };
Main(Genode::Env &env) : _env(env)
{
_handle_config();
env.parent().announce(env.ep().manage(_root));
}
};