mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-18 10:46:25 +00:00
dde_linux: USB-client driver for HID version 4.16
This commit is contained in:
parent
b02f483841
commit
b32a3cd4d9
33
repos/dde_linux/lib/import/import-usb_hid_include.mk
Normal file
33
repos/dde_linux/lib/import/import-usb_hid_include.mk
Normal file
@ -0,0 +1,33 @@
|
||||
USB_HID_CONTRIB_DIR := $(call select_from_ports,dde_linux)/src/drivers/usb_hid
|
||||
|
||||
# architecture-dependent includes
|
||||
ifeq ($(filter-out $(SPECS),x86),)
|
||||
ARCH_SRC_INC_DIR += $(REP_DIR)/src/include/spec/x86
|
||||
ifeq ($(filter-out $(SPECS),32bit),)
|
||||
ARCH_SRC_INC_DIR += $(REP_DIR)/src/include/spec/x86_32
|
||||
endif # 32bit
|
||||
ifeq ($(filter-out $(SPECS),64bit),)
|
||||
ARCH_SRC_INC_DIR += $(REP_DIR)/src/include/spec/x86_64
|
||||
endif # 64bit
|
||||
endif # x86
|
||||
|
||||
ifeq ($(filter-out $(SPECS),arm),)
|
||||
ARCH_SRC_INC_DIR += $(REP_DIR)/src/include/spec/arm
|
||||
ifeq ($(filter-out $(SPECS),arm_v6),)
|
||||
ARCH_SRC_INC_DIR += $(REP_DIR)/src/include/spec/arm_v6
|
||||
endif # arm_v6
|
||||
ifeq ($(filter-out $(SPECS),arm_v7),)
|
||||
ARCH_SRC_INC_DIR += $(REP_DIR)/src/include/spec/arm_v7
|
||||
endif # arm_v7
|
||||
endif # arm
|
||||
|
||||
|
||||
#
|
||||
# The order of include-search directories is important, we need to look into
|
||||
# 'contrib' before falling back to our custom 'lx_emul.h' header.
|
||||
#
|
||||
INC_DIR += $(ARCH_SRC_INC_DIR)
|
||||
INC_DIR += $(USB_HID_CONTRIB_DIR)/include
|
||||
INC_DIR += $(USB_HID_CONTRIB_DIR)/drivers/hid
|
||||
INC_DIR += $(USB_HID_CONTRIB_DIR)/drivers/input
|
||||
INC_DIR += $(LIB_CACHE_DIR)/usb_hid_include/include/include/include
|
37
repos/dde_linux/lib/mk/usb_hid_include.mk
Normal file
37
repos/dde_linux/lib/mk/usb_hid_include.mk
Normal file
@ -0,0 +1,37 @@
|
||||
ifeq ($(called_from_lib_mk),yes)
|
||||
|
||||
USB_HID_CONTRIB_DIR := $(call select_from_ports,dde_linux)/src/drivers/usb_hid
|
||||
LX_EMUL_H := $(REP_DIR)/src/drivers/usb_hid/lx_emul.h
|
||||
|
||||
#
|
||||
# Determine the header files included by the contrib code. For each
|
||||
# of these header files we create a symlink to 'lx_emul.h'.
|
||||
#
|
||||
SCAN_DIRS := $(addprefix $(USB_HID_CONTRIB_DIR)/include/, asm-generic linux uapi) \
|
||||
$(addprefix $(USB_HID_CONTRIB_DIR)/, drivers)
|
||||
GEN_INCLUDES := $(shell grep -rIh "^\#include .*\/" $(SCAN_DIRS) |\
|
||||
sed "s/^\#include [^<\"]*[<\"]\([^>\"]*\)[>\"].*/\1/" |\
|
||||
sort | uniq)
|
||||
#
|
||||
# Filter out original Linux headers that exist in the contrib directory
|
||||
#
|
||||
NO_GEN_INCLUDES := $(shell cd $(USB_HID_CONTRIB_DIR)/; find include -name "*.h" |\
|
||||
sed "s/.\///" | sed "s/.*include\///")
|
||||
GEN_INCLUDES := $(filter-out $(NO_GEN_INCLUDES),$(GEN_INCLUDES))
|
||||
|
||||
#
|
||||
# Put Linux headers in 'GEN_INC' dir, since some include use "../../" paths use
|
||||
# three level include hierarchy
|
||||
#
|
||||
GEN_INC := $(shell pwd)/include/include/include
|
||||
GEN_INCLUDES := $(addprefix $(GEN_INC)/,$(GEN_INCLUDES))
|
||||
|
||||
all: $(GEN_INCLUDES)
|
||||
|
||||
$(GEN_INCLUDES):
|
||||
$(VERBOSE)mkdir -p $(dir $@)
|
||||
$(VERBOSE)ln -s $(LX_EMUL_H) $@
|
||||
|
||||
endif
|
||||
|
||||
CC_CXX_WARN_STRICT =
|
22
repos/dde_linux/patches/usb_hid_evdev.patch
Normal file
22
repos/dde_linux/patches/usb_hid_evdev.patch
Normal file
@ -0,0 +1,22 @@
|
||||
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
|
||||
index c81c79d..c75bd8d 100644
|
||||
--- a/drivers/input/evdev.c
|
||||
+++ b/drivers/input/evdev.c
|
||||
@@ -1425,6 +1425,7 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
|
||||
if (error)
|
||||
goto err_cleanup_evdev;
|
||||
|
||||
+ evdev_open_device(evdev);
|
||||
return 0;
|
||||
|
||||
err_cleanup_evdev:
|
||||
@@ -1456,8 +1457,7 @@ static const struct input_device_id evdev_ids[] = {
|
||||
MODULE_DEVICE_TABLE(input, evdev_ids);
|
||||
|
||||
static struct input_handler evdev_handler = {
|
||||
- .event = evdev_event,
|
||||
- .events = evdev_events,
|
||||
+ .event = genode_evdev_event,
|
||||
.connect = evdev_connect,
|
||||
.disconnect = evdev_disconnect,
|
||||
.legacy_minors = true,
|
31
repos/dde_linux/patches/usb_hid_usbhid.patch
Normal file
31
repos/dde_linux/patches/usb_hid_usbhid.patch
Normal file
@ -0,0 +1,31 @@
|
||||
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
|
||||
index 77c50cd..55379da 100644
|
||||
--- a/drivers/hid/usbhid/hid-core.c
|
||||
+++ b/drivers/hid/usbhid/hid-core.c
|
||||
@@ -1636,7 +1636,7 @@ struct usb_interface *usbhid_find_interface(int minor)
|
||||
return usb_find_interface(&hid_driver, minor);
|
||||
}
|
||||
|
||||
-static int __init hid_init(void)
|
||||
+static int __init usbhid_init(void)
|
||||
{
|
||||
int retval = -ENOMEM;
|
||||
|
||||
@@ -1655,14 +1655,14 @@ usbhid_quirks_init_fail:
|
||||
return retval;
|
||||
}
|
||||
|
||||
-static void __exit hid_exit(void)
|
||||
+static void __exit usbhid_exit(void)
|
||||
{
|
||||
usb_deregister(&hid_driver);
|
||||
hid_quirks_exit(BUS_USB);
|
||||
}
|
||||
|
||||
-module_init(hid_init);
|
||||
-module_exit(hid_exit);
|
||||
+module_init(usbhid_init);
|
||||
+module_exit(usbhid_exit);
|
||||
|
||||
MODULE_AUTHOR("Andreas Gal");
|
||||
MODULE_AUTHOR("Vojtech Pavlik");
|
12
repos/dde_linux/patches/usb_hid_wacom_sys.patch
Normal file
12
repos/dde_linux/patches/usb_hid_wacom_sys.patch
Normal file
@ -0,0 +1,12 @@
|
||||
diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
|
||||
index 4095431..92ea1ab 100644
|
||||
--- a/drivers/hid/wacom_sys.c
|
||||
+++ b/drivers/hid/wacom_sys.c
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "wacom_wac.h"
|
||||
#include "wacom.h"
|
||||
#include <linux/input/mt.h>
|
||||
+#include <linux/usb.h>
|
||||
|
||||
#define WAC_MSG_RETRIES 5
|
||||
#define WAC_CMD_RETRIES 10
|
@ -1 +1 @@
|
||||
d0b8fe75d35d994df3bc98161d5d7558513a5d4a
|
||||
66e54dcbcd22c597db5794f080d92df114b88985
|
||||
|
@ -2,7 +2,7 @@ LICENSE := GPLv2
|
||||
VERSION := 2
|
||||
DOWNLOADS := dwc_otg.git usb.archive intel_fb.archive lxip.archive \
|
||||
wifi.archive fec.archive libnl.archive wpa_supplicant.git \
|
||||
fw.archive usb_host.archive dwc_otg_host.git
|
||||
fw.archive usb_host.archive dwc_otg_host.git usb_hid.archive
|
||||
|
||||
#
|
||||
# Tools
|
||||
@ -43,6 +43,14 @@ DIR(usb_host) := $(SRC_DIR_USB_HOST)
|
||||
TAR_OPT(usb_host) := --strip-components=1 --files-from - < <(sed 's/-x.x.x/-$(VERSION_USB_HOST)/g' $(REP_DIR)/usb_host.list)
|
||||
HASH_INPUT += $(REP_DIR)/usb_host.list
|
||||
|
||||
SRC_DIR_USB_HID := src/drivers/usb_hid
|
||||
VERSION_USB_HID := 4.16.3
|
||||
URL(usb_hid) := https://www.kernel.org/pub/linux/kernel/v4.x/linux-$(VERSION_USB_HID).tar.xz
|
||||
SHA(usb_hid) := 0d6971a81da97e38b974c5eba31a74803bfe41aabc46d406c3acda56306c81a3
|
||||
DIR(usb_hid) := $(SRC_DIR_USB_HID)
|
||||
TAR_OPT(usb_hid) := --strip-components=1 --files-from - < <(sed 's/-x.x.x/-$(VERSION_USB_HID)/g' $(REP_DIR)/usb_hid.list)
|
||||
HASH_INPUT += $(REP_DIR)/usb_hid.list
|
||||
|
||||
#
|
||||
# Raspberry Pi USB controller
|
||||
#
|
||||
@ -135,6 +143,7 @@ PATCHES += $(addprefix patches/,$(notdir $(wildcard $(REP_DIR)/patches/usb_host*
|
||||
PATCHES += $(addprefix patches/,$(notdir $(wildcard $(REP_DIR)/patches/usb*.patch)))
|
||||
PATCHES += $(addprefix patches/,$(notdir $(wildcard $(REP_DIR)/patches/intel*.patch)))
|
||||
PATCHES += $(addprefix patches/,$(notdir $(wildcard $(REP_DIR)/patches/fec_*.patch)))
|
||||
PATCHES += $(addprefix patches/,$(notdir $(wildcard $(REP_DIR)/patches/usb_hid*.patch)))
|
||||
|
||||
#IP stack
|
||||
LXIP_OPT = -p1 -d$(SRC_DIR_LXIP)
|
||||
@ -172,6 +181,12 @@ USB_HOST_OPT = -p1 -d$(SRC_DIR_USB_HOST)
|
||||
PATCH_OPT(patches/usb_host_mem.patch) := $(USB_HOST_OPT)
|
||||
PATCH_OPT(patches/usb_host_omap.patch) := $(USB_HOST_OPT)
|
||||
|
||||
# USB HID
|
||||
USB_HID_OPT = -p1 -d$(SRC_DIR_USB_HID)
|
||||
PATCH_OPT(patches/usb_hid_usbhid.patch) := $(USB_HID_OPT)
|
||||
PATCH_OPT(patches/usb_hid_wacom_sys.patch) := $(USB_HID_OPT)
|
||||
PATCH_OPT(patches/usb_hid_evdev.patch) := $(USB_HID_OPT)
|
||||
|
||||
# INTEL FB
|
||||
PATCH_OPT(patches/intel_fb_backlight.patch) := -p1 -d$(SRC_DIR_INTEL_FB)
|
||||
PATCH_OPT(patches/intel_fb_drm.patch) := -p1 -d$(SRC_DIR_INTEL_FB)
|
||||
|
@ -60,9 +60,11 @@ if { [get_cmd_switch --autopilot] && ![have_spec x86_64] } {
|
||||
set build_components {
|
||||
core init
|
||||
drivers/timer
|
||||
drivers/usb
|
||||
drivers/usb_host
|
||||
drivers/usb_hid
|
||||
test/input
|
||||
server/dynamic_rom
|
||||
server/report_rom
|
||||
}
|
||||
|
||||
lappend_if [have_spec gpio] build_components drivers/gpio
|
||||
@ -114,27 +116,39 @@ append config {
|
||||
<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"
|
||||
capslock_led="rom" numlock_led="rom" scrlock_led="rom"
|
||||
bios_handoff="no">
|
||||
<hid/>
|
||||
<start name="report_rom">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides> <service name="Report"/> <service name="ROM"/> </provides>
|
||||
<config verbose="no">
|
||||
<default-policy report="usb_drv -> devices"/>
|
||||
</config>
|
||||
</start>
|
||||
|
||||
<start name="usb_drv" caps="120"> }
|
||||
append config "<binary name=\"[usb_host_drv_binary]\"/>"
|
||||
append config {
|
||||
<resource name="RAM" quantum="10M"/>
|
||||
<provides> <service name="Usb"/> </provides>
|
||||
<config bios_handoff="no">
|
||||
<report devices="yes"/>
|
||||
<policy label_prefix="usb_hid_drv" class="0x3"/>
|
||||
</config>
|
||||
<route>
|
||||
<service name="Report"> <child name="report_rom"/> </service>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
|
||||
<start name="usb_hid_drv" caps="120">
|
||||
<resource name="RAM" quantum="10M"/>
|
||||
<provides><service name="Input"/></provides>
|
||||
<config use_report="yes" 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>
|
||||
<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>
|
||||
<service name="ROM" label="report"> <child name="report_rom"/> </service>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
|
||||
@ -183,15 +197,17 @@ install_config $config
|
||||
|
||||
# generic modules
|
||||
set boot_modules {
|
||||
core ld.lib.so init timer usb_drv test-input dynamic_rom
|
||||
core ld.lib.so init timer usb_hid_drv test-input dynamic_rom report_rom
|
||||
}
|
||||
|
||||
append boot_modules [usb_host_drv_binary]
|
||||
lappend_if [have_spec gpio] boot_modules [gpio_drv]
|
||||
|
||||
append_platform_drv_boot_modules
|
||||
|
||||
build_boot_image $boot_modules
|
||||
|
||||
append qemu_args " -nographic"
|
||||
append qemu_args " -usb -usbdevice mouse -usbdevice keyboard"
|
||||
append qemu_args " -device usb-ehci,id=ehci"
|
||||
append xen_args { usbdevice=\["mouse","keyboard"\] }
|
||||
@ -211,7 +227,7 @@ run_genode_until {\[init -\> test-input\] Input event #11.*\n} 40 [output_spawn_
|
||||
grep_output {^\[init }
|
||||
|
||||
unify_output { number [0-9]+} ""
|
||||
unify_output {(?n)on usb-dummy.*$} ""
|
||||
unify_output {(?n)on usb-usbbus.*$} ""
|
||||
unify_output {(?n)using .*$} ""
|
||||
unify_output {(?n)^.*__wait_event.*$} ""
|
||||
unify_output {(?n)^.*Failed to submit URB.*$} ""
|
||||
@ -228,10 +244,8 @@ compare_output_to {
|
||||
[init -> test-input] Input event #5 RELEASE BTN_LEFT
|
||||
[init -> usb_drv] dev_info: USB disconnect, device
|
||||
[init -> usb_drv] dev_info: new full-speed USB device
|
||||
[init -> usb_drv] dev_info: D L
|
||||
[init -> usb_drv] dev_info: input: USB HID v1.11 Keyboard [D L]
|
||||
[init -> usb_drv] dev_info: D L
|
||||
[init -> usb_drv] dev_info: input: USB HID v1.11 Mouse [D L]
|
||||
[init -> usb_hid_drv] dev_info: input: USB HID v1.11 Keyboard [HID 03eb:204d]
|
||||
[init -> usb_hid_drv] dev_info: input: USB HID v1.11 Mouse [HID 03eb:204d]
|
||||
[init -> test-input] Input event #6 PRESS KEY_X 0
|
||||
[init -> test-input] Input event #7 RELEASE KEY_X
|
||||
[init -> test-input] Input event #8 PRESS BTN_LEFT 0
|
||||
|
49
repos/dde_linux/src/drivers/usb_hid/README
Normal file
49
repos/dde_linux/src/drivers/usb_hid/README
Normal file
@ -0,0 +1,49 @@
|
||||
USB HID driver
|
||||
##############
|
||||
|
||||
Supports keyboard and mouse connected via USB.
|
||||
It connects to one or multiple USB sessions. A run script can be found
|
||||
under 'run/usb_hid.run'.
|
||||
|
||||
Configuration snippet:
|
||||
|
||||
!<start name="usb_hid_drv">
|
||||
! <resource name="RAM" quantum="10M"/>
|
||||
! <provides><service name="Input"/></provides>
|
||||
! <config use_report="yes"/>
|
||||
!</start>
|
||||
|
||||
When the use_report attribute is set, the HID driver will request a ROM called
|
||||
"report" that is used to iterate over all devices provided by the USB host
|
||||
controller driver (resp. a rom filter). In that mode the driver tries to
|
||||
claim all HID devices (class 0x3) via dedicated USB sessions.
|
||||
|
||||
Note: It has been observed that certain 1.0 versions of Qemu do not generate
|
||||
mouse interrupts. The mouse driver should work correctly on Qemu 1.0.93 and
|
||||
above.
|
||||
|
||||
HID - Touchscreen support
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Touchscreen absolute coordinates must be calibrated (e.g. re-calculated) to
|
||||
screen absolute coordinates. The screen resolution is not determined
|
||||
automatically by the HID driver, but can be configured:
|
||||
|
||||
!...
|
||||
!<config touchscreen width="1024" height="768" multitouch="no"/>
|
||||
!...
|
||||
|
||||
If a touchscreen is multi-touch-capable than the multitouch attribute gears
|
||||
which type of Genode input events are generated. If set to 'no' (default)
|
||||
than absolute events are generated and no multitouch events. If set to 'yes'
|
||||
solely multitouch events are generated.
|
||||
|
||||
Keyboard LED handling
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The state of the keyboard LEDs like capslock can be controlled by providing
|
||||
a corresponding ROM to the driver and configure it appropriatedly:
|
||||
|
||||
!...
|
||||
!<config capslock_led="rom" numlock_led="rom" scrlock_led="rom"/>
|
||||
!...
|
121
repos/dde_linux/src/drivers/usb_hid/driver.h
Normal file
121
repos/dde_linux/src/drivers/usb_hid/driver.h
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* \brief USB HID driver
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2018-06-27
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2018 Genode Labs GmbH
|
||||
*
|
||||
* This file is distributed under the terms of the GNU General Public License
|
||||
* version 2.
|
||||
*/
|
||||
|
||||
#ifndef _SRC__DRIVERS__USB_HID__DRIVER_H_
|
||||
#define _SRC__DRIVERS__USB_HID__DRIVER_H_
|
||||
|
||||
#include <base/allocator_avl.h>
|
||||
#include <base/attached_rom_dataspace.h>
|
||||
#include <base/heap.h>
|
||||
#include <input/root.h>
|
||||
#include <usb_session/connection.h>
|
||||
#include <lx_kit/scheduler.h>
|
||||
|
||||
struct usb_device_id;
|
||||
struct usb_interface;
|
||||
struct usb_device;
|
||||
|
||||
struct Driver
|
||||
{
|
||||
using Label = Genode::String<64>;
|
||||
|
||||
struct Task
|
||||
{
|
||||
Lx::Task task;
|
||||
Genode::Signal_handler<Task> handler;
|
||||
|
||||
void handle_signal()
|
||||
{
|
||||
task.unblock();
|
||||
Lx::scheduler().schedule();
|
||||
}
|
||||
|
||||
template <typename... ARGS>
|
||||
Task(Genode::Entrypoint & ep, ARGS &&... args)
|
||||
: task(args...), handler(ep, *this, &Task::handle_signal) {}
|
||||
};
|
||||
|
||||
struct Device
|
||||
{
|
||||
using Le = Genode::List_element<Device>;
|
||||
|
||||
Le le { this };
|
||||
Label label;
|
||||
Driver &driver;
|
||||
Genode::Env &env;
|
||||
Genode::Allocator_avl &alloc;
|
||||
Task state_task;
|
||||
Task urb_task;
|
||||
Usb::Connection usb { env, &alloc, label.string(),
|
||||
512 * 1024, state_task.handler };
|
||||
usb_device * udev = nullptr;
|
||||
bool updated = true;
|
||||
|
||||
Device(Driver & drv, Label label);
|
||||
~Device();
|
||||
|
||||
static void state_task_entry(void *);
|
||||
static void urb_task_entry(void *);
|
||||
void register_device();
|
||||
void unregister_device();
|
||||
void scan_interfaces(unsigned iface_idx);
|
||||
void scan_altsettings(usb_interface * iface,
|
||||
unsigned iface_idx, unsigned alt_idx);
|
||||
void probe_interface(usb_interface *, usb_device_id *);
|
||||
void remove_interface(usb_interface *);
|
||||
};
|
||||
|
||||
struct Devices : Genode::List<Device::Le>
|
||||
{
|
||||
template <typename FN>
|
||||
void for_each(FN const & fn)
|
||||
{
|
||||
Device::Le * cur = first();
|
||||
for (Device::Le * next = cur ? cur->next() : nullptr; cur;
|
||||
cur = next, next = cur ? cur->next() : nullptr)
|
||||
fn(*cur->object());
|
||||
}
|
||||
};
|
||||
|
||||
enum Input_event {
|
||||
EVENT_TYPE_PRESS,
|
||||
EVENT_TYPE_RELEASE,
|
||||
EVENT_TYPE_MOTION,
|
||||
EVENT_TYPE_WHEEL,
|
||||
EVENT_TYPE_TOUCH
|
||||
};
|
||||
|
||||
Devices devices;
|
||||
Genode::Env &env;
|
||||
Genode::Entrypoint &ep { env.ep() };
|
||||
Genode::Heap heap { env.ram(), env.rm() };
|
||||
Genode::Allocator_avl alloc { &heap };
|
||||
Input::Session_component session { env, env.ram() };
|
||||
Input::Root_component root { env.ep().rpc_ep(), session };
|
||||
Genode::Constructible<Task> main_task;
|
||||
Genode::Constructible<Genode::Attached_rom_dataspace> report_rom;
|
||||
|
||||
Driver(Genode::Env &env);
|
||||
|
||||
void scan_report();
|
||||
|
||||
static unsigned long screen_x;
|
||||
static unsigned long screen_y;
|
||||
static bool multi_touch;
|
||||
|
||||
static void main_task_entry(void *);
|
||||
static void input_callback(Input_event type, unsigned code,
|
||||
int ax, int ay, int rx, int ry);
|
||||
};
|
||||
|
||||
#endif /* _SRC__DRIVERS__USB_HID__DRIVER_H_ */
|
662
repos/dde_linux/src/drivers/usb_hid/dummies.c
Normal file
662
repos/dde_linux/src/drivers/usb_hid/dummies.c
Normal file
@ -0,0 +1,662 @@
|
||||
#include <lx_emul.h>
|
||||
|
||||
#if 0
|
||||
#define TRACE \
|
||||
do { \
|
||||
lx_printf("%s not implemented\n", __func__); \
|
||||
} while (0)
|
||||
#else
|
||||
#define TRACE do { ; } while (0)
|
||||
#endif
|
||||
|
||||
#define TRACE_AND_STOP \
|
||||
do { \
|
||||
lx_printf("%s not implemented\n", __func__); \
|
||||
BUG(); \
|
||||
} while (0)
|
||||
|
||||
int bitmap_subset(const unsigned long *src1, const unsigned long *src2, int nbits)
|
||||
{
|
||||
TRACE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int bitmap_weight(const unsigned long *src, unsigned int nbits)
|
||||
{
|
||||
TRACE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data, int (*fn)(struct device *dev, void *data))
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int bus_for_each_drv(struct bus_type *bus, struct device_driver *start, void *data, int (*fn)(struct device_driver *, void *))
|
||||
{
|
||||
TRACE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bus_register(struct bus_type *bus)
|
||||
{
|
||||
TRACE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bus_unregister(struct bus_type *bus)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
}
|
||||
|
||||
int cdev_device_add(struct cdev *cdev, struct device *dev)
|
||||
{
|
||||
TRACE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cdev_device_del(struct cdev *cdev, struct device *dev)
|
||||
{
|
||||
TRACE;
|
||||
}
|
||||
|
||||
int class_register(struct class *cls)
|
||||
{
|
||||
TRACE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void class_unregister(struct class *cls)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
}
|
||||
|
||||
unsigned long clear_user(void *to, unsigned long n)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
long copy_from_user(void *to, const void *from, unsigned long n)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t copy_to_user(void *dst, void const *src, size_t len)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int device_create_file(struct device *device, const struct device_attribute *entry)
|
||||
{
|
||||
TRACE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void device_enable_async_suspend(struct device *dev)
|
||||
{
|
||||
TRACE;
|
||||
}
|
||||
|
||||
void device_initialize(struct device *dev)
|
||||
{
|
||||
TRACE;
|
||||
}
|
||||
|
||||
void device_lock(struct device *dev)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
}
|
||||
|
||||
void device_release_driver(struct device *dev)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
}
|
||||
|
||||
void device_remove_file(struct device *dev, const struct device_attribute *attr)
|
||||
{
|
||||
TRACE;
|
||||
}
|
||||
|
||||
int device_set_wakeup_enable(struct device *dev, bool enable)
|
||||
{
|
||||
TRACE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void device_unlock(struct device *dev)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
}
|
||||
|
||||
int devm_add_action(struct device *dev, void (*action)(void *), void *data)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int devm_add_action_or_reset(struct device *dev, void (*action)(void *), void *data)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *devm_kasprintf(struct device *dev, gfp_t gfp, const char *fmt, ...)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int devm_led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int devm_led_trigger_register(struct device *dev, struct led_trigger *trigger)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void devres_add(struct device *dev, void *res)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
}
|
||||
|
||||
void *devres_alloc(dr_release_t release, size_t size, gfp_t gfp)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void devres_close_group(struct device *dev, void *id)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
}
|
||||
|
||||
int devres_destroy(struct device *dev, dr_release_t release, dr_match_t match, void *match_data)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void * devres_open_group(struct device *dev, void *id, gfp_t gfp)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int devres_release_group(struct device *dev, void *id)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int dev_set_name(struct device *dev, const char *name, ...)
|
||||
{
|
||||
TRACE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int down_interruptible(struct semaphore *sem)
|
||||
{
|
||||
TRACE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int down_trylock(struct semaphore *sem)
|
||||
{
|
||||
TRACE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int driver_attach(struct device_driver *drv)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fasync_helper(int a1, struct file * f, int a2, struct fasync_struct ** fas)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
u64 get_unaligned_le64(const void *p)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ida_simple_get(struct ida *ida, unsigned int start, unsigned int end, gfp_t gfp_mask)
|
||||
{
|
||||
TRACE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ida_simple_remove(struct ida *ida, unsigned int id)
|
||||
{
|
||||
TRACE;
|
||||
}
|
||||
|
||||
struct input_event;
|
||||
int input_event_from_user(const char __user *buffer, struct input_event *event)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int input_event_to_user(char __user *buffer, const struct input_event *event)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct input_dev;
|
||||
void input_ff_destroy(struct input_dev *dev)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
}
|
||||
|
||||
struct ff_effect;
|
||||
int input_ff_effect_from_user(const char __user *buffer, size_t size, struct ff_effect *effect)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int input_ff_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int input_ff_upload(struct input_dev *dev, struct ff_effect *effect, struct file *file)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned long int_sqrt(unsigned long x)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned int jiffies_to_usecs(const unsigned long j)
|
||||
{
|
||||
TRACE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kill_fasync(struct fasync_struct **a0, int a1, int a2)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
}
|
||||
|
||||
struct kobject * kobject_create_and_add(const char * a0, struct kobject * a1)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *kobject_get_path(struct kobject *kobj, gfp_t gfp_mask)
|
||||
{
|
||||
TRACE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void kobject_put(struct kobject * a0)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
}
|
||||
|
||||
struct device *kobj_to_dev(struct kobject *kobj)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void kref_get(struct kref *kref)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
}
|
||||
|
||||
void kref_init(struct kref *kref)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
}
|
||||
|
||||
int kref_put(struct kref *kref, void (*release) (struct kref *kref))
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int kstrtou8(const char *s, unsigned int base, u8 *res)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int kstrtouint(const char *s, unsigned int base, unsigned int *res)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int kstrtoul(const char *s, unsigned int base, unsigned long *res)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ktime_t ktime_get_boottime(void)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ktime_t ktime_get_real(void)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ktime_t ktime_mono_to_any(ktime_t tmono, enum tk_offsets offs)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ktime_t ktime_mono_to_real(ktime_t mono)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct timespec64 ktime_to_timespec64(const s64 nsec)
|
||||
{
|
||||
struct timespec64 ret;
|
||||
TRACE_AND_STOP;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void kvfree(const void *addr)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
}
|
||||
|
||||
int memcmp(const void * a0, const void * a1, size_t a2)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void __module_get(struct module *module)
|
||||
{
|
||||
TRACE;
|
||||
}
|
||||
|
||||
void module_put(struct module * module)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
}
|
||||
|
||||
loff_t no_llseek(struct file *file, loff_t offset, int whence)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int nonseekable_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void *power_supply_get_drvdata(struct power_supply *psy)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int power_supply_powers(struct power_supply *psy, struct device *dev)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int register_chrdev_region(dev_t a0, unsigned a1, const char * a2)
|
||||
{
|
||||
TRACE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scnprintf(char *buf, size_t size, const char *fmt, ...)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void sema_init(struct semaphore *sem, int val)
|
||||
{
|
||||
TRACE;
|
||||
}
|
||||
|
||||
void spin_lock(spinlock_t *lock)
|
||||
{
|
||||
TRACE;
|
||||
}
|
||||
|
||||
void spin_lock_irq(spinlock_t *lock)
|
||||
{
|
||||
TRACE;
|
||||
}
|
||||
|
||||
void spin_unlock_irq(spinlock_t *lock)
|
||||
{
|
||||
TRACE;
|
||||
}
|
||||
|
||||
int sscanf(const char * a0, const char * a1, ...)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int strcmp(const char *s1, const char *s2)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t strlcpy(char *dest, const char *src, size_t size)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int strncmp(const char *cs, const char *ct, size_t count)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *strrchr(const char * a0, int a1)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *strstr(const char * a0, const char * a1)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int sysfs_create_files(struct kobject *kobj, const struct attribute **ptr)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void sysfs_remove_group(struct kobject *kobj, const struct attribute_group *grp)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
}
|
||||
|
||||
struct urb;
|
||||
void usb_block_urb(struct urb *urb)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
}
|
||||
|
||||
struct usb_device;
|
||||
int usb_clear_halt(struct usb_device *dev, int pipe)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct usb_interface;
|
||||
void usb_queue_reset_device(struct usb_interface *dev)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
}
|
||||
|
||||
int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
|
||||
{
|
||||
TRACE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void usb_unpoison_urb(struct urb *urb)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
}
|
||||
|
||||
struct __kfifo;
|
||||
int __kfifo_alloc(struct __kfifo *fifo, unsigned int size, size_t esize, gfp_t gfp_mask)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void __kfifo_free(struct __kfifo *fifo)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
}
|
||||
|
||||
unsigned int __kfifo_in(struct __kfifo *fifo, const void *buf, unsigned int len)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int __kfifo_in_r(struct __kfifo *fifo, const void *buf, unsigned int len, size_t recsize)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int __kfifo_out(struct __kfifo *fifo, void *buf, unsigned int len)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int __kfifo_out_r(struct __kfifo *fifo, void *buf, unsigned int len, size_t recsize)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __kfifo_skip_r(struct __kfifo *fifo, size_t recsize)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
}
|
||||
|
||||
unsigned int __kfifo_max_r(unsigned int len, size_t recsize)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
}
|
||||
|
||||
void usb_kill_urb(struct urb *urb)
|
||||
{
|
||||
TRACE;
|
||||
}
|
||||
|
||||
int usb_unlink_urb(struct urb *urb)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct power_supply;
|
||||
struct power_supply_desc;
|
||||
struct power_supply_config;
|
||||
struct power_supply * devm_power_supply_register(struct device *parent, const struct power_supply_desc *desc, const struct power_supply_config *cfg)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void devres_free(void *res)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
}
|
||||
|
||||
char *kasprintf(gfp_t gfp, const char *fmt, ...)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void poll_wait(struct file *a0, wait_queue_head_t *a1, poll_table *a2)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
}
|
||||
|
||||
void power_supply_changed(struct power_supply *psy)
|
||||
{
|
||||
TRACE_AND_STOP;
|
||||
}
|
||||
|
||||
void put_device(struct device *dev)
|
||||
{
|
||||
TRACE;
|
||||
}
|
||||
|
||||
int sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp)
|
||||
{
|
||||
TRACE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void up(struct semaphore *sem)
|
||||
{
|
||||
TRACE;
|
||||
}
|
496
repos/dde_linux/src/drivers/usb_hid/evdev.cc
Normal file
496
repos/dde_linux/src/drivers/usb_hid/evdev.cc
Normal file
@ -0,0 +1,496 @@
|
||||
/*
|
||||
* \brief Input service and event handler
|
||||
* \author Christian Helmuth
|
||||
* \author Dirk Vogt
|
||||
* \author Sebastian Sumpf
|
||||
* \author Christian Menard
|
||||
* \author Alexander Boettcher
|
||||
* \date 2009-04-20
|
||||
*
|
||||
* TODO make this a complete replacement for evdev.c from Linux
|
||||
* TODO per-device slot handling
|
||||
*
|
||||
* The original implementation was in the L4Env from the TUD:OS group
|
||||
* (l4/pkg/input/lib/src/l4evdev.c). This file was released under the terms of
|
||||
* the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2009-2017 Genode Labs GmbH
|
||||
* Copyright (C) 2014 Ksys Labs LLC
|
||||
*
|
||||
* This file is distributed under the terms of the GNU General Public License
|
||||
* version 2.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/log.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 <driver.h>
|
||||
#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>
|
||||
|
||||
|
||||
static struct slot
|
||||
{
|
||||
int id = -1; /* current tracking id */
|
||||
int x = -1; /* last reported x axis */
|
||||
int y = -1; /* last reported y axis */
|
||||
int event = -1; /* last reported ABS_MT_ event */
|
||||
} slots[16];
|
||||
|
||||
static int slot = 0; /* store current input slot */
|
||||
|
||||
|
||||
static bool transform(input_dev *dev, int &x, int &y)
|
||||
{
|
||||
if (!Driver::screen_x || !Driver::screen_y) return true;
|
||||
|
||||
int const min_x_dev = input_abs_get_min(dev, ABS_X);
|
||||
int const min_y_dev = input_abs_get_min(dev, ABS_Y);
|
||||
int const max_x_dev = input_abs_get_max(dev, ABS_X);
|
||||
int const max_y_dev = input_abs_get_max(dev, ABS_Y);
|
||||
int const max_y_norm = max_y_dev - min_y_dev;
|
||||
int const max_x_norm = max_x_dev - min_x_dev;
|
||||
|
||||
if (!max_x_norm || !max_y_norm ||
|
||||
x < min_x_dev || y < min_y_dev || x > max_x_dev || y > max_y_dev) {
|
||||
Genode::warning("ignore input source with coordinates out of range");
|
||||
return false;
|
||||
}
|
||||
|
||||
x = Driver::screen_x * (x - min_x_dev) / (max_x_norm);
|
||||
y = Driver::screen_y * (y - min_y_dev) / (max_y_norm);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void handle_mt_tracking_id(input_dev *dev, int value)
|
||||
{
|
||||
if (value != -1) {
|
||||
if (slots[slot].id != -1)
|
||||
Genode::warning("old tracking id in use and got new one");
|
||||
|
||||
slots[slot].id = value;
|
||||
return;
|
||||
}
|
||||
|
||||
/* send end of slot usage event for clients */
|
||||
int x = slots[slot].x < 0 ? 0 : slots[slot].x;
|
||||
int y = slots[slot].y < 0 ? 0 : slots[slot].y;
|
||||
|
||||
if (!transform(dev, x, y)) return;
|
||||
|
||||
Driver::input_callback(Driver::EVENT_TYPE_TOUCH, slot, x, y, -1, -1);
|
||||
|
||||
slots[slot].event = slots[slot].x = slots[slot].y = -1;
|
||||
slots[slot].id = value;
|
||||
}
|
||||
|
||||
|
||||
static void handle_mt_slot(int value)
|
||||
{
|
||||
if ((unsigned)value >= sizeof(slots) / sizeof(slots[0])) {
|
||||
Genode::warning("drop multi-touch slot id ", value);
|
||||
return;
|
||||
}
|
||||
|
||||
slot = value;
|
||||
}
|
||||
|
||||
|
||||
enum Axis { AXIS_X, AXIS_Y };
|
||||
|
||||
static void handle_absolute_axis(input_dev *dev, unsigned code, int value, Axis axis)
|
||||
{
|
||||
slots[slot].event = code;
|
||||
|
||||
Driver::Input_event type = Driver::EVENT_TYPE_MOTION;
|
||||
|
||||
switch (axis) {
|
||||
case AXIS_X:
|
||||
type = code == ABS_X ? Driver::EVENT_TYPE_MOTION
|
||||
: Driver::EVENT_TYPE_TOUCH;
|
||||
slots[slot].x = value;
|
||||
break;
|
||||
case AXIS_Y:
|
||||
type = code == ABS_Y ? Driver::EVENT_TYPE_MOTION
|
||||
: Driver::EVENT_TYPE_TOUCH;
|
||||
slots[slot].y = value;
|
||||
break;
|
||||
}
|
||||
|
||||
int x = slots[slot].x;
|
||||
int y = slots[slot].y;
|
||||
|
||||
if (x == -1 || y == -1) return;
|
||||
|
||||
if (!transform(dev, x, y)) return;
|
||||
|
||||
Driver::input_callback(type, slot, x, y, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
static void handle_absolute(input_dev *dev, unsigned code, int value)
|
||||
{
|
||||
switch (code) {
|
||||
case ABS_WHEEL:
|
||||
Driver::input_callback(Driver::EVENT_TYPE_WHEEL, 0, 0, 0, 0, value);
|
||||
return;
|
||||
|
||||
case ABS_X:
|
||||
if (dev->mt && Driver::multi_touch) return;
|
||||
handle_absolute_axis(dev, code, value, AXIS_X);
|
||||
return;
|
||||
|
||||
case ABS_MT_POSITION_X:
|
||||
if (!Driver::multi_touch) return;
|
||||
handle_absolute_axis(dev, code, value, AXIS_X);
|
||||
return;
|
||||
|
||||
case ABS_Y:
|
||||
if (dev->mt && Driver::multi_touch) return;
|
||||
handle_absolute_axis(dev, code, value, AXIS_Y);
|
||||
return;
|
||||
|
||||
case ABS_MT_POSITION_Y:
|
||||
if (!Driver::multi_touch) return;
|
||||
handle_absolute_axis(dev, code, value, AXIS_Y);
|
||||
return;
|
||||
|
||||
case ABS_MT_TRACKING_ID:
|
||||
if (!Driver::multi_touch) return;
|
||||
handle_mt_tracking_id(dev, value);
|
||||
return;
|
||||
|
||||
case ABS_MT_SLOT:
|
||||
if (!Driver::multi_touch) return;
|
||||
handle_mt_slot(value);
|
||||
return;
|
||||
|
||||
case ABS_MT_TOUCH_MAJOR:
|
||||
case ABS_MT_TOUCH_MINOR:
|
||||
case ABS_MT_ORIENTATION:
|
||||
case ABS_MT_TOOL_TYPE:
|
||||
case ABS_MT_BLOB_ID:
|
||||
case ABS_MT_PRESSURE:
|
||||
case ABS_MT_DISTANCE:
|
||||
case ABS_MT_TOOL_X:
|
||||
case ABS_MT_TOOL_Y:
|
||||
/* ignore unused multi-touch events */
|
||||
return;
|
||||
|
||||
default:
|
||||
Genode::warning("unknown absolute event code ", code, " not handled");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void handle_relative(unsigned code, int value)
|
||||
{
|
||||
Driver::Input_event type;
|
||||
int x = 0, y = 0;
|
||||
|
||||
switch (code) {
|
||||
case REL_X:
|
||||
type = Driver::EVENT_TYPE_MOTION;
|
||||
x = value;
|
||||
break;
|
||||
|
||||
case REL_Y:
|
||||
type = Driver::EVENT_TYPE_MOTION;
|
||||
y = value;
|
||||
break;
|
||||
|
||||
case REL_HWHEEL:
|
||||
type = Driver::EVENT_TYPE_WHEEL;
|
||||
x = value;
|
||||
break;
|
||||
|
||||
case REL_WHEEL:
|
||||
type = Driver::EVENT_TYPE_WHEEL;
|
||||
y = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
Genode::warning("unknown relative event code ", code, " not handled");
|
||||
return;
|
||||
}
|
||||
|
||||
Driver::input_callback(type, 0, 0, 0, x, y);
|
||||
}
|
||||
|
||||
|
||||
static void handle_key(input_dev *dev, unsigned code, int value)
|
||||
{
|
||||
/* no press/release events for multi-touch devices in multi-touch mode */
|
||||
if (dev->mt && Driver::multi_touch) return;
|
||||
|
||||
/* map BTN_TOUCH to BTN_LEFT */
|
||||
if (code == BTN_TOUCH) code = BTN_LEFT;
|
||||
|
||||
Driver::Input_event type;
|
||||
switch (value) {
|
||||
case 0: type = Driver::EVENT_TYPE_RELEASE; break;
|
||||
case 1: type = Driver::EVENT_TYPE_PRESS; break;
|
||||
|
||||
default:
|
||||
Genode::warning("unknown key event value ", value, " not handled");
|
||||
return;
|
||||
}
|
||||
|
||||
Driver::input_callback(type, code, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
extern "C" void genode_evdev_event(input_handle *handle, unsigned int type,
|
||||
unsigned int code, int value)
|
||||
{
|
||||
input_dev *dev = handle->dev;
|
||||
|
||||
/* filter sound events */
|
||||
if (test_bit(EV_SND, handle->dev->evbit)) return;
|
||||
|
||||
/* filter input_repeat_key() */
|
||||
if ((type == EV_KEY) && (value == 2)) return;
|
||||
|
||||
/* filter EV_SYN and EV_MSC */
|
||||
if (type == EV_SYN || type == EV_MSC) return;
|
||||
|
||||
switch (type) {
|
||||
case EV_KEY: handle_key(dev, code, value); return;
|
||||
case EV_REL: handle_relative(code, value); return;
|
||||
case EV_ABS: handle_absolute(dev, code, value); return;
|
||||
|
||||
default:
|
||||
Genode::warning("unknown event type ", type, " not handled");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***************************
|
||||
** 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, 500);
|
||||
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;
|
||||
completion _led_update;
|
||||
|
||||
enum Update_state { NONE, UPDATE, BLOCKED };
|
||||
Update_state _update_state { NONE };
|
||||
|
||||
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) {
|
||||
/* config update from EP */
|
||||
wait_for_completion(&led->_config_update);
|
||||
|
||||
led->_update_state = UPDATE;
|
||||
|
||||
_registry.for_each([&] (Keyboard_led &keyboard) {
|
||||
led->update(keyboard); });
|
||||
|
||||
/* wake up other task that waits for regestry access */
|
||||
if (led->_update_state == BLOCKED)
|
||||
complete(&led->_led_update);
|
||||
|
||||
led->_update_state = NONE;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Led()
|
||||
{
|
||||
init_completion(&_config_update);
|
||||
init_completion(&_led_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);
|
||||
}
|
||||
|
||||
/*
|
||||
* wait for completion of registry and led state updates
|
||||
*/
|
||||
void wait_for_registry()
|
||||
{
|
||||
/* task in _run function might receive multiple updates */
|
||||
while ((_update_state == UPDATE)) {
|
||||
_update_state = BLOCKED;
|
||||
wait_for_completion(&_led_update);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
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);
|
||||
|
||||
input_handle *handle = (input_handle *)kzalloc(sizeof(input_handle), 0);
|
||||
handle->dev = input_get_device(dev);
|
||||
handle->handler = handler;
|
||||
|
||||
input_register_handle(handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void led_disconnect(struct input_handle *handle)
|
||||
{
|
||||
input_dev *dev = handle->dev;
|
||||
|
||||
_led->wait_for_registry();
|
||||
|
||||
_registry.for_each([&] (Keyboard_led &keyboard) {
|
||||
if (keyboard.match(dev))
|
||||
destroy(Lx_kit::env().heap(), &keyboard);
|
||||
});
|
||||
|
||||
input_unregister_handle(handle);
|
||||
input_put_device(dev);
|
||||
kfree(handle);
|
||||
}
|
||||
|
||||
|
||||
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/drivers/usb_hid/led_state.h
Normal file
66
repos/dde_linux/src/drivers/usb_hid/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_ */
|
310
repos/dde_linux/src/drivers/usb_hid/lx_emul.cc
Normal file
310
repos/dde_linux/src/drivers/usb_hid/lx_emul.cc
Normal file
@ -0,0 +1,310 @@
|
||||
|
||||
#include <base/env.h>
|
||||
#include <usb_session/client.h>
|
||||
|
||||
#include <driver.h>
|
||||
#include <lx_emul.h>
|
||||
|
||||
#include <lx_emul/extern_c_begin.h>
|
||||
#include <linux/usb.h>
|
||||
#include <lx_emul/extern_c_end.h>
|
||||
|
||||
#define TRACE do { ; } while (0)
|
||||
|
||||
#include <lx_emul/impl/kernel.h>
|
||||
#include <lx_emul/impl/delay.h>
|
||||
#include <lx_emul/impl/slab.h>
|
||||
#include <lx_emul/impl/work.h>
|
||||
#include <lx_emul/impl/spinlock.h>
|
||||
#include <lx_emul/impl/mutex.h>
|
||||
#include <lx_emul/impl/sched.h>
|
||||
#include <lx_emul/impl/timer.h>
|
||||
#include <lx_emul/impl/completion.h>
|
||||
#include <lx_emul/impl/wait.h>
|
||||
#include <lx_emul/impl/usb.h>
|
||||
|
||||
#include <lx_kit/backend_alloc.h>
|
||||
|
||||
struct Lx_driver
|
||||
{
|
||||
using Element = Genode::List_element<Lx_driver>;
|
||||
using List = Genode::List<Element>;
|
||||
|
||||
device_driver & dev_drv;
|
||||
Element le { this };
|
||||
|
||||
Lx_driver(device_driver & drv) : dev_drv(drv) { list().insert(&le); }
|
||||
|
||||
bool match(struct device *dev) {
|
||||
return dev_drv.bus->match ? dev_drv.bus->match(dev, &dev_drv)
|
||||
: false; }
|
||||
|
||||
int probe(struct device *dev)
|
||||
{
|
||||
dev->driver = &dev_drv;
|
||||
if (dev_drv.bus->probe) return dev_drv.bus->probe(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static List & list()
|
||||
{
|
||||
static List _list;
|
||||
return _list;
|
||||
}
|
||||
};
|
||||
|
||||
struct task_struct *current;
|
||||
struct workqueue_struct *system_wq;
|
||||
unsigned long jiffies;
|
||||
|
||||
Genode::Ram_dataspace_capability Lx::backend_alloc(Genode::addr_t size, Genode::Cache_attribute cached) {
|
||||
return Lx_kit::env().env().ram().alloc(size, cached); }
|
||||
|
||||
const char *dev_name(const struct device *dev) { return dev->name; }
|
||||
|
||||
size_t strlen(const char *s) { return Genode::strlen(s); }
|
||||
|
||||
int mutex_lock_interruptible(struct mutex *m)
|
||||
{
|
||||
mutex_lock(m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int driver_register(struct device_driver *drv)
|
||||
{
|
||||
if (drv) new (Lx::Malloc::mem()) Lx_driver(*drv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct usb_driver * hid_driver = nullptr;
|
||||
int usb_register_driver(struct usb_driver * driver, struct module *, const char *)
|
||||
{
|
||||
hid_driver = driver;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void Driver::Device::probe_interface(usb_interface * iface, usb_device_id * id)
|
||||
{
|
||||
hid_driver->probe(iface, id);
|
||||
}
|
||||
|
||||
|
||||
void Driver::Device::remove_interface(usb_interface * iface)
|
||||
{
|
||||
hid_driver->disconnect(iface);
|
||||
for (unsigned i = 0; i < iface->num_altsetting; i++) {
|
||||
if (iface->altsetting[i].extra)
|
||||
kfree(iface->altsetting[i].extra);
|
||||
kfree(iface->altsetting[i].endpoint);
|
||||
kfree(iface->altsetting);
|
||||
}
|
||||
kfree(iface);
|
||||
}
|
||||
|
||||
|
||||
long __wait_completion(struct completion *work, unsigned long timeout)
|
||||
{
|
||||
Lx::timer_update_jiffies();
|
||||
struct process_timer timer { *Lx::scheduler().current() };
|
||||
unsigned long expire = timeout + jiffies;
|
||||
|
||||
if (timeout) {
|
||||
timer_setup(&timer.timer, process_timeout, 0);
|
||||
mod_timer(&timer.timer, expire);
|
||||
}
|
||||
|
||||
while (!work->done) {
|
||||
|
||||
if (timeout && expire <= jiffies) return 0;
|
||||
|
||||
Lx::Task * task = Lx::scheduler().current();
|
||||
work->task = (void *)task;
|
||||
task->block_and_schedule();
|
||||
}
|
||||
|
||||
if (timeout) del_timer(&timer.timer);
|
||||
|
||||
work->done = 0;
|
||||
return (expire > jiffies) ? (expire - jiffies) : 1;
|
||||
}
|
||||
|
||||
|
||||
int dev_set_drvdata(struct device *dev, void *data)
|
||||
{
|
||||
dev->driver_data = data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void *dev_get_drvdata(const struct device *dev)
|
||||
{
|
||||
return dev->driver_data;
|
||||
}
|
||||
|
||||
|
||||
size_t strlcat(char *dest, const char *src, size_t dest_size)
|
||||
{
|
||||
size_t len_d = strlen(dest);
|
||||
|
||||
if (len_d > dest_size) return 0;
|
||||
|
||||
size_t len = dest_size - len_d - 1;
|
||||
|
||||
memcpy(dest + len_d, src, len);
|
||||
dest[len_d + len] = 0;
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
int __usb_get_extra_descriptor(char *buffer, unsigned size, unsigned char type, void **ptr)
|
||||
{
|
||||
struct usb_descriptor_header *header;
|
||||
|
||||
while (size >= sizeof(struct usb_descriptor_header)) {
|
||||
header = (struct usb_descriptor_header *)buffer;
|
||||
|
||||
if (header->bLength < 2) {
|
||||
printk(KERN_ERR
|
||||
"%s: bogus descriptor, type %d length %d\n",
|
||||
usbcore_name,
|
||||
header->bDescriptorType,
|
||||
header->bLength);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (header->bDescriptorType == type) {
|
||||
*ptr = header;
|
||||
return 0;
|
||||
}
|
||||
|
||||
buffer += header->bLength;
|
||||
size -= header->bLength;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void *vzalloc(unsigned long size)
|
||||
{
|
||||
size_t *addr;
|
||||
try { addr = (size_t *)Lx::Malloc::mem().alloc_large(size); }
|
||||
catch (...) { return 0; }
|
||||
|
||||
memset(addr, 0, size);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
|
||||
void vfree(void *addr)
|
||||
{
|
||||
if (!addr) return;
|
||||
Lx::Malloc::mem().free_large(addr);
|
||||
}
|
||||
|
||||
|
||||
int device_add(struct device *dev)
|
||||
{
|
||||
if (dev->driver) return 0;
|
||||
|
||||
/* foreach driver match and probe device */
|
||||
using Le = Genode::List_element<Lx_driver>;
|
||||
for (Le *le = Lx_driver::list().first(); le; le = le->next())
|
||||
if (le->object()->match(dev)) {
|
||||
int ret = le->object()->probe(dev);
|
||||
if (!ret) return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void device_del(struct device *dev)
|
||||
{
|
||||
if (dev->bus && dev->bus->remove)
|
||||
dev->bus->remove(dev);
|
||||
}
|
||||
|
||||
|
||||
void *usb_alloc_coherent(struct usb_device *dev, size_t size, gfp_t mem_flags, dma_addr_t *dma)
|
||||
{
|
||||
return kmalloc(size, GFP_KERNEL);
|
||||
}
|
||||
|
||||
|
||||
struct device *get_device(struct device *dev)
|
||||
{
|
||||
//dev->ref++;
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
||||
void cdev_init(struct cdev *c, const struct file_operations *fops)
|
||||
{
|
||||
c->ops = fops;
|
||||
}
|
||||
|
||||
|
||||
void usb_free_coherent(struct usb_device *dev, size_t size, void *addr, dma_addr_t dma)
|
||||
{
|
||||
//kfree(dev);
|
||||
}
|
||||
|
||||
|
||||
int mutex_lock_killable(struct mutex *lock)
|
||||
{
|
||||
mutex_lock(lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
u16 get_unaligned_le16(const void *p)
|
||||
{
|
||||
const struct __una_u16 *ptr = (const struct __una_u16 *)p;
|
||||
return ptr->x;
|
||||
}
|
||||
|
||||
|
||||
unsigned long find_next_bit(const unsigned long *addr, unsigned long size, unsigned long offset)
|
||||
{
|
||||
unsigned long i = offset / BITS_PER_LONG;
|
||||
offset -= (i * BITS_PER_LONG);
|
||||
|
||||
for (; offset < size; offset++)
|
||||
if (addr[i] & (1UL << offset))
|
||||
return offset + (i * BITS_PER_LONG);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
long find_next_zero_bit_le(const void *addr,
|
||||
unsigned long size, unsigned long offset)
|
||||
{
|
||||
unsigned long max_size = sizeof(long) * 8;
|
||||
if (offset >= max_size) {
|
||||
Genode::warning("Offset greater max size");
|
||||
return offset + size;
|
||||
}
|
||||
|
||||
for (; offset < max_size; offset++)
|
||||
if (!(*(unsigned long*)addr & (1L << offset)))
|
||||
return offset;
|
||||
|
||||
return offset + size;
|
||||
}
|
||||
|
||||
|
||||
u32 get_unaligned_le32(const void *p)
|
||||
{
|
||||
const struct __una_u32 *ptr = (const struct __una_u32 *)p;
|
||||
return ptr->x;
|
||||
}
|
||||
|
||||
|
||||
void *devm_kzalloc(struct device *dev, size_t size, gfp_t gfp)
|
||||
{
|
||||
return kzalloc(size, gfp);
|
||||
}
|
622
repos/dde_linux/src/drivers/usb_hid/lx_emul.h
Normal file
622
repos/dde_linux/src/drivers/usb_hid/lx_emul.h
Normal file
@ -0,0 +1,622 @@
|
||||
/*
|
||||
* \brief USB HID driver Linux emulation environment
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2018-06-13
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2018 Genode Labs GmbH
|
||||
*
|
||||
* This file is distributed under the terms of the GNU General Public License
|
||||
* version 2.
|
||||
*/
|
||||
|
||||
#ifndef _SRC__DRIVERS__USB_HID__LX_EMUL_H_
|
||||
#define _SRC__DRIVERS__USB_HID__LX_EMUL_H_
|
||||
|
||||
#include <base/fixed_stdint.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <lx_emul/extern_c_begin.h>
|
||||
|
||||
#define __KERNEL__ 1
|
||||
|
||||
#include <lx_emul/compiler.h>
|
||||
#include <lx_emul/printf.h>
|
||||
#include <lx_emul/types.h>
|
||||
#include <lx_emul/kernel.h>
|
||||
|
||||
enum { HZ = 100UL };
|
||||
|
||||
#include <lx_emul/jiffies.h>
|
||||
#include <lx_emul/time.h>
|
||||
#include <lx_emul/bitops.h>
|
||||
|
||||
typedef int clockid_t;
|
||||
|
||||
#include <lx_emul/timer.h>
|
||||
#include <lx_emul/spinlock.h>
|
||||
#include <lx_emul/mutex.h>
|
||||
|
||||
typedef __u16 __le16;
|
||||
typedef __u32 __le32;
|
||||
typedef __u64 __le64;
|
||||
typedef __u64 __be64;
|
||||
|
||||
#include <lx_emul/byteorder.h>
|
||||
#include <lx_emul/atomic.h>
|
||||
#include <lx_emul/work.h>
|
||||
#include <lx_emul/bug.h>
|
||||
#include <lx_emul/errno.h>
|
||||
#include <lx_emul/module.h>
|
||||
#include <lx_emul/gfp.h>
|
||||
|
||||
static inline void barrier() { asm volatile ("": : :"memory"); }
|
||||
|
||||
#define READ_ONCE(x) x
|
||||
|
||||
#include <lx_emul/list.h>
|
||||
#include <lx_emul/string.h>
|
||||
#include <lx_emul/kobject.h>
|
||||
#include <lx_emul/completion.h>
|
||||
|
||||
struct file
|
||||
{
|
||||
unsigned int f_flags;
|
||||
void * private_data;
|
||||
};
|
||||
|
||||
struct device;
|
||||
|
||||
typedef unsigned long kernel_ulong_t;
|
||||
typedef struct { __u8 b[16]; } uuid_le;
|
||||
|
||||
struct device * get_device(struct device *dev);
|
||||
void put_device(struct device *);
|
||||
void * dev_get_drvdata(const struct device *dev);
|
||||
int dev_set_drvdata(struct device *dev, void *data);
|
||||
|
||||
#define dev_info(dev, format, arg...) lx_printf("dev_info: " format , ## arg)
|
||||
#define dev_warn(dev, format, arg...) lx_printf("dev_warn: " format , ## arg)
|
||||
#define dev_err( dev, format, arg...) lx_printf("dev_err: " format , ## arg)
|
||||
#define dev_dbg( dev, format, arg...)
|
||||
|
||||
#define pr_info(fmt, ...) printk(KERN_INFO fmt, ##__VA_ARGS__)
|
||||
#define pr_err(fmt, ...) printk(KERN_ERR fmt, ##__VA_ARGS__)
|
||||
#define pr_warn(fmt, ...) printk(KERN_WARN fmt, ##__VA_ARGS__)
|
||||
|
||||
struct semaphore {};
|
||||
|
||||
struct device_driver
|
||||
{
|
||||
char const *name;
|
||||
struct bus_type *bus;
|
||||
struct module *owner;
|
||||
const char *mod_name;
|
||||
};
|
||||
|
||||
typedef int devt;
|
||||
|
||||
struct class
|
||||
{
|
||||
const char *name;
|
||||
char *(*devnode)(struct device *dev, mode_t *mode);
|
||||
};
|
||||
|
||||
struct device
|
||||
{
|
||||
char const * name;
|
||||
struct device * parent;
|
||||
struct kobject * kobj;
|
||||
struct device_driver * driver;
|
||||
struct bus_type * bus;
|
||||
dev_t devt;
|
||||
struct class * class;
|
||||
const struct device_type * type;
|
||||
void (*release)(struct device *dev);
|
||||
void * driver_data;
|
||||
};
|
||||
|
||||
void down(struct semaphore *sem);
|
||||
void up(struct semaphore *sem);
|
||||
|
||||
#define module_driver(__driver, __register, __unregister, ...) \
|
||||
static int __init __driver##_init(void) \
|
||||
{ \
|
||||
return __register(&(__driver) , ##__VA_ARGS__); \
|
||||
} \
|
||||
module_init(__driver##_init); \
|
||||
static void __exit __driver##_exit(void) \
|
||||
{ \
|
||||
__unregister(&(__driver) , ##__VA_ARGS__); \
|
||||
} \
|
||||
module_exit(__driver##_exit);
|
||||
|
||||
void device_lock(struct device *dev);
|
||||
void device_release_driver(struct device *dev);
|
||||
|
||||
#define KBUILD_MODNAME ""
|
||||
|
||||
struct attribute
|
||||
{
|
||||
const char * name;
|
||||
mode_t mode;
|
||||
};
|
||||
|
||||
struct device_attribute {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct device *dev, struct device_attribute *attr,
|
||||
char *buf);
|
||||
ssize_t (*store)(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count);
|
||||
};
|
||||
|
||||
#define __ATTR(_name,_mode,_show,_store) { \
|
||||
.attr = {.name = #_name, .mode = _mode }, \
|
||||
.show = _show, \
|
||||
.store = _store, \
|
||||
}
|
||||
|
||||
#define DEVICE_ATTR(_name, _mode, _show, _store) \
|
||||
struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
|
||||
|
||||
int sprintf(char *buf, const char *fmt, ...);
|
||||
int kstrtoul(const char *s, unsigned int base, unsigned long *res);
|
||||
|
||||
void device_unlock(struct device *dev);
|
||||
|
||||
struct kobj_uevent_env;
|
||||
|
||||
struct bus_type {
|
||||
const char * name;
|
||||
const struct attribute_group **dev_groups;
|
||||
const struct attribute_group **drv_groups;
|
||||
int (*match)(struct device *dev, struct device_driver *drv);
|
||||
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
|
||||
int (*probe)(struct device *dev);
|
||||
int (*remove)(struct device *dev);
|
||||
};
|
||||
|
||||
int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data, int (*fn)(struct device *dev, void *data));
|
||||
int bus_for_each_drv(struct bus_type *bus, struct device_driver *start, void *data, int (*fn)(struct device_driver *, void *));
|
||||
int driver_attach(struct device_driver *drv);
|
||||
|
||||
struct file_operations;
|
||||
struct cdev { const struct file_operations * ops; };
|
||||
|
||||
typedef __s64 time64_t;
|
||||
|
||||
struct timespec64 {
|
||||
time64_t tv_sec; /* seconds */
|
||||
long tv_nsec; /* nanoseconds */
|
||||
};
|
||||
|
||||
struct timespec64 ktime_to_timespec64(const s64 nsec);
|
||||
|
||||
enum {
|
||||
S_IWGRP = 20,
|
||||
S_IRGRP = 40,
|
||||
S_IRUGO = 444,
|
||||
S_IWUSR = 200,
|
||||
S_IRUSR = 400,
|
||||
};
|
||||
|
||||
struct attribute_group
|
||||
{
|
||||
const char *name;
|
||||
struct attribute **attrs;
|
||||
struct bin_attribute **bin_attrs;
|
||||
};
|
||||
|
||||
void kfree(const void *);
|
||||
unsigned int jiffies_to_usecs(const unsigned long j);
|
||||
void *devm_kzalloc(struct device *dev, size_t size, gfp_t gfp);
|
||||
size_t strlen(const char *s);
|
||||
|
||||
#define from_timer(var, callback_timer, timer_fieldname) \
|
||||
container_of(callback_timer, typeof(*var), timer_fieldname)
|
||||
|
||||
int sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp);
|
||||
void sysfs_remove_group(struct kobject *kobj, const struct attribute_group *grp);
|
||||
static inline void devm_kfree(struct device *dev, void *p) {}
|
||||
|
||||
#define module_param_array_named(name, array, type, nump, perm)
|
||||
|
||||
void *kmalloc(size_t size, gfp_t flags);
|
||||
void *kzalloc(size_t size, gfp_t flags);
|
||||
void *kcalloc(size_t n, size_t size, gfp_t flags);
|
||||
|
||||
int snprintf(char *buf, size_t size, const char *fmt, ...);
|
||||
const char *dev_name(const struct device *dev);
|
||||
u16 get_unaligned_le16(const void *p);
|
||||
u32 get_unaligned_le32(const void *p);
|
||||
|
||||
void *vzalloc(unsigned long size);
|
||||
void vfree(void *addr);
|
||||
|
||||
struct pm_message {};
|
||||
typedef struct pm_message pm_message_t;
|
||||
|
||||
#define clamp(val, lo, hi) min((typeof(val))max(val, lo), hi)
|
||||
|
||||
struct task_struct
|
||||
{
|
||||
char comm[16];
|
||||
};
|
||||
|
||||
extern struct task_struct *current;
|
||||
|
||||
struct completion
|
||||
{
|
||||
unsigned int done;
|
||||
void * task;
|
||||
};
|
||||
|
||||
long __wait_completion(struct completion *work, unsigned long timeout);
|
||||
|
||||
struct notifier_block;
|
||||
|
||||
enum {
|
||||
EPOLLIN = 0x00000001,
|
||||
EPOLLOUT = 0x00000004,
|
||||
EPOLLERR = 0x00000008,
|
||||
EPOLLHUP = 0x00000010,
|
||||
EPOLLRDNORM = 0x00000040,
|
||||
EPOLLWRNORM = 0x00000100,
|
||||
EPOLLRDHUP = 0x00002000,
|
||||
ESHUTDOWN = 58,
|
||||
};
|
||||
|
||||
enum led_brightness { LED_OFF = 0, LED_FULL = 255 };
|
||||
|
||||
struct led_classdev
|
||||
{
|
||||
const char * name;
|
||||
enum led_brightness max_brightness;
|
||||
int flags;
|
||||
void (*brightness_set)(struct led_classdev *led_cdev,
|
||||
enum led_brightness brightness);
|
||||
int (*brightness_set_blocking)(struct led_classdev *led_cdev,
|
||||
enum led_brightness brightness);
|
||||
enum led_brightness (*brightness_get)(struct led_classdev *led_cdev);
|
||||
const char *default_trigger;
|
||||
struct led_trigger *trigger;
|
||||
};
|
||||
|
||||
struct led_trigger
|
||||
{
|
||||
const char * name;
|
||||
};
|
||||
|
||||
int sscanf(const char *, const char *, ...);
|
||||
|
||||
#define hid_dump_input(a,b,c) do { } while (0)
|
||||
#define hid_dump_report(a, b, c, d) do { } while (0)
|
||||
#define hid_debug_register(a, b) do { } while (0)
|
||||
#define hid_debug_unregister(a) do { } while (0)
|
||||
#define hid_debug_init() do { } while (0)
|
||||
#define hid_debug_exit() do { } while (0)
|
||||
|
||||
struct hid_device;
|
||||
|
||||
static inline int hidraw_report_event(struct hid_device *hid, u8 *data, int len) { return 0; }
|
||||
|
||||
int down_trylock(struct semaphore *sem);
|
||||
|
||||
struct bin_attribute {
|
||||
struct attribute attr;
|
||||
size_t size;
|
||||
ssize_t (*read)(struct file *, struct kobject *,
|
||||
struct bin_attribute *, char *, loff_t, size_t);
|
||||
};
|
||||
|
||||
struct device *kobj_to_dev(struct kobject *kobj);
|
||||
|
||||
static inline int hidraw_connect(struct hid_device *hid) { return -1; }
|
||||
static inline void hidraw_disconnect(struct hid_device *hid) { }
|
||||
|
||||
struct hidraw { u32 minor; };
|
||||
|
||||
int device_create_file(struct device *device, const struct device_attribute *entry);
|
||||
void device_remove_file(struct device *dev, const struct device_attribute *attr);
|
||||
|
||||
int mutex_lock_killable(struct mutex *lock);
|
||||
|
||||
struct driver_attribute {
|
||||
struct attribute attr;
|
||||
};
|
||||
|
||||
#define DRIVER_ATTR_WO(_name) \
|
||||
struct driver_attribute driver_attr_##_name = { .attr = { .name = NULL } }
|
||||
|
||||
void msleep(unsigned int);
|
||||
|
||||
long find_next_zero_bit_le(const void *addr, unsigned long size, unsigned long offset);
|
||||
|
||||
int sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp);
|
||||
|
||||
int down_interruptible(struct semaphore *sem);
|
||||
|
||||
int scnprintf(char *buf, size_t size, const char *fmt, ...);
|
||||
|
||||
enum { PAGE_SIZE = 4096, };
|
||||
|
||||
#define __ATTRIBUTE_GROUPS(_name) \
|
||||
static const struct attribute_group *_name##_groups[] = { \
|
||||
&_name##_group, \
|
||||
NULL, \
|
||||
}
|
||||
|
||||
#define ATTRIBUTE_GROUPS(_name) \
|
||||
static const struct attribute_group _name##_group = { \
|
||||
.attrs = _name##_attrs, \
|
||||
}; \
|
||||
__ATTRIBUTE_GROUPS(_name)
|
||||
|
||||
#define DEVICE_ATTR_RO(_name) \
|
||||
struct device_attribute dev_attr_##_name = { .attr = { .name = NULL } }
|
||||
|
||||
struct kobj_uevent_env;
|
||||
|
||||
int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...);
|
||||
|
||||
int dev_set_name(struct device *dev, const char *name, ...);
|
||||
int device_add(struct device *dev);
|
||||
|
||||
void device_initialize(struct device *dev);
|
||||
|
||||
void device_enable_async_suspend(struct device *dev);
|
||||
|
||||
void device_del(struct device *dev);
|
||||
|
||||
void sema_init(struct semaphore *sem, int val);
|
||||
|
||||
int driver_register(struct device_driver *drv);
|
||||
void driver_unregister(struct device_driver *drv);
|
||||
int bus_register(struct bus_type *bus);
|
||||
void bus_unregister(struct bus_type *bus);
|
||||
|
||||
enum { CLOCK_BOOTTIME = 7, };
|
||||
|
||||
struct fasync_struct;
|
||||
void kill_fasync(struct fasync_struct **, int, int);
|
||||
|
||||
enum { SIGIO = 29 };
|
||||
|
||||
enum {
|
||||
POLL_IN = 1,
|
||||
POLL_HUP = 6,
|
||||
};
|
||||
|
||||
enum tk_offsets { TK_OFFS_BOOT = 1, };
|
||||
|
||||
ktime_t ktime_mono_to_real(ktime_t mono);
|
||||
ktime_t ktime_mono_to_any(ktime_t tmono, enum tk_offsets offs);
|
||||
|
||||
static inline void rcu_read_lock(void) { }
|
||||
static inline void rcu_read_unlock(void) { }
|
||||
|
||||
#define rcu_dereference(p) p
|
||||
#define rcu_assign_pointer(p,v) p = v
|
||||
#define rcu_dereference_protected(p, c) p
|
||||
|
||||
static inline int hidraw_init(void) { return 0; }
|
||||
static inline int hidraw_exit(void) { return 0; }
|
||||
static inline int hidraw_debug_init(void) { return 0; }
|
||||
static inline int hidraw_debug_exit(void) { return 0; }
|
||||
|
||||
#define list_for_each_entry_rcu(pos, head, member) \
|
||||
list_for_each_entry(pos, head, member)
|
||||
|
||||
int fasync_helper(int, struct file *, int, struct fasync_struct **);
|
||||
|
||||
typedef unsigned fl_owner_t;
|
||||
|
||||
struct scatterlist;
|
||||
|
||||
bool lockdep_is_held(void *);
|
||||
|
||||
struct power_supply;
|
||||
void power_supply_changed(struct power_supply *psy);
|
||||
|
||||
static inline u16 get_unaligned_be16(const void *p) {
|
||||
return be16_to_cpup((__be16 *)p); }
|
||||
|
||||
static inline void synchronize_rcu(void) { }
|
||||
|
||||
static inline void list_add_tail_rcu(struct list_head *n,
|
||||
struct list_head *head) {
|
||||
list_add_tail(n, head); }
|
||||
|
||||
static inline void list_del_rcu(struct list_head *entry) {
|
||||
list_del(entry); }
|
||||
|
||||
int mutex_lock_interruptible(struct mutex *m);
|
||||
|
||||
void kvfree(const void *addr);
|
||||
|
||||
struct inode
|
||||
{
|
||||
struct cdev * i_cdev;
|
||||
};
|
||||
|
||||
int nonseekable_open(struct inode *inode, struct file *filp);
|
||||
|
||||
enum { O_NONBLOCK = 0x4000 };
|
||||
|
||||
typedef unsigned __poll_t;
|
||||
|
||||
typedef struct poll_table_struct { } poll_table;
|
||||
|
||||
size_t copy_to_user(void *dst, void const *src, size_t len);
|
||||
long copy_from_user(void *to, const void *from, unsigned long n);
|
||||
#define put_user(x, ptr) ({ lx_printf("put_user not implemented"); (0);})
|
||||
|
||||
int devm_add_action(struct device *dev, void (*action)(void *), void *data);
|
||||
|
||||
void poll_wait(struct file *f, wait_queue_head_t *w, poll_table *p);
|
||||
|
||||
#define get_user(x, ptr) ({ x = *ptr; 0; })
|
||||
|
||||
unsigned long clear_user(void *to, unsigned long n);
|
||||
|
||||
#define _IOC_NRSHIFT 0
|
||||
#define _IOC_TYPESHIFT (_IOC_NRSHIFT + 8)
|
||||
#define _IOC_SIZESHIFT (_IOC_TYPESHIFT + 8)
|
||||
#define _IOC_DIRSHIFT (_IOC_SIZESHIFT + 14)
|
||||
|
||||
#define _IOC_WRITE 1U
|
||||
#define _IOC_READ 2U
|
||||
#define _IOC_SIZEMASK ((1 << 14) - 1)
|
||||
#define _IOC_DIR(cmd) cmd
|
||||
#define _IOC(dir,type,nr,size) (type+nr+sizeof(size))
|
||||
#define _IOR(type,nr,size) (type+nr+sizeof(size)+10)
|
||||
#define _IOW(type,nr,size) (type+nr+sizeof(size)+20)
|
||||
#define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
|
||||
#define _IOC_TYPE(cmd) cmd
|
||||
#define _IOC_NR(cmd) cmd
|
||||
|
||||
signed long schedule_timeout(signed long timeout);
|
||||
|
||||
int kstrtouint(const char *s, unsigned int base, unsigned int *res);
|
||||
|
||||
#define find_next_zero_bit find_next_zero_bit_le
|
||||
|
||||
int device_set_wakeup_enable(struct device *dev, bool enable);
|
||||
|
||||
struct ida {};
|
||||
#define DEFINE_IDA(name) struct ida name;
|
||||
|
||||
loff_t no_llseek(struct file *file, loff_t offset, int whence);
|
||||
|
||||
struct file_operations
|
||||
{
|
||||
struct module *owner;
|
||||
int (*open) (struct inode *, struct file *);
|
||||
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
|
||||
loff_t (*llseek) (struct file *, loff_t, int);
|
||||
unsigned int (*poll) (struct file *, struct poll_table_struct *);
|
||||
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
|
||||
int (*flush) (struct file *, fl_owner_t id);
|
||||
int (*release) (struct inode *, struct file *);
|
||||
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
|
||||
int (*fasync) (int, struct file *, int);
|
||||
};
|
||||
|
||||
#define MKDEV(major, minor) 0
|
||||
|
||||
unsigned long int_sqrt(unsigned long x);
|
||||
|
||||
u64 get_unaligned_le64(const void *p);
|
||||
|
||||
#define U8_MAX ((u8)~0U)
|
||||
#define S8_MAX ((s8)(U8_MAX>>1))
|
||||
#define S8_MIN ((s8)(-S8_MAX - 1))
|
||||
#define U16_MAX ((u16)~0U)
|
||||
#define S16_MAX ((s16)(U16_MAX>>1))
|
||||
#define S16_MIN ((s16)(-S16_MAX - 1))
|
||||
#define U32_MAX ((u32)~0U)
|
||||
#define S32_MAX ((s32)(U32_MAX>>1))
|
||||
#define S32_MIN ((s32)(-S32_MAX - 1))
|
||||
|
||||
typedef void (*dr_release_t)(struct device *dev, void *res);
|
||||
void *devres_alloc(dr_release_t release, size_t size, gfp_t gfp);
|
||||
void devres_add(struct device *dev, void *res);
|
||||
int devres_release_group(struct device *dev, void *id);
|
||||
void * devres_open_group(struct device *dev, void *id, gfp_t gfp);
|
||||
void devres_close_group(struct device *dev, void *id);
|
||||
|
||||
static inline void add_input_randomness(unsigned int type, unsigned int code, unsigned int value) { }
|
||||
|
||||
unsigned long find_next_bit(const unsigned long *addr, unsigned long size, unsigned long offset);
|
||||
#define find_first_bit(addr, size) find_next_bit((addr), (size), 0)
|
||||
|
||||
char *devm_kasprintf(struct device *dev, gfp_t gfp, const char *fmt, ...);
|
||||
|
||||
int devm_led_trigger_register(struct device *dev, struct led_trigger *trigger);
|
||||
|
||||
int devm_add_action_or_reset(struct device *dev, void (*action)(void *), void *data);
|
||||
|
||||
int devm_led_classdev_register(struct device *parent, struct led_classdev *led_cdev);
|
||||
|
||||
enum { LED_HW_PLUGGABLE = 1 << 19 };
|
||||
|
||||
int kstrtou8(const char *s, unsigned int base, u8 *res);
|
||||
|
||||
struct kobj_attribute
|
||||
{
|
||||
struct attribute attr;
|
||||
void * show;
|
||||
void * store;
|
||||
};
|
||||
|
||||
int bitmap_subset(const unsigned long *src1, const unsigned long *src2, int nbits);
|
||||
|
||||
struct device_type {
|
||||
const char *name;
|
||||
const struct attribute_group **groups;
|
||||
void (*release)(struct device *dev);
|
||||
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
|
||||
char *(*devnode)(struct device *dev, mode_t *mode, kuid_t *, kgid_t *);
|
||||
};
|
||||
|
||||
char *kasprintf(gfp_t gfp, const char *fmt, ...);
|
||||
|
||||
void cdev_init(struct cdev *c, const struct file_operations *fops);
|
||||
int cdev_device_add(struct cdev *cdev, struct device *dev);
|
||||
void cdev_device_del(struct cdev *cdev, struct device *dev);
|
||||
|
||||
#define MINOR(dev) ((dev) & 0xff)
|
||||
|
||||
typedef int (*dr_match_t)(struct device *dev, void *res, void *match_data);
|
||||
|
||||
void devres_free(void *res);
|
||||
int devres_destroy(struct device *dev, dr_release_t release, dr_match_t match, void *match_data);
|
||||
|
||||
static inline void dump_stack(void) { }
|
||||
|
||||
int bitmap_weight(const unsigned long *src, unsigned int nbits);
|
||||
|
||||
#define list_add_rcu list_add
|
||||
|
||||
int ida_simple_get(struct ida *ida, unsigned int start, unsigned int end, gfp_t gfp_mask);
|
||||
void ida_simple_remove(struct ida *ida, unsigned int id);
|
||||
|
||||
int class_register(struct class *cls);
|
||||
void class_unregister(struct class *cls);
|
||||
int register_chrdev_region(dev_t, unsigned, const char *);
|
||||
void unregister_chrdev_region(dev_t, unsigned);
|
||||
|
||||
int sysfs_create_files(struct kobject *kobj, const struct attribute **ptr);
|
||||
|
||||
static inline void led_trigger_event(struct led_trigger *trigger,
|
||||
enum led_brightness event) {}
|
||||
|
||||
typedef unsigned slab_flags_t;
|
||||
|
||||
struct tasklet_struct
|
||||
{
|
||||
void (*func)(unsigned long);
|
||||
unsigned long data;
|
||||
};
|
||||
|
||||
struct __una_u16 { u16 x; } __attribute__((packed));
|
||||
struct __una_u32 { u32 x; } __attribute__((packed));
|
||||
|
||||
void subsys_input_init();
|
||||
int module_evdev_init();
|
||||
int module_led_init();
|
||||
int module_usbhid_init();
|
||||
int module_hid_init();
|
||||
int module_hid_generic_init();
|
||||
int module_ch_driver_init();
|
||||
int module_ms_driver_init();
|
||||
int module_mt_driver_init();
|
||||
int module_wacom_driver_init();
|
||||
|
||||
struct input_handle;
|
||||
void genode_evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value);
|
||||
|
||||
#include <lx_emul/extern_c_end.h>
|
||||
|
||||
#endif /* _SRC__DRIVERS__USB_HID__LX_EMUL_H_ */
|
323
repos/dde_linux/src/drivers/usb_hid/main.cc
Normal file
323
repos/dde_linux/src/drivers/usb_hid/main.cc
Normal file
@ -0,0 +1,323 @@
|
||||
/*
|
||||
* \brief USB HID driver
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2018-06-07
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2018 Genode Labs GmbH
|
||||
*
|
||||
* This file is distributed under the terms of the GNU General Public License
|
||||
* version 2.
|
||||
*/
|
||||
|
||||
#include <base/component.h>
|
||||
|
||||
#include <lx_kit/env.h>
|
||||
#include <lx_kit/malloc.h>
|
||||
#include <lx_kit/scheduler.h>
|
||||
#include <lx_kit/timer.h>
|
||||
|
||||
#include <driver.h>
|
||||
#include <lx_emul.h>
|
||||
|
||||
#include <lx_emul/extern_c_begin.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/usb.h>
|
||||
#include <lx_emul/extern_c_end.h>
|
||||
|
||||
void Driver::Device::scan_altsettings(usb_interface * iface,
|
||||
unsigned iface_idx, unsigned alt_idx)
|
||||
{
|
||||
Usb::Interface_descriptor iface_desc;
|
||||
usb.interface_descriptor(iface_idx, alt_idx, &iface_desc);
|
||||
Genode::memcpy(&iface->altsetting[alt_idx].desc, &iface_desc,
|
||||
sizeof(usb_interface_descriptor));
|
||||
if (iface_desc.active)
|
||||
iface->cur_altsetting = &iface->altsetting[alt_idx];
|
||||
|
||||
if (iface_desc.iclass == USB_CLASS_HID) {
|
||||
hid_descriptor * hd = (hid_descriptor*)
|
||||
kzalloc(sizeof(hid_descriptor), GFP_KERNEL);
|
||||
if (usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
|
||||
USB_REQ_GET_DESCRIPTOR,
|
||||
USB_RECIP_INTERFACE | USB_DIR_IN,
|
||||
(HID_DT_HID << 8), iface_idx, (void*)hd,
|
||||
sizeof(hid_descriptor), USB_CTRL_GET_TIMEOUT) < 0) {
|
||||
Genode::warning("could not get HID descriptor");
|
||||
} else {
|
||||
iface->altsetting[alt_idx].extra = (unsigned char*)hd;
|
||||
iface->altsetting[alt_idx].extralen = sizeof(hid_descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
iface->altsetting[alt_idx].endpoint = (usb_host_endpoint*)
|
||||
kzalloc(sizeof(usb_host_endpoint)*iface->altsetting[alt_idx].desc.bNumEndpoints, GFP_KERNEL);
|
||||
|
||||
for (unsigned i = 0; i < iface->altsetting[alt_idx].desc.bNumEndpoints; i++) {
|
||||
Usb::Endpoint_descriptor ep_desc;
|
||||
usb.endpoint_descriptor(iface_idx, alt_idx, i, &ep_desc);
|
||||
Genode::memcpy(&iface->altsetting[alt_idx].endpoint[i].desc,
|
||||
&ep_desc, sizeof(usb_endpoint_descriptor));
|
||||
int epnum = usb_endpoint_num(&iface->altsetting[alt_idx].endpoint[i].desc);
|
||||
if (usb_endpoint_dir_out(&iface->altsetting[alt_idx].endpoint[i].desc))
|
||||
udev->ep_out[epnum] = &iface->altsetting[alt_idx].endpoint[i];
|
||||
else
|
||||
udev->ep_in[epnum] = &iface->altsetting[alt_idx].endpoint[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Driver::Device::scan_interfaces(unsigned iface_idx)
|
||||
{
|
||||
struct usb_interface * iface =
|
||||
(usb_interface*) kzalloc(sizeof(usb_interface), GFP_KERNEL);
|
||||
iface->num_altsetting = usb.alt_settings(iface_idx);
|
||||
iface->altsetting = (usb_host_interface*)
|
||||
kzalloc(sizeof(usb_host_interface)*iface->num_altsetting, GFP_KERNEL);
|
||||
iface->dev.parent = &udev->dev;
|
||||
iface->dev.bus = (bus_type*) 0xdeadbeef;
|
||||
|
||||
for (unsigned i = 0; i < iface->num_altsetting; i++)
|
||||
scan_altsettings(iface, iface_idx, i);
|
||||
|
||||
struct usb_device_id id;
|
||||
probe_interface(iface, &id);
|
||||
udev->config->interface[iface_idx] = iface;
|
||||
};
|
||||
|
||||
|
||||
void Driver::Device::register_device()
|
||||
{
|
||||
if (udev) {
|
||||
Genode::error("device already registered!");
|
||||
return;
|
||||
}
|
||||
|
||||
Usb::Device_descriptor dev_desc;
|
||||
Usb::Config_descriptor config_desc;
|
||||
usb.config_descriptor(&dev_desc, &config_desc);
|
||||
|
||||
udev = (usb_device*) kzalloc(sizeof(usb_device), GFP_KERNEL);
|
||||
udev->bus = (usb_bus*) kzalloc(sizeof(usb_bus), GFP_KERNEL);
|
||||
udev->config = (usb_host_config*) kzalloc(sizeof(usb_host_config), GFP_KERNEL);
|
||||
udev->bus->bus_name = "usbbus";
|
||||
udev->bus->controller = (device*) (&usb);
|
||||
|
||||
udev->descriptor.idVendor = dev_desc.vendor_id;
|
||||
udev->descriptor.idProduct = dev_desc.product_id;
|
||||
udev->descriptor.bcdDevice = dev_desc.device_release;
|
||||
|
||||
for (unsigned i = 0; i < config_desc.num_interfaces; i++)
|
||||
scan_interfaces(i);
|
||||
}
|
||||
|
||||
|
||||
void Driver::Device::unregister_device()
|
||||
{
|
||||
for (unsigned i = 0; i < USB_MAXINTERFACES; i++) {
|
||||
if (!udev->config->interface[i]) break;
|
||||
else remove_interface(udev->config->interface[i]);
|
||||
}
|
||||
kfree(udev->bus);
|
||||
kfree(udev->config);
|
||||
kfree(udev);
|
||||
udev = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void Driver::Device::state_task_entry(void * arg)
|
||||
{
|
||||
Device & dev = *reinterpret_cast<Device*>(arg);
|
||||
|
||||
for (;;) {
|
||||
if (dev.usb.plugged() && !dev.udev)
|
||||
dev.register_device();
|
||||
|
||||
if (!dev.usb.plugged() && dev.udev)
|
||||
dev.unregister_device();
|
||||
|
||||
Lx::scheduler().current()->block_and_schedule();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Driver::Device::urb_task_entry(void * arg)
|
||||
{
|
||||
Device & dev = *reinterpret_cast<Device*>(arg);
|
||||
|
||||
for (;;) {
|
||||
while (dev.udev && dev.usb.source()->ack_avail()) {
|
||||
Usb::Packet_descriptor p = dev.usb.source()->get_acked_packet();
|
||||
if (p.completion) p.completion->complete(p);
|
||||
dev.usb.source()->release_packet(p);
|
||||
}
|
||||
|
||||
Lx::scheduler().current()->block_and_schedule();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Driver::Device::Device(Driver & driver, Label label)
|
||||
: label(label),
|
||||
driver(driver),
|
||||
env(driver.env),
|
||||
alloc(driver.alloc),
|
||||
state_task(env.ep(), state_task_entry, reinterpret_cast<void*>(this),
|
||||
"usb_state", Lx::Task::PRIORITY_0, Lx::scheduler()),
|
||||
urb_task(env.ep(), urb_task_entry, reinterpret_cast<void*>(this),
|
||||
"usb_urb", Lx::Task::PRIORITY_0, Lx::scheduler())
|
||||
{
|
||||
usb.tx_channel()->sigh_ack_avail(urb_task.handler);
|
||||
driver.devices.insert(&le);
|
||||
}
|
||||
|
||||
|
||||
Driver::Device::~Device()
|
||||
{
|
||||
driver.devices.remove(&le);
|
||||
if (udev) unregister_device();
|
||||
}
|
||||
|
||||
|
||||
unsigned long Driver::screen_x = 0;
|
||||
unsigned long Driver::screen_y = 0;
|
||||
bool Driver::multi_touch = false;
|
||||
static Driver * driver = nullptr;
|
||||
|
||||
|
||||
void Driver::main_task_entry(void * arg)
|
||||
{
|
||||
driver = reinterpret_cast<Driver*>(arg);
|
||||
|
||||
subsys_input_init();
|
||||
module_evdev_init();
|
||||
module_led_init();
|
||||
module_usbhid_init();
|
||||
module_hid_init();
|
||||
module_hid_generic_init();
|
||||
module_ch_driver_init();
|
||||
module_ms_driver_init();
|
||||
module_mt_driver_init();
|
||||
module_wacom_driver_init();
|
||||
|
||||
bool use_report = false;
|
||||
|
||||
try {
|
||||
Genode::Xml_node config_node = Lx_kit::env().config_rom().xml();
|
||||
use_report = config_node.attribute_value("use_report", false);
|
||||
config_node.attribute("width").value(&screen_x);
|
||||
config_node.attribute("height").value(&screen_y);
|
||||
multi_touch = config_node.attribute_value("multitouch", false);
|
||||
} catch(...) { }
|
||||
|
||||
if (use_report)
|
||||
Genode::warning("use compatibility mode: ",
|
||||
"will claim all HID devices from USB report");
|
||||
|
||||
Genode::log("Configured HID screen with ", screen_x, "x", screen_y,
|
||||
" (multitouch=", multi_touch ? "true" : "false", ")");
|
||||
|
||||
driver->env.parent().announce(driver->ep.manage(driver->root));
|
||||
|
||||
for (;;) {
|
||||
if (!use_report)
|
||||
static Device dev(*driver, Label(""));
|
||||
else
|
||||
driver->scan_report();
|
||||
Lx::scheduler().current()->block_and_schedule();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Driver::scan_report()
|
||||
{
|
||||
if (!report_rom.constructed()) {
|
||||
report_rom.construct(env, "report");
|
||||
report_rom->sigh(main_task->handler);
|
||||
} else
|
||||
report_rom->update();
|
||||
|
||||
devices.for_each([&] (Device & d) { d.updated = false; });
|
||||
|
||||
try {
|
||||
Genode::Xml_node report_node = report_rom->xml();
|
||||
report_node.for_each_sub_node([&] (Genode::Xml_node & dev_node)
|
||||
{
|
||||
unsigned long c = 0;
|
||||
dev_node.attribute("class").value(&c);
|
||||
if (c != USB_CLASS_HID) return;
|
||||
|
||||
Label label;
|
||||
dev_node.attribute("label").value(&label);
|
||||
|
||||
bool found = false;
|
||||
|
||||
devices.for_each([&] (Device & d) {
|
||||
if (d.label == label) d.updated = found = true; });
|
||||
|
||||
if (!found)
|
||||
new (heap) Device(*this, label);
|
||||
});
|
||||
} catch(...) {
|
||||
Genode::error("Error parsing USB devices report");
|
||||
};
|
||||
|
||||
devices.for_each([&] (Device & d) {
|
||||
if (!d.updated) destroy(heap, &d); });
|
||||
}
|
||||
|
||||
|
||||
void Driver::input_callback(Input_event type, unsigned code,
|
||||
int ax, int ay, int rx, int ry)
|
||||
{
|
||||
using namespace Input;
|
||||
|
||||
auto submit = [&] (Event const &ev) { driver->session.submit(ev); };
|
||||
|
||||
switch (type) {
|
||||
case EVENT_TYPE_PRESS: submit(Press{Keycode(code)}); break;
|
||||
case EVENT_TYPE_RELEASE: submit(Release{Keycode(code)}); break;
|
||||
case EVENT_TYPE_MOTION:
|
||||
if (rx == 0 && ry == 0)
|
||||
submit(Absolute_motion{ax, ay});
|
||||
else
|
||||
submit(Relative_motion{rx, ry});
|
||||
break;
|
||||
case EVENT_TYPE_WHEEL: submit(Wheel{rx, ry}); break;
|
||||
case EVENT_TYPE_TOUCH:
|
||||
{
|
||||
Touch_id const id { (int)code };
|
||||
|
||||
if (rx == -1 && ry == -1)
|
||||
submit(Touch_release{id});
|
||||
else
|
||||
submit(Touch{id, (float)ax, (float)ay});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Driver::Driver(Genode::Env &env) : env(env)
|
||||
{
|
||||
Genode::log("--- USB HID input driver ---");
|
||||
|
||||
Lx_kit::construct_env(env);
|
||||
Lx::scheduler(&env);
|
||||
Lx::malloc_init(env, heap);
|
||||
Lx::timer(&env, &ep, &heap, &jiffies);
|
||||
|
||||
main_task.construct(env.ep(), main_task_entry, reinterpret_cast<void*>(this),
|
||||
"main", Lx::Task::PRIORITY_0, Lx::scheduler());
|
||||
|
||||
/* give all task a first kick before returning */
|
||||
Lx::scheduler().schedule();
|
||||
}
|
||||
|
||||
|
||||
void Component::construct(Genode::Env &env)
|
||||
{
|
||||
env.exec_static_constructors();
|
||||
static Driver driver(env);
|
||||
}
|
34
repos/dde_linux/src/drivers/usb_hid/target.mk
Normal file
34
repos/dde_linux/src/drivers/usb_hid/target.mk
Normal file
@ -0,0 +1,34 @@
|
||||
TARGET := usb_hid_drv
|
||||
SRC_C := dummies.c
|
||||
SRC_CC := main.cc lx_emul.cc evdev.cc
|
||||
SRC_CC += printf.cc timer.cc scheduler.cc malloc.cc env.cc work.cc
|
||||
|
||||
LIBS := base usb_hid_include lx_kit_setjmp
|
||||
|
||||
USB_CONTRIB_DIR := $(call select_from_ports,dde_linux)/src/drivers/usb_hid
|
||||
|
||||
INC_DIR += $(PRG_DIR)
|
||||
INC_DIR += $(REP_DIR)/src/include
|
||||
|
||||
SRC_C += drivers/hid/hid-cherry.c
|
||||
SRC_C += drivers/hid/hid-core.c
|
||||
SRC_C += drivers/hid/hid-generic.c
|
||||
SRC_C += drivers/hid/hid-input.c
|
||||
SRC_C += drivers/hid/hid-microsoft.c
|
||||
SRC_C += drivers/hid/hid-multitouch.c
|
||||
SRC_C += drivers/hid/hid-quirks.c
|
||||
SRC_C += drivers/hid/wacom_sys.c
|
||||
SRC_C += drivers/hid/wacom_wac.c
|
||||
SRC_C += drivers/hid/usbhid/hid-core.c
|
||||
SRC_C += drivers/input/evdev.c
|
||||
SRC_C += drivers/input/input-mt.c
|
||||
SRC_C += drivers/input/input.c
|
||||
|
||||
CC_C_OPT += -Wno-unused-but-set-variable -Wno-pointer-sign \
|
||||
-Wno-incompatible-pointer-types -Wno-unused-variable \
|
||||
-Wno-unused-function -Wno-uninitialized -Wno-maybe-uninitialized
|
||||
|
||||
CC_CXX_WARN_STRICT =
|
||||
|
||||
vpath %.c $(USB_CONTRIB_DIR)
|
||||
vpath %.cc $(REP_DIR)/src/lx_kit
|
72
repos/dde_linux/src/include/lx_emul/impl/usb.h
Normal file
72
repos/dde_linux/src/include/lx_emul/impl/usb.h
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* \brief Implementation of linux/usb.h
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2018-08-25
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2018 Genode Labs GmbH
|
||||
*
|
||||
* This file is distributed under the terms of the GNU General Public License
|
||||
* version 2.
|
||||
*/
|
||||
|
||||
/* Linux kit includes */
|
||||
#include <lx_kit/malloc.h>
|
||||
#include <lx_kit/usb.h>
|
||||
|
||||
int usb_control_msg(struct usb_device *dev, unsigned int pipe,
|
||||
__u8 request, __u8 requesttype, __u16 value,
|
||||
__u16 index, void *data, __u16 size, int timeout)
|
||||
{
|
||||
usb_ctrlrequest *dr = (usb_ctrlrequest*)
|
||||
kmalloc(sizeof(usb_ctrlrequest), GFP_KERNEL);
|
||||
if (!dr) return -ENOMEM;
|
||||
|
||||
dr->bRequestType = requesttype;
|
||||
dr->bRequest = request;
|
||||
dr->wValue = cpu_to_le16(value);
|
||||
dr->wIndex = cpu_to_le16(index);
|
||||
dr->wLength = cpu_to_le16(size);
|
||||
|
||||
urb * u = (urb*) usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!u) return -ENOMEM;
|
||||
|
||||
usb_fill_control_urb(u, dev, pipe, (unsigned char *)dr, data,
|
||||
size, nullptr, nullptr);
|
||||
|
||||
Sync_ctrl_urb * scu = new (Lx::Malloc::mem())
|
||||
Sync_ctrl_urb(*(Usb::Connection*)(dev->bus->controller), *u);
|
||||
scu->send(timeout);
|
||||
int ret = u->actual_length;
|
||||
usb_free_urb(u);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)
|
||||
{
|
||||
struct urb *urb = (struct urb*)
|
||||
kmalloc(sizeof(struct urb) +
|
||||
iso_packets * sizeof(struct usb_iso_packet_descriptor),
|
||||
GFP_KERNEL);
|
||||
if (!urb) return NULL;
|
||||
Genode::memset(urb, 0, sizeof(*urb));
|
||||
INIT_LIST_HEAD(&urb->anchor_list);
|
||||
return urb;
|
||||
}
|
||||
|
||||
|
||||
int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
|
||||
{
|
||||
Urb * u = new (Lx::Malloc::mem())
|
||||
Urb(*(Usb::Connection*)(urb->dev->bus->controller), *urb);
|
||||
u->send();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void usb_free_urb(struct urb *urb)
|
||||
{
|
||||
kfree(urb);
|
||||
}
|
133
repos/dde_linux/src/include/lx_kit/usb.h
Normal file
133
repos/dde_linux/src/include/lx_kit/usb.h
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* \brief USB URB implementation
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2018-06-13
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2018 Genode Labs GmbH
|
||||
*
|
||||
* This file is distributed under the terms of the GNU General Public License
|
||||
* version 2.
|
||||
*/
|
||||
|
||||
#ifndef _LX_KIT__USB_H_
|
||||
#define _LX_KIT__USB_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <usb_session/client.h>
|
||||
#include <util/string.h>
|
||||
|
||||
|
||||
class Urb : public Usb::Completion
|
||||
{
|
||||
protected:
|
||||
|
||||
Usb::Session_client & _usb;
|
||||
urb & _urb;
|
||||
Usb::Packet_descriptor _packet {
|
||||
_usb.source()->alloc_packet(_urb.transfer_buffer_length) };
|
||||
|
||||
public:
|
||||
|
||||
Urb(Usb::Session_client &usb, urb & urb) : _usb(usb), _urb(urb)
|
||||
{
|
||||
_packet.completion = this;
|
||||
|
||||
switch(usb_pipetype(_urb.pipe)) {
|
||||
case PIPE_INTERRUPT:
|
||||
{
|
||||
struct usb_host_endpoint *ep =
|
||||
usb_pipe_endpoint(_urb.dev, _urb.pipe);
|
||||
_packet.type = Usb::Packet_descriptor::IRQ;
|
||||
_packet.transfer.polling_interval = _urb.interval;
|
||||
_packet.transfer.ep = ep->desc.bEndpointAddress;
|
||||
return;
|
||||
}
|
||||
|
||||
case PIPE_CONTROL:
|
||||
{
|
||||
usb_ctrlrequest * ctrl = (usb_ctrlrequest *)
|
||||
_urb.setup_packet;
|
||||
_packet.type = Usb::Packet_descriptor::CTRL;
|
||||
_packet.control.request = ctrl->bRequest;
|
||||
_packet.control.request_type = ctrl->bRequestType;
|
||||
_packet.control.value = ctrl->wValue;
|
||||
_packet.control.index = ctrl->wIndex;
|
||||
|
||||
if (!(ctrl->bRequestType & USB_DIR_IN))
|
||||
Genode::memcpy(_usb.source()->packet_content(_packet),
|
||||
_urb.transfer_buffer, _urb.transfer_buffer_length);
|
||||
return;
|
||||
}
|
||||
|
||||
case PIPE_BULK:
|
||||
{
|
||||
struct usb_host_endpoint *ep =
|
||||
usb_pipe_endpoint(_urb.dev, _urb.pipe);
|
||||
_packet.type = Usb::Packet_descriptor::BULK;
|
||||
_packet.transfer.ep = ep->desc.bEndpointAddress;
|
||||
|
||||
if (usb_pipeout(_urb.pipe))
|
||||
Genode::memcpy(_usb.source()->packet_content(_packet),
|
||||
_urb.transfer_buffer, _urb.transfer_buffer_length);
|
||||
return;
|
||||
}
|
||||
|
||||
default:
|
||||
Genode::error("unknown URB requested");
|
||||
};
|
||||
}
|
||||
|
||||
void send()
|
||||
{
|
||||
_usb.source()->submit_packet(_packet);
|
||||
}
|
||||
|
||||
void complete(Usb::Packet_descriptor & packet) override
|
||||
{
|
||||
if (packet.succeded) {
|
||||
bool ctrl = (usb_pipetype(_urb.pipe) == PIPE_CONTROL);
|
||||
_urb.actual_length = ctrl ? packet.control.actual_size
|
||||
: packet.transfer.actual_size;
|
||||
|
||||
if (_urb.actual_length && _urb.transfer_buffer &&
|
||||
(_urb.transfer_buffer_length >= _urb.actual_length))
|
||||
Genode::memcpy(_urb.transfer_buffer,
|
||||
_usb.source()->packet_content(packet),
|
||||
_urb.actual_length);
|
||||
}
|
||||
|
||||
if (_urb.complete) _urb.complete(&_urb);
|
||||
kfree(_packet.completion);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Sync_ctrl_urb : public Urb
|
||||
{
|
||||
private:
|
||||
|
||||
completion _comp;
|
||||
|
||||
public:
|
||||
|
||||
Sync_ctrl_urb(Usb::Session_client & usb, urb & urb) : Urb(usb, urb) {
|
||||
init_completion(&_comp); }
|
||||
|
||||
void complete(Usb::Packet_descriptor &p) override
|
||||
{
|
||||
Urb::complete(p);
|
||||
::complete(&_comp);
|
||||
}
|
||||
|
||||
void send(int timeout)
|
||||
{
|
||||
_packet.completion = this;
|
||||
_packet.control.timeout = timeout;
|
||||
Urb::send();
|
||||
wait_for_completion(&_comp);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _LX_KIT__USB_H_ */
|
43
repos/dde_linux/usb_hid.list
Normal file
43
repos/dde_linux/usb_hid.list
Normal file
@ -0,0 +1,43 @@
|
||||
linux-x.x.x/drivers/hid/hid-cherry.c
|
||||
linux-x.x.x/drivers/hid/hid-core.c
|
||||
linux-x.x.x/drivers/hid/hid-generic.c
|
||||
linux-x.x.x/drivers/hid/hid-ids.h
|
||||
linux-x.x.x/drivers/hid/hid-input.c
|
||||
linux-x.x.x/drivers/hid/hid-microsoft.c
|
||||
linux-x.x.x/drivers/hid/hid-multitouch.c
|
||||
linux-x.x.x/drivers/hid/hid-quirks.c
|
||||
linux-x.x.x/drivers/hid/wacom.h
|
||||
linux-x.x.x/drivers/hid/wacom_sys.c
|
||||
linux-x.x.x/drivers/hid/wacom_wac.c
|
||||
linux-x.x.x/drivers/hid/wacom_wac.h
|
||||
linux-x.x.x/drivers/hid/usbhid/hid-core.c
|
||||
linux-x.x.x/drivers/hid/usbhid/usbhid.h
|
||||
linux-x.x.x/drivers/input/evdev.c
|
||||
linux-x.x.x/drivers/input/input-compat.h
|
||||
linux-x.x.x/drivers/input/input-mt.c
|
||||
linux-x.x.x/drivers/input/input.c
|
||||
linux-x.x.x/include/asm-generic/atomic64.h
|
||||
linux-x.x.x/include/asm-generic/bitops/__ffs.h
|
||||
linux-x.x.x/include/asm-generic/bitops/__fls.h
|
||||
linux-x.x.x/include/asm-generic/bitops/ffs.h
|
||||
linux-x.x.x/include/asm-generic/bitops/fls.h
|
||||
linux-x.x.x/include/asm-generic/bitops/fls64.h
|
||||
linux-x.x.x/include/asm-generic/bitops/non-atomic.h
|
||||
linux-x.x.x/include/linux/hiddev.h
|
||||
linux-x.x.x/include/linux/hid.h
|
||||
linux-x.x.x/include/linux/input.h
|
||||
linux-x.x.x/include/linux/input/mt.h
|
||||
linux-x.x.x/include/linux/kfifo.h
|
||||
linux-x.x.x/include/linux/list.h
|
||||
linux-x.x.x/include/linux/log2.h
|
||||
linux-x.x.x/include/linux/mod_devicetable.h
|
||||
linux-x.x.x/include/linux/power_supply.h
|
||||
linux-x.x.x/include/linux/swab.h
|
||||
linux-x.x.x/include/linux/usb.h
|
||||
linux-x.x.x/include/linux/usb/ch9.h
|
||||
linux-x.x.x/include/uapi/linux/byteorder/little_endian.h
|
||||
linux-x.x.x/include/uapi/linux/hid.h
|
||||
linux-x.x.x/include/uapi/linux/input.h
|
||||
linux-x.x.x/include/uapi/linux/input-event-codes.h
|
||||
linux-x.x.x/include/uapi/linux/swab.h
|
||||
linux-x.x.x/include/uapi/linux/usb/ch9.h
|
Loading…
Reference in New Issue
Block a user