dde_linux: remove usb_hid_legacy

issue #4958
This commit is contained in:
Sebastian Sumpf 2023-06-30 10:05:07 +02:00 committed by Christian Helmuth
parent d5cf77539a
commit cd2910eb2c
14 changed files with 0 additions and 3172 deletions

View File

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

View File

@ -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 =

View File

@ -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" ) > $@

View File

@ -1 +0,0 @@
2023-08-21 1c6c779b2c30b83d3626ce36efbec0b0b45a05d1

View File

@ -1,7 +0,0 @@
base
os
format
event_session
report_session
usb_session
timer_session

View File

@ -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"/>
!...

View File

@ -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_ */

View File

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

View File

@ -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> &registry, 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); }

View File

@ -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_ */

View File

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

View File

@ -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_ */

View File

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

View File

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