mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-24 15:56:41 +00:00
usb: LED suppport
This commit is contained in:
parent
12461291b8
commit
fe4f304815
@ -62,6 +62,7 @@ set build_components {
|
|||||||
drivers/timer
|
drivers/timer
|
||||||
drivers/usb
|
drivers/usb
|
||||||
test/input
|
test/input
|
||||||
|
server/dynamic_rom
|
||||||
}
|
}
|
||||||
|
|
||||||
lappend_if [have_spec gpio] build_components drivers/gpio
|
lappend_if [have_spec gpio] build_components drivers/gpio
|
||||||
@ -112,13 +113,63 @@ append config {
|
|||||||
<resource name="RAM" quantum="1M"/>
|
<resource name="RAM" quantum="1M"/>
|
||||||
<provides><service name="Timer"/></provides>
|
<provides><service name="Timer"/></provides>
|
||||||
</start>
|
</start>
|
||||||
|
|
||||||
<start name="usb_drv" caps="120">
|
<start name="usb_drv" caps="120">
|
||||||
<resource name="RAM" quantum="16M"/>
|
<resource name="RAM" quantum="16M"/>
|
||||||
<provides><service name="Input"/></provides>
|
<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/>
|
<hid/>
|
||||||
</config>
|
</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>
|
||||||
|
|
||||||
|
<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">
|
<start name="test-input">
|
||||||
<resource name="RAM" quantum="1M"/>
|
<resource name="RAM" quantum="1M"/>
|
||||||
</start>
|
</start>
|
||||||
@ -132,7 +183,7 @@ install_config $config
|
|||||||
|
|
||||||
# generic modules
|
# generic modules
|
||||||
set boot_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]
|
lappend_if [have_spec gpio] boot_modules [gpio_drv]
|
||||||
|
@ -25,12 +25,24 @@
|
|||||||
|
|
||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
#include <base/log.h>
|
#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 */
|
/* Linux includes */
|
||||||
#include <lx_emul.h>
|
#include <lx_emul.h>
|
||||||
#include <lx_emul/extern_c_begin.h>
|
#include <lx_emul/extern_c_begin.h>
|
||||||
|
#include <linux/hid.h>
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
#include <linux/input/mt.h>
|
#include <linux/input/mt.h>
|
||||||
|
#include <linux/usb.h>
|
||||||
#include <lx_emul/extern_c_end.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;
|
screen_y = res_y;
|
||||||
multi_touch = multitouch;
|
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_ms_driver_init();
|
||||||
extern "C" void module_mt_driver_init();
|
extern "C" void module_mt_driver_init();
|
||||||
extern "C" void module_raw_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);
|
extern "C" void start_input_service(void *ep, void *services);
|
||||||
|
|
||||||
@ -80,6 +81,7 @@ static void run_linux(void *s)
|
|||||||
if (services->hid) {
|
if (services->hid) {
|
||||||
subsys_input_init();
|
subsys_input_init();
|
||||||
module_evdev_init();
|
module_evdev_init();
|
||||||
|
module_led_init();
|
||||||
|
|
||||||
/* HID */
|
/* HID */
|
||||||
module_hid_init_core();
|
module_hid_init_core();
|
||||||
|
Loading…
Reference in New Issue
Block a user