mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-19 13:47:56 +00:00
usb: LED suppport
This commit is contained in:
parent
12461291b8
commit
fe4f304815
@ -62,6 +62,7 @@ set build_components {
|
||||
drivers/timer
|
||||
drivers/usb
|
||||
test/input
|
||||
server/dynamic_rom
|
||||
}
|
||||
|
||||
lappend_if [have_spec gpio] build_components drivers/gpio
|
||||
@ -112,13 +113,63 @@ append config {
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Timer"/></provides>
|
||||
</start>
|
||||
|
||||
<start name="usb_drv" caps="120">
|
||||
<resource name="RAM" quantum="16M"/>
|
||||
<provides><service name="Input"/></provides>
|
||||
<config uhci="yes" ohci="yes" ehci="yes" xhci="yes">
|
||||
<config uhci="yes" ohci="yes" ehci="yes" xhci="yes"
|
||||
capslock_led="rom" numlock_led="rom" scrlock_led="rom"
|
||||
bios_handoff="no">
|
||||
<hid/>
|
||||
</config>
|
||||
<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>
|
||||
<service name="IO_PORT"> <parent/> </service>
|
||||
<service name="IO_MEM"> <parent/> </service>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="RM"> <parent/> </service>
|
||||
<service name="Platform"> <any-child/> </service>
|
||||
<service name="Timer"> <child name="timer"/> </service>
|
||||
</route>
|
||||
</start>
|
||||
|
||||
<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"/>
|
||||
</start>
|
||||
@ -132,7 +183,7 @@ install_config $config
|
||||
|
||||
# generic modules
|
||||
set boot_modules {
|
||||
core ld.lib.so init timer usb_drv test-input
|
||||
core ld.lib.so init timer usb_drv test-input dynamic_rom
|
||||
}
|
||||
|
||||
lappend_if [have_spec gpio] boot_modules [gpio_drv]
|
||||
|
@ -25,12 +25,24 @@
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/log.h>
|
||||
#include <base/debug.h>
|
||||
#include <base/registry.h>
|
||||
#include <util/reconstructible.h>
|
||||
|
||||
/* LX kit */
|
||||
#include <lx_kit/env.h>
|
||||
#include <lx_kit/scheduler.h>
|
||||
|
||||
/* local */
|
||||
#include "led_state.h"
|
||||
|
||||
/* Linux includes */
|
||||
#include <lx_emul.h>
|
||||
#include <lx_emul/extern_c_begin.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/mt.h>
|
||||
#include <linux/usb.h>
|
||||
#include <lx_emul/extern_c_end.h>
|
||||
|
||||
|
||||
@ -300,3 +312,173 @@ void genode_input_register(genode_input_event_cb h, unsigned long res_x,
|
||||
screen_y = res_y;
|
||||
multi_touch = multitouch;
|
||||
}
|
||||
|
||||
|
||||
/***************************
|
||||
** Keyboard LED handling **
|
||||
***************************/
|
||||
|
||||
class Keyboard_led
|
||||
{
|
||||
private:
|
||||
|
||||
Genode::Registry<Keyboard_led>::Element _reg_elem;
|
||||
input_dev * const _input_dev;
|
||||
|
||||
usb_interface *_interface() {
|
||||
return container_of(_input_dev->dev.parent->parent, usb_interface, dev); }
|
||||
|
||||
usb_device *_usb_device() {
|
||||
return interface_to_usbdev(_interface()); }
|
||||
|
||||
public:
|
||||
|
||||
Keyboard_led(Genode::Registry<Keyboard_led> ®istry, input_dev *dev)
|
||||
: _reg_elem(registry, *this), _input_dev(dev) { }
|
||||
|
||||
bool match(input_dev const *other) const { return _input_dev == other; }
|
||||
|
||||
void update(unsigned leds)
|
||||
{
|
||||
unsigned *buf = (unsigned *)kmalloc(4, GFP_LX_DMA);
|
||||
*buf = leds;
|
||||
usb_control_msg(_usb_device(), usb_sndctrlpipe(_usb_device(), 0),
|
||||
0x9, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0x200,
|
||||
_interface()->cur_altsetting->desc.bInterfaceNumber,
|
||||
buf, 1, 0);
|
||||
kfree(buf);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static Genode::Registry<Keyboard_led> _registry;
|
||||
|
||||
|
||||
namespace Usb { class Led; }
|
||||
|
||||
class Usb::Led
|
||||
{
|
||||
private:
|
||||
|
||||
Lx::Task _task { _run, this, "led_worker", Lx::Task::PRIORITY_2,
|
||||
Lx::scheduler() };
|
||||
|
||||
completion _config_update;
|
||||
|
||||
Led_state _capslock { Lx_kit::env().env(), "capslock" },
|
||||
_numlock { Lx_kit::env().env(), "numlock" },
|
||||
_scrlock { Lx_kit::env().env(), "scrlock" };
|
||||
|
||||
Genode::Signal_handler<Led> _config_handler {
|
||||
Lx_kit::env().env().ep(), *this, &Led::_handle_config };
|
||||
|
||||
void _handle_config()
|
||||
{
|
||||
Lx_kit::env().config_rom().update();
|
||||
Genode::Xml_node config = Lx_kit::env().config_rom().xml();
|
||||
|
||||
_capslock.update(config, _config_handler);
|
||||
_numlock .update(config, _config_handler);
|
||||
_scrlock .update(config, _config_handler);
|
||||
|
||||
complete(&_config_update);
|
||||
Lx::scheduler().schedule();
|
||||
}
|
||||
|
||||
static void _run(void *l)
|
||||
{
|
||||
Led *led = (Led *)l;
|
||||
|
||||
while (true) {
|
||||
wait_for_completion(&led->_config_update);
|
||||
_registry.for_each([&] (Keyboard_led &keyboard) {
|
||||
led->update(keyboard); });
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Led()
|
||||
{
|
||||
init_completion(&_config_update);
|
||||
Genode::Signal_transmitter(_config_handler).submit();
|
||||
}
|
||||
|
||||
void update(Keyboard_led &keyboard)
|
||||
{
|
||||
unsigned leds = 0;
|
||||
|
||||
leds |= _capslock.enabled() ? 1u << LED_CAPSL : 0;
|
||||
leds |= _numlock.enabled() ? 1u << LED_NUML : 0;
|
||||
leds |= _scrlock.enabled() ? 1u << LED_SCROLLL : 0;
|
||||
|
||||
keyboard.update(leds);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static Genode::Constructible<Usb::Led> _led;
|
||||
|
||||
|
||||
static int led_connect(struct input_handler *handler, struct input_dev *dev,
|
||||
const struct input_device_id *id)
|
||||
{
|
||||
Keyboard_led *keyboard = new (Lx_kit::env().heap()) Keyboard_led(_registry, dev);
|
||||
_led->update(*keyboard);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void led_disconnect(struct input_handle *handle)
|
||||
{
|
||||
input_dev *dev = handle->dev;
|
||||
|
||||
_registry.for_each([&] (Keyboard_led &keyboard) {
|
||||
if (keyboard.match(dev))
|
||||
destroy(Lx_kit::env().heap(), &keyboard);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
static bool led_match(struct input_handler *handler, struct input_dev *dev)
|
||||
{
|
||||
hid_device *hid = (hid_device *)input_get_drvdata(dev);
|
||||
hid_report *report;
|
||||
|
||||
/* search report for keyboard entries */
|
||||
list_for_each_entry(report, &hid->report_enum[0].report_list, list) {
|
||||
|
||||
for (unsigned i = 0; i < report->maxfield; i++)
|
||||
for (unsigned j = 0; j < report->field[i]->maxusage; j++) {
|
||||
hid_usage *usage = report->field[i]->usage + j;
|
||||
if ((usage->hid & HID_USAGE_PAGE) == HID_UP_KEYBOARD) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static struct input_handler led_handler;
|
||||
static struct input_device_id led_ids[2];
|
||||
|
||||
static int led_init(void)
|
||||
{
|
||||
led_ids[0].driver_info = 1; /* match all */
|
||||
led_ids[1] = {};
|
||||
|
||||
led_handler.name = "led";
|
||||
led_handler.connect = led_connect;
|
||||
led_handler.disconnect = led_disconnect;
|
||||
led_handler.id_table = led_ids;
|
||||
led_handler.match = led_match;
|
||||
|
||||
_led.construct();
|
||||
|
||||
return input_register_handler(&led_handler);
|
||||
}
|
||||
|
||||
|
||||
extern "C" { module_init(led_init); }
|
||||
|
66
repos/dde_linux/src/lib/usb/input/led_state.h
Normal file
66
repos/dde_linux/src/lib/usb/input/led_state.h
Normal 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 _INPUT__LED_STATE_H_
|
||||
#define _INPUT__LED_STATE_H_
|
||||
|
||||
#include <util/xml_node.h>
|
||||
#include <util/reconstructible.h>
|
||||
#include <base/component.h>
|
||||
|
||||
namespace Usb { struct Led_state; }
|
||||
|
||||
|
||||
struct Usb::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 /* _INPUT__LED_STATE_H_ */
|
@ -46,6 +46,7 @@ extern "C" void module_ch_driver_init();
|
||||
extern "C" void module_ms_driver_init();
|
||||
extern "C" void module_mt_driver_init();
|
||||
extern "C" void module_raw_driver_init();
|
||||
extern "C" void module_led_init();
|
||||
|
||||
extern "C" void start_input_service(void *ep, void *services);
|
||||
|
||||
@ -80,6 +81,7 @@ static void run_linux(void *s)
|
||||
if (services->hid) {
|
||||
subsys_input_init();
|
||||
module_evdev_init();
|
||||
module_led_init();
|
||||
|
||||
/* HID */
|
||||
module_hid_init_core();
|
||||
|
Loading…
Reference in New Issue
Block a user