mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-21 14:37:50 +00:00
parent
d5cf77539a
commit
cd2910eb2c
@ -1,13 +0,0 @@
|
||||
USB_HID_CONTRIB_DIR := $(call select_from_ports,dde_linux)/src/drivers/usb_hid
|
||||
|
||||
include $(call select_from_repositories,lib/import/import-usb_arch_include.mk)
|
||||
|
||||
#
|
||||
# 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
|
@ -1,37 +0,0 @@
|
||||
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_legacy/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 =
|
@ -1,29 +0,0 @@
|
||||
LIB_MK := lib/mk/usb_hid_include.mk \
|
||||
$(foreach SPEC,arm arm_64 x86_32 x86_64,lib/mk/spec/$(SPEC)/lx_kit_setjmp.mk)
|
||||
|
||||
PORT_DIR := $(call port_dir,$(REP_DIR)/ports/dde_linux)
|
||||
|
||||
MIRROR_FROM_REP_DIR := $(LIB_MK) \
|
||||
lib/import/import-usb_hid_include.mk \
|
||||
lib/import/import-usb_arch_include.mk \
|
||||
src/include/legacy src/lib/legacy/lx_kit \
|
||||
src/lib/lx_kit/spec \
|
||||
$(foreach SPEC,arm arm_64 arm_v6 arm_v7 x86 x86_32 x86_64,src/include/spec/$(SPEC)) \
|
||||
$(shell cd $(REP_DIR); find src/drivers/usb_hid_legacy -type f)
|
||||
|
||||
MIRROR_FROM_PORT_DIR := $(shell cd $(PORT_DIR); find src/drivers/usb_hid -type f | grep -v ".git")
|
||||
MIRROR_FROM_PORT_DIR := $(filter-out $(MIRROR_FROM_REP_DIR),$(MIRROR_FROM_PORT_DIR))
|
||||
|
||||
content: $(MIRROR_FROM_REP_DIR) $(MIRROR_FROM_PORT_DIR)
|
||||
|
||||
$(MIRROR_FROM_REP_DIR):
|
||||
$(mirror_from_rep_dir)
|
||||
|
||||
$(MIRROR_FROM_PORT_DIR):
|
||||
mkdir -p $(dir $@)
|
||||
cp $(PORT_DIR)/$@ $@
|
||||
|
||||
content: LICENSE
|
||||
LICENSE:
|
||||
( echo "GNU General Public License version 2, see:"; \
|
||||
echo "https://www.kernel.org/pub/linux/kernel/COPYING" ) > $@
|
@ -1 +0,0 @@
|
||||
2023-08-21 1c6c779b2c30b83d3626ce36efbec0b0b45a05d1
|
@ -1,7 +0,0 @@
|
||||
base
|
||||
os
|
||||
format
|
||||
event_session
|
||||
report_session
|
||||
usb_session
|
||||
timer_session
|
@ -1,48 +0,0 @@
|
||||
USB HID driver
|
||||
##############
|
||||
|
||||
Supports keyboard and mouse connected via USB. It connects to one or multiple
|
||||
USB sessions and reports input events to an event session. A run script can be
|
||||
found under 'run/usb_hid.run'.
|
||||
|
||||
Configuration snippet:
|
||||
|
||||
!<start name="usb_hid_drv">
|
||||
! <resource name="RAM" quantum="10M"/>
|
||||
! <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 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"/>
|
||||
!...
|
@ -1,145 +0,0 @@
|
||||
/*
|
||||
* \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 <usb_session/connection.h>
|
||||
#include <event_session/connection.h>
|
||||
#include <legacy/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;
|
||||
bool handling_signal { false };
|
||||
|
||||
/*
|
||||
* If the task is currently executing and the signal handler
|
||||
* is called again via 'block_and_schedule()', we need to
|
||||
* keep this information, so the task does not block at the
|
||||
* end when a new signal already occurred.
|
||||
*
|
||||
* Initialized as true for the initial run of the task.
|
||||
*/
|
||||
bool _signal_pending { true };
|
||||
|
||||
void handle_signal()
|
||||
{
|
||||
_signal_pending = true;
|
||||
task.unblock();
|
||||
handling_signal = true;
|
||||
Lx::scheduler().schedule();
|
||||
handling_signal = false;
|
||||
}
|
||||
|
||||
bool signal_pending()
|
||||
{
|
||||
bool ret = _signal_pending;
|
||||
_signal_pending = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
/*
|
||||
* Dedicated allocator per device to notice dangling
|
||||
* allocations on device destruction.
|
||||
*/
|
||||
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 probe_interface(usb_interface *, usb_device_id *);
|
||||
void remove_interface(usb_interface *);
|
||||
bool deinit();
|
||||
};
|
||||
|
||||
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() };
|
||||
Event::Connection event { env };
|
||||
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_ */
|
@ -1,647 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp)
|
||||
{
|
||||
TRACE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void up(struct semaphore *sem)
|
||||
{
|
||||
TRACE;
|
||||
}
|
||||
|
||||
bool usb_device_is_owned(struct usb_device *udev)
|
||||
{
|
||||
TRACE;
|
||||
return false;
|
||||
}
|
@ -1,498 +0,0 @@
|
||||
/*
|
||||
* \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 <legacy/lx_kit/env.h>
|
||||
#include <legacy/lx_kit/scheduler.h>
|
||||
|
||||
/* local */
|
||||
#include "led_state.h"
|
||||
|
||||
/* Linux includes */
|
||||
#include <driver.h>
|
||||
#include <lx_emul.h>
|
||||
#include <legacy/lx_emul/extern_c_begin.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/mt.h>
|
||||
#include <linux/usb.h>
|
||||
#include <legacy/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)
|
||||
{
|
||||
_led->wait_for_registry();
|
||||
|
||||
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); }
|
@ -1,66 +0,0 @@
|
||||
/*
|
||||
* \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_ */
|
@ -1,671 +0,0 @@
|
||||
|
||||
#include <base/env.h>
|
||||
#include <usb_session/client.h>
|
||||
|
||||
#include <driver.h>
|
||||
#include <lx_emul.h>
|
||||
|
||||
#include <legacy/lx_emul/extern_c_begin.h>
|
||||
#include <linux/usb.h>
|
||||
#include <legacy/lx_emul/extern_c_end.h>
|
||||
|
||||
#define TRACE do { ; } while (0)
|
||||
|
||||
#include <legacy/lx_emul/impl/kernel.h>
|
||||
#include <legacy/lx_emul/impl/delay.h>
|
||||
#include <legacy/lx_emul/impl/work.h>
|
||||
#include <legacy/lx_emul/impl/spinlock.h>
|
||||
#include <legacy/lx_emul/impl/mutex.h>
|
||||
#include <legacy/lx_emul/impl/sched.h>
|
||||
#include <legacy/lx_emul/impl/timer.h>
|
||||
#include <legacy/lx_emul/impl/completion.h>
|
||||
#include <legacy/lx_emul/impl/wait.h>
|
||||
#include <legacy/lx_emul/impl/usb.h>
|
||||
|
||||
#include <legacy/lx_kit/backend_alloc.h>
|
||||
|
||||
extern "C" int usb_match_device(struct usb_device *dev,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
|
||||
id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
|
||||
return 0;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
|
||||
id->idProduct != le16_to_cpu(dev->descriptor.idProduct))
|
||||
return 0;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
|
||||
(id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice)))
|
||||
return 0;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
|
||||
(id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice)))
|
||||
return 0;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
|
||||
(id->bDeviceClass != dev->descriptor.bDeviceClass))
|
||||
return 0;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
|
||||
(id->bDeviceSubClass != dev->descriptor.bDeviceSubClass))
|
||||
return 0;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
|
||||
(id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
extern "C" int usb_match_one_id_intf(struct usb_device *dev,
|
||||
struct usb_host_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
if (dev->descriptor.bDeviceClass == USB_CLASS_VENDOR_SPEC &&
|
||||
!(id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
|
||||
(id->match_flags & (USB_DEVICE_ID_MATCH_INT_CLASS |
|
||||
USB_DEVICE_ID_MATCH_INT_SUBCLASS |
|
||||
USB_DEVICE_ID_MATCH_INT_PROTOCOL |
|
||||
USB_DEVICE_ID_MATCH_INT_NUMBER)))
|
||||
return 0;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
|
||||
(id->bInterfaceClass != intf->desc.bInterfaceClass))
|
||||
return 0;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) &&
|
||||
(id->bInterfaceSubClass != intf->desc.bInterfaceSubClass))
|
||||
return 0;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) &&
|
||||
(id->bInterfaceProtocol != intf->desc.bInterfaceProtocol))
|
||||
return 0;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_NUMBER) &&
|
||||
(id->bInterfaceNumber != intf->desc.bInterfaceNumber))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
/*
|
||||
* Don't try if buses don't match, since drivers often use 'container_of'
|
||||
* which might cast the device to non-matching type
|
||||
*/
|
||||
if (dev_drv.bus != dev->bus)
|
||||
return false;
|
||||
|
||||
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 cache)
|
||||
{
|
||||
return Lx_kit::env().env().ram().alloc(size, cache);
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
return 1;
|
||||
|
||||
Lx_driver * driver = (Lx_driver *)kzalloc(sizeof(Lx_driver), GFP_KERNEL);
|
||||
|
||||
Genode::construct_at<Lx_driver>(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);
|
||||
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)
|
||||
{
|
||||
return kzalloc(size, 0);
|
||||
}
|
||||
|
||||
|
||||
void vfree(void *addr)
|
||||
{
|
||||
if (!addr) return;
|
||||
kfree(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 put_device(struct device *dev)
|
||||
{
|
||||
if (dev->ref) {
|
||||
dev->ref--;
|
||||
return;
|
||||
}
|
||||
|
||||
if (dev->release)
|
||||
dev->release(dev);
|
||||
else if (dev->type && dev->type->release)
|
||||
dev->type->release(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(addr);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
int usb_get_descriptor(struct usb_device *dev, unsigned char type,
|
||||
unsigned char index, void *buf, int size)
|
||||
{
|
||||
int i;
|
||||
int result;
|
||||
|
||||
memset(buf, 0, size);
|
||||
|
||||
for (i = 0; i < 3; ++i) {
|
||||
/* retry on length 0 or error; some devices are flakey */
|
||||
result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
|
||||
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
|
||||
(type << 8) + index, 0, buf, size,
|
||||
USB_CTRL_GET_TIMEOUT);
|
||||
if (result <= 0 && result != -ETIMEDOUT)
|
||||
continue;
|
||||
if (result > 1 && ((u8 *)buf)[1] != type) {
|
||||
result = -ENODATA;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev,
|
||||
struct usb_host_config *config,
|
||||
u8 inum)
|
||||
{
|
||||
struct usb_interface_assoc_descriptor *retval = NULL;
|
||||
struct usb_interface_assoc_descriptor *intf_assoc;
|
||||
int first_intf;
|
||||
int last_intf;
|
||||
int i;
|
||||
|
||||
for (i = 0; (i < USB_MAXIADS && config->intf_assoc[i]); i++) {
|
||||
intf_assoc = config->intf_assoc[i];
|
||||
if (intf_assoc->bInterfaceCount == 0)
|
||||
continue;
|
||||
|
||||
first_intf = intf_assoc->bFirstInterface;
|
||||
last_intf = first_intf + (intf_assoc->bInterfaceCount - 1);
|
||||
if (inum >= first_intf && inum <= last_intf) {
|
||||
if (!retval)
|
||||
retval = intf_assoc;
|
||||
else
|
||||
dev_err(&dev->dev, "Interface #%d referenced"
|
||||
" by multiple IADs\n", inum);
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
struct usb_host_interface *usb_altnum_to_altsetting(const struct usb_interface *intf,
|
||||
unsigned int altnum)
|
||||
{
|
||||
for (unsigned i = 0; i < intf->num_altsetting; i++) {
|
||||
if (intf->altsetting[i].desc.bAlternateSetting == altnum)
|
||||
return &intf->altsetting[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int usb_set_configuration(struct usb_device *dev, int configuration)
|
||||
{
|
||||
int i, ret;
|
||||
struct usb_host_config *cp = NULL;
|
||||
struct usb_interface **new_interfaces = NULL;
|
||||
int n, nintf;
|
||||
|
||||
if (dev->authorized == 0 || configuration == -1)
|
||||
configuration = 0;
|
||||
else {
|
||||
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
|
||||
if (dev->config[i].desc.bConfigurationValue ==
|
||||
configuration) {
|
||||
cp = &dev->config[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((!cp && configuration != 0))
|
||||
return -EINVAL;
|
||||
|
||||
/* The USB spec says configuration 0 means unconfigured.
|
||||
* But if a device includes a configuration numbered 0,
|
||||
* we will accept it as a correctly configured state.
|
||||
* Use -1 if you really want to unconfigure the device.
|
||||
*/
|
||||
if (cp && configuration == 0)
|
||||
dev_warn(&dev->dev, "config 0 descriptor??\n");
|
||||
|
||||
/* Allocate memory for new interfaces before doing anything else,
|
||||
* so that if we run out then nothing will have changed. */
|
||||
n = nintf = 0;
|
||||
if (cp) {
|
||||
nintf = cp->desc.bNumInterfaces;
|
||||
new_interfaces = (struct usb_interface **)
|
||||
kmalloc(nintf * sizeof(*new_interfaces), GFP_KERNEL);
|
||||
if (!new_interfaces)
|
||||
return -ENOMEM;
|
||||
|
||||
for (; n < nintf; ++n) {
|
||||
new_interfaces[n] = (struct usb_interface*)
|
||||
kzalloc( sizeof(struct usb_interface), GFP_KERNEL);
|
||||
if (!new_interfaces[n]) {
|
||||
ret = -ENOMEM;
|
||||
while (--n >= 0)
|
||||
kfree(new_interfaces[n]);
|
||||
kfree(new_interfaces);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the new interface structures and the
|
||||
* hc/hcd/usbcore interface/endpoint state.
|
||||
*/
|
||||
for (i = 0; i < nintf; ++i) {
|
||||
struct usb_interface_cache *intfc;
|
||||
struct usb_interface *intf;
|
||||
struct usb_host_interface *alt;
|
||||
u8 ifnum;
|
||||
|
||||
cp->interface[i] = intf = new_interfaces[i];
|
||||
intfc = cp->intf_cache[i];
|
||||
intf->altsetting = intfc->altsetting;
|
||||
intf->num_altsetting = intfc->num_altsetting;
|
||||
intf->authorized = 1; //FIXME
|
||||
|
||||
alt = usb_altnum_to_altsetting(intf, 0);
|
||||
|
||||
/* No altsetting 0? We'll assume the first altsetting.
|
||||
* We could use a GetInterface call, but if a device is
|
||||
* so non-compliant that it doesn't have altsetting 0
|
||||
* then I wouldn't trust its reply anyway.
|
||||
*/
|
||||
if (!alt)
|
||||
alt = &intf->altsetting[0];
|
||||
|
||||
ifnum = alt->desc.bInterfaceNumber;
|
||||
intf->intf_assoc = find_iad(dev, cp, ifnum);
|
||||
intf->cur_altsetting = alt;
|
||||
intf->dev.parent = &dev->dev;
|
||||
intf->dev.driver = NULL;
|
||||
intf->dev.bus = (bus_type*) 0xdeadbeef /*&usb_bus_type*/;
|
||||
intf->minor = -1;
|
||||
device_initialize(&intf->dev);
|
||||
dev_set_name(&intf->dev, "%d-%s:%d.%d", dev->bus->busnum,
|
||||
dev->devpath, configuration, ifnum);
|
||||
}
|
||||
kfree(new_interfaces);
|
||||
|
||||
ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
|
||||
USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
|
||||
NULL, 0, USB_CTRL_SET_TIMEOUT);
|
||||
if (ret < 0 && cp) {
|
||||
for (i = 0; i < nintf; ++i) {
|
||||
put_device(&cp->interface[i]->dev);
|
||||
cp->interface[i] = NULL;
|
||||
}
|
||||
cp = NULL;
|
||||
}
|
||||
|
||||
dev->actconfig = cp;
|
||||
|
||||
if (!cp) {
|
||||
dev->state = USB_STATE_ADDRESS;
|
||||
return ret;
|
||||
}
|
||||
dev->state = USB_STATE_CONFIGURED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Genode::Allocator &heap()
|
||||
{
|
||||
static Genode::Heap heap(Lx_kit::env().env().ram(), Lx_kit::env().env().rm());
|
||||
return heap;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
void *kmalloc(size_t size, gfp_t flags)
|
||||
{
|
||||
try {
|
||||
void * const addr = heap().alloc(size);
|
||||
|
||||
if (!addr)
|
||||
return 0;
|
||||
|
||||
if ((Genode::addr_t)addr & 0x3)
|
||||
Genode::error("unaligned kmalloc ", (Genode::addr_t)addr);
|
||||
|
||||
if (flags & __GFP_ZERO)
|
||||
memset(addr, 0, size);
|
||||
|
||||
return addr;
|
||||
} catch (...) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
void kfree(const void *p)
|
||||
{
|
||||
if (!p) return;
|
||||
|
||||
heap().free((void *)p, 0);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
void *kzalloc(size_t size, gfp_t flags)
|
||||
{
|
||||
return kmalloc(size, flags | __GFP_ZERO);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
void *kcalloc(size_t n, size_t size, gfp_t flags)
|
||||
{
|
||||
if (size != 0 && n > (~0UL / size))
|
||||
return 0;
|
||||
|
||||
return kzalloc(n * size, flags);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
void *kmemdup(const void *src, size_t size, gfp_t flags)
|
||||
{
|
||||
void *addr = kmalloc(size, flags);
|
||||
|
||||
if (addr)
|
||||
memcpy(addr, src, size);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
/******************
|
||||
** linux/kref.h **
|
||||
******************/
|
||||
|
||||
void kref_init(struct kref *kref)
|
||||
{
|
||||
atomic_set(&kref->refcount, 1);
|
||||
}
|
||||
|
||||
|
||||
void kref_get(struct kref *kref)
|
||||
{
|
||||
atomic_inc(&kref->refcount);
|
||||
}
|
||||
|
||||
|
||||
int kref_put(struct kref *kref, void (*release) (struct kref *kref))
|
||||
{
|
||||
if(!atomic_dec_return(&kref->refcount)) {
|
||||
release(kref);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,642 +0,0 @@
|
||||
/*
|
||||
* \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 <legacy/lx_emul/extern_c_begin.h>
|
||||
|
||||
#include <legacy/lx_emul/compiler.h>
|
||||
#include <legacy/lx_emul/printf.h>
|
||||
#include <legacy/lx_emul/types.h>
|
||||
#include <legacy/lx_emul/kernel.h>
|
||||
|
||||
enum { HZ = 100UL };
|
||||
|
||||
#include <legacy/lx_emul/jiffies.h>
|
||||
#include <legacy/lx_emul/time.h>
|
||||
#include <legacy/lx_emul/bitops.h>
|
||||
|
||||
typedef int clockid_t;
|
||||
|
||||
#include <legacy/lx_emul/timer.h>
|
||||
#include <legacy/lx_emul/spinlock.h>
|
||||
|
||||
#include <legacy/lx_emul/mutex.h>
|
||||
|
||||
LX_MUTEX_INIT_DECLARE(dquirks_lock);
|
||||
LX_MUTEX_INIT_DECLARE(input_mutex);
|
||||
LX_MUTEX_INIT_DECLARE(wacom_udev_list_lock);
|
||||
|
||||
#define dquirks_lock LX_MUTEX(dquirks_lock)
|
||||
#define input_mutex LX_MUTEX(input_mutex)
|
||||
#define wacom_udev_list_lock LX_MUTEX(wacom_udev_list_lock)
|
||||
|
||||
|
||||
typedef __u16 __le16;
|
||||
typedef __u32 __le32;
|
||||
typedef __u64 __le64;
|
||||
typedef __u64 __be64;
|
||||
|
||||
#define DECLARE_BITMAP(name,bits) \
|
||||
unsigned long name[BITS_TO_LONGS(bits)]
|
||||
|
||||
#include <legacy/lx_emul/byteorder.h>
|
||||
#include <legacy/lx_emul/atomic.h>
|
||||
#include <legacy/lx_emul/work.h>
|
||||
#include <legacy/lx_emul/bug.h>
|
||||
#include <legacy/lx_emul/errno.h>
|
||||
#include <legacy/lx_emul/module.h>
|
||||
#include <legacy/lx_emul/gfp.h>
|
||||
|
||||
static inline void barrier() { asm volatile ("": : :"memory"); }
|
||||
|
||||
#define READ_ONCE(x) x
|
||||
|
||||
#include <legacy/lx_emul/list.h>
|
||||
#include <legacy/lx_emul/string.h>
|
||||
#include <legacy/lx_emul/kobject.h>
|
||||
#include <legacy/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;
|
||||
unsigned ref;
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
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_holtek_mouse_driver_init();
|
||||
int module_apple_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);
|
||||
|
||||
struct usb_device;
|
||||
extern int usb_get_configuration(struct usb_device *dev);
|
||||
extern void usb_destroy_configuration(struct usb_device *dev);
|
||||
|
||||
struct usb_hcd { unsigned amd_resume_bug:1; };
|
||||
|
||||
bool usb_device_is_owned(struct usb_device *udev);
|
||||
|
||||
#include <legacy/lx_emul/extern_c_end.h>
|
||||
|
||||
#endif /* _SRC__DRIVERS__USB_HID__LX_EMUL_H_ */
|
@ -1,327 +0,0 @@
|
||||
/*
|
||||
* \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 <driver.h>
|
||||
#include <lx_emul.h>
|
||||
|
||||
#include <legacy/lx_kit/env.h>
|
||||
#include <legacy/lx_kit/scheduler.h>
|
||||
#include <legacy/lx_kit/timer.h>
|
||||
#include <legacy/lx_kit/work.h>
|
||||
|
||||
#include <legacy/lx_emul/extern_c_begin.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/usb.h>
|
||||
#include <legacy/lx_emul/extern_c_end.h>
|
||||
|
||||
extern "C" void usb_detect_interface_quirks(struct usb_device *udev);
|
||||
|
||||
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->bus->bus_name = "usbbus";
|
||||
udev->bus->controller = (device*) (&usb);
|
||||
udev->bus_mA = 900; /* set to maximum USB3.0 */
|
||||
|
||||
Genode::memcpy(&udev->descriptor, &dev_desc, sizeof(usb_device_descriptor));
|
||||
udev->devnum = dev_desc.num;
|
||||
udev->speed = (usb_device_speed) dev_desc.speed;
|
||||
udev->authorized = 1;
|
||||
|
||||
int cfg = usb_get_configuration(udev);
|
||||
if (cfg < 0) {
|
||||
Genode::error("usb_get_configuration returned error ", cfg);
|
||||
return;
|
||||
}
|
||||
|
||||
usb_detect_interface_quirks(udev);
|
||||
cfg = usb_choose_configuration(udev);
|
||||
if (cfg < 0) {
|
||||
Genode::error("usb_choose_configuration returned error ", cfg);
|
||||
return;
|
||||
}
|
||||
|
||||
int ret = usb_set_configuration(udev, cfg);
|
||||
if (ret < 0) {
|
||||
Genode::error("usb_set_configuration returned error ", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < udev->config->desc.bNumInterfaces; i++) {
|
||||
struct usb_interface * iface = udev->config->interface[i];
|
||||
struct usb_host_interface * alt = iface->cur_altsetting;
|
||||
|
||||
if (alt->desc.bInterfaceClass != USB_CLASS_HID)
|
||||
continue;
|
||||
|
||||
for (int j = 0; j < alt->desc.bNumEndpoints; ++j) {
|
||||
|
||||
struct usb_host_endpoint * ep = &alt->endpoint[j];
|
||||
int epnum = usb_endpoint_num(&ep->desc);
|
||||
int is_out = usb_endpoint_dir_out(&ep->desc);
|
||||
if (is_out) udev->ep_out[epnum] = ep;
|
||||
else udev->ep_in[epnum] = ep;
|
||||
}
|
||||
|
||||
struct usb_device_id id;
|
||||
probe_interface(iface, &id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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]);
|
||||
}
|
||||
usb_destroy_configuration(udev);
|
||||
kfree(udev->bus);
|
||||
kfree(udev);
|
||||
udev = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void Driver::Device::state_task_entry(void * arg)
|
||||
{
|
||||
Device & dev = *reinterpret_cast<Device*>(arg);
|
||||
|
||||
for (;;) {
|
||||
while (dev.state_task.signal_pending()) {
|
||||
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.heap),
|
||||
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);
|
||||
|
||||
while (usb.source()->ack_avail()) {
|
||||
Usb::Packet_descriptor p = usb.source()->get_acked_packet();
|
||||
usb.source()->release_packet(p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Driver::Device::deinit()
|
||||
{
|
||||
return !udev && !state_task.handling_signal && !urb_task.handling_signal;
|
||||
}
|
||||
|
||||
|
||||
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_holtek_mouse_driver_init();
|
||||
module_apple_driver_init();
|
||||
module_ms_driver_init();
|
||||
module_mt_driver_init();
|
||||
/* disable wacom driver due to #3997 */
|
||||
// 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", ")");
|
||||
|
||||
for (;;) {
|
||||
while (driver->main_task->signal_pending()) {
|
||||
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);
|
||||
}
|
||||
|
||||
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 && d.deinit())
|
||||
destroy(heap, &d);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void Driver::input_callback(Input_event type, unsigned code,
|
||||
int ax, int ay, int rx, int ry)
|
||||
{
|
||||
auto submit = [&] (Input::Event const &ev)
|
||||
{
|
||||
driver->event.with_batch([&] (Event::Session_client::Batch &batch) {
|
||||
batch.submit(ev); });
|
||||
};
|
||||
|
||||
using namespace Input;
|
||||
|
||||
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 { 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_MUTEX_INIT(dquirks_lock);
|
||||
LX_MUTEX_INIT(input_mutex);
|
||||
LX_MUTEX_INIT(wacom_udev_list_lock);
|
||||
|
||||
Lx::scheduler(&env);
|
||||
Lx::timer(&env, &ep, &heap, &jiffies);
|
||||
Lx::Work::work_queue(&heap);
|
||||
|
||||
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);
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
TARGET := usb_hid_legacy_drv
|
||||
SRC_C := dummies.c
|
||||
SRC_CC := main.cc lx_emul.cc evdev.cc
|
||||
SRC_CC += printf.cc bug.cc timer.cc scheduler.cc env.cc work.cc
|
||||
|
||||
LIBS := base usb_hid_include lx_kit_setjmp format
|
||||
|
||||
USB_CONTRIB_DIR := $(call select_from_ports,dde_linux)/src/drivers/usb_hid
|
||||
|
||||
INC_DIR += $(USB_CONTRIB_DIR)/drivers/usb/core
|
||||
INC_DIR += $(PRG_DIR)
|
||||
INC_DIR += $(REP_DIR)/src/include
|
||||
|
||||
SRC_C += drivers/hid/hid-apple.c
|
||||
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-holtek-mouse.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
|
||||
SRC_C += drivers/usb/core/config.c
|
||||
SRC_C += drivers/usb/core/generic.c
|
||||
SRC_C += drivers/usb/core/quirks.c
|
||||
|
||||
CC_OPT += -D__KERNEL__
|
||||
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/lib/legacy/lx_kit
|
Loading…
Reference in New Issue
Block a user