usb: session renewal & new client API

Replace the USB session API by one that provides a devices ROM only,
which contains information about all USB devices available for this client,
as well as methods to acquire and release a single device.

The acquisition of an USB device returns the capability to a device session
that includes a packet stream buffer to communicate control transfers
in between the client and the USB host controller driver. Moreover,
additional methods to acquire and release an USB interface can be used.

The acquisition of an USB interface returns the capability to an interface
session that includes a packet stream buffer to communicate either
bulk, interrupt, or isochronous transfers in between the client and the
USB host controller driver.

This commit implements the API changes in behalf of the Genode C API's
USB server and client side. Addtionally, it provides Usb::Device,
Usb::Interface, and Usb::Endpoint utilities that can be used by native
C++ clients to use the new API and hide the sophisticated packet stream API.

The adaptations necessary target the following areas:

* lx_emul layer for USB host and client side
* Linux USB host controller driver port for PC
* Linux USB client ports: usb_hid_drv and usb_net_drv, additionally
  reduce the Linux tasks used inside these drivers
* Native usb_block_drv
* black_hole component
* Port of libusb, including smartcard and usb_webcam driver depending on it
* Port of Qemu XHCI model library, including vbox5 & vbox6 depending on it
* Adapt all run-scripts and drivers_interactive recipes to work
  with the new policy rules of the USB host controller driver

Fix genodelabs/genode#5021
This commit is contained in:
Stefan Kalkowski 2023-09-14 10:55:11 +02:00 committed by Christian Helmuth
parent 6e437674f7
commit 7ec08af6d9
98 changed files with 6937 additions and 9053 deletions

View File

@ -115,7 +115,7 @@ install_config {
<start name="usb_hid_drv" caps="180">
<resource name="RAM" quantum="11M"/>
<config use_report="yes" capslock_led="rom" numlock_led="rom" scrlock_led="rom"/>
<config capslock_led="rom" numlock_led="rom" scrlock_led="rom"/>
<route>
<service name="ROM" label="capslock"> <child name="dynamic_rom"/> </service>
<service name="ROM" label="numlock"> <child name="dynamic_rom"/> </service>
@ -192,7 +192,7 @@ set fd [open [run_dir]/genode/usb_host_drv.config w]
puts $fd {
<config bios_handoff="no">
<report devices="yes"/>
<policy label_prefix="usb_hid_drv" class="0x3"/>
<policy label_prefix="usb_hid_drv"> <device class="0x3"/> </policy>
</config>}
close $fd
@ -222,8 +222,7 @@ unify_output {(?n).*0557:2213.*} ""
unify_output {(?n) on usb-usbbus.*$} ""
unify_output {(?n) at usb-usbbus.*\)} ")"
unify_output {(?n)hid-generic.*input:} "hid-generic: input:"
unify_output {(?n)usb-[0-9]-[0-9]} "usb-X-X"
unify_output {(?n)device number [0-9]+} "device number X"
unify_output {(?n)usb-[0-9]-[0-9]: USB disconnect, device number [0-9]} "usb-X-X: USB disconnect, device number X"
unify_output {(?n)input[0-9]} "inputX"
unify_output {(?n) as /devices/.*} ""
unify_output {(?n)^\[init -\> usb_drv.*} ""
@ -238,12 +237,12 @@ compare_output_to {
[init -> usb_hid_drv] usb usb-X-X: USB disconnect, device number X
[init -> usb_hid_drv] Disconnected device: inputX
[init -> usb_hid_drv] Disconnected device: inputX
[init -> usb_hid_drv] input: HID 03eb:204d
[init -> usb_hid_drv] Connected device: inputX (HID 03eb:204d)
[init -> usb_hid_drv] hid-generic: input: USB HID v1.11 Keyboard [HID 03eb:204d]
[init -> usb_hid_drv] input: HID 03eb:204d
[init -> usb_hid_drv] Connected device: inputX (HID 03eb:204d) MOUSE
[init -> usb_hid_drv] hid-generic: input: USB HID v1.11 Mouse [HID 03eb:204d]
[init -> usb_hid_drv] input: Dean Camera LUFA Mouse and Keyboard Demo
[init -> usb_hid_drv] Connected device: inputX (Dean Camera LUFA Mouse and Keyboard Demo)
[init -> usb_hid_drv] hid-generic: input: USB HID v1.11 Keyboard [Dean Camera LUFA Mouse and Keyboard Demo]
[init -> usb_hid_drv] input: Dean Camera LUFA Mouse and Keyboard Demo
[init -> usb_hid_drv] Connected device: inputX (Dean Camera LUFA Mouse and Keyboard Demo) MOUSE
[init -> usb_hid_drv] hid-generic: input: USB HID v1.11 Mouse [Dean Camera LUFA Mouse and Keyboard Demo]
[init -> event_dump] Input event #5 PRESS KEY_X 65534 key count: 1
[init -> event_dump] Input event #6 RELEASE KEY_X key count: 0
[init -> event_dump] Input event #7 REL_MOTION -1+1 key count: 0

View File

@ -70,7 +70,7 @@ install_config {
<start name="usb_hid_drv" caps="180">
<resource name="RAM" quantum="11M"/>
<config use_report="yes" capslock_led="rom" numlock_led="rom" scrlock_led="rom"/>
<config capslock_led="rom" numlock_led="rom" scrlock_led="rom"/>
<route>
<service name="ROM" label="capslock"> <child name="dynamic_rom"/> </service>
<service name="ROM" label="numlock"> <child name="dynamic_rom"/> </service>
@ -127,7 +127,7 @@ set fd [open [run_dir]/genode/usb_host_drv.config w]
puts $fd {
<config bios_handoff="yes">
<report devices="yes"/>
<policy label_prefix="usb_hid_drv" class="0x3"/>
<policy label_prefix="usb_hid_drv"> <device class="0x3"/> </policy>
</config>}
close $fd
@ -136,7 +136,7 @@ build_boot_image [build_artifacts]
append qemu_args " -device nec-usb-xhci,id=xhci -device usb-kbd,bus=xhci.0 -nographic"
# wait for keyboard
run_genode_until {.*USB HID.*Keyboard.*} 60
run_genode_until {.*USB HID v1.11 Keyboard.*} 60
set spawn_id $qemu_spawn_id

View File

@ -16,6 +16,7 @@ import_from_depot [depot_user]/src/[base_src] \
[depot_user]/src/vfs \
[depot_user]/src/vfs_lwip \
[depot_user]/src/init
build { test/lwip/http_srv }
install_config {
@ -111,9 +112,11 @@ install_config {
#
set config {<config bios_handoff="yes">}
append_if [have_board rpi] config {
<policy label_prefix="usb_net_drv" vendor_id="0x0424" product_id="0xec00"/> }
<policy label_prefix="usb_net_drv">
<device vendor_id="0x0424" product_id="0xec00"/> </policy>}
append_if [have_spec x86] config {
<policy label_prefix="usb_net_drv" vendor_id="0x0b95" product_id="0x1790"/> }
<policy label_prefix="usb_net_drv">
<device vendor_id="0x0b95" product_id="0x1790"/> </policy> }
append config {</config>}
set fd [open [run_dir]/genode/usb_host_drv.config w]
puts $fd $config

View File

@ -1,21 +1,9 @@
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_raw.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.
Supports keyboard and mouse connected via USB. It drives one or multiple devices
depending on the provided ones in its USB sessions and reports input events to an
event session. A run script can be found under 'run/usb_hid_raw.run'.
Keyboard LED handling

View File

@ -166,29 +166,6 @@ int __init usb_devio_init(void)
}
#include <linux/usb.h>
int usb_string(struct usb_device * dev,int index,char * buf,size_t size)
{
lx_emul_trace(__func__);
return 0;
}
extern char * usb_cache_string(struct usb_device * udev,int index);
char * usb_cache_string(struct usb_device * udev,int index)
{
lx_emul_trace(__func__);
return NULL;
}
void usb_kill_urb(struct urb * urb)
{
lx_emul_trace(__func__);
}
#include <linux/usb/hcd.h>
struct usb_hcd * usb_get_hcd(struct usb_hcd * hcd)
@ -336,8 +313,53 @@ void usb_remove_sysfs_intf_files(struct usb_interface * intf)
}
extern void usb_disable_interface(struct usb_device * dev,struct usb_interface * intf,bool reset_hardware);
void usb_disable_interface(struct usb_device * dev,struct usb_interface * intf,bool reset_hardware)
const struct attribute_group *usb_interface_groups[] = { NULL };
#include <linux/random.h>
void add_device_randomness(const void * buf,size_t len)
{
lx_emul_trace(__func__);
}
#include <linux/usb/hcd.h>
int usb_hcd_alloc_bandwidth(struct usb_device * udev,struct usb_host_config * new_config,struct usb_host_interface * cur_alt,struct usb_host_interface * new_alt)
{
lx_emul_trace(__func__);
return 0;
}
void usb_hcd_flush_endpoint(struct usb_device *udev,
struct usb_host_endpoint *ep)
{
lx_emul_trace(__func__);
}
void usb_hcd_disable_endpoint(struct usb_device *udev,
struct usb_host_endpoint *ep)
{
lx_emul_trace(__func__);
}
void usb_hcd_reset_endpoint(struct usb_device *udev,
struct usb_host_endpoint *ep)
{
lx_emul_trace(__func__);
}
#if defined(CONFIG_OF)
#include <linux/usb/of.h>
bool usb_of_has_combined_node(struct usb_device * udev)
{
lx_emul_trace(__func__);
return true;
}
#endif

View File

@ -23,36 +23,7 @@
const struct attribute_group input_poller_attribute_group;
pteval_t __default_kernel_pte_mask __read_mostly = ~0;
struct device_type usb_if_device_type = {
.name = "usb_interface"
};
struct usb_driver usbfs_driver = {
.name = "usbfs"
};
const struct attribute_group *usb_device_groups[] = { };
/*
* Taken and ajdusted from linux/drivers/usb/core/message.c If this is required
* by more drivers in the future, we will move it to
* dde_linux/src/lib/virt/shadow/drivers/usb/core/message.c
*/
int usb_clear_halt(struct usb_device *dev, int pipe)
{
int result;
int endp = usb_pipeendpoint(pipe);
if (usb_pipein(pipe))
endp |= USB_DIR_IN;
/* we don't care if it wasn't halted first. in fact some devices
* (like some ibmcam model 1 units) seem to expect hosts to make
* this request for iso endpoints, which can't halt!
*/
result = usb_control_msg(dev, usb_sndctrlpipe(dev, endp),
USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT,
USB_ENDPOINT_HALT, endp, NULL, 0,
USB_CTRL_SET_TIMEOUT);
return result;
}

View File

@ -1,6 +1,7 @@
/*
* \brief Post kernel activity
* \author Sebastian Sumpf
* \author Stefan Kalkowski
* \date 2023-06-29
*/
@ -11,36 +12,20 @@
* version 2.
*/
#include <linux/sched/task.h>
#include <usb_hid.h>
static struct task_struct *main_task = NULL;
struct task_struct *lx_user_new_usb_task(int (*func)(void*), void *args)
{
int pid = kernel_thread(func, args, CLONE_FS | CLONE_FILES);
return find_task_by_pid_ns(pid, NULL);
}
void lx_user_destroy_usb_task(struct task_struct *task)
{
if (task != current) {
printk("%s: task: %px is not current: %px\n", __func__,
task, current);
return;
}
/* unblock main task which initiated destruction */
lx_emul_task_unblock(main_task);
do_exit(0);
}
#include <linux/types.h>
#include <lx_emul/input_leds.h>
#include <lx_emul/usb_client.h>
#include <lx_user/init.h>
#include <lx_user/io.h>
void lx_user_init(void)
{
int pid = kernel_thread(lx_user_main_task, &main_task, CLONE_FS | CLONE_FILES);
main_task = find_task_by_pid_ns(pid, NULL);
lx_emul_usb_client_init();
lx_emul_input_leds_init();
}
void lx_user_handle_io(void)
{
lx_emul_usb_client_ticker();
}

View File

@ -1,6 +1,7 @@
/*
* \brief C++ initialization, session, and client handling
* \author Sebastian Sumpf
* \author Stefan Kalkowski
* \date 2023-06-29
*/
@ -19,6 +20,7 @@
#include <lx_emul/init.h>
#include <lx_emul/task.h>
#include <lx_emul/input_leds.h>
#include <lx_user/io.h>
#include <lx_kit/env.h>
#include <genode_c_api/event.h>
@ -30,343 +32,65 @@
using namespace Genode;
struct Task_handler
{
task_struct *task;
Signal_handler<Task_handler> handler;
bool handling_signal { false };
bool running { true };
/*
* 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;
lx_emul_task_unblock(task);
handling_signal = true;
Lx_kit::env().scheduler.execute();
handling_signal = false;
}
bool signal_pending()
{
bool ret = _signal_pending;
_signal_pending = false;
return ret;
}
void block_and_schedule()
{
lx_emul_task_schedule(true);
}
void destroy_task()
{
running = false;
lx_emul_task_unblock(task);
/* will be unblocked by lx_user_destroy_usb_task */
lx_emul_task_schedule(true);
}
Task_handler(Entrypoint & ep, task_struct *task)
: task(task), handler(ep, *this, &Task_handler::handle_signal) { }
/* non-copyable */
Task_handler(const Task_handler&) = delete;
Task_handler & operator=(const Task_handler&) = delete;
};
struct Leds
struct Main
{
Env &env;
Attached_rom_dataspace &config_rom;
task_struct *led_task { lx_user_new_usb_task(led_task_entry, this) };
Task_handler led_task_handler { env.ep(), led_task };
Attached_rom_dataspace config_rom { env, "config" };
Usb::Led_state capslock { env, "capslock" },
numlock { env, "numlock" },
scrlock { env, "scrlock" };
Leds(Env &env, Attached_rom_dataspace &config_rom)
: env(env), config_rom(config_rom) { };
Signal_handler<Main> signal_handler { env.ep(), *this,
&Main::handle_signal };
Signal_handler<Main> usb_rom_handler { env.ep(), *this,
&Main::handle_usb_rom };
Signal_handler<Main> config_handler { env.ep(), *this,
&Main::handle_config };
/* non-copyable */
Leds(const Leds&) = delete;
Leds & operator=(const Leds&) = delete;
Main(Env &env)
:
env(env)
{
Lx_kit::initialize(env, signal_handler);
Genode_c_api::initialize_usb_client(env, Lx_kit::env().heap,
signal_handler, usb_rom_handler);
genode_event_init(genode_env_ptr(env),
genode_allocator_ptr(Lx_kit::env().heap));
config_rom.sigh(config_handler);
handle_config();
lx_emul_start_kernel(nullptr);
}
void handle_signal()
{
lx_user_handle_io();
Lx_kit::env().scheduler.execute();
}
void handle_usb_rom()
{
lx_emul_usb_client_rom_update();
Lx_kit::env().scheduler.execute();
}
void handle_config()
{
config_rom.update();
Genode::Xml_node config =config_rom.xml();
capslock.update(config, led_task_handler.handler);
numlock .update(config, led_task_handler.handler);
scrlock .update(config, led_task_handler.handler);
}
/**********
** Task **
**********/
static int led_task_entry(void *arg)
{
Leds &led = *reinterpret_cast<Leds *>(arg);
while (true) {
led.handle_config();
lx_emul_input_leds_update(led.capslock.enabled(),
led.numlock.enabled(),
led.scrlock.enabled());
led.led_task_handler.block_and_schedule();
}
}
};
struct Device : Registry<Device>::Element
{
using Label = String<64>;
Env &env;
Label label;
/*
* Dedicated allocator per device to notice dangling
* allocations on device destruction.
*/
Allocator_avl alloc { &Lx_kit::env().heap };
task_struct *state_task { lx_user_new_usb_task(state_task_entry, this) };
task_struct *urb_task { lx_user_new_usb_task(urb_task_entry, this) };
Task_handler state_task_handler { env.ep(), state_task };
Task_handler urb_task_handler { env.ep(), urb_task };
genode_usb_client_handle_t usb_handle {
genode_usb_client_create(genode_env_ptr(env),
genode_allocator_ptr(Lx_kit::env().heap),
genode_range_allocator_ptr(alloc),
label.string(),
genode_signal_handler_ptr(state_task_handler.handler)) };
bool updated { true };
bool registered { false };
void *lx_device_handle { nullptr };
Device(Env &env, Registry<Device> &registry, Label label)
:
Registry<Device>::Element(registry, *this),
env(env), label(label)
{
genode_usb_client_sigh_ack_avail(usb_handle,
genode_signal_handler_ptr(urb_task_handler.handler));
}
~Device()
{
genode_usb_client_destroy(usb_handle,
genode_allocator_ptr(Lx_kit::env().heap));
state_task_handler.destroy_task();
urb_task_handler.destroy_task();
}
/* non-copyable */
Device(const Device&) = delete;
Device & operator=(const Device&) = delete;
void register_device()
{
registered = true;
lx_device_handle = lx_emul_usb_client_register_device(usb_handle, label.string());
if (!lx_device_handle) registered = false;
}
void unregister_device()
{
lx_emul_usb_client_unregister_device(usb_handle, lx_device_handle);
registered = false;
}
bool deinit() { return !registered &&
!state_task_handler.handling_signal &&
!urb_task_handler.handling_signal; }
/**********
** Task **
**********/
static int state_task_entry(void *arg)
{
Device &device = *reinterpret_cast<Device *>(arg);
while (device.state_task_handler.running) {
while (device.state_task_handler.signal_pending()) {
if (genode_usb_client_plugged(device.usb_handle) && !device.registered)
device.register_device();
if (!genode_usb_client_plugged(device.usb_handle) && device.registered)
device.unregister_device();
}
device.state_task_handler.block_and_schedule();
}
lx_user_destroy_usb_task(device.state_task_handler.task);
return 0;
}
static int urb_task_entry(void *arg)
{
Device &device = *reinterpret_cast<Device *>(arg);
while (device.urb_task_handler.running) {
if (device.registered)
genode_usb_client_execute_completions(device.usb_handle);
device.urb_task_handler.block_and_schedule();
}
lx_user_destroy_usb_task(device.urb_task_handler.task);
return 0;
}
};
struct Driver
{
Env &env;
Task_handler task_handler;
Heap &heap { Lx_kit::env().heap };
bool use_report { false };
Constructible<Attached_rom_dataspace> report_rom { };
Attached_rom_dataspace config_rom { env, "config" };
Leds leds { env, config_rom };
Registry<Device> devices { };
Driver(Env &env, task_struct *task)
: env(env), task_handler(env.ep(), task)
{
try {
Xml_node config = config_rom.xml();
use_report = config.attribute_value("use_report", false);
} catch(...) { }
if (use_report)
warning("use compatibility mode: ",
"will claim all HID devices from USB report");
}
void scan_report()
{
if (!report_rom.constructed()) {
report_rom.construct(env, "report");
report_rom->sigh(task_handler.handler);
}
report_rom->update();
devices.for_each([&] (Device & d) { d.updated = false; });
try {
Xml_node report_node = report_rom->xml();
report_node.for_each_sub_node([&] (Xml_node & dev_node)
{
unsigned long c = 0;
dev_node.attribute("class").value(c);
if (c != 0x3 /* USB_CLASS_HID */) return;
Device::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(env, devices, label);
});
} catch(...) {
error("Error parsing USB devices report");
throw;
};
devices.for_each([&] (Device & d) {
if (!d.updated && d.deinit()) {
destroy(heap, &d);
}
});
}
};
struct Main
{
Env &env;
Signal_handler<Main> signal_handler { env.ep(), *this, &Main::handle_signal };
Main(Env &env) : env(env) { }
void handle_signal()
{
Genode::Xml_node config = config_rom.xml();
capslock.update(config, config_handler);
numlock .update(config, config_handler);
scrlock .update(config, config_handler);
lx_emul_input_leds_update(capslock.enabled(), numlock.enabled(),
scrlock.enabled());
Lx_kit::env().scheduler.execute();
}
};
void Component::construct(Env & env)
{
static Main main { env };
Lx_kit::initialize(env, main.signal_handler);
env.exec_static_constructors();
genode_event_init(genode_env_ptr(env),
genode_allocator_ptr(Lx_kit::env().heap));
lx_emul_start_kernel(nullptr);
}
/**********
** Task **
**********/
int lx_user_main_task(void *data)
{
task_struct *task = *static_cast<task_struct **>(data);
static Driver driver { Lx_kit::env().env, task };
for (;;) {
while (driver.task_handler.signal_pending()) {
if (!driver.use_report)
static Device dev(driver.env, driver.devices, Device::Label(""));
else
driver.scan_report();
}
driver.task_handler.block_and_schedule();
}
return 0;
}
void Component::construct(Env & env) { static Main main(env); }

View File

@ -1,7 +1,7 @@
/*
* \brief Dummy definitions of Linux Kernel functions
* \author Automatically generated file - do no edit
* \date 2024-02-05
* \date 2024-02-22
*/
#include <lx_emul.h>
@ -89,14 +89,6 @@ int _printk_deferred(const char * fmt,...)
}
#include <linux/random.h>
void add_device_randomness(const void * buf,size_t len)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/kobject.h>
int add_uevent_var(struct kobj_uevent_env * env,const char * format,...)
@ -426,6 +418,14 @@ void led_trigger_event(struct led_trigger * trig,enum led_brightness brightness)
unsigned long lpj_fine;
#include <linux/of.h>
bool of_device_is_available(const struct device_node * device)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/of_device.h>
void of_device_uevent(struct device * dev,struct kobj_uevent_env * env)
@ -487,6 +487,14 @@ int power_supply_powers(struct power_supply * psy,struct device * dev)
}
#include <linux/scatterlist.h>
struct scatterlist * sg_next(struct scatterlist * sg)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/smp.h>
void smp_call_function_many(const struct cpumask * mask,smp_call_func_t func,void * info,bool wait)
@ -532,14 +540,6 @@ struct timerqueue_node * timerqueue_iterate_next(struct timerqueue_node * node)
}
#include <linux/usb.h>
void usb_block_urb(struct urb * urb)
{
lx_emul_trace_and_stop(__func__);
}
extern void usb_devio_cleanup(void);
void usb_devio_cleanup(void)
{
@ -547,13 +547,6 @@ void usb_devio_cleanup(void)
}
extern void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware);
void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb.h>
int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint ** eps,unsigned int num_eps,gfp_t mem_flags)
@ -562,29 +555,6 @@ int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint *
}
extern int usb_get_device_descriptor(struct usb_device * dev,unsigned int size);
int usb_get_device_descriptor(struct usb_device * dev,unsigned int size)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb.h>
int usb_get_status(struct usb_device * dev,int recip,int type,int target,void * data)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb/hcd.h>
int usb_hcd_alloc_bandwidth(struct usb_device * udev,struct usb_host_config * new_config,struct usb_host_interface * cur_alt,struct usb_host_interface * new_alt)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb/hcd.h>
int usb_hcd_find_raw_port_number(struct usb_hcd * hcd,int port1)
@ -607,14 +577,6 @@ void usb_hub_remove_port_device(struct usb_hub * hub,int port1)
}
#include <linux/usb.h>
int usb_interrupt_msg(struct usb_device * usb_dev,unsigned int pipe,void * data,int len,int * actual_length,int timeout)
{
lx_emul_trace_and_stop(__func__);
}
extern void usb_major_cleanup(void);
void usb_major_cleanup(void)
{
@ -630,8 +592,9 @@ struct device_node * usb_of_get_device_node(struct usb_device * hub,int port1)
}
extern int usb_set_isoch_delay(struct usb_device * dev);
int usb_set_isoch_delay(struct usb_device * dev)
#include <linux/usb/of.h>
struct device_node * usb_of_get_interface_node(struct usb_device * udev,u8 config,u8 ifnum)
{
lx_emul_trace_and_stop(__func__);
}
@ -645,22 +608,6 @@ const char * usb_speed_string(enum usb_device_speed speed)
}
#include <linux/usb.h>
int usb_unlink_urb(struct urb * urb)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb.h>
void usb_unpoison_urb(struct urb * urb)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/uuid.h>
const u8 uuid_index[16] = {};

View File

@ -32,8 +32,11 @@ drivers/usb/core/config.c
drivers/usb/core/driver.c
drivers/usb/core/generic.c
drivers/usb/core/hub.c
drivers/usb/core/message.c
drivers/usb/core/quirks.c
drivers/usb/core/urb.c
drivers/usb/core/usb.c
fs/nls/nls_base.c
kernel/kthread.c
kernel/locking/mutex.c
kernel/locking/osq_lock.c

View File

@ -1,7 +1,7 @@
/*
* \brief Dummy definitions of Linux Kernel functions
* \author Automatically generated file - do no edit
* \date 2024-02-05
* \date 2024-02-22
*/
#include <lx_emul.h>
@ -79,14 +79,6 @@ int _printk_deferred(const char * fmt,...)
}
#include <linux/random.h>
void add_device_randomness(const void * buf,size_t len)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/kobject.h>
int add_uevent_var(struct kobj_uevent_env * env,const char * format,...)
@ -328,6 +320,14 @@ void led_trigger_event(struct led_trigger * trig,enum led_brightness brightness)
unsigned long lpj_fine;
#include <linux/of.h>
bool of_device_is_available(const struct device_node * device)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/of_device.h>
void of_device_uevent(struct device * dev,struct kobj_uevent_env * env)
@ -384,6 +384,14 @@ int power_supply_powers(struct power_supply * psy,struct device * dev)
}
#include <linux/scatterlist.h>
struct scatterlist * sg_next(struct scatterlist * sg)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/jump_label.h>
bool static_key_initialized;
@ -413,14 +421,6 @@ struct timerqueue_node * timerqueue_iterate_next(struct timerqueue_node * node)
}
#include <linux/usb.h>
void usb_block_urb(struct urb * urb)
{
lx_emul_trace_and_stop(__func__);
}
extern void usb_devio_cleanup(void);
void usb_devio_cleanup(void)
{
@ -428,13 +428,6 @@ void usb_devio_cleanup(void)
}
extern void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware);
void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb.h>
int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint ** eps,unsigned int num_eps,gfp_t mem_flags)
@ -443,29 +436,6 @@ int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint *
}
extern int usb_get_device_descriptor(struct usb_device * dev,unsigned int size);
int usb_get_device_descriptor(struct usb_device * dev,unsigned int size)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb.h>
int usb_get_status(struct usb_device * dev,int recip,int type,int target,void * data)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb/hcd.h>
int usb_hcd_alloc_bandwidth(struct usb_device * udev,struct usb_host_config * new_config,struct usb_host_interface * cur_alt,struct usb_host_interface * new_alt)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb/hcd.h>
int usb_hcd_find_raw_port_number(struct usb_hcd * hcd,int port1)
@ -488,14 +458,6 @@ void usb_hub_remove_port_device(struct usb_hub * hub,int port1)
}
#include <linux/usb.h>
int usb_interrupt_msg(struct usb_device * usb_dev,unsigned int pipe,void * data,int len,int * actual_length,int timeout)
{
lx_emul_trace_and_stop(__func__);
}
extern void usb_major_cleanup(void);
void usb_major_cleanup(void)
{
@ -511,8 +473,9 @@ struct device_node * usb_of_get_device_node(struct usb_device * hub,int port1)
}
extern int usb_set_isoch_delay(struct usb_device * dev);
int usb_set_isoch_delay(struct usb_device * dev)
#include <linux/usb/of.h>
struct device_node * usb_of_get_interface_node(struct usb_device * udev,u8 config,u8 ifnum)
{
lx_emul_trace_and_stop(__func__);
}
@ -526,22 +489,6 @@ const char * usb_speed_string(enum usb_device_speed speed)
}
#include <linux/usb.h>
int usb_unlink_urb(struct urb * urb)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb.h>
void usb_unpoison_urb(struct urb * urb)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/uuid.h>
const u8 uuid_index[16] = {};

View File

@ -32,8 +32,11 @@ drivers/usb/core/config.c
drivers/usb/core/driver.c
drivers/usb/core/generic.c
drivers/usb/core/hub.c
drivers/usb/core/message.c
drivers/usb/core/quirks.c
drivers/usb/core/urb.c
drivers/usb/core/usb.c
fs/nls/nls_base.c
kernel/kthread.c
kernel/locking/mutex.c
kernel/locking/osq_lock.c

View File

@ -1,7 +1,7 @@
/*
* \brief Dummy definitions of Linux Kernel functions
* \author Automatically generated file - do no edit
* \date 2024-02-05
* \date 2024-02-22
*/
#include <lx_emul.h>
@ -89,14 +89,6 @@ int _printk_deferred(const char * fmt,...)
}
#include <linux/random.h>
void add_device_randomness(const void * buf,size_t len)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/kobject.h>
int add_uevent_var(struct kobj_uevent_env * env,const char * format,...)
@ -391,6 +383,14 @@ void led_trigger_event(struct led_trigger * trig,enum led_brightness brightness)
unsigned long lpj_fine;
#include <linux/of.h>
bool of_device_is_available(const struct device_node * device)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/of_device.h>
void of_device_uevent(struct device * dev,struct kobj_uevent_env * env)
@ -452,6 +452,14 @@ int power_supply_powers(struct power_supply * psy,struct device * dev)
}
#include <linux/scatterlist.h>
struct scatterlist * sg_next(struct scatterlist * sg)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/smp.h>
void smp_call_function_many(const struct cpumask * mask,smp_call_func_t func,void * info,bool wait)
@ -497,14 +505,6 @@ struct timerqueue_node * timerqueue_iterate_next(struct timerqueue_node * node)
}
#include <linux/usb.h>
void usb_block_urb(struct urb * urb)
{
lx_emul_trace_and_stop(__func__);
}
extern void usb_devio_cleanup(void);
void usb_devio_cleanup(void)
{
@ -512,13 +512,6 @@ void usb_devio_cleanup(void)
}
extern void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware);
void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb.h>
int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint ** eps,unsigned int num_eps,gfp_t mem_flags)
@ -527,29 +520,6 @@ int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint *
}
extern int usb_get_device_descriptor(struct usb_device * dev,unsigned int size);
int usb_get_device_descriptor(struct usb_device * dev,unsigned int size)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb.h>
int usb_get_status(struct usb_device * dev,int recip,int type,int target,void * data)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb/hcd.h>
int usb_hcd_alloc_bandwidth(struct usb_device * udev,struct usb_host_config * new_config,struct usb_host_interface * cur_alt,struct usb_host_interface * new_alt)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb/hcd.h>
int usb_hcd_find_raw_port_number(struct usb_hcd * hcd,int port1)
@ -572,14 +542,6 @@ void usb_hub_remove_port_device(struct usb_hub * hub,int port1)
}
#include <linux/usb.h>
int usb_interrupt_msg(struct usb_device * usb_dev,unsigned int pipe,void * data,int len,int * actual_length,int timeout)
{
lx_emul_trace_and_stop(__func__);
}
extern void usb_major_cleanup(void);
void usb_major_cleanup(void)
{
@ -595,8 +557,9 @@ struct device_node * usb_of_get_device_node(struct usb_device * hub,int port1)
}
extern int usb_set_isoch_delay(struct usb_device * dev);
int usb_set_isoch_delay(struct usb_device * dev)
#include <linux/usb/of.h>
struct device_node * usb_of_get_interface_node(struct usb_device * udev,u8 config,u8 ifnum)
{
lx_emul_trace_and_stop(__func__);
}
@ -610,22 +573,6 @@ const char * usb_speed_string(enum usb_device_speed speed)
}
#include <linux/usb.h>
int usb_unlink_urb(struct urb * urb)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb.h>
void usb_unpoison_urb(struct urb * urb)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/uuid.h>
const u8 uuid_index[16] = {};

View File

@ -30,8 +30,11 @@ drivers/usb/core/config.c
drivers/usb/core/driver.c
drivers/usb/core/generic.c
drivers/usb/core/hub.c
drivers/usb/core/message.c
drivers/usb/core/quirks.c
drivers/usb/core/urb.c
drivers/usb/core/usb.c
fs/nls/nls_base.c
kernel/kthread.c
kernel/locking/mutex.c
kernel/locking/osq_lock.c

View File

@ -75,14 +75,6 @@ void ack_bad_irq(unsigned int irq)
}
#include <linux/random.h>
void add_device_randomness(const void * buf,size_t len)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/kobject.h>
int add_uevent_var(struct kobj_uevent_env * env,const char * format,...)
@ -367,6 +359,14 @@ int power_supply_powers(struct power_supply * psy,struct device * dev)
}
#include <linux/scatterlist.h>
struct scatterlist * sg_next(struct scatterlist * sg)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/smp.h>
void smp_call_function_many(const struct cpumask * mask,smp_call_func_t func,void * info,bool wait)
@ -412,14 +412,6 @@ struct timerqueue_node * timerqueue_iterate_next(struct timerqueue_node * node)
}
#include <linux/usb.h>
void usb_block_urb(struct urb * urb)
{
lx_emul_trace_and_stop(__func__);
}
extern void usb_devio_cleanup(void);
void usb_devio_cleanup(void)
{
@ -427,13 +419,6 @@ void usb_devio_cleanup(void)
}
extern void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware);
void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb.h>
int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint ** eps,unsigned int num_eps,gfp_t mem_flags)
@ -442,29 +427,6 @@ int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint *
}
extern int usb_get_device_descriptor(struct usb_device * dev,unsigned int size);
int usb_get_device_descriptor(struct usb_device * dev,unsigned int size)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb.h>
int usb_get_status(struct usb_device * dev,int recip,int type,int target,void * data)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb/hcd.h>
int usb_hcd_alloc_bandwidth(struct usb_device * udev,struct usb_host_config * new_config,struct usb_host_interface * cur_alt,struct usb_host_interface * new_alt)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb/hcd.h>
int usb_hcd_find_raw_port_number(struct usb_hcd * hcd,int port1)
@ -487,14 +449,6 @@ void usb_hub_remove_port_device(struct usb_hub * hub,int port1)
}
#include <linux/usb.h>
int usb_interrupt_msg(struct usb_device * usb_dev,unsigned int pipe,void * data,int len,int * actual_length,int timeout)
{
lx_emul_trace_and_stop(__func__);
}
extern void usb_major_cleanup(void);
void usb_major_cleanup(void)
{
@ -502,13 +456,6 @@ void usb_major_cleanup(void)
}
extern int usb_set_isoch_delay(struct usb_device * dev);
int usb_set_isoch_delay(struct usb_device * dev)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb/ch9.h>
const char * usb_speed_string(enum usb_device_speed speed)
@ -517,22 +464,6 @@ const char * usb_speed_string(enum usb_device_speed speed)
}
#include <linux/usb.h>
int usb_unlink_urb(struct urb * urb)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb.h>
void usb_unpoison_urb(struct urb * urb)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/uuid.h>
const u8 uuid_index[16] = {};

View File

@ -25,8 +25,11 @@ drivers/usb/core/config.c
drivers/usb/core/driver.c
drivers/usb/core/generic.c
drivers/usb/core/hub.c
drivers/usb/core/message.c
drivers/usb/core/quirks.c
drivers/usb/core/urb.c
drivers/usb/core/usb.c
fs/nls/nls_base.c
kernel/kthread.c
kernel/locking/mutex.c
kernel/locking/osq_lock.c

View File

@ -75,14 +75,6 @@ void ack_bad_irq(unsigned int irq)
}
#include <linux/random.h>
void add_device_randomness(const void * buf,size_t len)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/kobject.h>
int add_uevent_var(struct kobj_uevent_env * env,const char * format,...)
@ -335,6 +327,14 @@ int power_supply_powers(struct power_supply * psy,struct device * dev)
}
#include <linux/scatterlist.h>
struct scatterlist * sg_next(struct scatterlist * sg)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/smp.h>
void smp_call_function_many(const struct cpumask * mask,smp_call_func_t func,void * info,bool wait)
@ -380,14 +380,6 @@ struct timerqueue_node * timerqueue_iterate_next(struct timerqueue_node * node)
}
#include <linux/usb.h>
void usb_block_urb(struct urb * urb)
{
lx_emul_trace_and_stop(__func__);
}
extern void usb_devio_cleanup(void);
void usb_devio_cleanup(void)
{
@ -395,13 +387,6 @@ void usb_devio_cleanup(void)
}
extern void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware);
void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb.h>
int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint ** eps,unsigned int num_eps,gfp_t mem_flags)
@ -410,29 +395,6 @@ int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint *
}
extern int usb_get_device_descriptor(struct usb_device * dev,unsigned int size);
int usb_get_device_descriptor(struct usb_device * dev,unsigned int size)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb.h>
int usb_get_status(struct usb_device * dev,int recip,int type,int target,void * data)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb/hcd.h>
int usb_hcd_alloc_bandwidth(struct usb_device * udev,struct usb_host_config * new_config,struct usb_host_interface * cur_alt,struct usb_host_interface * new_alt)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb/hcd.h>
int usb_hcd_find_raw_port_number(struct usb_hcd * hcd,int port1)
@ -455,14 +417,6 @@ void usb_hub_remove_port_device(struct usb_hub * hub,int port1)
}
#include <linux/usb.h>
int usb_interrupt_msg(struct usb_device * usb_dev,unsigned int pipe,void * data,int len,int * actual_length,int timeout)
{
lx_emul_trace_and_stop(__func__);
}
extern void usb_major_cleanup(void);
void usb_major_cleanup(void)
{
@ -470,13 +424,6 @@ void usb_major_cleanup(void)
}
extern int usb_set_isoch_delay(struct usb_device * dev);
int usb_set_isoch_delay(struct usb_device * dev)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb/ch9.h>
const char * usb_speed_string(enum usb_device_speed speed)
@ -485,22 +432,6 @@ const char * usb_speed_string(enum usb_device_speed speed)
}
#include <linux/usb.h>
int usb_unlink_urb(struct urb * urb)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb.h>
void usb_unpoison_urb(struct urb * urb)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/uuid.h>
const u8 uuid_index[16] = {};

View File

@ -25,8 +25,11 @@ drivers/usb/core/config.c
drivers/usb/core/driver.c
drivers/usb/core/generic.c
drivers/usb/core/hub.c
drivers/usb/core/message.c
drivers/usb/core/quirks.c
drivers/usb/core/urb.c
drivers/usb/core/usb.c
fs/nls/nls_base.c
kernel/kthread.c
kernel/locking/mutex.c
kernel/locking/osq_lock.c

View File

@ -8,11 +8,11 @@ SRC_C += dummies.c \
lx_emul.c \
lx_user.c
SRC_C += lx_emul/shadow/drivers/input/evdev.c \
lx_emul/shadow/drivers/input/input-leds.c \
lx_emul/virt/shadow/drivers/usb/core/message.c \
lx_emul/virt/shadow/drivers/usb/core/urb.c \
lx_emul/virt/usb_client.c
SRC_C += lx_emul/shadow/drivers/input/evdev.c
SRC_C += lx_emul/shadow/drivers/input/input-leds.c
SRC_C += lx_emul/virt/shadow/drivers/usb/core/buffer.c
SRC_C += lx_emul/virt/shadow/drivers/usb/core/hcd.c
SRC_C += lx_emul/virt/usb_client.c
SRC_CC = main.cc

View File

@ -18,14 +18,7 @@
extern "C" {
#endif
struct task_struct;
int lx_user_main_task(void *);
struct task_struct *lx_user_new_usb_task(int (*func)(void*), void *args);
void lx_user_destroy_usb_task(struct task_struct*);
void lx_led_state_update(bool capslock, bool numlock, bool scrlock);
void lx_emul_led_state_update(void);
#ifdef __cplusplus
} /* extern "C" */

View File

@ -157,42 +157,6 @@ void usb_hcd_synchronize_unlinks(struct usb_device * udev)
}
#include <linux/usb.h>
struct urb * usb_get_from_anchor(struct usb_anchor * anchor)
{
lx_emul_trace(__func__);
return NULL;
}
extern char * usb_cache_string(struct usb_device * udev,int index);
char * usb_cache_string(struct usb_device * udev,int index)
{
lx_emul_trace(__func__);
return NULL;
}
void usb_kill_urb(struct urb * urb)
{
lx_emul_trace(__func__);
}
int usb_unlink_urb(struct urb * urb)
{
lx_emul_trace(__func__);
return 0;
}
void usb_poison_urb(struct urb * urb)
{
lx_emul_trace(__func__);
}
#include <linux/usb/hcd.h>
struct usb_hcd * usb_get_hcd(struct usb_hcd * hcd)
@ -484,15 +448,51 @@ void usb_remove_ep_devs(struct usb_host_endpoint * endpoint)
}
extern void usb_disable_interface(struct usb_device * dev,struct usb_interface * intf,bool reset_hardware);
void usb_disable_interface(struct usb_device * dev,struct usb_interface * intf,bool reset_hardware)
{
lx_emul_trace(__func__);
}
extern void netdev_unregister_kobject(struct net_device * ndev);
void netdev_unregister_kobject(struct net_device * ndev)
{
lx_emul_trace(__func__);
}
void usb_hcd_flush_endpoint(struct usb_device *udev,
struct usb_host_endpoint *ep)
{
lx_emul_trace(__func__);
}
void usb_hcd_disable_endpoint(struct usb_device *udev,
struct usb_host_endpoint *ep)
{
lx_emul_trace(__func__);
}
void usb_hcd_reset_endpoint(struct usb_device *udev,
struct usb_host_endpoint *ep)
{
lx_emul_trace(__func__);
}
const struct attribute_group *usb_interface_groups[] = { NULL };
#include <linux/usb/hcd.h>
int usb_hcd_alloc_bandwidth(struct usb_device * udev,struct usb_host_config * new_config,struct usb_host_interface * cur_alt,struct usb_host_interface * new_alt)
{
lx_emul_trace(__func__);
return 0;
}
#if defined(CONFIG_OF)
#include <linux/usb/of.h>
bool usb_of_has_combined_node(struct usb_device * udev)
{
lx_emul_trace(__func__);
return true;
}
#endif

View File

@ -17,11 +17,6 @@
pteval_t __default_kernel_pte_mask __read_mostly = ~0;
struct device_type usb_if_device_type = {
.name = "usb_interface"
};
struct usb_driver usbfs_driver = {
.name = "usbfs"
};
@ -147,349 +142,3 @@ int netdev_register_kobject(struct net_device * ndev)
if (use_mac_address) eth_hw_addr_set(ndev, mac_address);
return 0;
}
/*
* core/message.c
*/
#include <linux/nls.h>
#include <linux/usb/quirks.h>
#include <linux/usb/cdc.h>
#include <linux/ctype.h>
int cdc_parse_cdc_header(struct usb_cdc_parsed_header *hdr,
struct usb_interface *intf,
u8 *buffer,
int buflen)
{
/* duplicates are ignored */
struct usb_cdc_union_desc *union_header = NULL;
/* duplicates are not tolerated */
struct usb_cdc_header_desc *header = NULL;
struct usb_cdc_ether_desc *ether = NULL;
struct usb_cdc_mdlm_detail_desc *detail = NULL;
struct usb_cdc_mdlm_desc *desc = NULL;
unsigned int elength;
int cnt = 0;
memset(hdr, 0x00, sizeof(struct usb_cdc_parsed_header));
hdr->phonet_magic_present = false;
while (buflen > 0) {
elength = buffer[0];
if (!elength) {
dev_err(&intf->dev, "skipping garbage byte\n");
elength = 1;
goto next_desc;
}
if ((buflen < elength) || (elength < 3)) {
dev_err(&intf->dev, "invalid descriptor buffer length\n");
break;
}
if (buffer[1] != USB_DT_CS_INTERFACE) {
dev_err(&intf->dev, "skipping garbage\n");
goto next_desc;
}
switch (buffer[2]) {
case USB_CDC_UNION_TYPE: /* we've found it */
if (elength < sizeof(struct usb_cdc_union_desc))
goto next_desc;
if (union_header) {
dev_err(&intf->dev, "More than one union descriptor, skipping ...\n");
goto next_desc;
}
union_header = (struct usb_cdc_union_desc *)buffer;
break;
case USB_CDC_COUNTRY_TYPE:
if (elength < sizeof(struct usb_cdc_country_functional_desc))
goto next_desc;
hdr->usb_cdc_country_functional_desc =
(struct usb_cdc_country_functional_desc *)buffer;
break;
case USB_CDC_HEADER_TYPE:
if (elength != sizeof(struct usb_cdc_header_desc))
goto next_desc;
if (header)
return -EINVAL;
header = (struct usb_cdc_header_desc *)buffer;
break;
case USB_CDC_ACM_TYPE:
if (elength < sizeof(struct usb_cdc_acm_descriptor))
goto next_desc;
hdr->usb_cdc_acm_descriptor =
(struct usb_cdc_acm_descriptor *)buffer;
break;
case USB_CDC_ETHERNET_TYPE:
if (elength != sizeof(struct usb_cdc_ether_desc))
goto next_desc;
if (ether)
return -EINVAL;
ether = (struct usb_cdc_ether_desc *)buffer;
break;
case USB_CDC_CALL_MANAGEMENT_TYPE:
if (elength < sizeof(struct usb_cdc_call_mgmt_descriptor))
goto next_desc;
hdr->usb_cdc_call_mgmt_descriptor =
(struct usb_cdc_call_mgmt_descriptor *)buffer;
break;
case USB_CDC_DMM_TYPE:
if (elength < sizeof(struct usb_cdc_dmm_desc))
goto next_desc;
hdr->usb_cdc_dmm_desc =
(struct usb_cdc_dmm_desc *)buffer;
break;
case USB_CDC_MDLM_TYPE:
if (elength < sizeof(struct usb_cdc_mdlm_desc))
goto next_desc;
if (desc)
return -EINVAL;
desc = (struct usb_cdc_mdlm_desc *)buffer;
break;
case USB_CDC_MDLM_DETAIL_TYPE:
if (elength < sizeof(struct usb_cdc_mdlm_detail_desc))
goto next_desc;
if (detail)
return -EINVAL;
detail = (struct usb_cdc_mdlm_detail_desc *)buffer;
break;
case USB_CDC_NCM_TYPE:
if (elength < sizeof(struct usb_cdc_ncm_desc))
goto next_desc;
hdr->usb_cdc_ncm_desc = (struct usb_cdc_ncm_desc *)buffer;
break;
case USB_CDC_MBIM_TYPE:
if (elength < sizeof(struct usb_cdc_mbim_desc))
goto next_desc;
hdr->usb_cdc_mbim_desc = (struct usb_cdc_mbim_desc *)buffer;
break;
case USB_CDC_MBIM_EXTENDED_TYPE:
if (elength < sizeof(struct usb_cdc_mbim_extended_desc))
break;
hdr->usb_cdc_mbim_extended_desc =
(struct usb_cdc_mbim_extended_desc *)buffer;
break;
case CDC_PHONET_MAGIC_NUMBER:
hdr->phonet_magic_present = true;
break;
default:
/*
* there are LOTS more CDC descriptors that
* could legitimately be found here.
*/
dev_dbg(&intf->dev, "Ignoring descriptor: type %02x, length %ud\n",
buffer[2], elength);
goto next_desc;
}
cnt++;
next_desc:
buflen -= elength;
buffer += elength;
}
hdr->usb_cdc_union_desc = union_header;
hdr->usb_cdc_header_desc = header;
hdr->usb_cdc_mdlm_detail_desc = detail;
hdr->usb_cdc_mdlm_desc = desc;
hdr->usb_cdc_ether_desc = ether;
return cnt;
}
/**
* usb_get_string - gets a string descriptor
* @dev: the device whose string descriptor is being retrieved
* @langid: code for language chosen (from string descriptor zero)
* @index: the number of the descriptor
* @buf: where to put the string
* @size: how big is "buf"?
*
* Context: task context, might sleep.
*
* Retrieves a string, encoded using UTF-16LE (Unicode, 16 bits per character,
* in little-endian byte order).
* The usb_string() function will often be a convenient way to turn
* these strings into kernel-printable form.
*
* Strings may be referenced in device, configuration, interface, or other
* descriptors, and could also be used in vendor-specific ways.
*
* This call is synchronous, and may not be used in an interrupt context.
*
* Return: The number of bytes received on success, or else the status code
* returned by the underlying usb_control_msg() call.
*/
static int usb_get_string(struct usb_device *dev, unsigned short langid,
unsigned char index, void *buf, int size)
{
int i;
int result;
if (size <= 0) /* No point in asking for no data */
return -EINVAL;
for (i = 0; i < 3; ++i) {
/* retry on length 0 or stall; some devices are flakey */
result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
(USB_DT_STRING << 8) + index, langid, buf, size,
USB_CTRL_GET_TIMEOUT);
if (result == 0 || result == -EPIPE)
continue;
if (result > 1 && ((u8 *) buf)[1] != USB_DT_STRING) {
result = -ENODATA;
continue;
}
break;
}
return result;
}
static void usb_try_string_workarounds(unsigned char *buf, int *length)
{
int newlength, oldlength = *length;
for (newlength = 2; newlength + 1 < oldlength; newlength += 2)
if (!isprint(buf[newlength]) || buf[newlength + 1])
break;
if (newlength > 2) {
buf[0] = newlength;
*length = newlength;
}
}
static int usb_string_sub(struct usb_device *dev, unsigned int langid,
unsigned int index, unsigned char *buf)
{
int rc;
/* Try to read the string descriptor by asking for the maximum
* possible number of bytes */
if (dev->quirks & USB_QUIRK_STRING_FETCH_255)
rc = -EIO;
else
rc = usb_get_string(dev, langid, index, buf, 255);
/* If that failed try to read the descriptor length, then
* ask for just that many bytes */
if (rc < 2) {
rc = usb_get_string(dev, langid, index, buf, 2);
if (rc == 2)
rc = usb_get_string(dev, langid, index, buf, buf[0]);
}
if (rc >= 2) {
if (!buf[0] && !buf[1])
usb_try_string_workarounds(buf, &rc);
/* There might be extra junk at the end of the descriptor */
if (buf[0] < rc)
rc = buf[0];
rc = rc - (rc & 1); /* force a multiple of two */
}
if (rc < 2)
rc = (rc < 0 ? rc : -EINVAL);
return rc;
}
static int usb_get_langid(struct usb_device *dev, unsigned char *tbuf)
{
int err;
if (dev->have_langid)
return 0;
if (dev->string_langid < 0)
return -EPIPE;
err = usb_string_sub(dev, 0, 0, tbuf);
/* If the string was reported but is malformed, default to english
* (0x0409) */
if (err == -ENODATA || (err > 0 && err < 4)) {
dev->string_langid = 0x0409;
dev->have_langid = 1;
dev_err(&dev->dev,
"language id specifier not provided by device, defaulting to English\n");
return 0;
}
/* In case of all other errors, we assume the device is not able to
* deal with strings at all. Set string_langid to -1 in order to
* prevent any string to be retrieved from the device */
if (err < 0) {
dev_info(&dev->dev, "string descriptor 0 read error: %d\n",
err);
dev->string_langid = -1;
return -EPIPE;
}
/* always use the first langid listed */
dev->string_langid = tbuf[2] | (tbuf[3] << 8);
dev->have_langid = 1;
dev_dbg(&dev->dev, "default language 0x%04x\n",
dev->string_langid);
return 0;
}
/**
* usb_string - returns UTF-8 version of a string descriptor
* @dev: the device whose string descriptor is being retrieved
* @index: the number of the descriptor
* @buf: where to put the string
* @size: how big is "buf"?
*
* Context: task context, might sleep.
*
* This converts the UTF-16LE encoded strings returned by devices, from
* usb_get_string_descriptor(), to null-terminated UTF-8 encoded ones
* that are more usable in most kernel contexts. Note that this function
* chooses strings in the first language supported by the device.
*
* This call is synchronous, and may not be used in an interrupt context.
*
* Return: length of the string (>= 0) or usb_control_msg status (< 0).
*/
int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
{
unsigned char *tbuf;
int err;
if (dev->state == USB_STATE_SUSPENDED)
return -EHOSTUNREACH;
if (size <= 0 || !buf)
return -EINVAL;
buf[0] = 0;
if (index <= 0 || index >= 256)
return -EINVAL;
tbuf = kmalloc(256, GFP_NOIO);
if (!tbuf)
return -ENOMEM;
err = usb_get_langid(dev, tbuf);
if (err < 0)
goto errout;
err = usb_string_sub(dev, dev->string_langid, index, tbuf);
if (err < 0)
goto errout;
size--; /* leave room for trailing NULL char in output buffer */
err = utf16s_to_utf8s((wchar_t *) &tbuf[2], (err - 2) / 2,
UTF16_LITTLE_ENDIAN, buf, size);
buf[err] = 0;
if (tbuf[1] != USB_DT_STRING)
dev_dbg(&dev->dev,
"wrong descriptor type %02x for string %d (\"%s\")\n",
tbuf[1], index, buf);
errout:
kfree(tbuf);
return err;
}

View File

@ -165,7 +165,7 @@ static genode_uplink_rx_result_t uplink_rx_one_packet(struct genode_uplink_rx_co
}
static int user_task_function(void *arg)
static int network_loop(void *arg)
{
for (;;) {
@ -206,18 +206,23 @@ static int user_task_function(void *arg)
}
struct task_struct *user_task_struct_ptr; /* used by 'Device' for lx_emul_task_unblock */
static struct task_struct *net_task;
void lx_user_init(void)
{
pid_t pid;
lx_user_main_task(NULL);
lx_emul_usb_client_init();
pid = kernel_thread(user_task_function, NULL, CLONE_FS | CLONE_FILES);
pid = kernel_thread(network_loop, NULL, CLONE_FS | CLONE_FILES);
net_task = find_task_by_pid_ns(pid, NULL);
}
user_task_struct_ptr = find_task_by_pid_ns(pid, NULL);
void lx_user_handle_io(void)
{
lx_emul_usb_client_ticker();
if (net_task) lx_emul_task_unblock(net_task);
}
@ -232,8 +237,7 @@ bool force_uplink_destroy = false;
void rtmsg_ifinfo(int type, struct net_device * dev, unsigned int change, gfp_t flags)
{
/* trigger handle_create_uplink / handle_destroy_uplink */
if (user_task_struct_ptr)
lx_emul_task_unblock(user_task_struct_ptr);
if (net_task) lx_emul_task_unblock(net_task);
if (force_uplink_destroy) {
struct genode_uplink *uplink = dev_genode_uplink(dev);

View File

@ -21,7 +21,7 @@
#include <nic_session/nic_session.h>
#include <lx_kit/env.h>
#include <lx_emul/task.h>
#include <lx_user/io.h>
#include <lx_emul/init.h>
/* C-interface */
@ -29,106 +29,55 @@
using namespace Genode;
extern task_struct *user_task_struct_ptr;
extern bool force_uplink_destroy;
extern bool use_mac_address;
extern unsigned char mac_address[6];
struct Device
struct Main
{
Env &env;
Env &env;
Attached_rom_dataspace config_rom { env, "config" };
unsigned long usb_config { 0 };
/*
* Dedicated allocator per device to notice dangling
* allocations on device destruction.
*/
Allocator_avl alloc { &Lx_kit::env().heap };
Signal_handler<Main> signal_handler { env.ep(), *this,
&Main::handle_signal };
Signal_handler<Main> usb_rom_handler { env.ep(), *this,
&Main::handle_usb_rom };
Signal_handler<Main> config_handler { env.ep(), *this,
&Main::handle_config };
task_struct *state_task { lx_user_new_usb_task(state_task_entry, this) };
task_struct *urb_task { lx_user_new_usb_task(urb_task_entry, this) };
Signal_handler<Device> task_state_handler { env.ep(), *this, &Device::handle_task_state };
Signal_handler<Device> urb_handler { env.ep(), *this, &Device::handle_urb };
genode_usb_client_handle_t usb_handle {
genode_usb_client_create(genode_env_ptr(env),
genode_allocator_ptr(Lx_kit::env().heap),
genode_range_allocator_ptr(alloc),
"",
genode_signal_handler_ptr(task_state_handler)) };
Signal_handler<Device> nic_handler { env.ep(), *this, &Device::handle_nic };
Signal_handler<Device> config_handler { env.ep(), *this, &Device::handle_config };
bool registered { false };
void *lx_device_handle { nullptr };
Device(Env &env)
Main(Env &env)
:
env(env)
{
genode_usb_client_sigh_ack_avail(usb_handle,
genode_signal_handler_ptr(urb_handler));
Lx_kit::initialize(env, signal_handler);
Genode_c_api::initialize_usb_client(env, Lx_kit::env().heap,
signal_handler, usb_rom_handler);
genode_mac_address_reporter_init(env, Lx_kit::env().heap);
genode_uplink_init(genode_env_ptr(env),
genode_allocator_ptr(Lx_kit::env().heap),
genode_signal_handler_ptr(nic_handler));
genode_signal_handler_ptr(signal_handler));
config_rom.sigh(config_handler);
handle_config();
lx_emul_start_kernel(nullptr);
}
/* non-copyable */
Device(const Device&) = delete;
Device & operator=(const Device&) = delete;
void register_device()
void handle_signal()
{
registered = true;
lx_device_handle = lx_emul_usb_client_register_device(usb_handle, "usb_nic");
if (!lx_device_handle) {
registered = false;
return;
}
if (usb_config != 0)
lx_emul_usb_client_set_configuration(usb_handle, lx_device_handle, usb_config);
}
void unregister_device()
{
force_uplink_destroy = true;
lx_emul_usb_client_unregister_device(usb_handle, lx_device_handle);
registered = false;
force_uplink_destroy = false;
}
void handle_task_state()
{
lx_emul_task_unblock(state_task);
Lx_kit::env().scheduler.execute();
}
void handle_urb()
{
lx_emul_task_unblock(urb_task);
lx_user_handle_io();
Lx_kit::env().scheduler.execute();
genode_uplink_notify_peers();
}
void handle_nic()
void handle_usb_rom()
{
if (!user_task_struct_ptr)
return;
lx_emul_task_unblock(user_task_struct_ptr);
lx_emul_usb_client_rom_update();
Lx_kit::env().scheduler.execute();
}
@ -138,15 +87,11 @@ struct Device
genode_mac_address_reporter_config(config_rom.xml());
/* read USB configuration setting */
unsigned long config = config_rom.xml().attribute_value("configuration", 0ul);
if (registered && config != 0 && config != usb_config)
lx_emul_usb_client_set_configuration(usb_handle, lx_device_handle, config);
usb_config = config;
usb_config = config_rom.xml().attribute_value("configuration", 0ul);
/* retrieve possible MAC */
Nic::Mac_address mac;
try {
Nic::Mac_address mac;
Xml_node::Attribute mac_node = config_rom.xml().attribute("mac");
mac_node.value(mac);
mac.copy(mac_address);
@ -156,79 +101,7 @@ struct Device
use_mac_address = false;
}
}
/**********
** Task **
**********/
static int state_task_entry(void *arg)
{
Device &device = *reinterpret_cast<Device *>(arg);
while (true) {
if (genode_usb_client_plugged(device.usb_handle) && !device.registered)
device.register_device();
if (!genode_usb_client_plugged(device.usb_handle) && device.registered)
device.unregister_device();
lx_emul_task_schedule(true);
}
return 0;
}
static int urb_task_entry(void *arg)
{
Device &device = *reinterpret_cast<Device *>(arg);
while (true) {
if (device.registered) {
genode_usb_client_execute_completions(device.usb_handle);
}
lx_emul_task_schedule(true);
}
return 0;
}
};
struct Main
{
Env &env;
Signal_handler<Main> signal_handler { env.ep(), *this, &Main::handle_signal };
Main(Env &env) : env(env) { }
void handle_signal()
{
Lx_kit::env().scheduler.execute();
}
};
void Component::construct(Env & env)
{
static Main main { env };
Lx_kit::initialize(env, main.signal_handler);
env.exec_static_constructors();
lx_emul_start_kernel(nullptr);
}
/**********
** Task **
**********/
int lx_user_main_task(void *)
{
/* one device only */
static Device dev(Lx_kit::env().env);
return 0;
}
void Component::construct(Env & env) { static Main main { env }; }

View File

@ -1,7 +1,7 @@
/*
* \brief Dummy definitions of Linux Kernel functions
* \author Automatically generated file - do no edit
* \date 2024-01-23
* \date 2024-02-22
*/
#include <lx_emul.h>
@ -651,6 +651,14 @@ loff_t noop_llseek(struct file * file,loff_t offset,int whence)
}
#include <linux/of.h>
bool of_device_is_available(const struct device_node * device)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/of_device.h>
void of_device_uevent(struct device * dev,struct kobj_uevent_env * env)
@ -888,14 +896,6 @@ void rtmsg_ifinfo_send(struct sk_buff * skb,struct net_device * dev,gfp_t flags)
}
#include <linux/scatterlist.h>
void sg_init_table(struct scatterlist * sgl,unsigned int nents)
{
lx_emul_trace_and_stop(__func__);
}
#include <net/sock.h>
void sk_error_report(struct sock * sk)
@ -954,14 +954,6 @@ void tick_broadcast(const struct cpumask * mask)
}
#include <linux/usb.h>
int usb_clear_halt(struct usb_device * dev,int pipe)
{
lx_emul_trace_and_stop(__func__);
}
extern void usb_devio_cleanup(void);
void usb_devio_cleanup(void)
{
@ -969,13 +961,6 @@ void usb_devio_cleanup(void)
}
extern void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware);
void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb.h>
int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint ** eps,unsigned int num_eps,gfp_t mem_flags)
@ -984,29 +969,6 @@ int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint *
}
extern int usb_get_device_descriptor(struct usb_device * dev,unsigned int size);
int usb_get_device_descriptor(struct usb_device * dev,unsigned int size)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb.h>
int usb_get_status(struct usb_device * dev,int recip,int type,int target,void * data)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb/hcd.h>
int usb_hcd_alloc_bandwidth(struct usb_device * udev,struct usb_host_config * new_config,struct usb_host_interface * cur_alt,struct usb_host_interface * new_alt)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb/hcd.h>
int usb_hcd_find_raw_port_number(struct usb_hcd * hcd,int port1)
@ -1044,8 +1006,9 @@ struct device_node * usb_of_get_device_node(struct usb_device * hub,int port1)
}
extern int usb_set_isoch_delay(struct usb_device * dev);
int usb_set_isoch_delay(struct usb_device * dev)
#include <linux/usb/of.h>
struct device_node * usb_of_get_interface_node(struct usb_device * udev,u8 config,u8 ifnum)
{
lx_emul_trace_and_stop(__func__);
}
@ -1059,14 +1022,6 @@ const char * usb_speed_string(enum usb_device_speed speed)
}
#include <linux/usb.h>
void usb_unpoison_urb(struct urb * urb)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/uuid.h>
const u8 uuid_index[16] = {};

View File

@ -28,7 +28,9 @@ drivers/usb/core/config.c
drivers/usb/core/driver.c
drivers/usb/core/generic.c
drivers/usb/core/hub.c
drivers/usb/core/message.c
drivers/usb/core/quirks.c
drivers/usb/core/urb.c
drivers/usb/core/usb.c
fs/nls/nls_base.c
kernel/kthread.c
@ -71,6 +73,7 @@ lib/kstrtox.c
lib/radix-tree.c
lib/rbtree.c
lib/rhashtable.c
lib/scatterlist.c
lib/siphash.c
lib/string.c
lib/string_helpers.c

View File

@ -1,7 +1,7 @@
/*
* \brief Dummy definitions of Linux Kernel functions
* \author Automatically generated file - do no edit
* \date 2024-02-01
* \date 2024-02-22
*/
#include <lx_emul.h>
@ -474,6 +474,14 @@ loff_t noop_llseek(struct file * file,loff_t offset,int whence)
}
#include <linux/of.h>
bool of_device_is_available(const struct device_node * device)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/of_device.h>
void of_device_uevent(struct device * dev,struct kobj_uevent_env * env)
@ -682,14 +690,6 @@ void rtmsg_ifinfo_send(struct sk_buff * skb,struct net_device * dev,gfp_t flags)
}
#include <linux/scatterlist.h>
void sg_init_table(struct scatterlist * sgl,unsigned int nents)
{
lx_emul_trace_and_stop(__func__);
}
#include <net/sock.h>
void sk_error_report(struct sock * sk)
@ -732,14 +732,6 @@ struct sk_buff * tcp_get_timestamping_opt_stats(const struct sock * sk,const str
}
#include <linux/usb.h>
int usb_clear_halt(struct usb_device * dev,int pipe)
{
lx_emul_trace_and_stop(__func__);
}
extern void usb_devio_cleanup(void);
void usb_devio_cleanup(void)
{
@ -747,13 +739,6 @@ void usb_devio_cleanup(void)
}
extern void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware);
void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb.h>
int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint ** eps,unsigned int num_eps,gfp_t mem_flags)
@ -762,29 +747,6 @@ int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint *
}
extern int usb_get_device_descriptor(struct usb_device * dev,unsigned int size);
int usb_get_device_descriptor(struct usb_device * dev,unsigned int size)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb.h>
int usb_get_status(struct usb_device * dev,int recip,int type,int target,void * data)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb/hcd.h>
int usb_hcd_alloc_bandwidth(struct usb_device * udev,struct usb_host_config * new_config,struct usb_host_interface * cur_alt,struct usb_host_interface * new_alt)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb/hcd.h>
int usb_hcd_find_raw_port_number(struct usb_hcd * hcd,int port1)
@ -822,8 +784,9 @@ struct device_node * usb_of_get_device_node(struct usb_device * hub,int port1)
}
extern int usb_set_isoch_delay(struct usb_device * dev);
int usb_set_isoch_delay(struct usb_device * dev)
#include <linux/usb/of.h>
struct device_node * usb_of_get_interface_node(struct usb_device * udev,u8 config,u8 ifnum)
{
lx_emul_trace_and_stop(__func__);
}
@ -837,14 +800,6 @@ const char * usb_speed_string(enum usb_device_speed speed)
}
#include <linux/usb.h>
void usb_unpoison_urb(struct urb * urb)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/uuid.h>
const u8 uuid_index[16] = {};

View File

@ -27,7 +27,9 @@ drivers/usb/core/config.c
drivers/usb/core/driver.c
drivers/usb/core/generic.c
drivers/usb/core/hub.c
drivers/usb/core/message.c
drivers/usb/core/quirks.c
drivers/usb/core/urb.c
drivers/usb/core/usb.c
fs/nls/nls_base.c
kernel/kthread.c
@ -69,6 +71,7 @@ lib/radix-tree.c
lib/rhashtable.c
lib/rbtree.c
lib/xarray.c
lib/scatterlist.c
lib/siphash.c
lib/string.c
lib/string_helpers.c

View File

@ -1,7 +1,7 @@
/*
* \brief Dummy definitions of Linux Kernel functions
* \author Automatically generated file - do no edit
* \date 2024-01-23
* \date 2024-02-22
*/
#include <lx_emul.h>
@ -569,6 +569,14 @@ loff_t noop_llseek(struct file * file,loff_t offset,int whence)
}
#include <linux/of.h>
bool of_device_is_available(const struct device_node * device)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/of_device.h>
void of_device_uevent(struct device * dev,struct kobj_uevent_env * env)
@ -782,14 +790,6 @@ void rtmsg_ifinfo_send(struct sk_buff * skb,struct net_device * dev,gfp_t flags)
}
#include <linux/scatterlist.h>
void sg_init_table(struct scatterlist * sgl,unsigned int nents)
{
lx_emul_trace_and_stop(__func__);
}
#include <net/sock.h>
void sk_error_report(struct sock * sk)
@ -848,14 +848,6 @@ void tick_broadcast(const struct cpumask * mask)
}
#include <linux/usb.h>
int usb_clear_halt(struct usb_device * dev,int pipe)
{
lx_emul_trace_and_stop(__func__);
}
extern void usb_devio_cleanup(void);
void usb_devio_cleanup(void)
{
@ -863,13 +855,6 @@ void usb_devio_cleanup(void)
}
extern void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware);
void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb.h>
int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint ** eps,unsigned int num_eps,gfp_t mem_flags)
@ -878,29 +863,6 @@ int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint *
}
extern int usb_get_device_descriptor(struct usb_device * dev,unsigned int size);
int usb_get_device_descriptor(struct usb_device * dev,unsigned int size)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb.h>
int usb_get_status(struct usb_device * dev,int recip,int type,int target,void * data)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb/hcd.h>
int usb_hcd_alloc_bandwidth(struct usb_device * udev,struct usb_host_config * new_config,struct usb_host_interface * cur_alt,struct usb_host_interface * new_alt)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb/hcd.h>
int usb_hcd_find_raw_port_number(struct usb_hcd * hcd,int port1)
@ -938,8 +900,9 @@ struct device_node * usb_of_get_device_node(struct usb_device * hub,int port1)
}
extern int usb_set_isoch_delay(struct usb_device * dev);
int usb_set_isoch_delay(struct usb_device * dev)
#include <linux/usb/of.h>
struct device_node * usb_of_get_interface_node(struct usb_device * udev,u8 config,u8 ifnum)
{
lx_emul_trace_and_stop(__func__);
}
@ -953,14 +916,6 @@ const char * usb_speed_string(enum usb_device_speed speed)
}
#include <linux/usb.h>
void usb_unpoison_urb(struct urb * urb)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/uuid.h>
const u8 uuid_index[16] = {};

View File

@ -26,7 +26,9 @@ drivers/usb/core/config.c
drivers/usb/core/driver.c
drivers/usb/core/generic.c
drivers/usb/core/hub.c
drivers/usb/core/message.c
drivers/usb/core/quirks.c
drivers/usb/core/urb.c
drivers/usb/core/usb.c
fs/nls/nls_base.c
kernel/kthread.c
@ -70,6 +72,7 @@ lib/radix-tree.c
lib/rhashtable.c
lib/rbtree.c
lib/xarray.c
lib/scatterlist.c
lib/siphash.c
lib/string.c
lib/string_helpers.c

View File

@ -707,14 +707,6 @@ void rtmsg_ifinfo_send(struct sk_buff * skb,struct net_device * dev,gfp_t flags)
}
#include <linux/scatterlist.h>
void sg_init_table(struct scatterlist * sgl,unsigned int nents)
{
lx_emul_trace_and_stop(__func__);
}
#include <net/sock.h>
void sk_error_report(struct sock * sk)
@ -773,14 +765,6 @@ struct sk_buff * tcp_get_timestamping_opt_stats(const struct sock * sk,const str
}
#include <linux/usb.h>
int usb_clear_halt(struct usb_device * dev,int pipe)
{
lx_emul_trace_and_stop(__func__);
}
extern void usb_devio_cleanup(void);
void usb_devio_cleanup(void)
{
@ -788,13 +772,6 @@ void usb_devio_cleanup(void)
}
extern void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware);
void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb.h>
int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint ** eps,unsigned int num_eps,gfp_t mem_flags)
@ -803,29 +780,6 @@ int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint *
}
extern int usb_get_device_descriptor(struct usb_device * dev,unsigned int size);
int usb_get_device_descriptor(struct usb_device * dev,unsigned int size)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb.h>
int usb_get_status(struct usb_device * dev,int recip,int type,int target,void * data)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb/hcd.h>
int usb_hcd_alloc_bandwidth(struct usb_device * udev,struct usb_host_config * new_config,struct usb_host_interface * cur_alt,struct usb_host_interface * new_alt)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb/hcd.h>
int usb_hcd_find_raw_port_number(struct usb_hcd * hcd,int port1)
@ -855,13 +809,6 @@ void usb_major_cleanup(void)
}
extern int usb_set_isoch_delay(struct usb_device * dev);
int usb_set_isoch_delay(struct usb_device * dev)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb/ch9.h>
const char * usb_speed_string(enum usb_device_speed speed)
@ -870,14 +817,6 @@ const char * usb_speed_string(enum usb_device_speed speed)
}
#include <linux/usb.h>
void usb_unpoison_urb(struct urb * urb)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/uuid.h>
const u8 uuid_index[16] = {};

View File

@ -21,7 +21,9 @@ drivers/usb/core/config.c
drivers/usb/core/driver.c
drivers/usb/core/generic.c
drivers/usb/core/hub.c
drivers/usb/core/message.c
drivers/usb/core/quirks.c
drivers/usb/core/urb.c
drivers/usb/core/usb.c
fs/nls/nls_base.c
kernel/kthread.c
@ -63,6 +65,7 @@ lib/radix-tree.c
lib/rhashtable.c
lib/rbtree.c
lib/xarray.c
lib/scatterlist.c
lib/siphash.c
lib/string.c
lib/string_helpers.c

View File

@ -680,14 +680,6 @@ void rtmsg_ifinfo_send(struct sk_buff * skb,struct net_device * dev,gfp_t flags)
}
#include <linux/scatterlist.h>
void sg_init_table(struct scatterlist * sgl,unsigned int nents)
{
lx_emul_trace_and_stop(__func__);
}
#include <net/sock.h>
void sk_error_report(struct sock * sk)
@ -746,14 +738,6 @@ struct sk_buff * tcp_get_timestamping_opt_stats(const struct sock * sk,const str
}
#include <linux/usb.h>
int usb_clear_halt(struct usb_device * dev,int pipe)
{
lx_emul_trace_and_stop(__func__);
}
extern void usb_devio_cleanup(void);
void usb_devio_cleanup(void)
{
@ -761,13 +745,6 @@ void usb_devio_cleanup(void)
}
extern void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware);
void usb_disable_endpoint(struct usb_device * dev,unsigned int epaddr,bool reset_hardware)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb.h>
int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint ** eps,unsigned int num_eps,gfp_t mem_flags)
@ -776,29 +753,6 @@ int usb_free_streams(struct usb_interface * interface,struct usb_host_endpoint *
}
extern int usb_get_device_descriptor(struct usb_device * dev,unsigned int size);
int usb_get_device_descriptor(struct usb_device * dev,unsigned int size)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb.h>
int usb_get_status(struct usb_device * dev,int recip,int type,int target,void * data)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb/hcd.h>
int usb_hcd_alloc_bandwidth(struct usb_device * udev,struct usb_host_config * new_config,struct usb_host_interface * cur_alt,struct usb_host_interface * new_alt)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb/hcd.h>
int usb_hcd_find_raw_port_number(struct usb_hcd * hcd,int port1)
@ -828,13 +782,6 @@ void usb_major_cleanup(void)
}
extern int usb_set_isoch_delay(struct usb_device * dev);
int usb_set_isoch_delay(struct usb_device * dev)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/usb/ch9.h>
const char * usb_speed_string(enum usb_device_speed speed)
@ -843,14 +790,6 @@ const char * usb_speed_string(enum usb_device_speed speed)
}
#include <linux/usb.h>
void usb_unpoison_urb(struct urb * urb)
{
lx_emul_trace_and_stop(__func__);
}
#include <linux/uuid.h>
const u8 uuid_index[16] = {};

View File

@ -21,7 +21,9 @@ drivers/usb/core/config.c
drivers/usb/core/driver.c
drivers/usb/core/generic.c
drivers/usb/core/hub.c
drivers/usb/core/message.c
drivers/usb/core/quirks.c
drivers/usb/core/urb.c
drivers/usb/core/usb.c
fs/nls/nls_base.c
kernel/kthread.c
@ -63,6 +65,7 @@ lib/radix-tree.c
lib/rhashtable.c
lib/rbtree.c
lib/xarray.c
lib/scatterlist.c
lib/siphash.c
lib/string.c
lib/string_helpers.c

View File

@ -8,9 +8,9 @@ SRC_C += dummies.c \
lx_emul.c \
lx_user.c
SRC_C += lx_emul/virt/shadow/drivers/usb/core/message.c \
lx_emul/virt/shadow/drivers/usb/core/urb.c \
lx_emul/virt/usb_client.c
SRC_C += lx_emul/virt/shadow/drivers/usb/core/buffer.c
SRC_C += lx_emul/virt/shadow/drivers/usb/core/hcd.c
SRC_C += lx_emul/virt/usb_client.c
SRC_CC = main.cc \
wdm_terminal.cc

View File

@ -18,6 +18,7 @@
extern "C" {
#endif
extern void lx_emul_input_leds_init(void);
extern void lx_emul_input_leds_update(bool capslock, bool numlock, bool scrolllock);
#ifdef __cplusplus

View File

@ -14,11 +14,14 @@
#ifndef _LX_EMUL__USB_H_
#define _LX_EMUL__USB_H_
#include <genode_c_api/usb.h>
#ifdef __cplusplus
extern "C" {
#endif
extern struct genode_usb_rpc_callbacks lx_emul_usb_rpc_callbacks;
extern void lx_emul_usb_release_device(genode_usb_bus_num_t bus,
genode_usb_dev_num_t dev);
#ifdef __cplusplus
}

View File

@ -4,9 +4,10 @@
extern "C" {
#endif
void *lx_emul_usb_client_register_device(genode_usb_client_handle_t handle, char const *label);
void lx_emul_usb_client_unregister_device(genode_usb_client_handle_t handle, void *data);
int lx_emul_usb_client_set_configuration(genode_usb_client_handle_t, void *data, unsigned long config);
int lx_emul_usb_client_set_configuration(genode_usb_client_dev_handle_t, void *data, unsigned long config);
void lx_emul_usb_client_init(void);
void lx_emul_usb_client_rom_update(void);
void lx_emul_usb_client_ticker(void);
#ifdef __cplusplus
} /* extern "C" */

View File

@ -52,25 +52,49 @@ static void update_leds(struct led_handler *handler)
}
static int led_task_loop(void *arg)
{
for (;;) {
struct led_handler *handler;
list_for_each_entry(handler, &led_handlers, list) {
update_leds(handler);
}
if (led_update.state == BLOCKED)
complete(&led_update.update);
led_update.state = NONE;
lx_emul_task_schedule(true);
}
return 0;
}
static struct task_struct *led_task = NULL;
void lx_emul_input_leds_init(void)
{
int pid = kernel_thread(led_task_loop, &led_task, CLONE_FS | CLONE_FILES);
led_task = find_task_by_pid_ns(pid, NULL);
}
void lx_emul_input_leds_update(bool capslock, bool numlock, bool scrolllock)
{
struct led_handler *handler;
led_update.state = UPDATE;
led_update.state = UPDATE;
led_update.capsl = capslock;
led_update.numl = numlock;
led_update.scrolll = scrolllock;
list_for_each_entry(handler, &led_handlers, list) {
update_leds(handler);
}
if (!led_task)
return;
if (led_update.state == BLOCKED)
complete(&led_update.update);
led_update.state = NONE;
lx_emul_task_unblock(led_task);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,15 @@
#include <linux/usb.h>
#include <linux/usb/hcd.h>
void * hcd_buffer_alloc(struct usb_bus * bus, size_t size, gfp_t mem_flags, dma_addr_t * dma)
{
return kmalloc(size, GFP_KERNEL);
}
void hcd_buffer_free(struct usb_bus * bus, size_t size, void * addr, dma_addr_t dma)
{
kfree(addr);
}

View File

@ -0,0 +1,89 @@
#include <linux/workqueue.h>
#include <linux/types.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include <genode_c_api/usb_client.h>
#include <lx_emul/usb_client.h>
/* wait queue for synchronous unlinks */
DECLARE_WAIT_QUEUE_HEAD(usb_kill_urb_queue);
extern void lx_user_handle_io(void);
int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
{
genode_usb_client_dev_handle_t handle;
genode_usb_client_ret_val_t r = INVALID;
/* increment urb's reference count as part of giving it to the HCD
* (which will control it). HCD guarantees that it either returns
* an error or calls giveback(), but not both.
*/
usb_get_urb(urb);
atomic_inc(&urb->use_count);
atomic_inc(&urb->dev->urbnum);
if (!urb->dev->bus)
return -ENODEV;
handle = (genode_usb_client_dev_handle_t)urb->dev->filelist.prev;
switch(usb_pipetype(urb->pipe)) {
case PIPE_CONTROL:
{
struct usb_ctrlrequest * ctrl = (struct usb_ctrlrequest *)
urb->setup_packet;
r = genode_usb_client_device_control(handle,
ctrl->bRequest,
ctrl->bRequestType,
ctrl->wValue,
ctrl->wIndex,
urb->transfer_buffer_length,
urb);
break;
}
case PIPE_INTERRUPT:
{
r = genode_usb_client_iface_transfer(handle, IRQ,
urb->ep->desc.bEndpointAddress,
urb->transfer_buffer_length,
urb);
break;
}
case PIPE_BULK:
r = genode_usb_client_iface_transfer(handle, BULK,
urb->ep->desc.bEndpointAddress,
urb->transfer_buffer_length,
urb);
break;
default:
printk("unknown URB requested: %d\n", usb_pipetype(urb->pipe));
}
switch (r) {
case NO_DEVICE: return -ENODEV;
case NO_MEMORY: return -ENOMEM;
case HALT: return -EPIPE;
case INVALID: return -EINVAL;
case TIMEOUT: return -ETIMEDOUT;
case OK: break;
};
lx_emul_usb_client_ticker();
return 0;
}
int usb_hcd_unlink_urb (struct urb *urb, int status)
{
struct usb_device *udev = urb->dev;
int ret = -EIDRM;
if (atomic_read(&urb->use_count) > 0 &&
udev->state == USB_STATE_NOTATTACHED) {
ret = 0;
atomic_set(&urb->use_count, 0);
}
return ret;
}

View File

@ -1,451 +0,0 @@
/*
* \brief message.c functions using genode_c_api/usb_client.h
* \author Sebastian Sumpf
* \date 2023-06-20
*/
/*
* Copyright (C) 2023 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include <genode_c_api/usb_client.h>
#include "urb_helper.h"
extern struct bus_type usb_bus_type;
extern struct device_type usb_if_device_type;
static void sync_complete(struct genode_usb_client_request_packet *packet)
{
complete((struct completion *)packet->opaque_data);
};
int usb_control_msg(struct usb_device *dev, unsigned int pipe,
__u8 request, __u8 requesttype, __u16 value,
__u16 index, void *data, __u16 size, int timeout)
{
unsigned timeout_jiffies;
int ret;
struct urb *urb;
struct completion comp;
struct genode_usb_client_request_packet packet;
struct genode_usb_request_control control;
struct genode_usb_config config;
genode_usb_client_handle_t handle;
if (!dev->bus) return -ENODEV;
handle = (genode_usb_client_handle_t)dev->bus->controller;
/*
* If this function is called with a timeout of 0 to wait forever,
* we wait in pieces of 10s each as 'schedule_timeout' might trigger
* immediately otherwise. The intend to wait forever is reflected
* back nonetheless when sending the urb.
*/
timeout_jiffies = timeout ? msecs_to_jiffies(timeout)
: msecs_to_jiffies(10000u);
/* dummy alloc urb for wait_for_free_urb below */
urb = (struct urb *)usb_alloc_urb(0, GFP_KERNEL);
if (!urb) return -ENOMEM;
/*
* Set configuration also calls this function, but maps to different packet
* Note: Some calls using set configuration do not change the profile but send
* data to the device (e.g., keyboard led handling) where size != 0
*/
if (request == USB_REQ_SET_CONFIGURATION && size == 0) {
packet.request.type = CONFIG;
config.value = value;
packet.request.req = &config;
packet.buffer.size = 0;
} else {
packet.request.type = CTRL;
control.request = request;
control.request_type = requesttype;
control.value = value;
control.index = index;
control.timeout = timeout ? jiffies_to_msecs(timeout_jiffies) : 0;
packet.request.req = &control;
packet.buffer.size = size;
}
for (;;) {
if (genode_usb_client_request(handle, &packet)) break;
timeout_jiffies = wait_for_free_urb(timeout_jiffies);
if (!timeout_jiffies && timeout) {
ret = -ETIMEDOUT;
goto err_request;
}
}
if (!(requesttype & USB_DIR_IN))
memcpy(packet.buffer.addr, data, size);
init_completion(&comp);
packet.complete_callback = sync_complete;
packet.free_callback = sync_complete;
packet.opaque_data = &comp;
genode_usb_client_request_submit(handle, &packet);
wait_for_completion(&comp);
if (packet.actual_length && data && (size >= packet.actual_length))
memcpy(data, packet.buffer.addr, packet.actual_length);
ret = packet.error ? packet_errno(packet.error) : packet.actual_length;
genode_usb_client_request_finish(handle, &packet);
err_request:
kfree(urb);
return ret;
}
int usb_get_descriptor(struct usb_device *dev, unsigned char type,
unsigned char index, void *buf, int size)
{
int i;
int result;
if (size <= 0) /* No point in asking for no data */
return -EINVAL;
memset(buf, 0, size); /* Make sure we parse really received data */
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;
}
void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep, bool reset_ep)
{
int epnum = usb_endpoint_num(&ep->desc);
int is_out = usb_endpoint_dir_out(&ep->desc);
int is_control = usb_endpoint_xfer_control(&ep->desc);
if (is_out || is_control)
dev->ep_out[epnum] = ep;
if (!is_out || is_control)
dev->ep_in[epnum] = ep;
ep->enabled = 1;
}
void usb_enable_interface(struct usb_device *dev,
struct usb_interface *intf, bool reset_eps)
{
struct usb_host_interface *alt = intf->cur_altsetting;
int i;
for (i = 0; i < alt->desc.bNumEndpoints; ++i) {
usb_enable_endpoint(dev, &alt->endpoint[i], reset_eps);
}
}
int usb_set_interface(struct usb_device *udev, int ifnum, int alternate)
{
int ret;
struct urb *urb;
struct completion comp;
unsigned timeout_jiffies = msecs_to_jiffies(10000u);
struct genode_usb_client_request_packet packet;
struct genode_usb_altsetting alt_setting;
genode_usb_client_handle_t handle;
struct usb_interface *iface;
if (!udev->bus) return -ENODEV;
if (!udev->config)
return -ENODEV;
if (ifnum >= USB_MAXINTERFACES || ifnum < 0)
return -EINVAL;
iface = udev->actconfig->interface[ifnum];
handle = (genode_usb_client_handle_t)udev->bus->controller;
/* dummy alloc urb for wait_for_free_urb below */
urb = (struct urb *)usb_alloc_urb(0, GFP_KERNEL);
if (!urb) return -ENOMEM;
packet.request.type = ALT_SETTING;
alt_setting.interface_number = ifnum;
alt_setting.alt_setting = alternate;
packet.request.req = &alt_setting;
packet.buffer.size = 0;
for (;;) {
if (genode_usb_client_request(handle, &packet)) break;
timeout_jiffies = wait_for_free_urb(timeout_jiffies);
if (!timeout_jiffies) {
ret = -ETIMEDOUT;
goto err_request;
}
}
init_completion(&comp);
packet.complete_callback = sync_complete;
packet.free_callback = sync_complete;
packet.opaque_data = &comp;
genode_usb_client_request_submit(handle, &packet);
wait_for_completion(&comp);
ret = packet.error ? packet_errno(packet.error) : 0;
genode_usb_client_request_finish(handle, &packet);
/* reset via alt setting 0 */
if (!iface) {
printk("%s:%d: Error: interface is null: infum: %d alt setting: %d\n",
__func__, __LINE__, ifnum, alternate);
return 0;
}
if (!ret) {
iface->cur_altsetting = &iface->altsetting[alternate];
}
usb_enable_interface(udev, iface, true);
err_request:
kfree(urb);
return ret;
}
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;
}
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 = &usb_bus_type;
intf->dev.type = &usb_if_device_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;
for (i = 0; i < nintf; ++i) {
struct usb_interface *intf = cp->interface[i];
usb_enable_interface(dev, intf, true);
ret = device_add(&intf->dev);
if (ret != 0) {
printk("error: device_add(%s) --> %d\n", dev_name(&intf->dev), ret);
continue;
}
}
return 0;
}
void usb_disable_device(struct usb_device *dev, int skip_ep0)
{
int i;
/* getting rid of interfaces will disconnect
* any drivers bound to them (a key side effect)
*/
if (dev->actconfig) {
/*
* FIXME: In order to avoid self-deadlock involving the
* bandwidth_mutex, we have to mark all the interfaces
* before unregistering any of them.
*/
for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++)
dev->actconfig->interface[i]->unregistering = 1;
for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
struct usb_interface *interface;
/* remove this interface if it has been registered */
interface = dev->actconfig->interface[i];
if (!device_is_registered(&interface->dev))
continue;
dev_dbg(&dev->dev, "unregistering interface %s\n",
dev_name(&interface->dev));
device_del(&interface->dev);
}
/* Now that the interfaces are unbound, nobody should
* try to access them.
*/
for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
put_device(&dev->actconfig->interface[i]->dev);
dev->actconfig->interface[i] = NULL;
}
dev->actconfig = NULL;
if (dev->state == USB_STATE_CONFIGURED)
usb_set_device_state(dev, USB_STATE_ADDRESS);
}
dev_dbg(&dev->dev, "%s nuking %s URBs\n", __func__,
skip_ep0 ? "non-ep0" : "all");
}

View File

@ -1,218 +0,0 @@
/*
* \brief urb.c functions using genode_c_api/usb_client.h
* \author Sebastian Sumpf
* \date 2023-06-20
*/
/*
* Copyright (C) 2023 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include <genode_c_api/usb_client.h>
#include "urb_helper.h"
#define to_urb(d) container_of(d, struct urb, kref)
static DECLARE_WAIT_QUEUE_HEAD(lx_emul_urb_wait);
int wait_for_free_urb(unsigned int timeout_jiffies)
{
int ret = 0;
DECLARE_WAITQUEUE(wait, current);
add_wait_queue(&lx_emul_urb_wait, &wait);
ret = schedule_timeout(timeout_jiffies);
remove_wait_queue(&lx_emul_urb_wait, &wait);
return ret;
}
struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)
{
struct urb *urb = (struct urb*)
kmalloc(sizeof(struct urb) +
iso_packets * sizeof(struct usb_iso_packet_descriptor),
GFP_KERNEL);
if (!urb) return NULL;
memset(urb, 0, sizeof(*urb));
kref_init(&urb->kref);
INIT_LIST_HEAD(&urb->urb_list);
INIT_LIST_HEAD(&urb->anchor_list);
return urb;
}
static void free_packet(struct genode_usb_client_request_packet *packet)
{
kfree(packet->request.req);
kfree(packet);
}
static void urb_submit_complete(struct genode_usb_client_request_packet *packet)
{
struct urb *urb = (struct urb *)packet->opaque_data;
genode_usb_client_handle_t handle = (genode_usb_client_handle_t)urb->hcpriv;
urb->status = packet->error ? packet_errno(packet->error) : 0;
if (packet->error == 0 &&
packet->actual_length && urb->transfer_buffer &&
urb->transfer_buffer_length >= packet->actual_length)
memcpy(urb->transfer_buffer, packet->buffer.addr, packet->actual_length);
urb->actual_length = packet->actual_length;
genode_usb_client_request_finish(handle, packet);
free_packet(packet);
if (urb->complete) urb->complete(urb);
};
int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
{
genode_usb_client_handle_t handle;
struct genode_usb_client_request_packet *packet;
struct genode_usb_request_transfer *transfer;
struct genode_usb_request_control *control;
int ret = 0;
unsigned timeout_jiffies = msecs_to_jiffies(10000u);
if (!urb || !urb->complete)
return -EINVAL;
if (!urb->dev->bus)
return -ENODEV;
handle = (genode_usb_client_handle_t)urb->dev->bus->controller;
packet = (struct genode_usb_client_request_packet *)
kzalloc(sizeof(*packet), GFP_KERNEL);
if (!packet) return -ENOMEM;
if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
control = (struct genode_usb_request_control *)
kzalloc(sizeof(*control), GFP_KERNEL);
if (!control) {
ret = -ENOMEM;
goto transfer;
}
}
else {
transfer = (struct genode_usb_request_transfer *)
kzalloc(sizeof(*transfer), GFP_KERNEL);
if (!transfer) {
ret = -ENOMEM;
goto transfer;
}
}
switch(usb_pipetype(urb->pipe)) {
case PIPE_CONTROL:
{
struct usb_ctrlrequest * ctrl = (struct usb_ctrlrequest *)
urb->setup_packet;
packet->request.type = CTRL;
control->request = ctrl->bRequest;
control->request_type = ctrl->bRequestType;
control->value = ctrl->wValue;
control->index = ctrl->wIndex;
packet->request.req = control;
break;
}
case PIPE_INTERRUPT:
{
packet->request.type = IRQ;
transfer->polling_interval = urb->interval;
transfer->ep = usb_pipeendpoint(urb->pipe)
| (usb_pipein(urb->pipe) ? USB_DIR_IN : 0);
packet->request.req = transfer;
break;
}
case PIPE_BULK:
{
packet->request.type = BULK;
transfer->ep = usb_pipeendpoint(urb->pipe)
| (usb_pipein(urb->pipe) ? USB_DIR_IN : 0);
packet->request.req = transfer;
break;
}
default:
printk("unknown URB requested: %d\n", usb_pipetype(urb->pipe));
}
packet->buffer.size = urb->transfer_buffer_length;
packet->complete_callback = urb_submit_complete;
packet->opaque_data = urb;
packet->free_callback = free_packet;
for (;;) {
if (genode_usb_client_request(handle, packet)) break;
timeout_jiffies = wait_for_free_urb(timeout_jiffies);
if (!timeout_jiffies) {
ret = -ETIMEDOUT;
goto err_request;
}
}
if (usb_pipeout(urb->pipe))
memcpy(packet->buffer.addr, urb->transfer_buffer, urb->transfer_buffer_length);
urb->hcpriv = (void *)handle;
genode_usb_client_request_submit(handle, packet);
return ret;
err_request:
if (transfer) kfree(transfer);
if (control) kfree(control);
transfer:
kfree(packet);
return ret;
}
struct urb *usb_get_urb(struct urb *urb)
{
if (urb)
kref_get(&urb->kref);
return urb;
}
static void urb_destroy(struct kref *kref)
{
struct urb *urb = to_urb(kref);
kfree(urb);
wake_up(&lx_emul_urb_wait);
}
/* usb_put_urb is defined as usb_free_urb, therefore we need reference counting */
void usb_free_urb(struct urb *urb)
{
if (urb)
kref_put(&urb->kref, urb_destroy);
}

View File

@ -1,43 +0,0 @@
/*
* \brief URB handling helpers
* \author Sebastian Sumpf
* \date 2023-06-20
*/
/*
* Copyright (C) 2023 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#include <linux/usb.h>
#include <genode_c_api/usb_client.h>
/*
* Translate USB-client packet errors to errno
*/
static inline int packet_errno(int error)
{
switch (error) {
case INTERFACE_OR_ENDPOINT_ERROR: return -ENOENT;
case MEMORY_ERROR: return -ENOMEM;
case NO_DEVICE_ERROR: return -ESHUTDOWN;
case PACKET_INVALID_ERROR: return -EINVAL;
case PROTOCOL_ERROR: return -EPROTO;
case STALL_ERROR: return -EPIPE;
case TIMEOUT_ERROR: return -ETIMEDOUT;
case UNKNOWN_ERROR:
printk("%s: got UNKNOWN_ERROR code\n", __func__);
return -EIO;
}
return -EIO;
}
/*
* Wait for a call to 'urb_destroy'
*/
int wait_for_free_urb(unsigned int timeout_jiffies);

View File

@ -1,9 +1,10 @@
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include <../drivers/usb/core/usb.h>
#include <lx_emul/usb_client.h>
#include <genode_c_api/usb_client.h>
static struct hc_driver _hc_driver = { };
struct meta_data
{
@ -12,128 +13,208 @@ struct meta_data
struct usb_device *udev;
};
void *lx_emul_usb_client_register_device(genode_usb_client_handle_t handle, char const *label)
static struct usb_hcd * dummy_hc_device(void)
{
static int initialized = 0;
static struct hc_driver _hc_driver = { };
static struct usb_hcd hcd;
static struct device sysdev;
static struct mutex address0_mutex;
static struct mutex bandwidth_mutex;
if (!initialized) {
device_initialize(&sysdev);
mutex_init(&address0_mutex);
mutex_init(&bandwidth_mutex);
kref_init(&hcd.kref);
hcd.driver = &_hc_driver;
hcd.self.bus_name = "usbbus";
hcd.self.sysdev = &sysdev;
hcd.dev_policy = USB_DEVICE_AUTHORIZE_ALL;
hcd.address0_mutex = &address0_mutex;
hcd.bandwidth_mutex = &bandwidth_mutex;
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd.flags);
set_bit(HCD_FLAG_INTF_AUTHORIZED, &hcd.flags);
initialized = 1;
}
return &hcd;
}
static void * register_device(genode_usb_client_dev_handle_t handle,
char const *label, genode_usb_speed_t speed)
{
struct meta_data *meta;
int err;
struct genode_usb_device_descriptor dev_descr;
struct genode_usb_config_descriptor conf_descr;
static int num = 0;
struct usb_device * udev;
err = genode_usb_client_config_descriptor(handle, &dev_descr, &conf_descr);
if (err) {
printk("error: failed to read config descriptor\n");
return NULL;;
}
meta = (struct meta_data *)kmalloc(sizeof(struct meta_data), GFP_KERNEL);
if (!meta) return NULL;
meta->sysdev = (struct device*)kzalloc(sizeof(struct device), GFP_KERNEL);
if (!meta->sysdev) goto sysdev;
device_initialize(meta->sysdev);
meta->hcd = (struct usb_hcd *)kzalloc(sizeof(struct usb_hcd), GFP_KERNEL);
if (!meta->hcd) goto hcd;
/* hcd->self is usb_bus */
meta->hcd->driver = &_hc_driver;
meta->hcd->self.bus_name = "usbbus";
meta->hcd->self.sysdev = meta->sysdev;
meta->udev = usb_alloc_dev(NULL, &meta->hcd->self, 0);
if (!meta->udev) {
udev = usb_alloc_dev(NULL, &dummy_hc_device()->self, 0);
if (!udev) {
printk("error: could not allocate udev for %s\n", label);
goto udev;
}
/* usb_alloc_dev sets parent to bus->controller if first argument is NULL */
meta->hcd->self.controller = (struct device *)handle;
memcpy(&meta->udev->descriptor, &dev_descr, sizeof(struct usb_device_descriptor));
meta->udev->devnum = dev_descr.num;
meta->udev->speed = (enum usb_device_speed)dev_descr.speed;
meta->udev->authorized = 1;
meta->udev->bus_mA = 900; /* set to maximum USB3.0 */
meta->udev->state = USB_STATE_NOTATTACHED;
dev_set_name(&meta->udev->dev, "%s", label);
err = usb_new_device(meta->udev);
if (err) {
printk("error: usb_new_device failed %d\n", err);
goto new_device;
}
return meta;
new_device:
usb_put_dev(meta->udev);
udev:
kfree(meta->hcd);
hcd:
kfree(meta->sysdev);
sysdev:
kfree(meta);
return NULL;
}
void lx_emul_usb_client_unregister_device(genode_usb_client_handle_t handle, void *data)
{
struct meta_data *meta = (struct meta_data *)data;
usb_disconnect(&meta->udev);
usb_put_dev(meta->udev);
kfree(meta->hcd);
kobject_put(&meta->sysdev->kobj);
kfree(meta->sysdev);
kfree(meta);
}
#define for_each_claimed_interface(udev, num, intf) \
for (num = 0, intf = udev->actconfig->interface[num]; \
num < udev->actconfig->desc.bNumInterfaces; \
intf = udev->actconfig->interface[++num]) \
if (!usb_interface_claimed(intf)) continue; else
int lx_emul_usb_client_set_configuration(genode_usb_client_handle_t handle, void *data, unsigned long config)
{
struct meta_data *meta = (struct meta_data *)data;
struct usb_device *udev = meta->udev;
unsigned i = 0;
struct usb_interface *intf;
/* release claimed interfaces at session */
for_each_claimed_interface(udev, i, intf) {
genode_usb_client_release_interface(handle, i);
return NULL;
}
/*
* Release claimed interfaces at driver, 'usb_driver_release_interface' may
* release more than one interface
* We store handle in filelist list head to be used in hcd urb submission
* before sending any URB. The filelist member is referenced in devio.c
* only which is not used here.
*/
for_each_claimed_interface(udev, i, intf) {
usb_driver_release_interface(to_usb_driver(intf->dev.driver), intf);
udev->filelist.prev = (struct list_head *) handle;
udev->devnum = num++;
switch (speed) {
case GENODE_USB_SPEED_LOW: udev->speed = USB_SPEED_LOW; break;
case GENODE_USB_SPEED_FULL: udev->speed = USB_SPEED_FULL; break;
case GENODE_USB_SPEED_HIGH: udev->speed = USB_SPEED_HIGH; break;
case GENODE_USB_SPEED_SUPER: udev->speed = USB_SPEED_SUPER; break;
case GENODE_USB_SPEED_SUPER_PLUS:
udev->speed = USB_SPEED_SUPER_PLUS;
udev->ssp_rate = USB_SSP_GEN_2x1;
break;
case GENODE_USB_SPEED_SUPER_PLUS_2X2:
udev->speed = USB_SPEED_SUPER_PLUS;
udev->ssp_rate = USB_SSP_GEN_2x2;
break;
default:
udev->speed = USB_SPEED_FULL;
break;
};
udev->authorized = 1;
udev->bus_mA = 900; /* set to maximum USB3.0 */
usb_set_device_state(udev, USB_STATE_ADDRESS);
dev_set_name(&udev->dev, "%s", label);
device_set_wakeup_capable(&udev->dev, 1);
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
err = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);
if (err < 0) {
dev_err(&udev->dev, "can't read device descriptor: %d\n", err);
usb_put_dev(udev);
return NULL;
}
/* set unconfigured (internal reset in host driver) first */
usb_set_configuration(meta->udev, 0);
return usb_set_configuration(meta->udev, config);
err = usb_new_device(udev);
if (err) {
printk("error: usb_new_device failed %d\n", err);
usb_put_dev(udev);
return NULL;
}
return udev;
}
void * hcd_buffer_alloc(struct usb_bus * bus, size_t size, gfp_t mem_flags, dma_addr_t * dma)
static void urb_out(void * data, genode_buffer_t buf)
{
return kmalloc(size, GFP_KERNEL);
struct urb *urb = (struct urb *) data;
memcpy(buf.addr, urb->transfer_buffer,
urb->transfer_buffer_length);
}
void hcd_buffer_free(struct usb_bus * bus, size_t size, void * addr, dma_addr_t dma)
static void urb_in(void * data, genode_buffer_t buf)
{
kfree(addr);
struct urb *urb = (struct urb *) data;
memcpy(urb->transfer_buffer, buf.addr, buf.size);
urb->actual_length = buf.size;
}
static genode_uint32_t isoc_urb_out(void * data, genode_uint32_t idx,
genode_buffer_t buf)
{
printk("%s: not implemented yet, we had no isochronous Linux driver yet",
__func__);
return 0;
}
static void isoc_urb_in(void * data, genode_uint32_t idx, genode_buffer_t buf)
{
printk("%s: not implemented yet, we had no isochronous Linux driver yet",
__func__);
}
static void urb_complete(void * data, genode_usb_client_ret_val_t result)
{
struct urb *urb = (struct urb *) data;
switch (result) {
case OK: urb->status = 0; break;
case NO_DEVICE: urb->status = -ENOENT; break;
case NO_MEMORY: urb->status = -ENOMEM; break;
case HALT: urb->status = -EPIPE; break;
case INVALID: urb->status = -EINVAL; break;
case TIMEOUT: urb->status = -ETIMEDOUT;
};
if (urb->complete) urb->complete(urb);
atomic_dec(&urb->use_count);
usb_put_urb(urb);
}
static void unregister_device(genode_usb_client_dev_handle_t handle, void *data)
{
struct usb_device *udev = (struct usb_device *)data;
genode_usb_client_device_update(urb_out, urb_in, isoc_urb_out,
isoc_urb_in, urb_complete);
udev->filelist.prev = NULL;
usb_disconnect(&udev);
usb_put_dev(udev);
}
static int usb_loop(void *arg)
{
for (;;) {
genode_usb_client_device_update(urb_out, urb_in, isoc_urb_out,
isoc_urb_in, urb_complete);
lx_emul_task_schedule(true);
}
return -1;
}
static struct task_struct * usb_task = NULL;
static int usb_rom_loop(void *arg)
{
for (;;) {
genode_usb_client_update(register_device, unregister_device);
/* block until lx_emul_task_unblock */
lx_emul_task_schedule(true);
}
return 0;
}
static struct task_struct *usb_rom_task = NULL;
void lx_emul_usb_client_init(void)
{
pid_t pid;
pid = kernel_thread(usb_rom_loop, NULL, CLONE_FS | CLONE_FILES);
usb_rom_task = find_task_by_pid_ns(pid, NULL);
pid = kernel_thread(usb_loop, NULL, CLONE_FS | CLONE_FILES);
usb_task = find_task_by_pid_ns(pid, NULL);
}
void lx_emul_usb_client_rom_update(void)
{
if (usb_rom_task) lx_emul_task_unblock(usb_rom_task);
}
void lx_emul_usb_client_ticker(void)
{
if (usb_task) lx_emul_task_unblock(usb_task);
}

View File

@ -7,7 +7,7 @@ gpu_drv: intel
import: pkg/drivers_managed-pc pkg/pc_wifi src/pc_nic_drv
# selection of launcher-menu entries
launcher: vm_fs shared_fs usb_devices_rom download_debug_info
launcher: vm_fs shared_fs download_debug_info
# selection of accepted depot-package providers
depot: genodelabs cnuke alex-ab mstein nfeske cproc chelmuth jschlatow

View File

@ -173,7 +173,7 @@
<start name="usb_hid_drv" caps="180">
<resource name="RAM" quantum="11M"/>
<config use_report="yes" capslock_led="rom" numlock_led="rom"/>
<config capslock_led="rom" numlock_led="rom"/>
<route>
<service name="ROM" label="report"> <child name="report_rom"/> </service>
<service name="ROM" label="capslock"> <parent label="capslock"/> </service>

View File

@ -1,8 +0,0 @@
<launcher pkg="rom_filter">
<config>
<output node="devices">
<inline>
</inline>
</output>
</config>
</launcher>

View File

@ -735,39 +735,41 @@ void Driver_manager::Main::_generate_usb_drv_config(Reporter &usb_drv_config,
/* usb hid drv gets all hid devices */
xml.node("policy", [&] () {
xml.attribute("label_prefix", "usb_hid_drv");
xml.attribute("class", "0x3");
xml.node("device", [&] () {
xml.attribute("class", "0x3");
});
});
/* produce policy nodes for all storage devices */
devices.for_each_sub_node("device", [&] (Xml_node device) {
typedef String<64> Label;
typedef String<32> Id;
bool usb_storage = false;
device.for_each_sub_node("config", [&] (Xml_node cfg) {
Label const label = device.attribute_value("label", Label());
Id const vendor_id = device.attribute_value("vendor_id", Id());
Id const product_id = device.attribute_value("product_id", Id());
cfg.for_each_sub_node("interface", [&] (Xml_node iface) {
/*
* Limit USB sessions to storage and vendor specific in order to avoid
* conflicts with the USB driver's built-in HID drivers.
*/
unsigned long const class_code = device.attribute_value("class", 0UL);
enum { USB_CLASS_MASS_STORAGE = 8 };
enum { USB_CLASS_MASS_STORAGE = 8, USB_CLASS_VENDOR_SPECIFIC = 0xff };
if (iface.attribute_value("class", 0UL) ==
USB_CLASS_MASS_STORAGE)
usb_storage = true;
});
});
bool const expose_as_usb_raw = (class_code == USB_CLASS_MASS_STORAGE) ||
(class_code == USB_CLASS_VENDOR_SPECIFIC);
if (!expose_as_usb_raw)
if (!usb_storage)
return;
xml.node("policy", [&] () {
xml.attribute("label_suffix", label);
xml.attribute("vendor_id", vendor_id);
xml.attribute("product_id", product_id);
using Name = String<64>;
/* annotate policy to make storage devices easy to spot */
if (class_code == USB_CLASS_MASS_STORAGE)
xml.attribute("class", "storage");
Name const name = device.attribute_value("name", Name());
xml.node("policy", [&] () {
xml.attribute("label_suffix", name);
xml.attribute("class", "storage");
xml.node("device", [&] () {
xml.attribute("name", name);
});
});
});
});

View File

@ -72,7 +72,7 @@
</parent-provides>
<default caps="128"/>
<start name="usb_webcam" caps="250">
<resource name="RAM" quantum="48M"/>
<resource name="RAM" quantum="52M"/>
<config ld_verbose="no" enabled="yes" width="640" height="480" format="yuv" fps="15">
<vfs>
<dir name="dev">
@ -101,7 +101,7 @@
<start name="webcam" caps="350">
<binary name="init"/>
<resource name="RAM" quantum="50MB"/>
<resource name="RAM" quantum="54M"/>
<route>
<service name="ROM" label="config">
<child name="webcam_config" label="config"/>

View File

@ -113,7 +113,7 @@ set config {
<provides> <service name="Usb"/> </provides>
<config bios_handoff="no">
<report devices="yes"/>
<policy label_prefix="usb_hid_drv" class="0x3"/>
<policy label_prefix="usb_hid_drv"><device class="0x3"/></policy>
</config>
<route>
<service name="Report"> <child name="drivers_reports"/> </service>
@ -123,7 +123,6 @@ set config {
<start name="usb_hid_drv" caps="140">
<resource name="RAM" quantum="10M"/>
<config use_report="yes"/>
<route>
<service name="ROM" label="report"> <child name="drivers_reports"/> </service>
<service name="Event"> <child name="event_filter" label="usb"/> </service>

View File

@ -79,7 +79,7 @@ install_config {
</start>
<start name="test-smartcard" caps="150">
<resource name="RAM" quantum="4M"/>
<resource name="RAM" quantum="5M"/>
<config>
<vfs>
<dir name="dev">
@ -106,7 +106,7 @@ install_config {
append usb_config {
<config bios_handoff="yes">
<report devices="yes"/>
<policy label="test-smartcard -> usb_device" vendor_id="} [smartcard_vendor_id] {" product_id="} [smartcard_product_id] {"/>
<policy label="test-smartcard -> "><device vendor_id="} [smartcard_vendor_id] {" product_id="} [smartcard_product_id] {"/></policy>
</config>}
set fd [open [run_dir]/genode/usb_host_drv.config w]
puts $fd $usb_config

View File

@ -87,7 +87,7 @@ append config {
</start>
<start name="platform_drv" caps="100" managing_system="yes">
<resource name="RAM" quantum="1M"/>
<resource name="RAM" quantum="2M"/>
<provides>
<service name="Platform"/>
</provides>
@ -108,8 +108,9 @@ append config {
<!-- <resource name="CPU" quantum="10"/> -->
<provides><service name="Usb"/></provides>
<config bios_handoff="no">
<policy label_suffix="usb_webcam -> usb_device"
vendor_id="} [libuvc_vendor_id] {" product_id="} [libuvc_product_id] {"/>
<policy label_suffix="usb_webcam -> ">
<device vendor_id="} [libuvc_vendor_id] {" product_id="} [libuvc_product_id] {"/>
</policy>
</config>
<route>
<any-service> <parent/> <any-child/> </any-service>
@ -161,7 +162,7 @@ append config {
<service name="Capture"/>
</parent-provides>
<start name="} $test_binary {" caps="100">
<resource name="RAM" quantum="8M"/>
<resource name="RAM" quantum="15M"/>
<config period_ms="20" width="640" height="480"> }
append config $test_vfs_config
append config {
@ -200,7 +201,7 @@ append config {
<start name="webcam" priority="-1" caps="800">
<binary name="init"/>
<resource name="RAM" quantum="64MB"/>
<resource name="RAM" quantum="64M"/>
<route>
<service name="ROM" label="config"> <parent label="usb_webcam.config"/> </service>
<service name="Timer"> <child name="timer"/> </service>

View File

@ -1,6 +1,7 @@
/*
* \brief Genode backend for libusb
* \author Christian Prochaska
* \author Stefan Kalkowski
* \date 2016-09-19
*/
@ -12,10 +13,11 @@
*/
#include <base/log.h>
#include <base/registry.h>
#include <base/allocator_avl.h>
#include <base/signal.h>
#include <usb/usb.h>
#include <usb_session/connection.h>
#include <base/tslab.h>
#include <usb_session/device.h>
#include <fcntl.h>
#include <time.h>
@ -25,275 +27,244 @@
#include "libusbi.h"
using namespace Genode;
static Libc::Allocator libc_alloc { };
struct Completion : Usb::Completion
{
struct usbi_transfer *itransfer;
Completion(struct usbi_transfer *itransfer)
: itransfer(itransfer) { }
void complete(Usb::Packet_descriptor &p) override { }
};
bool libusb_genode_backend_signaling = false;
static int vfs_libusb_fd { -1 };
struct Usb_device
{
private:
template <typename URB>
struct Urb_tpl : URB
{
void * const buf;
size_t const size;
usbi_transfer * const itransfer { nullptr };
unsigned _open { 0 };
template <typename... ARGS>
Urb_tpl(void *buf, size_t size, usbi_transfer *itransfer,
ARGS &&... args)
: URB(args...), buf(buf), size(size), itransfer(itransfer) {}
public:
template <typename... ARGS>
Urb_tpl(void *buf, size_t size, ARGS &&... args)
: URB(args...), buf(buf), size(size) {}
};
struct Device_has_vanished {};
struct Interface : Usb::Interface, Registry<Usb_device::Interface>::Element
{
using Urb = Urb_tpl<Usb::Interface::Urb>;
Usb::Connection *usb_connection;
int vfs_libusb_fd;
Usb_device &_device;
Usb::Device_descriptor device_descriptor;
Usb::Config_descriptor config_descriptor;
char *raw_config_descriptor = nullptr;
Interface(Usb_device &device, uint8_t idx);
bool _retrieve_raw_config_descriptor()
{
Genode::log("libusb: retrieve configuration descriptor");
void handle_events();
};
Usb::Packet_descriptor p =
usb_connection->alloc_packet(config_descriptor.total_length);
p.type = Usb::Packet_descriptor::CTRL;
p.control.request = LIBUSB_REQUEST_GET_DESCRIPTOR;
p.control.request_type = LIBUSB_ENDPOINT_IN;
p.control.value = (LIBUSB_DT_CONFIG << 8) | 0;
p.control.index = 0;
using Urb = Urb_tpl<Usb::Device::Urb>;
usb_connection->source()->submit_packet(p);
Env &_env;
Allocator &_alloc;
Tslab<Interface::Urb, 4096> _iface_slab { _alloc };
Signal_context_capability _handler_cap;
Usb::Connection _session { _env };
Usb::Device _device { _session, _alloc, _env.rm() };
libusb_speed _speed { LIBUSB_SPEED_UNKNOWN };
unsigned _open { 0 };
Registry<Interface> _interfaces {};
/* wait for ack */
struct pollfd pollfds {
.fd = vfs_libusb_fd,
.events = POLLIN,
.revents = 0
};
void _wait_for_urb(Urb &urb);
int poll_result = poll(&pollfds, 1, -1);
Usb_device(Env &env, Allocator &alloc, Signal_context_capability cap)
:
_env(env), _alloc(alloc), _handler_cap(cap)
{
String<32> speed;
_session.with_xml([&] (Xml_node xml) {
xml.with_optional_sub_node("device", [&] (Xml_node node) {
speed = node.attribute_value("speed", String<32>()); });
});
if ((poll_result != 1) || !(pollfds.revents & POLLIN)) {
Genode::error(__PRETTY_FUNCTION__,
": could not read raw configuration descriptor");
return false;
}
if (speed == "low") _speed = LIBUSB_SPEED_LOW;
else if (speed == "full") _speed = LIBUSB_SPEED_FULL;
else if (speed == "high") _speed = LIBUSB_SPEED_HIGH;
else if (speed == "super" ||
speed == "super_plus" ||
speed == "super_plus_2x2") _speed = LIBUSB_SPEED_SUPER;
p = usb_connection->source()->get_acked_packet();
_device.sigh(_handler_cap);
}
bool ret = false;
if (!p.succeded) {
Genode::error(__PRETTY_FUNCTION__,
": could not read raw configuration descriptor");
} else if (p.control.actual_size != config_descriptor.total_length) {
Genode::error(__PRETTY_FUNCTION__,
": received configuration descriptor of unexpected size");
} else {
char *packet_content = usb_connection->source()->packet_content(p);
Genode::memcpy(raw_config_descriptor, packet_content,
config_descriptor.total_length);
ret = true;
}
void close() { _open--; }
void open() { _open++; }
usb_connection->source()->release_packet(p);
return ret;
}
void handle_events();
Usb_device(Usb::Connection *usb, int vfs_libusb_fd)
: usb_connection(usb), vfs_libusb_fd(vfs_libusb_fd)
{
usb_connection->config_descriptor(&device_descriptor, &config_descriptor);
raw_config_descriptor = (char*)malloc(config_descriptor.total_length);
for (unsigned attempt = 0; attempt < 10; ++attempt)
if (_retrieve_raw_config_descriptor())
break;
}
~Usb_device()
{
free(raw_config_descriptor);
}
bool altsetting(int number, int alt_setting)
{
if (!usb_connection->source()->ready_to_submit())
return false;
Usb::Packet_descriptor p =
usb_connection->alloc_packet(0);
p.type = Usb::Packet_descriptor::ALT_SETTING;
p.interface.number = number;
p.interface.alt_setting = alt_setting;
usb_connection->source()->submit_packet(p);
return true;
}
void close() { _open--; }
void open() { _open++; }
void handle_events()
{
struct libusb_context *ctx = nullptr;
while (usb_connection->source()->ack_avail()) {
Usb::Packet_descriptor p =
usb_connection->source()->get_acked_packet();
if (p.type == Usb::Packet_descriptor::ALT_SETTING) {
usb_connection->source()->release_packet(p);
continue;
}
Completion *completion = static_cast<Completion*>(p.completion);
struct usbi_transfer *itransfer = completion->itransfer;
if (_open)
ctx = ITRANSFER_CTX(itransfer);
destroy(libc_alloc, completion);
if (_open == 0) {
usb_connection->source()->release_packet(p);
continue;
}
if (!p.succeded || itransfer->flags & USBI_TRANSFER_CANCELLING) {
if (!p.succeded) {
if (p.error == Usb::Packet_descriptor::NO_DEVICE_ERROR)
throw Device_has_vanished();
}
itransfer->transferred = 0;
usb_connection->source()->release_packet(p);
usbi_signal_transfer_completion(itransfer);
continue;
}
char *packet_content = usb_connection->source()->packet_content(p);
struct libusb_transfer *transfer =
USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
switch (transfer->type) {
case LIBUSB_TRANSFER_TYPE_CONTROL: {
itransfer->transferred = p.control.actual_size;
struct libusb_control_setup *setup =
(struct libusb_control_setup*)transfer->buffer;
if ((setup->bmRequestType & LIBUSB_ENDPOINT_DIR_MASK) ==
LIBUSB_ENDPOINT_IN) {
Genode::memcpy(transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE,
packet_content, p.control.actual_size);
}
break;
}
case LIBUSB_TRANSFER_TYPE_BULK:
case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
case LIBUSB_TRANSFER_TYPE_INTERRUPT: {
itransfer->transferred = p.transfer.actual_size;
if (IS_XFERIN(transfer))
Genode::memcpy(transfer->buffer, packet_content,
p.transfer.actual_size);
break;
}
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: {
itransfer->transferred = p.transfer.actual_size;
if (IS_XFERIN(transfer)) {
Usb::Isoc_transfer &isoc = *(Usb::Isoc_transfer *)packet_content;
unsigned out_offset = 0;
for (unsigned i = 0; i < isoc.number_of_packets; i++) {
size_t const actual_length = isoc.actual_packet_size[i];
/*
* Copy the data from the proper offsets within the buffer as
* a short read is still stored at this location.
*/
unsigned char * dst = transfer->buffer + out_offset;
char const * src = isoc.data() + out_offset;
Genode::memcpy(dst, src, actual_length);
out_offset += transfer->iso_packet_desc[i].length;
transfer->iso_packet_desc[i].actual_length = actual_length;
transfer->iso_packet_desc[i].status = LIBUSB_TRANSFER_COMPLETED;
}
transfer->num_iso_packets = isoc.number_of_packets;
}
break;
}
default:
Genode::error(__PRETTY_FUNCTION__,
": unsupported transfer type");
usb_connection->source()->release_packet(p);
continue;
}
usb_connection->source()->release_packet(p);
usbi_signal_transfer_completion(itransfer);
}
if (ctx != nullptr)
usbi_signal_event(ctx);
}
static Constructible<Usb_device>& singleton();
};
static int vfs_libusb_fd { -1 };
static Usb::Connection *usb_connection { nullptr };
static Usb_device *device_instance { nullptr };
/*
* This function is called by the VFS plugin on 'open()'
* to pass a pointer to the USB connection.
*/
void libusb_genode_usb_connection(Usb::Connection *usb)
Usb_device::Interface::Interface(Usb_device &device, uint8_t idx)
:
Usb::Interface(device._device, Usb::Interface::Index{idx, 0}, (1UL << 20)),
Registry<Usb_device::Interface>::Element(device._interfaces, *this),
_device(device)
{
usb_connection = usb;
sigh(device._handler_cap);
}
static inline addr_t isoc_packet_offset(uint32_t idx,
struct libusb_transfer *transfer)
{
addr_t offset = 0;
for (uint32_t i = 0; i < idx; i++)
offset += transfer->iso_packet_desc[i].length;
return offset;
}
void Usb_device::Interface::handle_events()
{
update_urbs<Urb>(
/* produce out content */
[] (Urb &urb, Byte_range_ptr &dst) {
memcpy(dst.start, urb.buf, min(dst.num_bytes, urb.size)); },
/* consume in results */
[] (Urb &urb, Const_byte_range_ptr const &src) {
memcpy(urb.buf, src.start, min(src.num_bytes, urb.size));
if (urb.itransfer) urb.itransfer->transferred = src.num_bytes;
},
/* produce out content of isochronous packet i */
[] (Urb &urb, uint32_t i, Byte_range_ptr &dst) {
struct libusb_transfer *transfer =
USBI_TRANSFER_TO_LIBUSB_TRANSFER(urb.itransfer);
if (IS_XFEROUT(transfer)) {
addr_t src = (addr_t)urb.buf+isoc_packet_offset(i, transfer);
memcpy(dst.start, (void*)src, min(transfer->iso_packet_desc[i].length,
dst.num_bytes));
}
return transfer->iso_packet_desc[i].length;
},
/* consume in results of isochronous packet i */
[] (Urb &urb, uint32_t i, Const_byte_range_ptr const &src) {
struct libusb_transfer *transfer =
USBI_TRANSFER_TO_LIBUSB_TRANSFER(urb.itransfer);
addr_t dst = (addr_t)urb.buf+isoc_packet_offset(i, transfer);
memcpy((void*)dst, src.start, src.num_bytes);
transfer->iso_packet_desc[i].actual_length = src.num_bytes;
transfer->iso_packet_desc[i].status = LIBUSB_TRANSFER_COMPLETED;
},
/* complete USB request */
[this] (Urb &urb, Usb::Tagged_packet::Return_value v)
{
if (v != Usb::Tagged_packet::OK)
error("transfer failed, return value ", (int)v);
if (!urb.itransfer)
return;
libusb_context *ctx = _device._open ? ITRANSFER_CTX(urb.itransfer)
: nullptr;
usbi_signal_transfer_completion(urb.itransfer);
if (ctx) usbi_signal_event(ctx);
destroy(_device._iface_slab, &urb);
});
}
void Usb_device::_wait_for_urb(Urb &urb)
{
while (!urb.completed()) {
handle_events();
struct pollfd pollfds {
.fd = vfs_libusb_fd,
.events = POLLIN,
.revents = 0
};
int poll_result = poll(&pollfds, 1, -1);
if ((poll_result != 1) || !(pollfds.revents & POLLIN))
error("could not complete request");
}
}
void Usb_device::handle_events()
{
_device.update_urbs<Urb>(
/* produce out content */
[] (Urb &urb, Byte_range_ptr &dst) {
memcpy(dst.start, urb.buf, min(dst.num_bytes, urb.size)); },
/* consume in results */
[] (Urb &urb, Const_byte_range_ptr const &src) {
memcpy(urb.buf, src.start, min(src.num_bytes, urb.size));
if (urb.itransfer) urb.itransfer->transferred = src.num_bytes;
},
/* complete USB request */
[this] (Urb &urb, Usb::Tagged_packet::Return_value v)
{
if (v != Usb::Tagged_packet::OK)
error("control transfer failed, return value ", (int)v);
if (!urb.itransfer)
return;
libusb_context *ctx = _open ? ITRANSFER_CTX(urb.itransfer)
: nullptr;
usbi_signal_transfer_completion(urb.itransfer);
if (ctx) usbi_signal_event(ctx);
destroy(_alloc, &urb);
});
}
Constructible<Usb_device>& Usb_device::singleton()
{
static Constructible<Usb_device> dev {};
return dev;
}
static Usb_device& device()
{
struct Libusb_not_initialized {};
if (!Usb_device::singleton().constructed())
throw Libusb_not_initialized();
return *Usb_device::singleton();
}
void libusb_genode_backend_init(Env &env, Allocator &alloc,
Signal_context_capability handler)
{
Usb_device::singleton().construct(env, alloc, handler);
}
static int genode_init(struct libusb_context* ctx)
{
if (!device_instance) {
if (vfs_libusb_fd == -1) {
vfs_libusb_fd = open("/dev/libusb", O_RDONLY);
if (vfs_libusb_fd == -1) {
Genode::error("could not open /dev/libusb");
return LIBUSB_ERROR_OTHER;
}
device_instance = new (libc_alloc) Usb_device(usb_connection,
vfs_libusb_fd);
} else {
Genode::error("tried to init genode usb context twice");
return LIBUSB_ERROR_OTHER;
@ -305,11 +276,11 @@ static int genode_init(struct libusb_context* ctx)
static void genode_exit(void)
{
if (device_instance) {
destroy(libc_alloc, device_instance);
device_instance = nullptr;
Usb_device::singleton().constructed();
Usb_device::singleton().destruct();
if (vfs_libusb_fd != -1) {
close(vfs_libusb_fd);
usb_connection = nullptr;
vfs_libusb_fd = -1;
}
}
@ -341,27 +312,7 @@ int genode_get_device_list(struct libusb_context *ctx,
/* initialize device structure */
dev->bus_number = busnum;
dev->device_address = devaddr;
Usb_device *usb_device = device_instance;
*(Usb_device**)dev->os_priv = usb_device;
switch (usb_device->device_descriptor.speed) {
case Usb::Device::SPEED_LOW:
dev->speed = LIBUSB_SPEED_LOW;
break;
case Usb::Device::SPEED_FULL:
dev->speed = LIBUSB_SPEED_FULL;
break;
case Usb::Device::SPEED_HIGH:
dev->speed = LIBUSB_SPEED_HIGH;
break;
case Usb::Device::SPEED_SUPER:
dev->speed = LIBUSB_SPEED_SUPER;
break;
default:
Genode::warning(__PRETTY_FUNCTION__, ": unknown device speed");
dev->speed = LIBUSB_SPEED_UNKNOWN;
}
dev->speed = device()._speed;
int result = usbi_sanitize_device(dev);
if (result < 0) {
@ -386,9 +337,7 @@ int genode_get_device_list(struct libusb_context *ctx,
static int genode_open(struct libusb_device_handle *dev_handle)
{
if (device_instance)
device_instance->open();
device().open();
return usbi_add_pollfd(HANDLE_CTX(dev_handle), vfs_libusb_fd,
POLLIN);
}
@ -396,47 +345,47 @@ static int genode_open(struct libusb_device_handle *dev_handle)
static void genode_close(struct libusb_device_handle *dev_handle)
{
if (device_instance)
device_instance->close();
device().close();
usbi_remove_pollfd(HANDLE_CTX(dev_handle), vfs_libusb_fd);
}
static int genode_get_device_descriptor(struct libusb_device *device,
static int genode_get_device_descriptor(struct libusb_device *,
unsigned char* buffer,
int *host_endian)
{
Usb_device *usb_device = *(Usb_device**)device->os_priv;
Genode::memcpy(buffer, &usb_device->device_descriptor,
sizeof(libusb_device_descriptor));
Usb_device::Urb urb(buffer, sizeof(libusb_device_descriptor),
device()._device, LIBUSB_REQUEST_GET_DESCRIPTOR,
LIBUSB_ENDPOINT_IN, (LIBUSB_DT_DEVICE << 8) | 0, 0,
LIBUSB_DT_DEVICE_SIZE);
device()._wait_for_urb(urb);
*host_endian = 0;
return LIBUSB_SUCCESS;
}
static int genode_get_config_descriptor(struct libusb_device *device,
uint8_t config_index,
static int genode_get_config_descriptor(struct libusb_device *,
uint8_t idx,
unsigned char *buffer,
size_t len,
int *host_endian)
{
if (config_index != 0) {
Genode::error(__PRETTY_FUNCTION__,
": only the first configuration is supported");
return LIBUSB_ERROR_NOT_SUPPORTED;
}
/* read minimal config descriptor */
genode_usb_config_descriptor desc;
Usb_device::Urb cfg(&desc, sizeof(desc), device()._device,
LIBUSB_REQUEST_GET_DESCRIPTOR, LIBUSB_ENDPOINT_IN,
(LIBUSB_DT_CONFIG << 8) | idx, 0, sizeof(desc));
device()._wait_for_urb(cfg);
Usb_device *usb_device = *(Usb_device**)device->os_priv;
Genode::memcpy(buffer, usb_device->raw_config_descriptor, len);
/* read again whole configuration */
Usb_device::Urb all(buffer, len, device()._device,
LIBUSB_REQUEST_GET_DESCRIPTOR, LIBUSB_ENDPOINT_IN,
(LIBUSB_DT_CONFIG << 8) | idx, 0,
(size_t)desc.total_length);
device()._wait_for_urb(all);
*host_endian = 0;
return len;
return desc.total_length;
}
@ -445,7 +394,6 @@ static int genode_get_active_config_descriptor(struct libusb_device *device,
size_t len,
int *host_endian)
{
/* only configuration 0 is currently supported */
return genode_get_config_descriptor(device, 0, buffer, len, host_endian);
}
@ -464,21 +412,24 @@ static int genode_set_configuration(struct libusb_device_handle *dev_handle,
static int genode_claim_interface(struct libusb_device_handle *dev_handle,
int interface_number)
{
Usb_device *usb_device = *(Usb_device**)dev_handle->dev->os_priv;
bool found = false;
try {
usb_device->usb_connection->claim_interface(interface_number);
} catch (Usb::Session::Interface_not_found) {
Genode::error(__PRETTY_FUNCTION__, ": interface not found");
return LIBUSB_ERROR_NOT_FOUND;
} catch (Usb::Session::Interface_already_claimed) {
Genode::error(__PRETTY_FUNCTION__, ": interface already claimed");
device()._interfaces.for_each([&] (Usb_device::Interface const &iface) {
if (iface.index().number == interface_number) found = true; });
if (found) {
error(__PRETTY_FUNCTION__, ": interface already claimed");
return LIBUSB_ERROR_BUSY;
} catch (...) {
Genode::error(__PRETTY_FUNCTION__, ": unknown exception");
}
if (interface_number > 0xff || interface_number < 0) {
error(__PRETTY_FUNCTION__, ": invalid interface number ",
interface_number);
return LIBUSB_ERROR_OTHER;
}
new (device()._alloc)
Usb_device::Interface(device(), (uint8_t) interface_number);
return LIBUSB_SUCCESS;
}
@ -486,19 +437,16 @@ static int genode_claim_interface(struct libusb_device_handle *dev_handle,
static int genode_release_interface(struct libusb_device_handle *dev_handle,
int interface_number)
{
Usb_device *usb_device = *(Usb_device**)dev_handle->dev->os_priv;
int ret = LIBUSB_ERROR_NOT_FOUND;
try {
usb_device->usb_connection->release_interface(interface_number);
} catch (Usb::Session::Interface_not_found) {
Genode::error(__PRETTY_FUNCTION__, ": interface not found");
return LIBUSB_ERROR_NOT_FOUND;
} catch (...) {
Genode::error(__PRETTY_FUNCTION__, ": unknown exception");
return LIBUSB_ERROR_OTHER;
}
device()._interfaces.for_each([&] (Usb_device::Interface &iface) {
if (iface.index().number != interface_number)
return;
destroy(device()._alloc, &iface);
ret = LIBUSB_SUCCESS;
});
return LIBUSB_SUCCESS;
return ret;
}
@ -506,10 +454,19 @@ static int genode_set_interface_altsetting(struct libusb_device_handle* dev_hand
int interface_number,
int altsetting)
{
Usb_device *usb_device = *(Usb_device**)dev_handle->dev->os_priv;
using P = Usb::Device::Packet_descriptor;
using Rt = P::Request_type;
return usb_device->altsetting(interface_number, altsetting) ? LIBUSB_SUCCESS
: LIBUSB_ERROR_BUSY;
if (interface_number < 0 || interface_number > 0xff ||
altsetting < 0 || altsetting > 0xff)
return LIBUSB_ERROR_INVALID_PARAM;
Usb_device::Urb urb(nullptr, 0, device()._device, P::Request::SET_INTERFACE,
Rt::value(P::Recipient::IFACE, P::Type::STANDARD,
P::Direction::OUT),
(uint8_t)altsetting, (uint8_t)interface_number, 0);
device()._wait_for_urb(urb);
return LIBUSB_SUCCESS;
}
@ -517,11 +474,8 @@ static int genode_submit_transfer(struct usbi_transfer * itransfer)
{
struct libusb_transfer *transfer =
USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
Usb_device *usb_device = *(Usb_device**)transfer->dev_handle->dev->os_priv;
if (!usb_device->usb_connection->source()->ready_to_submit())
return LIBUSB_ERROR_BUSY;
Usb::Interface::Packet_descriptor::Type type =
Usb::Interface::Packet_descriptor::FLUSH;
switch (transfer->type) {
@ -530,123 +484,49 @@ static int genode_submit_transfer(struct usbi_transfer * itransfer)
struct libusb_control_setup *setup =
(struct libusb_control_setup*)transfer->buffer;
Usb::Packet_descriptor p;
try {
p = usb_device->usb_connection->alloc_packet(setup->wLength);
} catch (Usb::Session::Tx::Source::Packet_alloc_failed) {
return LIBUSB_ERROR_BUSY;
}
p.completion = new (libc_alloc) Completion(itransfer);
p.type = Usb::Packet_descriptor::CTRL;
p.control.request = setup->bRequest;
p.control.request_type = setup->bmRequestType;
p.control.value = setup->wValue;
p.control.index = setup->wIndex;
p.control.timeout = transfer->timeout;
if ((setup->bmRequestType & LIBUSB_ENDPOINT_DIR_MASK) ==
LIBUSB_ENDPOINT_OUT) {
char *packet_content =
usb_device->usb_connection->source()->packet_content(p);
Genode::memcpy(packet_content,
transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE,
setup->wLength);
}
usb_device->usb_connection->source()->submit_packet(p);
void * addr = transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE;
new (device()._alloc)
Usb_device::Urb(addr, setup->wLength, itransfer,
device()._device, setup->bRequest,
setup->bmRequestType, setup->wValue,
setup->wIndex, setup->wLength);
device().handle_events();
return LIBUSB_SUCCESS;
}
case LIBUSB_TRANSFER_TYPE_BULK:
case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
case LIBUSB_TRANSFER_TYPE_INTERRUPT: {
if (IS_XFEROUT(transfer) &&
transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET) {
Genode::error(__PRETTY_FUNCTION__,
": zero packet not supported");
return LIBUSB_ERROR_NOT_SUPPORTED;
}
Usb::Packet_descriptor p;
try {
p = usb_device->usb_connection->alloc_packet(transfer->length);
} catch (Usb::Session::Tx::Source::Packet_alloc_failed) {
return LIBUSB_ERROR_BUSY;
}
if (transfer->type == LIBUSB_TRANSFER_TYPE_INTERRUPT) {
p.type = Usb::Packet_descriptor::IRQ;
p.transfer.polling_interval =
Usb::Packet_descriptor::DEFAULT_POLLING_INTERVAL;
} else
p.type = Usb::Packet_descriptor::BULK;
p.completion = new (libc_alloc) Completion(itransfer);
p.transfer.ep = transfer->endpoint;
if (IS_XFEROUT(transfer)) {
char *packet_content =
usb_device->usb_connection->source()->packet_content(p);
Genode::memcpy(packet_content, transfer->buffer,
transfer->length);
}
usb_device->usb_connection->source()->submit_packet(p);
return LIBUSB_SUCCESS;
}
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: {
size_t total_length = 0;
for (int i = 0; i < transfer->num_iso_packets; i++) {
total_length += transfer->iso_packet_desc[i].length;
}
Usb::Packet_descriptor p;
size_t p_size = Usb::Isoc_transfer::size(total_length);
try {
p = usb_device->usb_connection->alloc_packet(p_size);
} catch (Usb::Session::Tx::Source::Packet_alloc_failed) {
return LIBUSB_ERROR_BUSY;
}
p.type = Usb::Packet_descriptor::ISOC;
p.transfer.polling_interval =
Usb::Packet_descriptor::DEFAULT_POLLING_INTERVAL;
p.completion = new (libc_alloc) Completion(itransfer);
p.transfer.ep = transfer->endpoint;
Usb::Isoc_transfer &isoc =
*(Usb::Isoc_transfer *) usb_device->usb_connection->source()->packet_content(p);
isoc.number_of_packets = transfer->num_iso_packets;
for (int i = 0; i < transfer->num_iso_packets; i++) {
isoc.packet_size[i] = transfer->iso_packet_desc[i].length;
isoc.actual_packet_size[i] = 0;
}
if (IS_XFEROUT(transfer))
Genode::memcpy(isoc.data(), transfer->buffer, transfer->length);
usb_device->usb_connection->source()->submit_packet(p);
return LIBUSB_SUCCESS;
}
type = Usb::Interface::Packet_descriptor::BULK;
break;
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
type = Usb::Interface::Packet_descriptor::IRQ;
break;
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
type = Usb::Interface::Packet_descriptor::ISOC;
break;
default:
usbi_err(TRANSFER_CTX(transfer),
"unknown endpoint type %d", transfer->type);
return LIBUSB_ERROR_INVALID_PARAM;
}
bool found = false;
device()._interfaces.for_each([&] (Usb_device::Interface &iface) {
iface.for_each_endpoint([&] (Usb::Endpoint &ep) {
if (found || transfer->endpoint != ep.address())
return;
found = true;
new (device()._iface_slab)
Usb_device::Interface::Urb(transfer->buffer, transfer->length,
itransfer, iface, ep, type,
transfer->length,
transfer->num_iso_packets);
iface.handle_events();
});
});
return found ? LIBUSB_SUCCESS : LIBUSB_ERROR_NOT_FOUND;
}
@ -659,16 +539,14 @@ static int genode_cancel_transfer(struct usbi_transfer * itransfer)
static void genode_clear_transfer_priv(struct usbi_transfer * itransfer) { }
static int genode_handle_events(struct libusb_context *,
struct pollfd *,
POLL_NFDS_TYPE, int)
static int genode_handle_events(struct libusb_context *, struct pollfd *,
POLL_NFDS_TYPE, int)
{
if (device_instance) {
device_instance->handle_events();
return LIBUSB_SUCCESS;
}
return LIBUSB_ERROR_NO_DEVICE;
libusb_genode_backend_signaling = false;
device().handle_events();
device()._interfaces.for_each([&] (Usb_device::Interface &iface) {
iface.handle_events(); });
return LIBUSB_SUCCESS;
}
@ -679,8 +557,7 @@ static int genode_handle_transfer_completion(struct usbi_transfer * itransfer)
if (itransfer->flags & USBI_TRANSFER_CANCELLING)
status = LIBUSB_TRANSFER_CANCELLED;
return usbi_handle_transfer_completion(itransfer,
status);
return usbi_handle_transfer_completion(itransfer, status);
}
@ -743,7 +620,7 @@ const struct usbi_os_backend genode_usb_raw_backend = {
/*.get_timerfd_clockid =*/ NULL,
#endif
/*.device_priv_size =*/ sizeof(Usb_device*),
/*.device_priv_size =*/ 0,
/*.device_handle_priv_size =*/ 0,
/*.transfer_priv_size =*/ 0,
};

File diff suppressed because it is too large Load Diff

View File

@ -886,7 +886,7 @@ typedef struct USBHostDevice
} USBHostDevice;
USBHostDevice *create_usbdevice(void *data);
USBHostDevice *create_usbdevice(void *data, int speed);
void remove_usbdevice(USBHostDevice *device);
void usb_host_destroy();

View File

@ -448,12 +448,14 @@ static USBHostDevice *_create_usbdevice(int const type, FUNC const &fn_init)
}
USBHostDevice *create_usbdevice(void *data)
USBHostDevice *create_usbdevice(void *data, int speed)
{
return _create_usbdevice(Object_pool::USB_HOST_DEVICE,
[&](Wrapper &obj) {
/* set data pointer */
obj._usb_host_device.data = data;
obj._usb_device.speed = speed;
obj._usb_device.speedmask = (1 << speed);
});
}

View File

@ -14,17 +14,18 @@
/* Genode includes */
#include <base/allocator_avl.h>
#include <usb_session/connection.h>
#include <util/xml_node.h>
#include <vfs/file_system_factory.h>
#include <vfs/single_file_system.h>
using namespace Genode;
/*
* This function is implemented in the Genode backend
* of libusb.
* These functions are implemented in the Genode backend of libusb.
*/
extern void libusb_genode_usb_connection(Usb::Connection *);
extern void libusb_genode_backend_init(Env&, Allocator&, Signal_context_capability);
extern bool libusb_genode_backend_signaling;
class Libusb_file_system : public Vfs::Single_file_system
{
@ -36,30 +37,15 @@ class Libusb_file_system : public Vfs::Single_file_system
{
private:
Genode::Env &_env;
Vfs::Env::User &_vfs_user;
Genode::Allocator_avl _alloc_avl;
Env &_env;
Vfs::Env::User &_vfs_user;
Genode::Io_signal_handler<Libusb_vfs_handle> _state_changed_handler {
_env.ep(), *this, &Libusb_vfs_handle::_handle_state_changed };
Io_signal_handler<Libusb_vfs_handle> _handler {
_env.ep(), *this, &Libusb_vfs_handle::_handle };
void _handle_state_changed()
{
/*
* The handler is installed only to receive state-change
* signals from the USB connection using the 'Usb_device'
* constructor.
*/
}
Usb::Connection _usb_connection {
_env, &_alloc_avl, "usb_device", 1024*1024, _state_changed_handler };
Genode::Io_signal_handler<Libusb_vfs_handle> _ack_avail_handler {
_env.ep(), *this, &Libusb_vfs_handle::_handle_ack_avail };
void _handle_ack_avail()
void _handle()
{
libusb_genode_backend_signaling = true;
_vfs_user.wakeup_vfs_user();
}
@ -67,49 +53,35 @@ class Libusb_file_system : public Vfs::Single_file_system
Libusb_vfs_handle(Directory_service &ds,
File_io_service &fs,
Genode::Allocator &alloc,
Genode::Env &env,
Allocator &alloc,
Env &env,
Vfs::Env::User &vfs_user)
:
Single_vfs_handle(ds, fs, alloc, 0),
_env(env), _vfs_user(vfs_user), _alloc_avl(&alloc)
_env(env), _vfs_user(vfs_user)
{
_usb_connection.tx_channel()->sigh_ack_avail(_ack_avail_handler);
Genode::log("libusb: waiting until device is plugged...");
while (!_usb_connection.plugged())
_env.ep().wait_and_dispatch_one_io_signal();
Genode::log("libusb: device is plugged");
libusb_genode_usb_connection(&_usb_connection);
log("libusb: waiting until device is plugged...");
libusb_genode_backend_init(env, alloc, _handler);
log("libusb: device is plugged");
}
bool read_ready() const override
{
auto &nonconst_this = const_cast<Libusb_vfs_handle &>(*this);
return nonconst_this._usb_connection.source()->ack_avail();
}
bool read_ready() const override {
return libusb_genode_backend_signaling; }
Read_result read(Genode::Byte_range_ptr const &, Genode::size_t &) override
{
return READ_ERR_IO;
}
Read_result read(Byte_range_ptr const &, size_t &) override {
return READ_ERR_IO; }
bool write_ready() const override
{
return true;
}
bool write_ready() const override {
return true; }
Write_result write(Genode::Const_byte_range_ptr const &, Genode::size_t &) override
{
return WRITE_ERR_IO;
}
Write_result write(Const_byte_range_ptr const &,
size_t &) override {
return WRITE_ERR_IO; }
};
public:
Libusb_file_system(Vfs::Env &env,
Genode::Xml_node config)
Libusb_file_system(Vfs::Env &env, Xml_node config)
:
Single_file_system(Vfs::Node_type::CONTINUOUS_FILE, name(),
Vfs::Node_rwx::ro(), config),
@ -124,9 +96,9 @@ class Libusb_file_system : public Vfs::Single_file_system
** Directory service interface **
*********************************/
Open_result open(char const *path, unsigned,
Vfs::Vfs_handle **out_handle,
Genode::Allocator &alloc) override
Open_result open(char const *path, unsigned,
Vfs::Vfs_handle **out_handle,
Allocator &alloc) override
{
if (!_single_file(path))
return OPEN_ERR_UNACCESSIBLE;
@ -141,7 +113,7 @@ class Libusb_file_system : public Vfs::Single_file_system
struct Libusb_factory : Vfs::File_system_factory
{
Vfs::File_system *create(Vfs::Env &env, Genode::Xml_node node) override
Vfs::File_system *create(Vfs::Env &env, Xml_node node) override
{
return new (env.alloc()) Libusb_file_system(env, node);
}

View File

@ -94,4 +94,11 @@ typedef struct genode_shared_dataspace *
typedef void
(*genode_shared_dataspace_free_t) (struct genode_shared_dataspace * ds);
struct genode_buffer
{
void * addr;
unsigned long size;
};
typedef struct genode_buffer genode_buffer_t;
#endif /* _INCLUDE__GENODE_C_API__BASE_H_ */

View File

@ -15,110 +15,77 @@
#define _GENODE_C_API__USB_H_
#include <genode_c_api/base.h>
#include <usb_session/types.h>
struct genode_usb_session; /* definition is private to the implementation */
struct genode_usb_device;
struct genode_usb_configuration;
struct genode_usb_interface;
typedef unsigned short genode_usb_vendor_id_t;
typedef unsigned short genode_usb_product_id_t;
typedef unsigned int genode_usb_bus_num_t;
typedef unsigned int genode_usb_dev_num_t;
typedef unsigned char genode_usb_class_num_t;
typedef unsigned int genode_usb_bus_num_t;
typedef unsigned int genode_usb_dev_num_t;
#ifdef __cplusplus
extern "C" {
#endif
/********************
** Initialization **
********************/
/**
* Callback to copy over config descriptor for given device
*/
typedef unsigned (*genode_usb_rpc_config_desc_t)
(genode_usb_bus_num_t bus, genode_usb_dev_num_t dev,
void * dev_desc, void * conf_desc);
/**
* Callback that returns number of alt-settings of an interface for given device
*/
typedef int (*genode_usb_rpc_alt_settings_t)
(genode_usb_bus_num_t bus, genode_usb_dev_num_t dev, unsigned idx);
/**
* Callback to copy over interface descriptor for given device/interface
*/
typedef int (*genode_usb_rpc_iface_desc_t)
(genode_usb_bus_num_t bus, genode_usb_dev_num_t dev, unsigned idx,
unsigned alt, void * buf, unsigned long buf_size, int * active);
/**
* Callback to copy over additional vendor specific data of an interface
*/
typedef int (*genode_usb_rpc_iface_extra_t)
(genode_usb_bus_num_t bus, genode_usb_dev_num_t dev, unsigned idx,
unsigned alt, void * buf, unsigned long buf_size);
/**
* Callback to copy over endpoint descriptor for given device/iface/endpoint
*/
typedef int (*genode_usb_rpc_endp_desc_t)
(genode_usb_bus_num_t bus, genode_usb_dev_num_t dev, unsigned idx,
unsigned alt, unsigned endp, void * buf, unsigned long buf_size);
/**
* Callback to claim a given interface
*/
typedef int (*genode_usb_rpc_claim_t)
(genode_usb_bus_num_t bus, genode_usb_dev_num_t dev, unsigned iface);
/**
* Callback to release a given interface
*/
typedef int (*genode_usb_rpc_release_t)
(genode_usb_bus_num_t bus, genode_usb_dev_num_t dev, unsigned iface);
/**
* Callback to release all interfaces
*/
typedef void (*genode_usb_rpc_release_all_t)
(genode_usb_bus_num_t bus, genode_usb_dev_num_t dev);
struct genode_usb_rpc_callbacks {
genode_shared_dataspace_alloc_attach_t alloc_fn;
genode_shared_dataspace_free_t free_fn;
genode_usb_rpc_config_desc_t cfg_desc_fn;
genode_usb_rpc_alt_settings_t alt_settings_fn;
genode_usb_rpc_iface_desc_t iface_desc_fn;
genode_usb_rpc_iface_extra_t iface_extra_fn;
genode_usb_rpc_endp_desc_t endp_desc_fn;
genode_usb_rpc_claim_t claim_fn;
genode_usb_rpc_release_t release_fn;
genode_usb_rpc_release_all_t release_all_fn;
};
/**
* Initialize USB root component
*
* \param handler signal handler to be installed at each USB session
*/
void genode_usb_init(struct genode_env * env,
struct genode_allocator * alloc,
struct genode_signal_handler * handler,
struct genode_usb_rpc_callbacks * callbacks);
/************************************
** USB device lifetime management **
************************************/
void genode_usb_announce_device(genode_usb_vendor_id_t vendor,
genode_usb_product_id_t product,
genode_usb_class_num_t cla,
genode_usb_bus_num_t bus,
genode_usb_dev_num_t dev);
/**
* Callback to announce configuration of a device
*/
typedef void (*genode_usb_dev_add_config_t)
(struct genode_usb_device *dev, unsigned idx, void *opaque_data);
/**
* Callback to announce interface of a device configuration
*/
typedef void (*genode_usb_dev_add_iface_t)
(struct genode_usb_configuration *cfg, unsigned idx, void *opaque_data);
/**
* Callback to announce endpoint of an interface
*/
typedef void (*genode_usb_dev_add_endp_t)
(struct genode_usb_interface *cfg, unsigned idx, void *opaque_data);
/**
* Callback to request string item of a device
*/
typedef void (*genode_usb_dev_string_item_t)
(genode_buffer_t string, void *opaque_data);
void
genode_usb_device_add_endpoint(struct genode_usb_interface *iface,
struct genode_usb_endpoint_descriptor desc);
void
genode_usb_device_add_interface(struct genode_usb_configuration *cfg,
genode_usb_dev_string_item_t info_string,
struct genode_usb_interface_descriptor desc,
genode_usb_dev_add_endp_t callback,
void *opaque_data,
bool active);
void
genode_usb_device_add_configuration(struct genode_usb_device *dev,
struct genode_usb_config_descriptor desc,
genode_usb_dev_add_iface_t callback,
void *opaque_data,
bool active);
void genode_usb_announce_device(genode_usb_bus_num_t bus,
genode_usb_dev_num_t dev,
genode_usb_speed_t speed,
genode_usb_dev_string_item_t manufacturer_string,
genode_usb_dev_string_item_t product_string,
struct genode_usb_device_descriptor desc,
genode_usb_dev_add_config_t callback,
void *opaque_data);
void genode_usb_discontinue_device(genode_usb_bus_num_t bus,
genode_usb_dev_num_t dev);
@ -128,145 +95,104 @@ void genode_usb_discontinue_device(genode_usb_bus_num_t bus,
** USB session request handling **
**********************************/
typedef unsigned short genode_usb_session_handle_t;
typedef unsigned short genode_usb_request_handle_t;
typedef void* genode_usb_request_handle_t;
struct genode_usb_request_string
{
unsigned char index;
unsigned length;
};
enum Request_return { OK, NO_DEVICE, INVALID, TIMEOUT, HALT, };
typedef enum Request_return genode_usb_request_ret_t;
struct genode_usb_request_control
{
unsigned char request;
unsigned char request_type;
unsigned short value;
unsigned short index;
int actual_size;
int timeout;
};
struct genode_usb_request_transfer
{
unsigned char ep;
int actual_size;
int polling_interval;
};
typedef void (*genode_usb_req_control_t)
(genode_usb_request_handle_t handle,
unsigned char ctrl_request,
unsigned char ctrl_request_type,
unsigned short ctrl_value,
unsigned short ctrl_index,
unsigned long ctrl_timeout,
genode_buffer_t payload,
void *opaque_data);
enum Isoc { MAX_PACKETS = 32 };
typedef void (*genode_usb_req_irq_t)
(genode_usb_request_handle_t handle,
unsigned char ep,
genode_buffer_t payload,
void *opaque_data);
struct genode_usb_isoc_transfer
{
unsigned number_of_packets;
unsigned packet_size[MAX_PACKETS];
unsigned actual_packet_size[MAX_PACKETS];
char data[];
};
typedef void (*genode_usb_req_bulk_t)
(genode_usb_request_handle_t handle,
unsigned char ep,
genode_buffer_t payload,
void *opaque_data);
enum Urb_type { CTRL, BULK, IRQ, ISOC, ALT_SETTING, CONFIG, NONE };
typedef enum Urb_type genode_usb_urb_t;
struct genode_usb_request_urb
{
genode_usb_urb_t type;
void * req;
};
struct genode_usb_buffer
{
void * addr;
unsigned long size;
};
static inline struct genode_usb_request_control *
genode_usb_get_request_control(struct genode_usb_request_urb * urb)
{
return (urb->type == CTRL) ? (struct genode_usb_request_control*)urb->req : 0;
}
static inline struct genode_usb_request_transfer *
genode_usb_get_request_transfer(struct genode_usb_request_urb * urb)
{
return (urb->type != CTRL) ? (struct genode_usb_request_transfer*)urb->req : 0;
}
enum Request_return_error {
NO_ERROR,
INTERFACE_OR_ENDPOINT_ERROR,
MEMORY_ERROR,
NO_DEVICE_ERROR,
PACKET_INVALID_ERROR,
PROTOCOL_ERROR,
STALL_ERROR,
TIMEOUT_ERROR,
UNKNOWN_ERROR
};
typedef enum Request_return_error genode_usb_request_ret_t;
typedef void (*genode_usb_req_urb_t)
(struct genode_usb_request_urb req,
genode_usb_session_handle_t session_handle,
genode_usb_request_handle_t request_handle,
struct genode_usb_buffer payload,
void * opaque_data);
typedef void (*genode_usb_req_string_t)
(struct genode_usb_request_string * req,
genode_usb_session_handle_t session_handle,
genode_usb_request_handle_t request_handle,
struct genode_usb_buffer payload,
void * opaque_data);
typedef void (*genode_usb_req_altsetting_t)
(unsigned iface, unsigned alt_setting,
genode_usb_session_handle_t session_handle,
genode_usb_request_handle_t request_handle,
void * opaque_data);
typedef void (*genode_usb_req_config_t)
(unsigned config_idx,
genode_usb_session_handle_t session_handle,
genode_usb_request_handle_t request_handle,
void * opaque_data);
typedef void (*genode_usb_req_isoc_t)
(genode_usb_request_handle_t handle,
unsigned char ep,
genode_uint32_t number_of_packets,
struct genode_usb_isoc_descriptor *packets,
genode_buffer_t payload,
void *opaque_data);
typedef void (*genode_usb_req_flush_t)
(unsigned char ep,
genode_usb_session_handle_t session_handle,
genode_usb_request_handle_t request_handle,
void * opaque_data);
typedef genode_usb_request_ret_t (*genode_usb_response_t)
(struct genode_usb_request_urb req,
struct genode_usb_buffer payload,
void * opaque_data);
(unsigned char ep,
genode_usb_request_handle_t handle,
void *opaque_data);
struct genode_usb_request_callbacks {
genode_usb_req_urb_t urb_fn;
genode_usb_req_string_t string_fn;
genode_usb_req_altsetting_t altsetting_fn;
genode_usb_req_config_t config_fn;
genode_usb_req_flush_t flush_fn;
genode_usb_req_control_t ctrl_fn;
genode_usb_req_irq_t irq_fn;
genode_usb_req_bulk_t bulk_fn;
genode_usb_req_isoc_t isoc_fn;
genode_usb_req_flush_t flush_fn;
};
genode_usb_session_handle_t genode_usb_session_by_bus_dev(genode_usb_bus_num_t bus,
genode_usb_dev_num_t dev);
typedef struct genode_usb_request_callbacks * genode_usb_req_callback_t;
int genode_usb_request_by_session(genode_usb_session_handle_t session_handle,
struct genode_usb_request_callbacks * const c,
void * callback_data);
bool genode_usb_device_acquired(genode_usb_bus_num_t bus,
genode_usb_dev_num_t dev);
void genode_usb_ack_request(genode_usb_session_handle_t session_handle,
genode_usb_request_handle_t request_handle,
genode_usb_response_t callback,
void * callback_data);
bool
genode_usb_request_by_bus_dev(genode_usb_bus_num_t bus,
genode_usb_dev_num_t dev,
genode_usb_req_callback_t const callback,
void *opaque_data);
void genode_usb_ack_request(genode_usb_request_handle_t request_handle,
genode_usb_request_ret_t ret,
genode_uint32_t *actual_sizes);
void genode_usb_notify_peers(void);
void genode_usb_handle_empty_sessions(void);
void genode_usb_handle_disconnected_sessions(void);
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
#include <base/env.h>
#include <base/signal.h>
/**
* Callback to signal release of device(s)
*/
typedef void (*genode_usb_dev_release_t) (genode_usb_bus_num_t bus,
genode_usb_dev_num_t dev);
namespace Genode_c_api {
using namespace Genode;
/**
* Initialize USB root component
*/
void initialize_usb_service(Env &env,
Signal_context_capability sigh_cap,
genode_shared_dataspace_alloc_attach_t alloc_fn,
genode_shared_dataspace_free_t free_fn,
genode_usb_dev_release_t release_fn);
}
#endif /* __cplusplus */
#endif /* _GENODE_C_API__USB_H_ */

View File

@ -1,6 +1,7 @@
/*
* \brief C-API Genode USB-client backend
* \author Sebastian Sumpf
* \author Stefan Kalkowski
* \date 2023-06-29
*/
@ -15,133 +16,136 @@
#define __GENODE_C_API__USB_CLIENT_H_
#include <base/fixed_stdint.h>
#include <genode_c_api/usb.h>
#include <genode_c_api/base.h>
#include <usb_session/types.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef unsigned long genode_usb_client_handle_t;
/*************************
** Lifetime management **
*************************/
struct genode_range_allocator;
typedef unsigned long genode_usb_client_dev_handle_t;
struct genode_usb_device_descriptor
{
genode_uint8_t length;
genode_uint8_t type;
genode_uint16_t usb;
genode_uint8_t dclass;
genode_uint8_t dsubclass;
genode_uint8_t dprotocol;
genode_uint8_t max_packet_size;
genode_uint16_t vendor_id;
genode_uint16_t product_id;
genode_uint16_t device_release;
genode_uint8_t manufactorer_index;
genode_uint8_t product_index;
genode_uint8_t serial_number_index;
genode_uint8_t num_configs;
/**
* Callback to announce a device
*/
typedef void* (*genode_usb_client_dev_add_t)
(genode_usb_client_dev_handle_t handle, char const *name,
genode_usb_speed_t speed);
/*
* Genode extensions (POD only)
*/
unsigned bus;
unsigned num ;
unsigned speed;
} __attribute__((packed));
/**
* Callback to delete a device
*/
typedef void (*genode_usb_client_dev_del_t)
(genode_usb_client_dev_handle_t handle, void *opaque_data);
void genode_usb_client_update(genode_usb_client_dev_add_t add,
genode_usb_client_dev_del_t del);
/******************************************
** USB device and interface interaction **
******************************************/
typedef enum {
INVALID,
HALT,
NO_DEVICE,
NO_MEMORY,
TIMEOUT,
OK
} genode_usb_client_ret_val_t;
/**
* Callback to produce out content of an USB request
*/
typedef void (*genode_usb_client_produce_out_t)
(void *opaque_data, genode_buffer_t buffer);
/**
* Callback to consume in result of an USB request
*/
typedef void (*genode_usb_client_consume_in_t)
(void *opaque_data, genode_buffer_t buffer);
/**
* Callback to produce out content of isochronous packet i
*/
typedef genode_uint32_t (*genode_usb_client_produce_out_isoc_t)
(void *opaque_data, genode_uint32_t i, genode_buffer_t buffer);
/**
* Callback to consume in result of isochronous packet i
*/
typedef void (*genode_usb_client_consume_in_isoc_t)
(void *opaque_data, genode_uint32_t i, genode_buffer_t buffer);
/**
* Callback to complete an USB request
*/
typedef void (*genode_usb_client_complete_t)
(void *opaque_data, genode_usb_client_ret_val_t result);
genode_usb_client_ret_val_t
genode_usb_client_device_control(genode_usb_client_dev_handle_t handle,
genode_uint8_t request,
genode_uint8_t request_type,
genode_uint16_t value,
genode_uint16_t index,
unsigned long size,
void *opaque_data);
void
genode_usb_client_device_update(genode_usb_client_produce_out_t out,
genode_usb_client_consume_in_t in,
genode_usb_client_produce_out_isoc_t out_isoc,
genode_usb_client_consume_in_isoc_t in_isoc,
genode_usb_client_complete_t complete);
struct genode_usb_config_descriptor
{
genode_uint8_t length;
genode_uint8_t type;
genode_uint16_t total_length;
genode_uint8_t num_interfaces;
genode_uint8_t config_value;
genode_uint8_t config_index;
genode_uint8_t attributes;
genode_uint8_t max_power;
} __attribute__((packed));
typedef enum { BULK, IRQ, ISOC, FLUSH } genode_usb_client_iface_type_t;
void
genode_usb_client_claim_interface(genode_usb_client_dev_handle_t handle,
unsigned interface_num);
genode_usb_client_handle_t
genode_usb_client_create(struct genode_env *env,
struct genode_allocator *md_alloc,
struct genode_range_allocator *alloc,
char const *label,
struct genode_signal_handler *handler);
void
genode_usb_client_release_interface(genode_usb_client_dev_handle_t handle,
unsigned interface_num);
void genode_usb_client_destroy(genode_usb_client_handle_t handle,
struct genode_allocator *md_alloc);
void genode_usb_client_sigh_ack_avail(genode_usb_client_handle_t handle,
struct genode_signal_handler *handler);
int genode_usb_client_config_descriptor(genode_usb_client_handle_t handle,
struct genode_usb_device_descriptor *device_descr,
struct genode_usb_config_descriptor *config_descr);
bool genode_usb_client_plugged(genode_usb_client_handle_t handle);
void genode_usb_client_claim_interface(genode_usb_client_handle_t handle,
unsigned interface_num);
void genode_usb_client_release_interface(genode_usb_client_handle_t handle,
unsigned interface_num);
struct genode_usb_altsetting
{
unsigned char interface_number;
unsigned char alt_setting;
};
struct genode_usb_config
{
unsigned char value;
};
struct genode_usb_request_packet
{
unsigned type;
void * req;
};
typedef struct genode_usb_request_packet genode_request_packet_t;
struct genode_usb_client_request_packet
{
genode_request_packet_t request;
struct genode_usb_buffer buffer;
int actual_length;
int error;
void (*complete_callback)(struct genode_usb_client_request_packet *);
void (*free_callback) (struct genode_usb_client_request_packet *);
void *completion;
void *opaque_data;
};
bool genode_usb_client_request(genode_usb_client_handle_t handle,
struct genode_usb_client_request_packet *request);
void genode_usb_client_request_submit(genode_usb_client_handle_t handle,
struct genode_usb_client_request_packet *request);
void genode_usb_client_request_finish(genode_usb_client_handle_t handle,
struct genode_usb_client_request_packet *request);
void genode_usb_client_execute_completions(genode_usb_client_handle_t handle);
genode_usb_client_ret_val_t
genode_usb_client_iface_transfer(genode_usb_client_dev_handle_t handle,
genode_usb_client_iface_type_t type,
genode_uint8_t index,
unsigned long size,
void *opaque_data);
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#ifdef __cplusplus
#include <base/allocator.h>
#include <base/env.h>
#include <base/signal.h>
struct genode_range_allocator : Genode::Range_allocator { };
namespace Genode_c_api {
static inline auto genode_range_allocator_ptr(Genode::Range_allocator &alloc)
{
return static_cast<genode_range_allocator *>(&alloc);
using namespace Genode;
/**
* Initialize USB client c++ backend
*/
void initialize_usb_client(Env &env,
Allocator &alloc,
Signal_context_capability io_handler,
Signal_context_capability rom_handler);
}
#endif /* __cplusplus */
#endif /* __GENODE_C_API__USB_CLIENT_H_ */

View File

@ -1,139 +0,0 @@
/*
* \brief Packet stream helper
* \author Sebastian Sumpf
* \date 2014-12-08
*/
/*
* Copyright (C) 2014-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 _INCLUDE__USB__PACKET_HANDLER_
#define _INCLUDE__USB__PACKET_HANDLER_
#include <usb_session/connection.h>
namespace Usb { class Packet_handler; }
class Usb::Packet_handler
{
private:
Usb::Connection &_connection;
Genode::Entrypoint &_ep;
Io_signal_handler<Packet_handler> _rpc_ack_avail {
_ep, *this, &Packet_handler::_packet_handler };
Io_signal_handler<Packet_handler> _rpc_ready_submit {
_ep, *this, &Packet_handler::_ready_handler };
bool _ready_submit = true;
bool _in_completion = false;
void _packet_handler()
{
if (!_ready_submit)
return;
while (packet_avail()) {
Packet_descriptor p = _connection.source()->get_acked_packet();
if (p.completion) {
_in_completion = true;
p.completion->complete(p);
_in_completion = false;
} else
release(p);
}
}
void _ready_handler()
{
_ready_submit = true;
};
public:
Packet_handler(Connection &connection, Genode::Entrypoint &ep)
: _connection(connection), _ep(ep)
{
/* connect 'ack_avail' to our rpc member */
_connection.tx_channel()->sigh_ack_avail(_rpc_ack_avail);
_connection.tx_channel()->sigh_ready_to_submit(_rpc_ready_submit);
}
/***************************
** Packet stream wrapper **
***************************/
bool packet_avail() const
{
return _connection.source()->ack_avail();
}
void wait_for_packet()
{
if (packet_avail()) { _packet_handler(); }
else { _ep.wait_and_dispatch_one_io_signal(); }
}
Packet_descriptor alloc(size_t size)
{
/* is size larger than packet stream */
if (size > _connection.source()->bulk_buffer_size()) {
Genode::error("packet allocation of (", size, " bytes) too large, "
"buffer has ", _connection.source()->bulk_buffer_size(),
" bytes");
throw Usb::Session::Tx::Source::Packet_alloc_failed();
}
while (true) {
try {
Packet_descriptor p = _connection.alloc_packet(size);
return p;
} catch (Usb::Session::Tx::Source::Packet_alloc_failed) {
/* block until some packets are freed */
wait_for_packet();
}
}
}
void submit(Packet_descriptor &p)
{
/* check if submit queue is full */
if (!_connection.source()->ready_to_submit()) {
_ready_submit = false;
/* wait for ready_to_submit signal */
while (!_ready_submit)
_ep.wait_and_dispatch_one_io_signal();
}
_connection.source()->submit_packet(p);
/*
* If an acknowledgement available signal occurred in the meantime,
* retrieve packets, but avoid recursion if 'submit()' was called
* from the completion handler.
*/
if (packet_avail() && !_in_completion)
_packet_handler();
}
void *content(Packet_descriptor &p)
{
return _connection.source()->packet_content(p);
}
void release(Packet_descriptor &p)
{
_connection.source()->release_packet(p);
}
};
#endif /* _INCLUDE__USB__PACKET_HANDLER_ */

View File

@ -1,223 +0,0 @@
/**
* \brief Basic types for USB
* \author Sebastian Sumpf
* \date 2014-12-08
*/
/*
* Copyright (C) 2014-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 _INCLUDE__USB__TYPES_H_
#define _INCLUDE__USB__TYPES_H_
#include <base/stdint.h>
namespace Usb {
struct Device_descriptor;
struct Config_descriptor;
struct Interface_descriptor;
struct Endpoint_descriptor;
struct String;
struct Interface_extra;
}
namespace Usb {
enum Endpoint_type {
ENDPOINT_BULK = 0x2,
ENDPOINT_INTERRUPT = 0x3,
};
/**
* The following three enums are ORed together to form a control request
* type
*/
enum Endpoint_direction {
ENDPOINT_OUT = 0,
ENDPOINT_IN = 0x80,
};
enum Request_type {
TYPE_STANDARD = 0,
TYPE_CLASS = (1U << 5),
TYPE_VENDOR = (2U << 5),
TYPE_RESERVED = (3U << 5),
};
enum Recipient {
RECIPIENT_DEVICE = 0,
RECIPIENT_INTERFACE = 0x1,
RECIPIENT_ENDPOINT = 0x2,
RECIPIENT_OTHER = 0x3,
};
/**
* UTF-16 string
*/
typedef Genode::uint16_t utf16_t;
}
/**
* String containing UTF-16 plane 0 characters
*/
struct Usb::String
{
utf16_t *string = nullptr;
unsigned length = 0;
void copy(unsigned len, void *from, Genode::Allocator *md_alloc)
{
length = len;
if (len == 0)
return;
string = (utf16_t *)md_alloc->alloc(length * sizeof(utf16_t));
Genode::memcpy(string, from, sizeof(utf16_t) * length);
}
void free(Genode::Allocator *md_alloc)
{
if (!string)
return;
md_alloc->free(string, length * sizeof(utf16_t));
string = nullptr;
}
/**
* Create char version
*/
char *to_char(char *buffer, unsigned len)
{
if (!length)
return (char *)"<unknown>";
len = Genode::min(length, len);
for (unsigned i = 0; i < len; i++)
buffer[i] = (char)(string[i] & 0xff);
buffer[len] = 0;
return buffer;
}
/**
* Print for debugging
*/
void print()
{
char buffer[128];
Genode::log(Genode::Cstring(to_char(buffer, 128)));
}
};
/**
* USB hardware device descriptor
*/
struct Usb::Device_descriptor
{
Genode::uint8_t length = 0;
Genode::uint8_t type = 0x1;
Genode::uint16_t usb = 0; /* USB version in BCD (binary-coded decimal ) */
Genode::uint8_t dclass = 0;
Genode::uint8_t dsubclass = 0;
Genode::uint8_t dprotocol = 0;
Genode::uint8_t max_packet_size = 0; /* of endpoint zero */
Genode::uint16_t vendor_id = 0;
Genode::uint16_t product_id = 0;
Genode::uint16_t device_release = 0; /* release number in BCD */
Genode::uint8_t manufactorer_index = 0; /* index of string describing manufacturer */
Genode::uint8_t product_index = 0;
Genode::uint8_t serial_number_index = 0;
Genode::uint8_t num_configs = 0;
/**
* Genode extensions (POD only)
*/
unsigned bus = 0;
unsigned num = 0;
unsigned speed = 0;
} __attribute__((packed));
/**
* USB hardware configuration descriptor
*/
struct Usb::Config_descriptor
{
Genode::uint8_t length = 0;
Genode::uint8_t type = 0x2;
/*
* Total length of data returned for this configuration. Includes the
* combined length of all descriptors (configuration, interface, endpoint,
* and class or vendor specific) returned for this configuration.
*/
Genode::uint16_t total_length = 0;
Genode::uint8_t num_interfaces = 0;
Genode::uint8_t config_value = 0; /* value used to set this configuration */
Genode::uint8_t config_index = 0; /* index of string descriptor */
Genode::uint8_t attributes = 0;
Genode::uint8_t max_power = 0; /* maximum power consumption */
} __attribute__((packed));
/**
* USB hardware interface descriptor
*/
struct Usb::Interface_descriptor
{
Genode::uint8_t length = 0;
Genode::uint8_t type = 0x4;
Genode::uint8_t number = 0; /* interface number */
Genode::uint8_t alt_settings = 0; /* value used for setting alternate setting
using the 'number' field */
Genode::uint8_t num_endpoints = 0;
Genode::uint8_t iclass = 0;
Genode::uint8_t isubclass = 0;
Genode::uint8_t iprotocol = 0;
Genode::uint8_t interface_index = 0; /* index of string descriptor */
/**
* Genode extensions (POD only)
*/
bool active = false;
} __attribute__((packed));
/**
* Vendor specific data
*/
struct Usb::Interface_extra
{
Genode::uint8_t length;
Genode::uint8_t data[32];
};
/**
* USB hardware endpoint descriptor
*/
struct Usb::Endpoint_descriptor
{
Genode::uint8_t length = 0;
Genode::uint8_t type = 0x5;
Genode::uint8_t address = 0;
Genode::uint8_t attributes = 0;
Genode::uint16_t max_packet_size = 0; /* for this endpoint */
Genode::uint8_t polling_interval = 0;
} __attribute__((packed));
#endif /* _INCLUDE__USB__TYPES_H_ */

View File

@ -1,597 +0,0 @@
/**
* \brief USB session wrapper
* \author Sebastian Sumpf
* \date 2014-12-08
*/
/*
* Copyright (C) 2014-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 _INCLUDE__USB__USB_H_
#define _INCLUDE__USB__USB_H_
#include <base/allocator.h>
#include <base/entrypoint.h>
#include <usb/types.h>
#include <usb/packet_handler.h>
#include <usb_session/connection.h>
#include <base/log.h>
namespace Usb {
/* debugging */
bool constexpr verbose_descr = false;
class Device;
class Config;
class Alternate_interface;
class Interface;
class Endpoint;
class Meta_data;
class Sync_completion;
}
class Usb::Meta_data
{
protected:
Genode::Allocator * const _md_alloc;
Connection &_connection;
Packet_handler &_handler;
public:
Meta_data(Genode::Allocator * const md_alloc, Connection &device,
Packet_handler &handler)
: _md_alloc(md_alloc), _connection(device), _handler(handler) { }
};
/**
* Completion for synchronous calls
*/
class Usb::Sync_completion : Completion
{
private:
bool _completed = false;
Packet_descriptor &_p;
public:
Sync_completion(Packet_handler &handler, Packet_descriptor &p)
: _p(p)
{
Completion *c = p.completion;
p.completion = this;
handler.submit(p);
while (!_completed)
handler.wait_for_packet();
if (c)
c->complete(p);
}
void complete(Packet_descriptor &p) override
{
_p = p;
_completed = true;
}
};
class Usb::Endpoint : public Endpoint_descriptor
{
public:
Endpoint(Endpoint_descriptor &endpoint_descr)
: Endpoint_descriptor(endpoint_descr) { }
bool bulk() const { return (attributes & 0x3) == ENDPOINT_BULK; }
bool interrupt() const { return (attributes & 0x3) == ENDPOINT_INTERRUPT; }
void dump()
{
if (verbose_descr)
Genode::log("\tEndpoint: "
"len: ", Genode::Hex(length), " "
"type: ", Genode::Hex(type), " "
"address: ", Genode::Hex(address), " "
"attributes: ", Genode::Hex(attributes));
}
};
class Usb::Alternate_interface : public Interface_descriptor,
public Meta_data
{
private:
enum { MAX_ENDPOINTS = 16 };
Endpoint *_endpoints[MAX_ENDPOINTS];
/*
* Noncopyable
*/
Alternate_interface(Alternate_interface const &);
Alternate_interface &operator = (Alternate_interface const &);
public:
String interface_string { };
Alternate_interface(Interface_descriptor &interface_desc,
Meta_data &md)
: Interface_descriptor(interface_desc), Meta_data(md)
{
dump();
for (Genode::uint8_t i = 0; i < num_endpoints; i++)
{
Endpoint_descriptor descr;
_connection.endpoint_descriptor(number, alt_settings, i, &descr);
_endpoints[i] = new (_md_alloc) Endpoint(descr);
_endpoints[i]->dump();
}
}
~Alternate_interface()
{
for (unsigned i = 0; i < num_endpoints; i++)
destroy(_md_alloc, _endpoints[i]);
interface_string.free(_md_alloc);
}
Endpoint &endpoint(unsigned index)
{
if (index >= num_endpoints)
throw Session::Invalid_endpoint();
return *_endpoints[index];
}
void dump()
{
if (!verbose_descr)
return;
Genode::warning("Interface: "
"len: ", Genode::Hex(length), " "
"type: ", Genode::Hex(type), " "
"number: ", Genode::Hex(number), " "
"alt_settings: ", Genode::Hex(alt_settings));
Genode::warning(" "
"num_endpoints: ", Genode::Hex(num_endpoints), " "
"class: ", Genode::Hex(iclass), " ",
"subclass: ", Genode::Hex(isubclass), " "
"protocol: ", Genode::Hex(iprotocol));
}
};
class Usb::Interface : public Meta_data
{
private:
friend class Config;
enum { MAX_ALT = 10 };
Alternate_interface *_interface[MAX_ALT];
unsigned _count = 0;
Alternate_interface *_current = nullptr;
bool _claimed = false;
void _check()
{
if (!_claimed)
throw Session::Interface_not_claimed();
}
protected:
void _add(Alternate_interface *iface)
{
_interface[_count++] = iface;
if (iface->active)
_current = iface;
}
public:
Interface(Meta_data &md)
: Meta_data(md) { }
/***************
** Accessors **
***************/
unsigned alternate_count() const { return _count; }
Alternate_interface &current() { return *_current; }
Alternate_interface &alternate_interface(unsigned index)
{
if (index >= _count)
throw Session::Interface_not_found();
return *_interface[index];
}
Endpoint &endpoint(unsigned index) { return _current->endpoint(index); }
/***************************
** Packet stream helpers **
***************************/
Packet_descriptor alloc(size_t size)
{
return _handler.alloc(size);
}
void submit(Packet_descriptor &p)
{
_handler.submit(p);
}
void release(Packet_descriptor &p)
{
_handler.release(p);
}
void *content(Packet_descriptor &p)
{
return _handler.content(p);
}
/******************************
** Interface to USB service **
******************************/
/**
* Claim interface
*/
void claim()
{
_connection.claim_interface(_interface[0]->number);
_claimed = true;
}
/**
* Release interface
*/
void release()
{
if (_claimed)
return;
Packet_descriptor p = alloc(0);
p.type = Packet_descriptor::RELEASE_IF;
p.number = _interface[0]->number;
p.succeded = false;
Sync_completion sync(_handler, p);
if (p.succeded)
_claimed = false;
}
void set_alternate_interface(Alternate_interface &alternate)
{
_check();
Packet_descriptor p = alloc(0);
p.type = Packet_descriptor::ALT_SETTING;
p.succeded = false;
p.interface.number = alternate.number;
p.interface.alt_setting = alternate.alt_settings;
Sync_completion sync(_handler, p);
if (p.succeded)
_current = _interface[p.interface.alt_setting];
}
void control_transfer(Packet_descriptor &p, uint8_t request_type, uint8_t request,
uint16_t value, uint16_t index, int timeout,
bool block = true, Completion *c = nullptr)
{
_check();
p.type = Usb::Packet_descriptor::CTRL;
p.succeded = false;
p.control.request = request;
p.control.request_type = request_type;
p.control.value = value;
p.control.index = index;
p.control.timeout = timeout;
p.completion = c;
if(block) Sync_completion sync(_handler, p);
else _handler.submit(p);
}
void bulk_transfer(Packet_descriptor &p, Endpoint &ep,
bool block = true, Completion *c = nullptr)
{
_check();
if (!ep.bulk())
throw Session::Invalid_endpoint();
p.type = Usb::Packet_descriptor::BULK;
p.succeded = false;
p.transfer.ep = ep.address;
p.completion = c;
if(block) Sync_completion sync(_handler, p);
else _handler.submit(p);
}
void interrupt_transfer(Packet_descriptor &p, Endpoint &ep,
int polling_interval =
Usb::Packet_descriptor::DEFAULT_POLLING_INTERVAL,
bool block = true, Completion *c = nullptr)
{
_check();
if (!ep.interrupt())
throw Session::Invalid_endpoint();
p.type = Usb::Packet_descriptor::IRQ;
p.succeded = false;
p.transfer.ep = ep.address;
p.transfer.polling_interval = polling_interval;
p.completion = c;
if(block) Sync_completion sync(_handler, p);
else _handler.submit(p);
}
};
class Usb::Config : public Config_descriptor,
public Meta_data
{
private:
enum { MAX_INTERFACES = 32 };
/*
* Noncopyable
*/
Config(Config const &);
Config &operator = (Config const &);
Interface *_interfaces[MAX_INTERFACES];
unsigned _total_interfaces = 0;
public:
String config_string { };
Config(Config_descriptor &config_desc, Meta_data &md)
: Config_descriptor(config_desc), Meta_data(md)
{
dump();
for (Genode::uint8_t i = 0; i < num_interfaces; i++) {
Interface_descriptor descr;
_connection.interface_descriptor(i, 0, &descr);
_interfaces[descr.number] = new(_md_alloc) Interface(md);
/* read number of alternative settings */
unsigned alt_settings = _connection.alt_settings(i);
_total_interfaces += alt_settings;
/* alt settings */
for (unsigned j = 0; j < alt_settings; j++) {
_connection.interface_descriptor(i, j, &descr);
if (descr.number != i)
error("Interface number != index");
_interfaces[descr.number]->_add(new(_md_alloc) Alternate_interface(descr, md));
}
}
}
~Config()
{
for (unsigned i = 0; i < num_interfaces; i++)
destroy(_md_alloc, _interfaces[i]);
config_string.free(_md_alloc);
}
Interface &interface(unsigned num)
{
if (num >= num_interfaces)
throw Session::Interface_not_found();
return *_interfaces[num];
}
void dump()
{
if (verbose_descr)
log("Config: "
"len: ", Genode::Hex(length), " "
"type: ", Genode::Hex(type), " "
"total_length: ", Genode::Hex(total_length), " "
"num_intf: ", Genode::Hex(num_interfaces), " "
"config_value: ", Genode::Hex(config_value));
}
};
class Usb::Device : public Meta_data
{
private:
/*
* Noncopyable
*/
Device(Device const &);
Device &operator = (Device const &);
Packet_handler _handler;
void _clear()
{
if (!config)
return;
manufactorer_string.free(_md_alloc);
product_string.free(_md_alloc);
serial_number_string.free(_md_alloc);
destroy(_md_alloc, config);
}
public:
enum Speed {
SPEED_UNKNOWN = 0, /* enumerating */
SPEED_LOW,
SPEED_FULL, /* usb 1.1 */
SPEED_HIGH, /* usb 2.0 */
SPEED_WIRELESS, /* wireless (usb 2.5) */
SPEED_SUPER, /* usb 3.0 */
};
Device_descriptor device_descr { };
Config *config = nullptr;
String manufactorer_string { };
String product_string { };
String serial_number_string { };
Device(Genode::Allocator * const md_alloc, Connection &connection,
Genode::Entrypoint &ep)
: Meta_data(md_alloc, connection, _handler), _handler(connection, ep)
{ }
Device_descriptor const *descriptor() { return &device_descr; }
Config *config_descriptor() { return config; }
char const *speed_string(unsigned speed)
{
switch (speed) {
case SPEED_LOW : return "LOW";
case SPEED_FULL : return "FULL";
case SPEED_HIGH : return "HIGH";
case SPEED_WIRELESS: return "WIRELESS";
case SPEED_SUPER : return "SUPER";
default: return "<unknown>";
}
}
void string_descriptor(uint8_t index, String *target)
{
Packet_descriptor p = _handler.alloc(128);
p.type = Packet_descriptor::STRING;
p.string.index = index;
p.string.length = 128;
Sync_completion sync(_handler, p);
target->copy(p.string.length, _handler.content(p), _md_alloc);
}
/**
* Re-read all descriptors (device, config, interface, and endpoints)
* Must be called before Usb::Device can be used (asynchronous)
*/
void update_config()
{
/* free info from previous call */
_clear();
Config_descriptor config_descr;
_connection.config_descriptor(&device_descr, &config_descr);
dump();
config = new (_md_alloc) Config(config_descr, *this);
/* retrieve string descriptors */
string_descriptor(device_descr.manufactorer_index, &manufactorer_string);
string_descriptor(device_descr.product_index, &product_string);
string_descriptor(device_descr.serial_number_index, &serial_number_string);
string_descriptor(config->config_index, &config->config_string);
for (unsigned i = 0; i < config->num_interfaces; i++) {
Interface &iface = config->interface(i);
for (unsigned j = 0; j < iface.alternate_count(); j++)
string_descriptor(iface.alternate_interface(j).interface_index,
&iface.alternate_interface(j).interface_string);
}
}
/**
* Set configuration, no interfaces can be claimed (asynchronous)
*/
void set_configuration(uint8_t num)
{
if (!config) {
Genode::error("No current configuration found");
return;
}
if (!num || num > device_descr.num_configs) {
Genode::error("Valid configuration values: 1 ... ", device_descr.num_configs);
return;
}
if (config && num == config->config_value)
return;
Packet_descriptor p = _handler.alloc(0);
p.type = Packet_descriptor::CONFIG;
p.number = num;
Sync_completion sync(_handler, p);
if (p.succeded)
update_config();
}
Interface &interface(unsigned interface_num)
{
return config->interface(interface_num);
}
void dump()
{
if (!verbose_descr)
return;
using Genode::Hex;
Genode::log("Device: "
"len: ", Hex(device_descr.length), " "
"type: " , Hex(device_descr.type), " "
"class: ", Hex(device_descr.dclass), " "
"sub-class: ", Hex(device_descr.dsubclass), " "
"proto: ", Hex(device_descr.dprotocol), " "
"max_packet: ", Hex(device_descr.max_packet_size));
Genode::log(" "
"vendor: ", Hex(device_descr.vendor_id), " "
"product: ", Hex(device_descr.product_id), " "
"configs: ", Hex(device_descr.num_configs));
}
};
#endif /* _INCLUDE__USB__USB_H_ */

View File

@ -1,11 +1,12 @@
/**
* \brief USB session capability
* \author Sebastian Sumpf
* \author Stefan Kalkowski
* \date 2014-12-08
*/
/*
* Copyright (C) 2014-2017 Genode Labs GmbH
* Copyright (C) 2014-2024 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.
@ -16,8 +17,13 @@
#include <base/capability.h>
namespace Usb {
class Session;
typedef Genode::Capability<Session> Session_capability;
struct Interface_session;
struct Device_session;
class Session;
using Interface_capability = Genode::Capability<Interface_session>;
using Device_capability = Genode::Capability<Device_session>;
using Session_capability = Genode::Capability<Session>;
}
#endif /* _INCLUDE__USB_SESSION__CAPABILITY_H_ */

View File

@ -1,11 +1,12 @@
/**
* \brief USB session client implementation
* \author Sebastian Sumpf
* \author Stefan Kalkowski
* \date 2014-12-08
*/
/*
* Copyright (C) 2014-2017 Genode Labs GmbH
* Copyright (C) 2014-2024 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.
@ -15,108 +16,27 @@
#include <base/rpc_client.h>
#include <packet_stream_tx/client.h>
#include <usb_session/capability.h>
#include <usb_session/usb_session.h>
namespace Usb {
class Session_client;
class Interface_client;
}
namespace Usb { struct Client; }
class Usb::Session_client : public Genode::Rpc_client<Session>
struct Usb::Client : Genode::Rpc_client<Session>
{
private:
Client(Session_capability session)
: Rpc_client<Session>(session) { }
Packet_stream_tx::Client<Tx> _tx;
Rom_session_capability devices_rom() override {
return call<Rpc_devices_rom>(); }
public:
Device_capability acquire_device(Device_name const &name) override {
return call<Rpc_acquire_device>(name); }
/**
* Constructor
*
* \param session session capability
* \param tx_buffer_alloc allocator used for managing the
* transmission buffer
*/
Session_client(Session_capability session,
Genode::Range_allocator &tx_buffer_alloc,
Genode::Region_map &rm,
Genode::Signal_context_capability state_change)
:
Genode::Rpc_client<Session>(session),
_tx(call<Rpc_tx_cap>(), rm, tx_buffer_alloc)
{
if (state_change.valid())
sigh_state_change(state_change);
}
Device_capability acquire_single_device() override {
return call<Rpc_acquire_single_device>(); }
/*
* Helper utility to always allocate correctly aligned USB packets
*/
Packet_descriptor alloc_packet(Genode::size_t size)
{
/*
* At least on ARM the minimal alignment for distinct
* DMA-capable USB URBs shall meet a maximum cache-line
* size of 128 bytes
*/
enum { URB_PAYLOAD_MIN_ALIGN_LOG2 = 7 };
return source()->alloc_packet(size, URB_PAYLOAD_MIN_ALIGN_LOG2);
}
/***************************
** USB session interface **
***************************/
bool plugged() override { return call<Rpc_plugged>(); }
Tx *tx_channel() override { return &_tx; }
Tx::Source *source() override { return _tx.source(); }
void sigh_state_change(Genode::Signal_context_capability sigh) override {
call<Rpc_sigh_state_change>(sigh); }
void config_descriptor(Device_descriptor *device_descr,
Config_descriptor *config_descr) override
{
call<Rpc_config_descr>(device_descr, config_descr);
}
unsigned alt_settings(unsigned index) override
{
return call<Rpc_alt_settings>(index);
}
void interface_descriptor(unsigned index, unsigned alt_setting,
Interface_descriptor *interface_descr) override
{
call<Rpc_iface_descr>(index, alt_setting, interface_descr);
}
bool interface_extra(unsigned index, unsigned alt_setting,
Interface_extra *interface_data) override
{
return call<Rpc_iface_extra>(index, alt_setting, interface_data);
}
void endpoint_descriptor(unsigned interface_num,
unsigned alt_setting,
unsigned endpoint_num,
Endpoint_descriptor *endpoint_descr) override
{
call<Rpc_ep_descr>(interface_num, alt_setting, endpoint_num, endpoint_descr);
}
void claim_interface(unsigned interface_num) override
{
call<Rpc_claim_interface>(interface_num);
}
void release_interface(unsigned interface_num) override
{
call<Rpc_release_interface>(interface_num);
}
void release_device(Device_capability device) override {
call<Rpc_release_device>(device); }
};
#endif /* _INCLUDE__USB_SESSION__CLIENT_H_ */

View File

@ -1,11 +1,12 @@
/*
* \brief Client connection to USB server
* \author Stefan Kalkowski
* \author Sebastian Sumpf
* \date 2014-12-08
*/
/*
* Copyright (C) 2014-2017 Genode Labs GmbH
* Copyright (C) 2014-2024 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.
@ -13,26 +14,104 @@
#ifndef _INCLUDE__USB_SESSION__CONNECTION_H_
#define _INCLUDE__USB_SESSION__CONNECTION_H_
#include <usb_session/client.h>
#include <base/attached_dataspace.h>
#include <base/connection.h>
#include <base/allocator.h>
#include <rom_session/client.h>
#include <usb_session/client.h>
namespace Usb { struct Connection; }
struct Usb::Connection : Genode::Connection<Session>, Session_client
class Usb::Connection : public Genode::Connection<Session>, public Usb::Client
{
Connection(Genode::Env &env,
Genode::Range_allocator *tx_block_alloc,
Label const &label = Label(),
Genode::size_t tx_buf_size = 512*1024,
Genode::Signal_context_capability sigh_state_changed =
Genode::Signal_context_capability())
:
Genode::Connection<Session>(env, label, Ram_quota { 5*4096 + tx_buf_size },
Args("tx_buf_size=", tx_buf_size)),
Session_client(cap(), *tx_block_alloc, env.rm(), sigh_state_changed)
{ }
private:
Env & _env;
Rom_session_client _rom { devices_rom() };
Constructible<Attached_dataspace> _ds {};
Io_signal_handler<Connection> _handler { _env.ep(), *this,
&Connection::_handle_io };
void _try_attach()
{
_ds.destruct();
try { _ds.construct(_env.rm(), _rom.dataspace()); }
catch (Attached_dataspace::Invalid_dataspace) {
warning("Invalid devices rom dataspace returned!");}
}
void _handle_io() { }
template <typename FN>
Device_capability _wait_for_device(FN const & fn)
{
for (;;) {
/* repeatedly check for availability of device */
Device_capability cap = fn();
if (cap.valid())
return cap;
_env.ep().wait_and_dispatch_one_io_signal();
}
}
public:
Connection(Genode::Env &env,
Genode::size_t ram_quota = RAM_QUOTA)
:
Genode::Connection<Session>(env, Label(),
Ram_quota { ram_quota }, Args()),
Client(cap()),
_env(env)
{
_try_attach();
/*
* Initially register dummy handler, to be able to receive signals
* if _wait_for_device probes for a valid devices rom
*/
sigh(_handler);
}
void update()
{
if (_ds.constructed() && _rom.update() == true)
return;
_try_attach();
}
void sigh(Signal_context_capability sigh) { _rom.sigh(sigh); }
template <typename FN>
void with_xml(FN const & fn)
{
update();
try {
if (_ds.constructed() && _ds->local_addr<void const>()) {
Xml_node xml(_ds->local_addr<char>(), _ds->size());
fn(xml);
}
} catch (Xml_node::Invalid_syntax) {
warning("Devices rom has invalid XML syntax"); }
}
Device_capability acquire_device(Device_name const &name) override
{
Ram_quota ram_quota(Device_session::TX_BUFFER_SIZE + 4096);
return retry_with_upgrade(ram_quota, Cap_quota{6}, [&] () {
return Client::acquire_device(name); });
}
Device_capability acquire_device()
{
return _wait_for_device([&] () {
Ram_quota ram_quota(Device_session::TX_BUFFER_SIZE + 4096);
return retry_with_upgrade(ram_quota, Cap_quota{6}, [&] () {
return Client::acquire_single_device(); });
});
}
};
#endif /* _INCLUDE__USB_SESSION__CONNECTION_H_ */

View File

@ -0,0 +1,798 @@
/*
* \brief USB device interface
* \author Stefan Kalkowski
* \date 2023-08-28
*/
/*
* Copyright (C) 2023-2024 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 _INCLUDE__USB_SESSION__DEVICE_H_
#define _INCLUDE__USB_SESSION__DEVICE_H_
#include <base/exception.h>
#include <base/rpc.h>
#include <base/rpc.h>
#include <os/packet_allocator.h>
#include <packet_stream_tx/client.h>
#include <usb_session/types.h>
#include <usb_session/connection.h>
namespace Usb {
template <typename SESSION> class Urb_handler;
class Endpoint;
class Interface;
class Device;
}
class Usb::Endpoint
{
public:
enum Direction { OUT, IN };
enum Type { CONTROL, ISOC, BULK, IRQ };
private:
enum { MAX_NUMBER = 0xf, INVALID = 0xff };
struct Address : Register<8>
{
struct Number : Bitfield<0, 4> {};
struct Direction : Bitfield<7, 1> {};
};
struct Attributes : Register<8>
{
struct Type : Bitfield<0, 2> {};
};
Address::access_t _address { INVALID };
Attributes::access_t _attributes { INVALID };
public:
struct Endpoint_not_avail : Exception {};
Endpoint(Address::access_t addr, Attributes::access_t attr)
: _address(addr), _attributes(attr) {}
Endpoint(Interface &iface, Direction d, Type t);
Endpoint() {}
bool valid() const {
return _address != INVALID || _attributes != INVALID; }
uint8_t address() const {
return _address; }
uint8_t number() const {
return Address::Number::get(_address); }
Type type() const {
return (Type) Attributes::Type::get(_attributes); }
Direction direction() const {
return Address::Direction::get(_address) ? IN : OUT; }
};
template <typename SESSION>
class Usb::Urb_handler
{
protected:
using Tx = typename SESSION::Tx;
using Packet_descriptor = typename SESSION::Packet_descriptor;
using Payload = typename Packet_descriptor::Payload;
public:
class Urb : Noncopyable
{
protected:
friend class Urb_handler;
using Direction = Endpoint::Direction;
using Isoc_header = genode_usb_isoc_transfer_header;
using Isoc_descriptor = genode_usb_isoc_descriptor;
Urb_handler &_urb_handler;
Direction const _direction;
uint32_t const _isoc_packets;
size_t const _size;
Payload _payload { };
bool _completed { false };
Constructible<typename Id_space<Urb>::Element> _tag {};
Fifo_element<Urb> _pending_elem { *this };
virtual Packet_descriptor _create() const
{
Tagged_packet::Tag const tag { _tag->id().value };
Packet_descriptor const p(_payload, tag);
return p;
}
size_t _isoc_payload_offset()
{
return _isoc_packets ? sizeof(Isoc_header) +
_isoc_packets*sizeof(Isoc_descriptor)
: 0;
}
template <typename URB,
typename OUT_FN,
typename ISOC_OUT_FN>
void _submit(URB &urb,
Tx::Source &tx,
OUT_FN const &out_fn,
ISOC_OUT_FN const &isoc_out_fn)
{
if (!_tag.constructed())
return;
Packet_descriptor const p = _create();
if (!_isoc_packets &&
_direction == Direction::OUT &&
_size) {
Byte_range_ptr dst { (char*)tx.packet_content(p), _size };
out_fn(urb, dst);
}
if (_isoc_packets) {
addr_t payload = (addr_t)tx.packet_content(p);
size_t off = _isoc_payload_offset();
Isoc_header &hdr = *(Isoc_header*)(payload);
hdr.number_of_packets = _isoc_packets;
for (uint32_t i = 0; i < _isoc_packets; i++) {
Byte_range_ptr dst { (char*)(payload+off), _size-off };
uint32_t psize = isoc_out_fn(urb, i, dst);
hdr.packets[i].actual_size = 0;
hdr.packets[i].size = psize;
off += psize;
}
}
tx.try_submit_packet(p);
}
template <typename URB,
typename IN_FN,
typename ISOC_IN_FN>
void _in_results(URB &urb,
Packet_descriptor p,
Tx::Source &tx,
IN_FN const &in_fn,
ISOC_IN_FN const &isoc_in_fn)
{
if (!_isoc_packets) {
Const_byte_range_ptr src { (const char*)tx.packet_content(p),
p.payload_return_size };
in_fn(urb, src);
return;
}
addr_t payload = (addr_t)tx.packet_content(p);
size_t off = _isoc_payload_offset();
Isoc_header &hdr = *(Isoc_header*)(payload);
for (uint32_t i = 0; i < _isoc_packets; i++) {
Const_byte_range_ptr src { (const char*)(payload+off),
hdr.packets[i].actual_size };
isoc_in_fn(urb, i, src);
off += hdr.packets[i].size;
}
}
Urb(Urb_handler &handler,
Direction direction,
size_t size = 0,
uint32_t isoc_packets = 0)
:
_urb_handler(handler),
_direction(direction),
_isoc_packets(isoc_packets),
_size(size + _isoc_payload_offset())
{
_urb_handler._pending.enqueue(_pending_elem);
}
public:
virtual ~Urb()
{
if (pending())
_urb_handler._pending.remove(_pending_elem);
else if (in_progress())
warning("usb-session urb prematurely destructed");
}
bool in_progress() const { return _tag.constructed(); }
bool completed() const { return _completed; }
bool pending() const { return !in_progress() && !_completed; }
};
protected:
enum { URB_ALLOC_GRANULARITY = 512 };
Packet_allocator _alloc;
Packet_stream_tx::Client<Tx> _tx;
Id_space<Urb> _tags { };
Fifo<Fifo_element<Urb>> _pending { };
template <typename URB,
typename IN_FN,
typename ISOC_IN_FN,
typename CPL_FN>
bool _try_process_ack(Tx::Source &, IN_FN const &,
ISOC_IN_FN const &, CPL_FN const &);
template <typename URB,
typename OUT_FN,
typename ISOC_OUT_FN>
bool _try_submit_pending_urb(Tx::Source &, OUT_FN const &,
ISOC_OUT_FN const &);
public:
Urb_handler(Capability<typename SESSION::Tx> cap,
Region_map &rm, Allocator &md_alloc)
:
_alloc(&md_alloc, URB_ALLOC_GRANULARITY),
_tx(cap, rm, _alloc) {}
/**
* Handle the submission and completion of URBs
*
* \return true if progress was made
*/
template <typename URB,
typename OUT_FN,
typename IN_FN,
typename ISOC_OUT_FN,
typename ISOC_IN_FN,
typename CPL_FN>
bool update_urbs(OUT_FN const &out_fn,
IN_FN const &in_fn,
ISOC_OUT_FN const &isoc_out_fn,
ISOC_IN_FN const &isoc_in_fn,
CPL_FN const &complete_fn)
{
typename Tx::Source &tx = *_tx.source();
bool overall_progress = false;
for (;;) {
/* track progress of a single iteration */
bool progress = false;
/* process acknowledgements */
while (_try_process_ack<URB>(tx, in_fn, isoc_in_fn, complete_fn))
progress = true;
/* try to submit pending requests */
while (_try_submit_pending_urb<URB>(tx, out_fn, isoc_out_fn))
progress = true;
overall_progress |= progress;
if (!progress)
break;
}
if (overall_progress)
tx.wakeup();
return overall_progress;
}
/**
* Call 'fn' with each urb as argument
*
* This method is intended for the destruction of the urbs associated
* with the handler before destructing the 'Urb_handler' object.
*/
template <typename URB, typename FN>
void dissolve_all_urbs(FN const &fn)
{
_pending.dequeue_all([&] (Fifo_element<Urb> &elem) {
fn(static_cast<URB&>(elem.object())); });
auto discard_tag_and_apply_fn = [&] (Urb &urb) {
urb._tag.destruct();
Packet_descriptor const p { urb._payload.offset,
urb._payload.bytes };
fn(static_cast<URB&>(urb));
_tx.source()->release_packet(p);
};
while (_tags.template apply_any<Urb>(discard_tag_and_apply_fn));
}
void sigh(Signal_context_capability cap)
{
_tx.sigh_ack_avail(cap);
_tx.sigh_ready_to_submit(cap);
}
};
class Usb::Interface
:
Noncopyable,
Interface_capability,
public Interface_session
{
public:
struct Index
{
uint8_t number;
uint8_t alt_setting;
};
struct Type
{
uint8_t cla;
uint8_t subcla;
uint8_t prot;
};
class Urb : public Urb_handler<Interface_session>::Urb
{
protected:
using Base = Urb_handler<Interface_session>::Urb;
Packet_descriptor::Type _type;
Endpoint _ep;
Packet_descriptor _create() const override
{
Packet_descriptor p = Base::_create();
p.index = _ep.address();
p.type = _type;
return p;
}
public:
Urb(Interface &iface, Endpoint &ep,
Packet_descriptor::Type type,
size_t size = 0,
uint32_t isoc_packets = 0)
:
Base(iface._urb_handler, ep.direction(),
size, isoc_packets),
_type(type), _ep(ep) { }
};
struct Alt_setting;
private:
friend class Endpoint;
friend class Urb;
enum { MAX_EPS = 16 };
Device &_device;
Index _idx;
Urb_handler<Interface_session> _urb_handler;
Endpoint _eps[2][MAX_EPS] { };
public:
struct Interface_not_avail : Exception {};
Interface(Device &device, Index idx, size_t buffer_size);
Interface(Device &device, Type type, size_t buffer_size);
Interface(Device &device, size_t buffer_size);
~Interface();
Index index() const { return _idx; }
void sigh(Signal_context_capability cap) {
_urb_handler.sigh(cap); }
template <typename URB,
typename OUT_FN,
typename IN_FN,
typename ISOC_OUT_FN,
typename ISOC_IN_FN,
typename CPL_FN>
bool update_urbs(OUT_FN const &out_fn,
IN_FN const &in_fn,
ISOC_OUT_FN const &isoc_out_fn,
ISOC_IN_FN const &isoc_in_fn,
CPL_FN const &complete_fn)
{
return _urb_handler.update_urbs<URB>(out_fn, in_fn, isoc_out_fn,
isoc_in_fn, complete_fn);
}
template <typename URB,
typename OUT_FN,
typename IN_FN,
typename CPL_FN>
bool update_urbs(OUT_FN const &out_fn,
IN_FN const &in_fn,
CPL_FN const &complete_fn)
{
auto isoc_out = [] (URB&, uint32_t, Byte_range_ptr&) { return 0; };
auto isoc_in = [] (URB&, uint32_t, Const_byte_range_ptr&) { };
return _urb_handler.update_urbs<URB>(out_fn, in_fn, isoc_out,
isoc_in, complete_fn);
}
template <typename URB, typename FN>
void dissolve_all_urbs(FN const &fn) {
_urb_handler.dissolve_all_urbs<URB>(fn); }
template <typename FN>
void for_each_endpoint(FN const &fn)
{
for (unsigned d = Endpoint::OUT; d <= Endpoint::IN; d++)
for (unsigned n = 0; n < MAX_EPS; n++)
if (_eps[d][n].valid()) fn(_eps[d][n]);
}
};
class Usb::Device
:
Noncopyable,
Device_capability,
public Device_session
{
public:
using Interface = Usb::Interface;
using Name = Usb::Session::Device_name;
class Urb : public Urb_handler<Device_session>::Urb
{
public:
using Type = Packet_descriptor::Request_type;
protected:
using Base = Urb_handler<Device_session>::Urb;
uint8_t _request;
Type::access_t _request_type;
uint16_t _value;
uint16_t _index;
Packet_descriptor _create() const override
{
Packet_descriptor p = Base::_create();
p.request_type = _request_type;
p.request = _request;
p.value = _value;
p.index = _index;
return p;
}
public:
Urb(Device &device,
uint8_t request, Type::access_t request_type,
uint16_t value, uint16_t index, size_t size = 0)
:
Base(device._urb_handler,
Type::D::get(request_type) ? Endpoint::IN
: Endpoint::OUT,
size),
_request(request), _request_type(request_type),
_value(value), _index(index) {}
};
private:
friend class Usb::Interface;
friend class Endpoint;
friend class Urb;
::Usb::Connection &_session;
Allocator &_md_alloc;
Region_map &_rm;
Name const _name { };
Urb_handler<Device_session> _urb_handler;
Interface_capability _interface_cap(uint8_t num, size_t buf_size);
Name _first_device_name();
template <typename FN>
void _for_each_iface(FN const & fn);
Interface::Index _interface_index(Interface::Type);
public:
Device(Connection &usb_session, Allocator &md_alloc,
Region_map &rm, Name name);
Device(Connection &session, Allocator &md_alloc, Region_map &rm);
~Device() { _session.release_device(*this); }
void sigh(Signal_context_capability cap) {
_urb_handler.sigh(cap); }
template <typename URB,
typename OUT_FN,
typename IN_FN,
typename CPL_FN>
bool update_urbs(OUT_FN const &out_fn,
IN_FN const &in_fn,
CPL_FN const &complete_fn)
{
auto isoc_out = [] (URB&, uint32_t, Byte_range_ptr&) { return 0; };
auto isoc_in = [] (URB&, uint32_t, Const_byte_range_ptr&) { };
return _urb_handler.update_urbs<URB>(out_fn, in_fn, isoc_out,
isoc_in, complete_fn);
}
template <typename URB, typename FN>
void dissolve_all_urbs(FN const &fn) {
_urb_handler.dissolve_all_urbs<URB>(fn); }
};
struct Usb::Interface::Alt_setting : Device::Urb
{
using P = Device::Packet_descriptor;
using Rt = P::Request_type;
Alt_setting(Device &dev, Interface &iface)
:
Device::Urb(dev,
P::Request::SET_INTERFACE,
Rt::value(P::Recipient::IFACE, P::Type::STANDARD,
P::Direction::IN),
iface.index().number, iface.index().alt_setting) {}
};
template <typename SESSION>
template <typename URB, typename IN_FN, typename ISOC_IN_FN, typename CPL_FN>
bool
Usb::Urb_handler<SESSION>::_try_process_ack(Tx::Source &tx,
IN_FN const &in_fn,
ISOC_IN_FN const &isoc_in,
CPL_FN const &complete_fn)
{
if (!tx.ack_avail())
return false;
Packet_descriptor const p = tx.try_get_acked_packet();
typename Id_space<Urb>::Id const id { p.tag.value };
try {
_tags.template apply<Urb>(id, [&] (Urb &urb) {
if (urb._direction == Urb::Direction::IN &&
p.return_value == Packet_descriptor::OK)
urb._in_results(static_cast<URB&>(urb), p, tx, in_fn, isoc_in);
urb._completed = true;
urb._tag.destruct();
complete_fn(static_cast<URB&>(urb), p.return_value);
});
} catch (typename Id_space<Urb>::Unknown_id) {
warning("spurious usb-session urb acknowledgement");
}
tx.release_packet(p);
return true;
}
template <typename SESSION>
template <typename URB, typename OUT_FN, typename ISOC_FN>
bool
Usb::Urb_handler<SESSION>::_try_submit_pending_urb(Tx::Source &tx,
OUT_FN const &out_fn,
ISOC_FN const &isoc_fn)
{
if (_pending.empty())
return false;
if (!tx.ready_to_submit())
return false;
/*
* Allocate space for the payload in the packet-stream buffer.
*/
Payload payload { };
try {
_pending.head([&] (Fifo_element<Urb> const &elem) {
Urb const &urb = elem.object();
size_t const align = Tagged_packet::PACKET_ALIGNMENT;
payload = {
.offset = tx.alloc_packet(urb._size, align).offset(),
.bytes = urb._size
};
});
} catch (typename Tx::Source::Packet_alloc_failed) {
/* the packet-stream buffer is saturated */
return false;
}
/*
* All preconditions for the submission of the urb are satisfied.
* So the urb can go from the pending to the in-progress stage.
*/
_pending.dequeue([&] (Genode::Fifo_element<Urb> &elem) {
Urb &urb = elem.object();
/* let the urb join the tag ID space, allocating a tag */
urb._tag.construct(elem.object(), _tags);
urb._payload = payload;
urb._submit(static_cast<URB&>(elem.object()), tx, out_fn, isoc_fn);
});
return true;
}
inline Usb::Endpoint::Endpoint(Interface &iface, Direction d, Type t)
{
bool found = false;
iface.for_each_endpoint([&] (Endpoint ep) {
if (ep.type() == t && ep.direction() == d) {
_attributes = ep._attributes;
_address = ep._address;
found = true;
}
});
if (!found)
throw Endpoint_not_avail();
};
inline Usb::Interface::Interface(Device &device, Index idx, size_t buffer_size)
:
Interface_capability(device._interface_cap(idx.number, buffer_size)),
_device(device), _idx(idx),
_urb_handler(call<Rpc_tx_cap>(), device._rm, device._md_alloc)
{
static constexpr uint16_t INVALID = 256;
device._for_each_iface([&] (Xml_node node) {
if (node.attribute_value<uint16_t>("number", INVALID) != idx.number)
return;
node.for_each_sub_node("endpoint", [&] (Xml_node node) {
Endpoint ep { node.attribute_value<uint8_t>("address", 0),
node.attribute_value<uint8_t>("attributes", 0) };
if (!_eps[ep.direction()][ep.number()].valid())
_eps[ep.direction()][ep.number()] = ep;
});
});
}
inline Usb::Interface::Interface(Device &device, Type type, size_t buffer_size)
: Interface(device, device._interface_index(type), buffer_size) { }
inline Usb::Interface::Interface(Device &device, size_t buffer_size)
: Interface(device, Index { 0, 0 }, buffer_size) { }
inline Usb::Interface::~Interface() {
_device.call<Device_session::Rpc_release_interface>(*this); }
inline Usb::Interface_capability
Usb::Device::_interface_cap(uint8_t num, size_t buf_size)
{
return _session.retry_with_upgrade(Ram_quota{buf_size + 4096},
Cap_quota{6}, [&] () {
return call<Device_session::Rpc_acquire_interface>(num, buf_size); });
}
inline Usb::Device::Name Usb::Device::_first_device_name()
{
Name ret;
_session.with_xml([&] (Xml_node & xml) {
xml.with_optional_sub_node("device", [&] (Xml_node node) {
ret = node.attribute_value("name", Name()); });
});
return ret;
}
template <typename FN>
void Usb::Device::_for_each_iface(FN const & fn)
{
_session.with_xml([&] (Xml_node & xml) {
xml.for_each_sub_node("device", [&] (Xml_node node) {
if (node.attribute_value("name", Name()) == _name)
node.for_each_sub_node("config", [&] (Xml_node node) {
if (node.attribute_value("active", false))
node.for_each_sub_node("interface", fn);
});
});
});
}
inline Usb::Interface::Index
Usb::Device::_interface_index(Interface::Type t)
{
static constexpr uint16_t INVALID = 256;
uint16_t num = INVALID, alt = INVALID;
_for_each_iface([&] (Xml_node node) {
uint16_t c = node.attribute_value("class", INVALID);
uint16_t s = node.attribute_value("subclass", INVALID);
uint16_t p = node.attribute_value("protocol", INVALID);
if (c == t.cla && s == t.subcla && p == t.prot) {
num = node.attribute_value("number", INVALID);
alt = node.attribute_value("alt_setting", INVALID);
}
});
if (num < INVALID && alt < INVALID)
return { (uint8_t)num, (uint8_t)alt };
throw Interface::Interface_not_avail();
}
inline Usb::Device::Device(Connection &session,
Allocator &md_alloc,
Region_map &rm,
Name name)
:
Device_capability(session.acquire_device(name)),
_session(session),
_md_alloc(md_alloc),
_rm(rm),
_name(name),
_urb_handler(call<Rpc_tx_cap>(), rm, md_alloc) {}
inline Usb::Device::Device(Connection &session,
Allocator &md_alloc,
Region_map &rm)
:
Device_capability(session.acquire_device()),
_session(session),
_md_alloc(md_alloc),
_rm(rm),
_name(_first_device_name()),
_urb_handler(call<Rpc_tx_cap>(), rm, md_alloc) {}
#endif /* _INCLUDE__USB_SESSION__DEVICE_H_ */

View File

@ -1,54 +0,0 @@
/**
* \brief Server RPC object with packet stream
* \author Sebastian Sumpf
* \date 2014-12-08
*/
/*
* Copyright (C) 2014-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 _INCLUDE__USB_SESSION__RPC_OBJECT_H_
#define _INCLUDE__USB_SESSION__RPC_OBJECT_H_
#include <base/rpc_server.h>
#include <packet_stream_tx/rpc_object.h>
#include <usb_session/usb_session.h>
namespace Usb { class Session_rpc_object; }
class Usb::Session_rpc_object : public Genode::Rpc_object<Session, Session_rpc_object>
{
protected:
Packet_stream_tx::Rpc_object<Tx> _tx;
public:
/**
* Constructor
*
* \param tx_ds dataspace used as communication buffer
* for the tx packet stream
* \param ep entry point used for packet-stream channel
*/
Session_rpc_object(Genode::Dataspace_capability tx_ds,
Genode::Rpc_entrypoint &ep,
Genode::Region_map &rm)
: _tx(tx_ds, rm, ep) { }
/**
* Return capability to packet-stream channel
*
* This method is called by the client via an RPC call at session
* construction time.
*/
Genode::Capability<Tx> _tx_cap() { return _tx.cap(); }
Tx::Sink *sink() { return _tx.sink(); }
};
#endif /* _INCLUDE__USB_SESSION__RPC_OBJECT_H_ */

View File

@ -0,0 +1,114 @@
/**
* \brief Basic types for USB (C/C++ compatible)
* \author Sebastian Sumpf
* \author Stefan Kalkowski
* \date 2014-12-08
*/
/*
* Copyright (C) 2014-2023 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 _INCLUDE__USB__TYPES_H_
#define _INCLUDE__USB__TYPES_H_
#include <base/fixed_stdint.h>
enum Usb_speed {
GENODE_USB_SPEED_LOW,
GENODE_USB_SPEED_FULL,
GENODE_USB_SPEED_HIGH,
GENODE_USB_SPEED_SUPER,
GENODE_USB_SPEED_SUPER_PLUS,
GENODE_USB_SPEED_SUPER_PLUS_2X2,
};
typedef enum Usb_speed genode_usb_speed_t;
struct genode_usb_isoc_descriptor
{
genode_uint32_t size;
genode_uint32_t actual_size;
} __attribute__((packed));
struct genode_usb_isoc_transfer_header
{
genode_uint32_t number_of_packets;
struct genode_usb_isoc_descriptor packets[0];
} __attribute__((packed));
/**
* USB hardware device descriptor
*/
struct genode_usb_device_descriptor
{
genode_uint8_t length;
genode_uint8_t type;
genode_uint16_t usb;
genode_uint8_t dclass;
genode_uint8_t dsubclass;
genode_uint8_t dprotocol;
genode_uint8_t max_packet_size;
genode_uint16_t vendor_id;
genode_uint16_t product_id;
genode_uint16_t device_release;
genode_uint8_t manufacturer_index;
genode_uint8_t product_index;
genode_uint8_t serial_number_index;
genode_uint8_t num_configs;
} __attribute__((packed));
/**
* USB hardware configuration descriptor
*/
struct genode_usb_config_descriptor
{
genode_uint8_t length;
genode_uint8_t type;
genode_uint16_t total_length;
genode_uint8_t num_interfaces;
genode_uint8_t config_value;
genode_uint8_t config_index;
genode_uint8_t attributes;
genode_uint8_t max_power;
} __attribute__((packed));
/**
* USB hardware interface descriptor
*/
struct genode_usb_interface_descriptor
{
genode_uint8_t length;
genode_uint8_t type;
genode_uint8_t number;
genode_uint8_t alt_settings;
genode_uint8_t num_endpoints;
genode_uint8_t iclass;
genode_uint8_t isubclass;
genode_uint8_t iprotocol;
genode_uint8_t interface_index;
} __attribute__((packed));
/**
* USB hardware endpoint descriptor
*/
struct genode_usb_endpoint_descriptor
{
genode_uint8_t length;
genode_uint8_t type;
genode_uint8_t address;
genode_uint8_t attributes;
genode_uint16_t max_packet_size;
genode_uint8_t polling_interval;
} __attribute__((packed));
#endif /* _INCLUDE__USB__TYPES_H_ */

View File

@ -1,11 +1,12 @@
/**
* \brief USB session for raw device connection
* \brief USB session for USB clients (mainly device drivers)
* \author Stefan Kalkowski
* \author Sebastian Sumpf
* \date 2014-12-08
*/
/*
* Copyright (C) 2014-2017 Genode Labs GmbH
* Copyright (C) 2014-2024 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.
@ -13,244 +14,218 @@
#ifndef _INCLUDE__USB_SESSION__USB_SESSION_H_
#define _INCLUDE__USB_SESSION__USB_SESSION_H_
#include <base/rpc_args.h>
#include <os/packet_stream.h>
#include <packet_stream_tx/packet_stream_tx.h>
#include <rom_session/capability.h>
#include <session/session.h>
#include <usb/types.h>
#include <usb_session/capability.h>
namespace Usb {
using namespace Genode;
class Session;
struct Packet_descriptor;
struct Isoc_transfer;
struct Completion;
struct Tagged_packet;
struct Interface_session;
struct Device_session;
class Session;
}
/**
* USB packet type
*/
struct Usb::Packet_descriptor : Genode::Packet_descriptor
struct Usb::Tagged_packet : Genode::Packet_descriptor
{
enum Type { STRING, CTRL, BULK, IRQ, ISOC, ALT_SETTING, CONFIG, RELEASE_IF, FLUSH_TRANSFERS };
/* use the polling interval stated in the endpoint descriptor */
enum { DEFAULT_POLLING_INTERVAL = -1 };
Type type { STRING };
bool succeded { false };
Completion *completion { nullptr };
union
{
struct
{
uint8_t index;
unsigned length;
} string;
struct
{
uint8_t request;
uint8_t request_type;
uint16_t value;
uint16_t index;
int actual_size; /* returned */
int timeout;
} control;
struct
{
uint8_t ep;
int actual_size; /* returned */
int polling_interval; /* for interrupt transfers */
} transfer;
struct
{
uint8_t number;
uint8_t alt_setting;
} interface;
struct
{
uint8_t number;
};
};
enum Error {
NO_ERROR,
INTERFACE_OR_ENDPOINT_ERROR,
MEMORY_ERROR,
NO_DEVICE_ERROR,
PACKET_INVALID_ERROR,
PROTOCOL_ERROR,
STALL_ERROR,
TIMEOUT_ERROR,
UNKNOWN_ERROR
};
Error error = NO_ERROR;
/*
* At least on ARM the minimal alignment for distinct
* DMA-capable USB URBs shall meet a maximum cache-line
* size of 128 bytes
*/
enum Alignment { PACKET_ALIGNMENT = 7 };
/**
* Return true if packet is a read transfer
* Payload location within the packet stream
*/
bool read_transfer() { return transfer.ep & ENDPOINT_IN; }
Packet_descriptor(off_t offset = 0, size_t size = 0)
: Genode::Packet_descriptor(offset, size) { }
Packet_descriptor(Genode::Packet_descriptor p, Type type, Completion *completion = nullptr)
: Genode::Packet_descriptor(p.offset(), p.size()), type(type), completion(completion) { }
};
/**
* Isochronous transfer metadata (located at start of stream packet)
*/
struct Usb::Isoc_transfer
{
enum { MAX_PACKETS = 32 };
unsigned number_of_packets;
unsigned packet_size[MAX_PACKETS];
unsigned actual_packet_size[MAX_PACKETS];
char *data() { return (char *)(this + 1); }
static size_t size(unsigned data_size)
struct Payload
{
return sizeof(Isoc_transfer) + data_size;
}
off_t offset;
size_t bytes;
};
struct Tag {
unsigned long value;
} tag { ~0UL };
enum Return_value {
UNHANDLED, NO_DEVICE, INVALID, TIMEOUT, HALT, OK
} return_value { UNHANDLED };
Tagged_packet(off_t offset = 0, size_t size = 0)
: Genode::Packet_descriptor(offset, size) {}
Tagged_packet(Payload p, Tag tag)
:
Genode::Packet_descriptor(p.offset, p.bytes),
tag(tag) {}
};
/**
* Completion for asynchronous communication
*/
struct Usb::Completion : Genode::Interface
struct Usb::Interface_session : Interface
{
virtual void complete(Usb::Packet_descriptor &p) = 0;
struct Packet_descriptor : Tagged_packet
{
enum Type {
BULK, IRQ, ISOC, FLUSH
} type { FLUSH };
uint8_t index { 0 };
size_t payload_return_size { 0 };
using Tagged_packet::Tagged_packet;
};
enum { TX_QUEUE_SIZE = 64 };
using Tx_policy = Packet_stream_policy<Packet_descriptor,
TX_QUEUE_SIZE, TX_QUEUE_SIZE, char>;
using Tx = Packet_stream_tx::Channel<Tx_policy>;
/*********************
** RPC declaration **
*********************/
GENODE_RPC(Rpc_tx_cap, Capability<Tx>, tx_cap);
GENODE_RPC_INTERFACE(Rpc_tx_cap);
};
struct Usb::Device_session : Interface
{
struct Packet_descriptor : Tagged_packet
{
enum Request : uint8_t {
GET_STATUS = 0x00,
CLEAR_FEATURE = 0x01,
SET_FEATURE = 0x03,
SET_ADDRESS = 0x05,
GET_DESCRIPTOR = 0x06,
SET_DESCRIPTOR = 0x07,
GET_CONFIGURATION = 0x08,
SET_CONFIGURATION = 0x09,
GET_INTERFACE = 0x0a,
SET_INTERFACE = 0x0b,
SYNCH_FRAME = 0x0c,
SET_SEL = 0x30,
SET_ISOCH_DELAY = 0x31,
};
uint8_t request { GET_STATUS };
enum Recipient { DEVICE, IFACE, ENDP, OTHER };
enum Type { STANDARD, CLASS, VENDOR, RESERVED };
enum Direction { OUT, IN };
struct Request_type : Register<8>
{
struct R : Bitfield<0, 5> { };
struct T : Bitfield<5, 2> { };
struct D : Bitfield<7, 1> { };
static access_t value(Recipient r, Type t, Direction d)
{
access_t ret = 0;
R::set(ret, r);
T::set(ret, t);
D::set(ret, d);
return ret;
}
};
Request_type::access_t request_type { 0 };
uint16_t value { 0 };
uint16_t index { 0 };
size_t payload_return_size { 0 };
size_t timeout { 0 };
using Tagged_packet::Tagged_packet;
};
enum { TX_QUEUE_SIZE = 8, TX_BUFFER_SIZE = 4096 };
using Tx_policy = Packet_stream_policy<Packet_descriptor,
TX_QUEUE_SIZE, TX_QUEUE_SIZE, char>;
using Tx = Packet_stream_tx::Channel<Tx_policy>;
/*********************
** RPC declaration **
*********************/
GENODE_RPC_THROW(Rpc_acquire_interface, Interface_capability,
acquire_interface,
GENODE_TYPE_LIST(Out_of_ram, Out_of_caps),
uint8_t, size_t);
GENODE_RPC(Rpc_release_interface, void, release_interface,
Interface_capability);
GENODE_RPC(Rpc_tx_cap, Capability<Tx>, tx_cap);
GENODE_RPC_INTERFACE(Rpc_acquire_interface, Rpc_release_interface,
Rpc_tx_cap);
};
struct Usb::Session : public Genode::Session
{
/****************
** Exceptions **
****************/
class Device_not_found : public Exception { };
class Interface_not_found : public Exception { };
class Interface_already_claimed : public Exception { };
class Interface_not_claimed : public Exception { };
class Invalid_endpoint : public Exception { };
/*******************
** Packet stream **
*******************/
enum { TX_QUEUE_SIZE = 64 };
typedef Packet_stream_policy<Usb::Packet_descriptor,
TX_QUEUE_SIZE, TX_QUEUE_SIZE,
char> Tx_policy;
typedef Packet_stream_tx::Channel<Tx_policy> Tx;
/**
* Request packet-transmission channel
*/
virtual Tx *tx_channel() { return 0; }
/**
* Request client-side packet-stream interface of tx channel
*/
virtual Tx::Source *source() { return 0; }
/***********************
** Session interface **
***********************/
/**
* \noapi
*/
static const char *service_name() { return "Usb"; }
static constexpr unsigned CAP_QUOTA = 5;
static constexpr unsigned CAP_QUOTA = 8;
static constexpr unsigned RAM_QUOTA = 512 * 1024;
virtual ~Session() {}
using Device_name = String<64>;
/**
* Send from the server to the client upon device state change
* Request ROM session containing information about available devices.
*
* \return capability to ROM dataspace
*/
virtual void sigh_state_change(Signal_context_capability sigh) = 0;
virtual Rom_session_capability devices_rom() = 0;
/**
* Is the device present
* Acquire device known by unique 'name'
*/
virtual bool plugged() = 0;
virtual Device_capability acquire_device(Device_name const &name) = 0;
/**
* Retrieve device and current configurations despcriptors
* Acquire the first resp. single device of this session
*/
virtual void config_descriptor(Device_descriptor *device_descr,
Config_descriptor *config_descr) = 0;
virtual Device_capability acquire_single_device() = 0;
/**
* Return number of alt settings for iterface
* Release all resources regarding the given 'device' session
*/
virtual unsigned alt_settings(unsigned index) = 0;
virtual void release_device(Device_capability device) = 0;
/**
* Return interface descriptor for interface index/alternate setting tuple
*/
virtual void interface_descriptor(unsigned index, unsigned alt_setting,
Interface_descriptor *interface_descr) = 0;
virtual bool interface_extra(unsigned index, unsigned alt_setting,
Interface_extra *interface_data) = 0;
/*********************
** RPC declaration **
*********************/
/**
* Return endpoint for interface index/alternate setting tuple
*/
virtual void endpoint_descriptor(unsigned interface_num,
unsigned alt_setting,
unsigned endpoint_num,
Endpoint_descriptor *endpoint_descr) = 0;
/**
* Claim an interface number
*/
virtual void claim_interface(unsigned interface_num) = 0;
/**
* Release an interface number
*/
virtual void release_interface(unsigned interface_num) = 0;
GENODE_RPC(Rpc_plugged, bool, plugged);
GENODE_RPC(Rpc_sigh_state_change, void, sigh_state_change, Signal_context_capability);
GENODE_RPC(Rpc_tx_cap, Capability<Tx>, _tx_cap);
GENODE_RPC_THROW(Rpc_config_descr, void, config_descriptor, GENODE_TYPE_LIST(Device_not_found),
Device_descriptor *, Config_descriptor *);
GENODE_RPC_THROW(Rpc_alt_settings, unsigned, alt_settings, GENODE_TYPE_LIST(Device_not_found,
Interface_not_found), unsigned);
GENODE_RPC_THROW(Rpc_iface_descr, void, interface_descriptor, GENODE_TYPE_LIST(Device_not_found,
Interface_not_found), unsigned, unsigned, Interface_descriptor *);
GENODE_RPC_THROW(Rpc_iface_extra, bool, interface_extra, GENODE_TYPE_LIST(Device_not_found,
Interface_not_found), unsigned, unsigned, Interface_extra *);
GENODE_RPC_THROW(Rpc_ep_descr, void, endpoint_descriptor, GENODE_TYPE_LIST(Device_not_found,
Interface_not_found), unsigned, unsigned, unsigned, Endpoint_descriptor *);
GENODE_RPC_THROW(Rpc_claim_interface, void, claim_interface, GENODE_TYPE_LIST(Device_not_found,
Interface_not_found, Interface_already_claimed), unsigned);
GENODE_RPC_THROW(Rpc_release_interface, void, release_interface, GENODE_TYPE_LIST(Device_not_found,
Interface_not_found), unsigned);
GENODE_RPC_INTERFACE(Rpc_plugged, Rpc_sigh_state_change, Rpc_tx_cap, Rpc_config_descr,
Rpc_iface_descr, Rpc_iface_extra, Rpc_ep_descr, Rpc_alt_settings,
Rpc_claim_interface, Rpc_release_interface);
GENODE_RPC(Rpc_devices_rom, Rom_session_capability, devices_rom);
GENODE_RPC_THROW(Rpc_acquire_device, Device_capability, acquire_device,
GENODE_TYPE_LIST(Out_of_ram, Out_of_caps),
Device_name const &);
GENODE_RPC_THROW(Rpc_acquire_single_device, Device_capability,
acquire_single_device,
GENODE_TYPE_LIST(Out_of_ram, Out_of_caps));
GENODE_RPC(Rpc_release_device, void, release_device, Device_capability);
GENODE_RPC_INTERFACE(Rpc_devices_rom, Rpc_acquire_device,
Rpc_acquire_single_device, Rpc_release_device);
};
#endif /* _INCLUDE__USB_SESSION__USB_SESSION_H_ */

View File

@ -1,2 +1,2 @@
MIRRORED_FROM_REP_DIR := include/usb_session include/usb
MIRRORED_FROM_REP_DIR := include/usb_session
include $(REP_DIR)/recipes/api/session.inc

View File

@ -124,7 +124,7 @@
<provides> <service name="Usb"/> </provides>
<config>
<report devices="yes"/>
<policy label_prefix="usb_hid_drv" class="0x3"/>
<policy label_prefix="usb_hid_drv"><device class="0x3"/></policy>
</config>
<route>
<service name="Platform"> <child name="platform_drv"/> </service>
@ -140,7 +140,6 @@
<start name="usb_hid_drv" caps="180">
<resource name="RAM" quantum="10M"/>
<config use_report="yes"/>
<route>
<service name="ROM" label="report"> <child name="report_rom"/> </service>
<service name="ROM"> <parent/> </service>

View File

@ -8,8 +8,6 @@ if {[get_cmd_switch --autopilot] && ![have_include "power_on/qemu"]} {
exit 0
}
proc usb_device_label {} { return "usb-1-2" }
create_boot_directory
import_from_depot [depot_user]/src/[base_src] \
[depot_user]/pkg/test_usb_host_drv-[board] \
@ -68,7 +66,7 @@ install_config {
<provides> <service name="Block"/> </provides>
<config report="yes" writeable="no"/>
<route>
<service name="Usb"> <child name="usb_drv" label="} [usb_device_label] {"/> </service>
<service name="Usb"> <child name="usb_drv"/> </service>
<service name="Report"> <child name="report_rom"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
@ -95,7 +93,11 @@ install_config {
# Define USB host controller config
#
set fd [open [run_dir]/genode/usb_host_drv.config w]
puts $fd { <config> <default-policy class="0x8"/> </config> }
puts $fd { <config>
<policy label="usb_block_drv -> ">
<device name="usb-1-2"/>
</policy>
</config> }
close $fd
build_boot_image [build_artifacts]

View File

@ -1,78 +0,0 @@
This directory contains a USB device report filter component. It filters the
device report coming from the USB driver by checking each device reported
against the given list of devices. Only approved devices are reported to a
consumer of the report coming from the filter component.
Configuration
~~~~~~~~~~~~~
A typical example configuration looks as follows:
!<config>
! <vfs> <fs/> </vfs>
! <client label="component_xyz"/>
! <device vendor_id="0x13fe" product_id="0x5200"/>
! <device vendor_id="0x148f" product_id="0x2573"/>
! <device vendor_id="0x04f9" product_id="0x0051"/>
! <device vendor_id="0x1b1c" product_id="0x1a09"/>
</config>
The component that may use the devices is identified by the 'client' node.
In addition to the 'vendor_id' and 'product_id' attribute a 'device' node
can contain a 'bus' and 'dev' attribute. If these attributes are present they
have a stronger significance than the 'vendor_id' and the 'product_id'.
Whenever the 'usb_report_filter' component receives a new USB device report
from the driver it will generate a new driver configuration that contains
a policy entry for each matching device. After the driver's configuration has
been updated, the filter component will generate a new USB device report that
only contains the devices the component is allowed to access.
Example
~~~~~~~
In the following example we will give a VirtualBox instance access to a
Corsair Voyager USB stick:
!<start name="usb_report_filter">
![...]
! <config>
! <client label="vbox"
! <device vendor_id="0x1b1c" product_id="0x1a09"/>
! </config>
!</start>
!<start name="report_rom">
! <resource name="RAM" quantum="1M"/>
! <provides> <service name="Report"/> <service name="ROM"/> </provides>
! <config>
! <policy label="usb_report_filter -> devices" report="usb_drv -> devices"/>
! <policy label="usb_report_filter -> usb_drv_config" report="usb_drv -> config"/>
! <policy label="vbox -> usb_devices" report="usb_report_filter -> usb_devices"/>
! </config>
!</start>
After the USB stick has been plugged in, the filter will generate the
following USB driver configuration:
!<start name="usb_drv">
![...]
! <config>
! <report devices="yes"/>
! <policy label="vbox -> usb-1-3" vendor_id="0x1b1c" product_id="0x1a09" bus="0x0001" device="0x0003"/>
! </config>
!</start>
After the driver has reloaded its configuration it will send a config report
that provokes the filter component to send the following USB device report to
VirtualBox:
!<devices>
! <device label="usb-1-3" vendor_id="0x1b1c" product_id="0x1a09" bus="0x0001" device="0x0003"/>
!</device>
In return, VirtualBox will try to access the USB device. Since the configuration
of the USB driver contains a matching policy entry the access attempt will
succeed.

View File

@ -1,431 +0,0 @@
/*
* \brief Component that filters USB device reports
* \author Josef Soentgen
* \date 2016-01-13
*/
/*
* Copyright (C) 2016-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.
*/
/* Genode includes */
#include <base/component.h>
#include <base/allocator_avl.h>
#include <base/attached_rom_dataspace.h>
#include <base/heap.h>
#include <os/reporter.h>
#include <os/vfs.h>
#include <util/list.h>
#include <util/string.h>
#include <util/xml_generator.h>
#include <util/xml_node.h>
namespace Usb_filter {
using Genode::Xml_node;
using Genode::Xml_generator;
using Genode::Attached_rom_dataspace;
using Genode::error;
using Genode::log;
using Genode::warning;
struct Device_registry;
struct Main;
}
static bool const verbose = false;
static char const * const config_file = "usb_drv.config";
class Usb_filter::Device_registry
{
private:
Genode::Env &_env;
Genode::Allocator &_alloc;
Genode::Directory &_root_dir;
Genode::Reporter _reporter { _env, "usb_devices" };
Attached_rom_dataspace _devices_rom { _env, "devices" };
Attached_rom_dataspace _usb_drv_config_rom { _env, "usb_drv_config" };
struct Entry : public Genode::List<Entry>::Element
{
unsigned bus;
unsigned dev;
unsigned vendor;
unsigned product;
Entry(unsigned b, unsigned d, unsigned v, unsigned p)
: bus(b), dev(d), vendor(v), product(p) { }
};
Genode::List<Entry> _list { };
enum { MAX_LABEL_LEN = 512 };
typedef Genode::String<MAX_LABEL_LEN> Label;
Label _client_label { };
template <typename FUNC>
void _for_each_entry(FUNC const &func) const
{
Entry const *e = _list.first();
Entry const *next = nullptr;
for (; e; e = next) {
/*
* Obtain next element prior calling the functor because
* the functor may remove the current element from the list.
*/
next = e->next();
func(*e);
}
}
static unsigned _get_value(Xml_node node, char const * const attr) {
return node.attribute_value<unsigned>(attr, 0U); }
static bool _config_has_device(Xml_node config, Entry const &entry)
{
bool result = false;
config.for_each_sub_node("device", [&] (Xml_node usb_device) {
result |= (_get_value(usb_device, "bus") == entry.bus &&
_get_value(usb_device, "dev") == entry.dev);
if (result) return;
result |= (_get_value(usb_device, "vendor") == entry.vendor &&
_get_value(usb_device, "product") == entry.product);
});
return result;
}
static bool _devices_matches(Xml_node &device, Entry const & entry)
{
unsigned const bus = _get_value(device, "bus");
unsigned const dev = _get_value(device, "dev");
unsigned const vendor = _get_value(device, "vendor_id");
unsigned const product = _get_value(device, "product_id");
return (bus == entry.bus && dev == entry.dev) ||
(vendor == entry.vendor && product == entry.product);
}
static void _gen_dev_attributes(Xml_generator &xml, Xml_node const &node)
{
auto copy_attr = [&] (auto name)
{
using Value = Genode::String<32>;
xml.attribute(name, node.attribute_value(name, Value()));
};
copy_attr("vendor_id");
copy_attr("product_id");
copy_attr("bus");
copy_attr("dev");
}
static void _gen_policy_entry(Xml_generator &xml, Xml_node &node,
Entry const &, char const *label)
{
xml.node("policy", [&] {
unsigned const bus = _get_value(node, "bus");
unsigned const dev = _get_value(node, "dev");
xml.attribute("label", Label(label, " -> usb-", bus, "-", dev));
_gen_dev_attributes(xml, node);
});
}
void _write_usb_drv_config(Xml_node const &drv_config,
Xml_node const &usb_devices)
{
using namespace Genode;
bool const uhci_enabled = drv_config.attribute_value<bool>("uhci", false);
bool const ehci_enabled = drv_config.attribute_value<bool>("ehci", false);
bool const xhci_enabled = drv_config.attribute_value<bool>("xhci", false);
char new_content[1024];
Xml_generator xml(new_content, sizeof(new_content), "config", [&] {
if (uhci_enabled) xml.attribute("uhci", "yes");
if (ehci_enabled) xml.attribute("ehci", "yes");
if (xhci_enabled) xml.attribute("xhci", "yes");
/* copy other nodes */
drv_config.for_each_sub_node([&] (Xml_node &node) {
if (!node.has_type("raw")) {
node.with_raw_node([&] (char const *start, size_t length) {
xml.append(start, length); });
return;
}
});
if (!drv_config.has_sub_node("raw"))
log("enable raw support in usb_drv");
xml.node("raw", [&] {
xml.node("report", [&] {
xml.attribute("devices", "yes");
});
char const * const label = _client_label.string();
usb_devices.for_each_sub_node("device", [&] (Xml_node &node) {
auto add_policy_entry = [&] (Entry const &entry) {
if (!_devices_matches(node, entry)) return;
_gen_policy_entry(xml, node, entry, label);
};
_for_each_entry(add_policy_entry);
});
});
});
new_content[xml.used()] = 0;
if (verbose)
log("new usb_drv configuration:\n", Cstring(new_content));
try {
New_file new_file(_root_dir, config_file);
new_file.append(new_content, xml.used());
}
catch (...) {
error("could not write '", config_file, "'");
}
}
void _write_usb_drv_config(Xml_node const &usb_devices)
{
using namespace Genode;
try {
File_content::Limit limit { 64*1024 };
File_content old_file { _alloc, _root_dir, config_file,
limit };
old_file.xml([&] (Xml_node const &old_drv_config) {
_write_usb_drv_config(old_drv_config, usb_devices); });
} catch (...) {
error("could not access '", config_file, "'");
return;
}
}
Genode::Signal_handler<Device_registry> _devices_handler
{ _env.ep(), *this, &Device_registry::_handle_devices };
void _handle_devices()
{
_devices_rom.update();
if (!_devices_rom.valid()) return;
if (verbose)
log("device report:\n", _devices_rom.local_addr<char const>());
Xml_node usb_devices(_devices_rom.local_addr<char>(), _devices_rom.size());
_write_usb_drv_config(usb_devices);
}
bool _check_config(Xml_node &drv_config)
{
if (!drv_config.has_sub_node("raw")) {
error("could not access <raw> node");
return false;
}
auto check_policy = [&] (Entry const &entry) {
bool result = false;
drv_config.sub_node("raw").for_each_sub_node("policy", [&] (Xml_node &node) {
result |= (entry.bus == _get_value(node, "bus") &&
entry.dev == _get_value(node, "dev"));
if (result) return;
result |= (entry.vendor == _get_value(node, "vendor_id") &&
entry.product == _get_value(node, "product_id"));
});
if (verbose && !result)
warning("No matching policy was created for "
"device ", entry.bus, "-", entry.dev, " "
"(", entry.vendor, ":", entry.product, ")");
};
_for_each_entry(check_policy);
return true;
}
static void _gen_device_entry(Xml_generator &xml, Xml_node &node,
Entry const &)
{
xml.node("device", [&] {
unsigned const bus = _get_value(node, "bus");
unsigned const dev = _get_value(node, "dev");
xml.attribute("label", Label("usb-", bus, "-", dev));
_gen_dev_attributes(xml, node);
});
}
void _report_usb_devices()
{
using namespace Genode;
if (!_devices_rom.valid()) return;
/*
* XXX it might happen that the device list has changed after we are
* waiting for the usb_drv_config update
*/
Xml_node usb_devices(_devices_rom.local_addr<char>(), _devices_rom.size());
Reporter::Xml_generator xml(_reporter, [&] () {
usb_devices.for_each_sub_node("device", [&] (Xml_node &node) {
auto check_entry = [&] (Entry const &entry) {
if (!_devices_matches(node, entry)) return;
_gen_device_entry(xml, node, entry);
};
_for_each_entry(check_entry);
});
});
}
Genode::Signal_handler<Device_registry> _usb_drv_config_handler =
{ _env.ep(), *this, &Device_registry::_handle_usb_drv_config };
void _handle_usb_drv_config()
{
_usb_drv_config_rom.update();
if (!_usb_drv_config_rom.valid()) return;
Xml_node config(_usb_drv_config_rom.local_addr<char>(),
_usb_drv_config_rom.size());
if (!_check_config(config)) return;
/* report devices if the USB drivers has changed its policies */
_report_usb_devices();
}
bool _entry_exists(unsigned bus, unsigned dev,
unsigned vendor, unsigned product)
{
bool result = false;
auto check_exists = [&] (Entry const &entry) {
result |= (bus && dev) &&
(entry.bus == bus && entry.dev == dev);
result |= (vendor && product) &&
(entry.vendor == vendor && entry.product == product);
};
_for_each_entry(check_exists);
return result;
}
public:
/**
* Constructor
*/
Device_registry(Genode::Env &env, Genode::Allocator &alloc,
Genode::Directory &root_dir)
:
_env(env), _alloc(alloc), _root_dir(root_dir)
{
_reporter.enabled(true);
_devices_rom.sigh(_devices_handler);
_usb_drv_config_rom.sigh(_usb_drv_config_handler);
}
/**
* Update internal device registry
*/
void update_entries(Genode::Xml_node config)
{
auto remove_stale_entry = [&] (Entry const &entry) {
if (_config_has_device(config, entry))
return;
_list.remove(const_cast<Entry *>(&entry));
Genode::destroy(&_alloc, const_cast<Entry *>(&entry));
};
_for_each_entry(remove_stale_entry);
auto add_new_entry = [&] (Xml_node const &node) {
unsigned const bus = _get_value(node, "bus");
unsigned const dev = _get_value(node, "dev");
unsigned const vendor = _get_value(node, "vendor_id");
unsigned const product = _get_value(node, "product_id");
if (_entry_exists(bus, dev, vendor, product)) return;
Entry *entry = new (&_alloc) Entry(bus, dev, vendor, product);
_list.insert(entry);
};
config.for_each_sub_node("device", add_new_entry);
try {
config.sub_node("client").attribute("label").value(_client_label);
} catch (...) {
error("could not update client label");
}
}
};
struct Usb_filter::Main
{
Genode::Env &_env;
Genode::Heap _heap { _env.ram(), _env.rm() };
Genode::Attached_rom_dataspace _config { _env, "config" };
Genode::Root_directory _root_dir { _env, _heap, _config.xml().sub_node("vfs") };
Genode::Signal_handler<Main> _config_handler =
{ _env.ep(), *this, &Main::_handle_config };
void _handle_config()
{
_config.update();
device_registry.update_entries(_config.xml());
}
Device_registry device_registry { _env, _heap, _root_dir };
Main(Genode::Env &env) : _env(env)
{
_config.sigh(_config_handler);
_handle_config();
}
};
void Component::construct(Genode::Env &env) {
static Usb_filter::Main main(env); }

View File

@ -1,3 +0,0 @@
TARGET = usb_report_filter
SRC_CC = main.cc
LIBS = base vfs

View File

@ -19,6 +19,7 @@
namespace Usb {
struct Cbw;
struct Csw;
enum { ENDPOINT_IN = 0x80, ENDPOINT_OUT = 0 };
}
@ -28,6 +29,7 @@ using Genode::uint32_t;
using Genode::uint64_t;
using Genode::size_t;
using Genode::addr_t;
using Genode::Byte_range_ptr;
/*****************************************************
@ -72,12 +74,15 @@ struct Usb::Cbw : Genode::Mmio<0xf>
struct Test_unit_ready : Usb::Cbw,
Scsi::Test_unit_ready
{
Test_unit_ready(Genode::Byte_range_ptr const &range, uint32_t tag, uint8_t lun)
Test_unit_ready(Byte_range_ptr const &range, uint32_t tag, uint8_t lun,
bool verbose)
:
Cbw(range, tag, 0, Usb::ENDPOINT_IN, lun,
Scsi::Test_unit_ready::LENGTH),
Scsi::Test_unit_ready(Cbw::range_at(15))
{ if (verbose_scsi) dump(); }
{
if (verbose) dump();
}
void dump()
{
@ -90,12 +95,15 @@ struct Test_unit_ready : Usb::Cbw,
struct Request_sense : Usb::Cbw, Scsi::Request_sense
{
Request_sense(Genode::Byte_range_ptr const &range, uint32_t tag, uint8_t lun)
Request_sense(Byte_range_ptr const &range, uint32_t tag, uint8_t lun,
bool verbose)
:
Cbw(range, tag, Scsi::Request_sense_response::LENGTH,
Usb::ENDPOINT_IN, lun, Scsi::Request_sense::LENGTH),
Scsi::Request_sense(Cbw::range_at(15))
{ if (verbose_scsi) dump(); }
{
if (verbose) dump();
}
void dump()
{
@ -108,11 +116,14 @@ struct Request_sense : Usb::Cbw, Scsi::Request_sense
struct Start_stop : Usb::Cbw, Scsi::Start_stop
{
Start_stop(Genode::Byte_range_ptr const &range, uint32_t tag, uint8_t lun)
Start_stop(Byte_range_ptr const &range, uint32_t tag, uint8_t lun,
bool verbose)
:
Cbw(range, tag, 0, Usb::ENDPOINT_IN, lun, Scsi::Start_stop::LENGTH),
Scsi::Start_stop(Cbw::range_at(15))
{ if (verbose_scsi) dump(); }
{
if (verbose) dump();
}
void dump()
{
@ -125,12 +136,15 @@ struct Start_stop : Usb::Cbw, Scsi::Start_stop
struct Inquiry : Usb::Cbw, Scsi::Inquiry
{
Inquiry(Genode::Byte_range_ptr const &range, uint32_t tag, uint8_t lun)
Inquiry(Byte_range_ptr const &range, uint32_t tag, uint8_t lun,
bool verbose)
:
Cbw(range, tag, Scsi::Inquiry_response::LENGTH,
Usb::ENDPOINT_IN, lun, Scsi::Inquiry::LENGTH),
Scsi::Inquiry(Cbw::range_at(15))
{ if (verbose_scsi) dump(); }
{
if (verbose) dump();
}
void dump()
{
@ -143,12 +157,15 @@ struct Inquiry : Usb::Cbw, Scsi::Inquiry
struct Read_capacity_10 : Usb::Cbw, Scsi::Read_capacity_10
{
Read_capacity_10(Genode::Byte_range_ptr const &range, uint32_t tag, uint8_t lun)
Read_capacity_10(Byte_range_ptr const &range, uint32_t tag, uint8_t lun,
bool verbose)
:
Cbw(range, tag, Scsi::Capacity_response_10::LENGTH,
Usb::ENDPOINT_IN, lun, Scsi::Read_capacity_10::LENGTH),
Scsi::Read_capacity_10(Cbw::range_at(15))
{ if (verbose_scsi) dump(); }
{
if (verbose) dump();
}
void dump()
{
@ -161,13 +178,15 @@ struct Read_capacity_10 : Usb::Cbw, Scsi::Read_capacity_10
struct Read_10 : Usb::Cbw, Scsi::Read_10
{
Read_10(Genode::Byte_range_ptr const &range, uint32_t tag, uint8_t lun,
uint32_t lba, uint16_t len, uint32_t block_size)
Read_10(Byte_range_ptr const &range, uint32_t tag, uint8_t lun,
uint32_t lba, uint16_t len, uint32_t block_size, bool verbose)
:
Cbw(range, tag, len * block_size,
Usb::ENDPOINT_IN, lun, Scsi::Read_10::LENGTH),
Scsi::Read_10(Cbw::range_at(15), lba, len)
{ if (verbose_scsi) dump(); }
{
if (verbose) dump();
}
void dump()
{
@ -180,13 +199,15 @@ struct Read_10 : Usb::Cbw, Scsi::Read_10
struct Write_10 : Usb::Cbw, Scsi::Write_10
{
Write_10(Genode::Byte_range_ptr const &range, uint32_t tag, uint8_t lun,
uint32_t lba, uint16_t len, uint32_t block_size)
Write_10(Byte_range_ptr const &range, uint32_t tag, uint8_t lun,
uint32_t lba, uint16_t len, uint32_t block_size, bool verbose)
:
Cbw(range, tag, len * block_size,
Usb::ENDPOINT_OUT, lun, Scsi::Write_10::LENGTH),
Scsi::Write_10(Cbw::range_at(15), lba, len)
{ if (verbose_scsi) dump(); }
{
if (verbose) dump();
}
void dump()
{
@ -199,12 +220,15 @@ struct Write_10 : Usb::Cbw, Scsi::Write_10
struct Read_capacity_16 : Usb::Cbw, Scsi::Read_capacity_16
{
Read_capacity_16(Genode::Byte_range_ptr const &range, uint32_t tag, uint8_t lun)
Read_capacity_16(Byte_range_ptr const &range, uint32_t tag, uint8_t lun,
bool verbose)
:
Cbw(range, tag, Scsi::Capacity_response_16::LENGTH,
Usb::ENDPOINT_IN, lun, Scsi::Read_capacity_16::LENGTH),
Scsi::Read_capacity_16(Cbw::range_at(15))
{ if (verbose_scsi) dump(); }
{
if (verbose) dump();
}
void dump()
{
@ -217,13 +241,15 @@ struct Read_capacity_16 : Usb::Cbw, Scsi::Read_capacity_16
struct Read_16 : Usb::Cbw, Scsi::Read_16
{
Read_16(Genode::Byte_range_ptr const &range, uint32_t tag, uint8_t lun,
uint64_t lba, uint32_t len, uint32_t block_size)
Read_16(Byte_range_ptr const &range, uint32_t tag, uint8_t lun,
uint64_t lba, uint32_t len, uint32_t block_size, bool verbose)
:
Cbw(range, tag, len * block_size,
Usb::ENDPOINT_IN, lun, Scsi::Read_16::LENGTH),
Scsi::Read_16(Cbw::range_at(15), (uint32_t)lba, (uint16_t)len)
{ if (verbose_scsi) dump(); }
{
if (verbose) dump();
}
void dump()
{
@ -236,13 +262,15 @@ struct Read_16 : Usb::Cbw, Scsi::Read_16
struct Write_16 : Usb::Cbw, Scsi::Write_16
{
Write_16(Genode::Byte_range_ptr const &range, uint32_t tag, uint8_t lun,
uint64_t lba, uint32_t len, uint32_t block_size)
Write_16(Byte_range_ptr const &range, uint32_t tag, uint8_t lun,
uint64_t lba, uint32_t len, uint32_t block_size, bool verbose)
:
Cbw(range, tag, len * block_size,
Usb::ENDPOINT_OUT, lun, Scsi::Write_16::LENGTH),
Scsi::Write_16(Cbw::range_at(15), (uint32_t)lba, (uint16_t)len)
{ if (verbose_scsi) dump(); }
{
if (verbose) dump();
}
void dump()
{
@ -253,7 +281,7 @@ struct Write_16 : Usb::Cbw, Scsi::Write_16
};
struct Usb::Csw : Genode::Mmio<0xd>
struct Usb::Csw : Genode::Const_mmio<0xd>
{
enum { LENGTH = 13 };
@ -264,7 +292,7 @@ struct Usb::Csw : Genode::Mmio<0xd>
enum { PASSED = 0, FAILED = 1, PHASE_ERROR = 2 };
struct Sts : Register<0xc, 8> { }; /* status */
Csw(Genode::Byte_range_ptr const &range) : Mmio(range) { }
Csw(Genode::Const_byte_range_ptr const &range) : Const_mmio(range) { }
uint32_t sig() const { return read<Sig>(); }
uint32_t tag() const { return read<Tag>(); }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,74 @@
/*
* \brief Extension of MMIO framework with const read-only MMIO regions
* \author Stefan Kalkowski
* \date 2024-02-21
*/
/*
* Copyright (C) 2024 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 _USB_BLOCK__MMIO_H_
#define _USB_BLOCK__MMIO_H_
#include <util/mmio.h>
namespace Genode {
class Const_mmio_plain_access;
template <size_t> class Const_mmio;
};
/**
* Plain access implementation for MMIO
*/
class Genode::Const_mmio_plain_access
{
friend Register_set_plain_access;
private:
Const_byte_range_ptr const _range;
template <typename ACCESS_T>
inline ACCESS_T _read(off_t const &offset) const {
return *(ACCESS_T volatile *)(_range.start + offset); }
public:
Const_mmio_plain_access(Const_byte_range_ptr const &range)
: _range(range.start, range.num_bytes) { }
Const_byte_range_ptr range_at(off_t offset) const {
return {_range.start + offset, _range.num_bytes - offset}; }
Const_byte_range_ptr range() const { return range_at(0); }
addr_t base() const { return (addr_t)range().start; }
};
template <Genode::size_t MMIO_SIZE>
struct Genode::Const_mmio : Const_mmio_plain_access,
Register_set<Const_mmio_plain_access, MMIO_SIZE>
{
static constexpr size_t SIZE = MMIO_SIZE;
class Range_violation : Exception { };
Const_mmio(Const_byte_range_ptr const &range)
:
Const_mmio_plain_access(range),
Register_set<Const_mmio_plain_access, SIZE>(*static_cast<Const_mmio_plain_access *>(this))
{
if (range.num_bytes < SIZE) {
error("MMIO range is unexpectedly too small");
throw Range_violation { };
}
}
};
#endif /* _USB_BLOCK__MMIO_H_ */

View File

@ -16,7 +16,8 @@
#include <base/stdint.h>
#include <util/endian.h>
#include <util/mmio.h>
#include <mmio.h>
namespace Scsi {
@ -84,7 +85,7 @@ namespace Scsi {
* SCSI command responses **
***************************/
struct Scsi::Inquiry_response : Genode::Mmio<0x24>
struct Scsi::Inquiry_response : Genode::Const_mmio<0x24>
{
/*
* Minimum response length is 36 bytes.
@ -105,7 +106,8 @@ struct Scsi::Inquiry_response : Genode::Mmio<0x24>
struct Pid : Register_array<0x10, 8, 16, 8> { }; /* product identification */
struct Rev : Register_array<0x20, 8, 4, 8> { }; /* product revision level */
Inquiry_response(Byte_range_ptr const &range) : Mmio(range) { }
Inquiry_response(Const_byte_range_ptr const &range, bool verbose)
: Const_mmio(range) { if (verbose) dump(); }
bool sbc() const { return read<Dt>() == 0x00; }
bool removable() const { return read<Rm::Rmb>(); }
@ -132,7 +134,7 @@ struct Scsi::Inquiry_response : Genode::Mmio<0x24>
};
struct Scsi::Request_sense_response : Genode::Mmio<0x13>
struct Scsi::Request_sense_response : Genode::Const_mmio<0x13>
{
enum { LENGTH = 18 };
@ -153,7 +155,8 @@ struct Scsi::Request_sense_response : Genode::Mmio<0x13>
struct Fru : Register<0xe, 8> { }; /* field replaceable unit code */
struct Sks : Register<0xf, 32> { }; /* sense key specific (3 byte) */
Request_sense_response(Byte_range_ptr const &range) : Mmio(range) { }
Request_sense_response(Const_byte_range_ptr const &range, bool verbose)
: Const_mmio(range) { if (verbose) dump(); }
void dump()
{
@ -167,14 +170,15 @@ struct Scsi::Request_sense_response : Genode::Mmio<0x13>
};
struct Scsi::Capacity_response_10 : Genode::Mmio<0x8>
struct Scsi::Capacity_response_10 : Genode::Const_mmio<0x8>
{
enum { LENGTH = 8 };
struct Lba : Register<0x0, 32> { };
struct Bs : Register<0x4, 32> { };
Capacity_response_10(Byte_range_ptr const &range) : Mmio(range) { }
Capacity_response_10(Const_byte_range_ptr const &range, bool verbose)
: Const_mmio(range) { if (verbose) dump(); }
uint32_t last_block() const { return be(read<Lba>()); }
uint32_t block_size() const { return be(read<Bs>()); }
@ -188,14 +192,15 @@ struct Scsi::Capacity_response_10 : Genode::Mmio<0x8>
};
struct Scsi::Capacity_response_16 : Genode::Mmio<0xc>
struct Scsi::Capacity_response_16 : Genode::Const_mmio<0xc>
{
enum { LENGTH = 32 };
struct Lba : Register<0x0, 64> { };
struct Bs : Register<0x8, 32> { };
Capacity_response_16(Byte_range_ptr const &range) : Mmio(range) { }
Capacity_response_16(Const_byte_range_ptr const &range, bool verbose)
: Const_mmio(range) { if (verbose) dump(); }
uint64_t last_block() const { return be(read<Lba>()); }
uint32_t block_size() const { return be(read<Bs>()); }

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,7 @@
/*
* \brief Genode USB client provider C-API
* \author Sebastian Sumpf
* \author Stefan Kalkowski
* \date 2023-06-29
*/
@ -12,329 +13,624 @@
*/
#include <base/id_space.h>
#include <usb_session/connection.h>
#include <base/heap.h>
#include <genode_c_api/usb_client.h>
#include <base/tslab.h>
#include <util/bit_allocator.h>
#include <util/reconstructible.h>
#include <util/list_model.h>
#include <util/string.h>
#include <usb_session/device.h>
#include <genode_c_api/usb_client.h>
using namespace Genode;
struct Usb_client;
struct Usb_completion;
struct Device;
using Usb_id_space = Id_space<Usb_client>;
struct Usb_completion : Usb::Completion
struct Endpoint : List_model<Endpoint>::Element
{
Usb::Packet_descriptor packet { };
uint8_t const address;
uint8_t const attributes;
uint8_t const max_packet_size;
genode_usb_client_request_packet *request = nullptr;
Endpoint(Xml_node const &n)
:
address(n.attribute_value<uint8_t>("address", 0xff)),
attributes(n.attribute_value<uint8_t>("attributes", 0xff)),
max_packet_size(n.attribute_value<uint8_t>("max_packet_size", 0)) {}
void complete(Usb::Packet_descriptor &p) override
{
packet = p;
request->actual_length = (packet.type == Usb::Packet_descriptor::CTRL) ?
packet.control.actual_size : packet.transfer.actual_size;
bool matches(Xml_node const &node) const {
return address == node.attribute_value<uint8_t>("address", 0xff); }
request->error = NO_ERROR;
if (!packet.succeded) {
switch (packet.error) {
case Usb::Packet_descriptor::NO_ERROR:
request->error = NO_ERROR; break;
case Usb::Packet_descriptor::INTERFACE_OR_ENDPOINT_ERROR:
request->error = INTERFACE_OR_ENDPOINT_ERROR; break;
case Usb::Packet_descriptor::MEMORY_ERROR:
request->error = MEMORY_ERROR; break;
case Usb::Packet_descriptor::NO_DEVICE_ERROR:
request->error = NO_DEVICE_ERROR; break;
case Usb::Packet_descriptor::PACKET_INVALID_ERROR:
request->error = PACKET_INVALID_ERROR; break;
case Usb::Packet_descriptor::PROTOCOL_ERROR:
request->error = PROTOCOL_ERROR; break;
case Usb::Packet_descriptor::STALL_ERROR:
request->error = STALL_ERROR; break;
case Usb::Packet_descriptor::TIMEOUT_ERROR:
request->error = TIMEOUT_ERROR; break;
case Usb::Packet_descriptor::UNKNOWN_ERROR:
request->error = UNKNOWN_ERROR; break;
}
}
if (request->complete_callback)
request->complete_callback(request);
}
void free()
{
request->error = NO_DEVICE_ERROR;
if (request->free_callback) request->free_callback(request);
}
static bool type_matches(Xml_node const &node) {
return node.has_type("endpoint"); }
};
struct Usb_client : Usb::Connection
class Interface : public List_model<::Interface>::Element
{
enum { PACKET_SLOTS = Usb::Session::TX_QUEUE_SIZE };
public:
Usb_completion completions[PACKET_SLOTS];
Bit_allocator<PACKET_SLOTS> slots { };
Usb_id_space::Element const elem;
class Urb : Usb::Endpoint, public Usb::Interface::Urb
{
private:
Usb_client(Env &env, Usb_id_space &space, char const *label,
Range_allocator *alloc,
Signal_context_capability state_changed)
: Usb::Connection(env, alloc, label, 512*1024, state_changed),
elem(*this, space)
{ }
friend class ::Interface;
using Pdesc = Usb::Interface::Packet_descriptor;
genode_usb_client_handle_t handle() const { return elem.id().value; }
static Pdesc::Type _type(genode_usb_client_iface_type_t t)
{
switch(t) {
case ::BULK: return Pdesc::BULK;
case ::IRQ: return Pdesc::IRQ;
case ::ISOC: return Pdesc::ISOC;
case ::FLUSH: return Pdesc::FLUSH;
};
return Pdesc::FLUSH;
}
void free_completion(Usb_completion *completion)
{
unsigned long slot_idx = (unsigned long)(completion - completions);
slots.free(slot_idx);
}
struct Driver_data { void * const data; } _driver_data;
Usb_completion *alloc(size_t size)
{
/*
* We don't need to check for 'ready_to_submit' because we have as many
* compltions as packet slots
public:
Urb(::Interface &iface,
::Endpoint &endp,
genode_usb_client_iface_type_t type,
size_t size,
void *opaque_data)
:
Usb::Endpoint(endp.address, endp.attributes),
Usb::Interface::Urb(iface._session(), *this, _type(type),
size),
_driver_data{opaque_data} {}
};
private:
Device &_device;
Constructible<Usb::Interface> _iface {};
List_model<Endpoint> _endpoints {};
uint8_t const _number;
uint8_t const _alt_setting;
bool _active;
Tslab<Urb, 4096> _slab;
/* The interface's buffer size might be configureable in the future */
size_t _buf_size { 4096 * 128 };
Usb::Interface &_session();
public:
Interface(Device &device, Xml_node const &n, Allocator &alloc)
:
_device(device),
_number(n.attribute_value<uint8_t>("number", 0xff)),
_alt_setting(n.attribute_value<uint8_t>("alt_setting", 0xff)),
_active(n.attribute_value("active", false)),
_slab(alloc) {}
~Interface()
{
if (_iface.constructed())
_iface->dissolve_all_urbs<Urb>([&] (Urb &urb) {
destroy(_slab, &urb); });
}
uint8_t number() const { return _number; };
uint8_t alt_setting() const { return _alt_setting; };
bool active() const { return _active; }
void active(bool active) { _active = active; }
Allocator &slab() { return _slab; }
bool matches(Xml_node const &n) const
{
uint8_t nr = n.attribute_value<uint8_t>("number", 0xff);
uint8_t alt = n.attribute_value<uint8_t>("alt_setting", 0xff);
return _number == nr && _alt_setting == alt;
}
static bool type_matches(Xml_node const &node) {
return node.has_type("interface"); }
void update(Allocator &alloc, Xml_node const &node)
{
_active = node.attribute_value("active", false);
_endpoints.update_from_xml(node,
/* create */
[&] (Xml_node const &node) -> Endpoint & {
return *new (alloc) Endpoint(node); },
/* destroy */
[&] (Endpoint &endp) {
destroy(alloc, &endp); },
/* update */
[&] (Endpoint &, Xml_node const &) { }
);
}
void update(genode_usb_client_produce_out_t out,
genode_usb_client_consume_in_t in,
genode_usb_client_produce_out_isoc_t out_isoc,
genode_usb_client_consume_in_isoc_t in_isoc,
genode_usb_client_complete_t complete)
{
if (!_iface.constructed())
return;
_iface->update_urbs<Urb>(
/* produce out content */
[&] (Urb &urb, Byte_range_ptr &dst) {
out(urb._driver_data.data, { dst.start, dst.num_bytes });
},
/* consume in results */
[&] (Urb &urb, Const_byte_range_ptr &src) {
in(urb._driver_data.data,
{ (void*)src.start, src.num_bytes });
},
/* produce out content */
[&] (Urb &urb, uint32_t idx, Byte_range_ptr &dst) {
return out_isoc(urb._driver_data.data, idx,
{ dst.start, dst.num_bytes });
},
/* consume in results */
[&] (Urb &urb, uint32_t idx, Const_byte_range_ptr &src) {
in_isoc(urb._driver_data.data, idx,
{ (void*)src.start, src.num_bytes });
},
/* complete USB request */
[&] (Urb &urb, Usb::Tagged_packet::Return_value v) {
using Retval = Usb::Tagged_packet::Return_value;
genode_usb_client_ret_val_t ret;
switch (v) {
case Retval::NO_DEVICE: ret = NO_DEVICE; break;
case Retval::INVALID: ret = INVALID; break;
case Retval::HALT: ret = HALT; break;
case Retval::OK: ret = OK; break;
default:
error("unhandled packet or timeout should not happen!");
ret = INVALID;
};
complete(urb._driver_data.data, ret);
destroy(_slab, &urb);
});
}
template <typename FN>
void with_endpoint(uint8_t index, FN const &fn)
{
_endpoints.for_each([&] (Endpoint &endp) {
if (endp.address == index) fn(endp);
});
}
void delete_all_urbs(genode_usb_client_complete_t complete)
{
_iface->dissolve_all_urbs<Urb>([&] (Urb &urb) {
complete(urb._driver_data.data, NO_DEVICE);
destroy(_slab, &urb);
});
}
};
class Device : public List_model<Device>::Element
{
public:
using Name = String<64>;
using Speed = String<32>;
struct Urb : Usb::Device::Urb
{
using Descriptor = Usb::Device::Packet_descriptor;
using Request_type = Descriptor::Request_type;
struct Driver_data { void * const data; } _driver_data;
Urb(Device & device,
uint8_t request,
uint8_t request_type,
uint16_t value,
uint16_t index,
size_t size,
void *opaque_data)
:
Usb::Device::Urb(device._device, request,
(Request_type::access_t)request_type,
value, index, size),
_driver_data{opaque_data} {}
bool set_interface() const;
uint16_t index() const { return _index; }
uint16_t value() const { return _value; }
};
private:
Name const _name;
Speed const _speed;
Id_space<Device>::Element const _elem;
Usb::Device _device;
Signal_context_capability _sigh_cap;
void *_driver_data { nullptr };
List_model<::Interface> _ifaces {};
Tslab<Urb, 4096> _slab;
enum State { AVAIL, REMOVED } _state { AVAIL };
/**
* Noncopyable
*/
Usb_completion *completion = nullptr;
try {
completion = &completions[slots.alloc()];
Usb::Packet_descriptor packet = Usb::Session_client::alloc_packet(size);
packet.completion = completion;
completion->packet = packet;
} catch (Tx::Source::Packet_alloc_failed) {
free_completion(completion);
return nullptr;
} catch (Bit_allocator<PACKET_SLOTS>::Out_of_indices) {
return nullptr;
Device(Device const &);
Device &operator = (Device const &);
friend class Session;
void _delete_all_urbs(genode_usb_client_complete_t complete)
{
_device.dissolve_all_urbs<Urb>([&] (Urb &urb) {
complete(urb._driver_data.data, NO_DEVICE);
destroy(_slab, &urb);
});
_ifaces.for_each([&] (::Interface &iface) {
iface.delete_all_urbs(complete); });
}
return completion;
}
public:
void release(Usb_completion *completion)
Device(Name &name,
Speed &speed,
Usb::Connection &usb,
Allocator &alloc,
Region_map &rm,
Id_space<Device> &space,
Signal_context_capability cap)
:
_name(name),
_speed(speed),
_elem(*this, space),
_device(usb, alloc, rm, name),
_sigh_cap(cap),
_slab(alloc)
{
_device.sigh(_sigh_cap);
}
~Device()
{
_device.dissolve_all_urbs<Urb>([&] (Urb &urb) {
destroy(_slab, &urb); });
}
Usb::Device &session() { return _device; }
Name name() { return _name; }
Usb_speed speed()
{
if (_speed == "low") return GENODE_USB_SPEED_LOW;
if (_speed == "full") return GENODE_USB_SPEED_FULL;
if (_speed == "high") return GENODE_USB_SPEED_HIGH;
if (_speed == "super") return GENODE_USB_SPEED_SUPER;
if (_speed == "super_plus") return GENODE_USB_SPEED_SUPER_PLUS;
if (_speed == "super_plus_2x2")
return GENODE_USB_SPEED_SUPER_PLUS_2X2;
return GENODE_USB_SPEED_FULL;
}
Signal_context_capability sigh_cap() { return _sigh_cap; }
genode_usb_client_dev_handle_t handle() const {
return _elem.id().value; }
void driver_data(void *data) { _driver_data = data; }
void* driver_data() { return _driver_data; }
Allocator &slab() { return _slab; }
bool matches(Xml_node const &node) const {
return _name == node.attribute_value("name", Name()); }
static bool type_matches(Xml_node const &node) {
return node.has_type("device"); }
void set_interface(uint16_t index, uint16_t value);
void update(Allocator &alloc, Xml_node const &node)
{
Xml_node active_config = node;
node.for_each_sub_node("config", [&] (Xml_node const &node) {
if (node.attribute_value("active", false))
active_config = node;
});
_ifaces.update_from_xml(active_config,
/* create */
[&] (Xml_node const &node) -> ::Interface & {
return *new (alloc) ::Interface(*this, node, alloc); },
/* destroy */
[&] (::Interface &iface) {
iface.update(alloc, Xml_node("<empty/>"));
destroy(alloc, &iface); },
/* update */
[&] (::Interface &iface, Xml_node const &node) {
iface.update(alloc, node); }
);
}
void update(genode_usb_client_produce_out_t out,
genode_usb_client_consume_in_t in,
genode_usb_client_produce_out_isoc_t out_isoc,
genode_usb_client_consume_in_isoc_t in_isoc,
genode_usb_client_complete_t complete)
{
if (_state == REMOVED) {
_delete_all_urbs(complete);
return;
}
_device.update_urbs<Urb>(
/* produce out content */
[&] (Urb &urb, Byte_range_ptr &dst) {
out(urb._driver_data.data, { (void*)dst.start,
dst.num_bytes });
},
/* consume in results */
[&] (Urb &urb, Const_byte_range_ptr &src) {
in(urb._driver_data.data, { (void*)src.start,
src.num_bytes });
},
/* complete USB request */
[&] (Urb &urb, Usb::Tagged_packet::Return_value v)
{
using Retval = Usb::Tagged_packet::Return_value;
genode_usb_client_ret_val_t ret;
switch (v) {
case Retval::NO_DEVICE: ret = NO_DEVICE; break;
case Retval::INVALID: ret = INVALID; break;
case Retval::HALT: ret = HALT; break;
case Retval::TIMEOUT: ret = TIMEOUT; break;
case Retval::OK:
ret = OK;
if (urb.set_interface())
set_interface(urb.index(), urb.value());
break;
default:
error("unhandled packet should not happen!");
ret = INVALID;
};
complete(urb._driver_data.data, ret);
destroy(_slab, &urb);
});
_ifaces.for_each([&] (::Interface &iface) {
iface.update(out, in, out_isoc, in_isoc, complete); });
}
template <typename FN>
void with_active_interfaces(FN const &fn)
{
_ifaces.for_each([&] (::Interface &iface) {
if (iface.active()) fn(iface); });
}
};
struct Session
{
Env &_env;
Allocator &_alloc;
Signal_context_capability _handler_cap;
Usb::Connection _usb { _env };
List_model<Device> _model {};
Id_space<Device> _space {};
Session(Env &env, Allocator &alloc, Signal_context_capability io_cap,
Signal_context_capability rom_cap)
:
_env(env), _alloc(alloc), _handler_cap(io_cap)
{
source()->release_packet(completion->packet);
free_completion(completion);
_usb.sigh(rom_cap);
}
~Session() {
_model.for_each([&] (Device &dev) { destroy(_alloc, &dev); }); }
void update(genode_usb_client_dev_add_t add,
genode_usb_client_dev_del_t del)
{
_usb.with_xml([&] (Xml_node node) {
_model.update_from_xml(node,
/* create */
[&] (Xml_node const &node) -> Device &
{
Device::Name name =
node.attribute_value("name", Device::Name());
Device::Speed speed =
node.attribute_value("speed", Device::Speed());
Device &dev = *new (_alloc)
Device(name, speed, _usb, _alloc, _env.rm(),
_space, _handler_cap);
return dev;
},
/* destroy */
[&] (Device &dev)
{
dev._state = Device::REMOVED;
if (dev.driver_data()) del(dev.handle(), dev.driver_data());
dev.update(_alloc, Xml_node("<empty/>"));
destroy(_alloc, &dev);
},
/* update */
[&] (Device &dev, Xml_node const &node)
{
dev.update(_alloc, node);
}
);
});
/* add new devices for C-API client after it got successfully added */
_model.for_each([&] (Device &dev) {
if (!dev.driver_data())
dev.driver_data(add(dev.handle(), dev.name().string(),
dev.speed()));
});
}
};
static Usb_id_space & usb_space()
Usb::Interface &::Interface::_session()
{
static Usb_id_space instance { };
if (!_iface.constructed()) {
_iface.construct(_device.session(),
Usb::Interface::Index{_number, _alt_setting},
_buf_size);
_iface->sigh(_device.sigh_cap());
}
return *_iface;
};
return instance;
bool Device::Urb::set_interface() const
{
return (_request == Descriptor::SET_INTERFACE) &&
(Request_type::R::get(_request_type) == Descriptor::IFACE) &&
(Request_type::T::get(_request_type) == Descriptor::STANDARD);
}
template <typename FUNC>
int usb_client_apply(genode_usb_client_handle_t handle, FUNC const &fn)
void Device::set_interface(uint16_t index, uint16_t value)
{
_ifaces.for_each([&] (::Interface &iface) {
if (iface.number() != index)
return;
iface.active(iface.alt_setting() == value);
});
}
static ::Session * _usb_session = nullptr;
void Genode_c_api::initialize_usb_client(Env &env,
Allocator &alloc,
Signal_context_capability io_handler,
Signal_context_capability rom_handler)
{
static ::Session session(env, alloc, io_handler, rom_handler);
_usb_session = &session;
};
extern "C"
void genode_usb_client_update(genode_usb_client_dev_add_t add,
genode_usb_client_dev_del_t del)
{
if (_usb_session) _usb_session->update(add, del);
}
extern "C"
genode_usb_client_ret_val_t
genode_usb_client_device_control(genode_usb_client_dev_handle_t handle,
genode_uint8_t request,
genode_uint8_t request_type,
genode_uint16_t value,
genode_uint16_t index,
unsigned long size,
void *opaque_data)
{
Usb_id_space::Id id { .value = handle };
try {
usb_space().apply<Usb_client>(id, fn);
} catch (Usb_id_space::Id_space::Unknown_id) {
error("Invalid handle: ", handle);
return -1;
if (!_usb_session)
return NO_DEVICE;
return _usb_session->_space.apply<Device>({ handle },
[&] (Device & device) {
new (device.slab())
Device::Urb(device, request, request_type,
value, index, size, opaque_data);
return OK;
});
} catch(Id_space<Device>::Unknown_id&) {
return NO_DEVICE;
} catch(...) {
return NO_MEMORY;
}
return 0;
}
genode_usb_client_handle_t
genode_usb_client_create(struct genode_env *env,
struct genode_allocator *md_alloc,
struct genode_range_allocator *alloc,
char const *label,
struct genode_signal_handler *handler)
extern "C"
void
genode_usb_client_device_update(genode_usb_client_produce_out_t out,
genode_usb_client_consume_in_t in,
genode_usb_client_produce_out_isoc_t out_isoc,
genode_usb_client_consume_in_isoc_t in_isoc,
genode_usb_client_complete_t complete)
{
Env &_env = *static_cast<Env *>(env);
Range_allocator *_alloc = static_cast<Range_allocator*>(alloc);
Allocator *_md_alloc = static_cast<Allocator *>(md_alloc);
try {
if (!_usb_session)
return;
_usb_session->_model.for_each([&] (Device & device) {
device.update(out, in, out_isoc, in_isoc, complete); });
Usb_client *client = new (_md_alloc) Usb_client(_env, usb_space(), label,
_alloc, cap(handler));
return client->handle();
} catch(...) { }
}
void genode_usb_client_destroy(genode_usb_client_handle_t handle,
struct genode_allocator *md_alloc)
extern "C"
genode_usb_client_ret_val_t
genode_usb_client_iface_transfer(genode_usb_client_dev_handle_t handle,
genode_usb_client_iface_type_t type,
genode_uint8_t index,
unsigned long size,
void *opaque_data)
{
usb_client_apply(handle, [&] (Usb_client &usb) {
while(usb.source()->ack_avail()) {
Usb::Packet_descriptor p = usb.source()->get_acked_packet();
if (p.completion) static_cast<Usb_completion *>(p.completion)->free();
usb.source()->release_packet(p);
}
destroy(md_alloc, &usb);
});
};
try {
if (!_usb_session)
return NO_DEVICE;
genode_usb_client_ret_val_t ret = NO_DEVICE;
void genode_usb_client_sigh_ack_avail(genode_usb_client_handle_t handle,
struct genode_signal_handler *handler)
{
usb_client_apply(handle, [&] (Usb_client &usb) {
usb.tx_channel()->sigh_ack_avail(cap(handler)); });
}
int genode_usb_client_config_descriptor(genode_usb_client_handle_t handle,
genode_usb_device_descriptor *device_descr,
genode_usb_config_descriptor *config_descr)
{
auto lambda = [&] (Usb_client &usb) {
Usb::Device_descriptor dev_descr;
Usb::Config_descriptor conf_descr;
usb.config_descriptor(&dev_descr, &conf_descr);
memcpy(device_descr, &dev_descr, sizeof(*device_descr));
memcpy(config_descr, &config_descr, sizeof(*config_descr));
};
return usb_client_apply(handle, lambda);
}
bool genode_usb_client_plugged(genode_usb_client_handle_t handle)
{
bool plugged = false;
usb_client_apply(handle, [&] (Usb_client &usb) {
plugged = usb.plugged(); });
return plugged;
}
void genode_usb_client_claim_interface(genode_usb_client_handle_t handle,
unsigned interface_num)
{
usb_client_apply(handle, [&] (Usb_client &usb) {
usb.claim_interface(interface_num);
});
}
void genode_usb_client_release_interface(genode_usb_client_handle_t handle,
unsigned interface_num)
{
usb_client_apply(handle, [&] (Usb_client &usb) {
usb.release_interface(interface_num);
});
}
bool genode_usb_client_request(genode_usb_client_handle_t handle,
genode_usb_client_request_packet *request)
{
Usb_completion *completion = nullptr;
usb_client_apply(handle, [&] (Usb_client &usb) {
completion = usb.alloc(request->buffer.size);
if (completion)
request->buffer.addr = usb.source()->packet_content(completion->packet);
});
if (!completion) return false;
completion->request = request;
request->completion = completion;
/* setup packet */
genode_request_packet_t *req = &request->request;
Usb::Packet_descriptor *packet = &completion->packet;
switch(req->type) {
case IRQ:
{
packet->type = Usb::Packet_descriptor::IRQ;
genode_usb_request_transfer *transfer = (genode_usb_request_transfer *)req->req;
packet->transfer.polling_interval = transfer->polling_interval;
packet->transfer.ep = transfer->ep;
break;
}
case CTRL:
{
packet->type = Usb::Packet_descriptor::CTRL;
genode_usb_request_control *ctrl = (genode_usb_request_control *)req->req;
packet->control.request = ctrl->request;
packet->control.request_type = ctrl->request_type;
packet->control.value = ctrl->value;
packet->control.index = ctrl->index;
packet->control.timeout = ctrl->timeout;
break;
}
case BULK:
{
packet->type = Usb::Packet_descriptor::BULK;
genode_usb_request_transfer *transfer = (genode_usb_request_transfer *)req->req;
packet->transfer.ep = transfer->ep;
break;
}
case ALT_SETTING:
{
genode_usb_altsetting *alt_setting = (genode_usb_altsetting*)req->req;
packet->type = Usb::Packet_descriptor::ALT_SETTING;
packet->interface.number = alt_setting->interface_number;
packet->interface.alt_setting = alt_setting->alt_setting;
break;
}
case CONFIG:
{
genode_usb_config *config = (genode_usb_config *)req->req;
packet->type = Usb::Packet_descriptor::CONFIG;
packet->number = config->value;
break;
}
default:
error("unknown USB client requested");
};
return true;
}
void genode_usb_client_request_submit(genode_usb_client_handle_t handle,
genode_usb_client_request_packet *request)
{
Usb_completion *completion = static_cast<Usb_completion *>(request->completion);
usb_client_apply(handle, [&] (Usb_client &usb) {
usb.source()->submit_packet(completion->packet); });
}
void genode_usb_client_request_finish(genode_usb_client_handle_t handle,
struct genode_usb_client_request_packet *request)
{
Usb_completion *completion = static_cast<Usb_completion *>(request->completion);
usb_client_apply(handle, [&] (Usb_client &usb) {
usb.release(completion); });
}
void genode_usb_client_execute_completions(genode_usb_client_handle_t handle)
{
usb_client_apply(handle, [&] (Usb_client &usb) {
while(usb.source()->ack_avail()) {
Usb::Packet_descriptor p = usb.source()->get_acked_packet();
if (p.completion) p.completion->complete(p);
}
});
_usb_session->_space.apply<Device>({ handle },
[&] (Device & device) {
device.with_active_interfaces([&] (::Interface &iface) {
iface.with_endpoint(index, [&] (Endpoint &endp) {
new (iface.slab())
::Interface::Urb(iface, endp, type, size, opaque_data);
ret = OK;
});
});
});
return ret;
} catch(Id_space<Device>::Unknown_id&) {
return NO_DEVICE;
} catch(...) {
return NO_MEMORY;
}
}

View File

@ -18,7 +18,8 @@
#include <root/component.h>
/* os includes */
#include <usb_session/rpc_object.h>
#include <usb_session/usb_session.h>
#include <os/dynamic_rom_session.h>
namespace Black_hole {
@ -30,42 +31,44 @@ namespace Black_hole {
}
class Black_hole::Usb_session : public Usb::Session_rpc_object
class Black_hole::Usb_session : public Session_object<Usb::Session>,
private Dynamic_rom_session::Xml_producer
{
private:
Env &_env;
Dynamic_rom_session _rom_session { _env.ep(), _env.ram(),
_env.rm(), *this };
public:
Usb_session(Ram_dataspace_capability tx_ds,
Entrypoint &ep,
Region_map &rm)
Usb_session(Env &env,
Label const &label,
Resources const &resources,
Diag const &diag)
:
Session_rpc_object { tx_ds, ep.rpc_ep(), rm }
{ }
Session_object<Usb::Session>(env.ep(), resources, label, diag),
Dynamic_rom_session::Xml_producer("devices"),
_env(env) { }
void sigh_state_change(Signal_context_capability /* sigh */) override { }
Rom_session_capability devices_rom() override {
return _rom_session.cap(); }
bool plugged() override { return false; }
Device_capability acquire_device(Device_name const &) override {
return Device_capability(); }
void config_descriptor(Device_descriptor * /* device_descr */,
Config_descriptor * /* config_descr */) override { }
Device_capability acquire_single_device() override {
return Device_capability(); }
unsigned alt_settings(unsigned /* index */) override { return 0; }
void release_device(Device_capability) override {}
void interface_descriptor(unsigned /* index */,
unsigned /* alt_setting */,
Interface_descriptor * /* interface_descr */) override { }
bool interface_extra(unsigned /* index */,
unsigned /* alt_setting */,
Interface_extra * /* interface_data */) override { return false; }
/*******************************************
** Dynamic_rom_session::Xml_producer API **
*******************************************/
void endpoint_descriptor(unsigned /* interface_num */,
unsigned /* alt_setting */,
unsigned /* endpoint_num */,
Endpoint_descriptor * /* endpoint_descr */) override { }
void claim_interface(unsigned /* interface_num */) override { }
void release_interface(unsigned /* interface_num */) override { }
void produce_xml(Xml_generator &) override {}
};
@ -79,18 +82,11 @@ class Black_hole::Usb_root : public Root_component<Usb_session>
Usb_session *_create_session(char const *args) override
{
size_t const ram_quota {
Arg_string::find_arg(args, "ram_quota" ).ulong_value(0) };
size_t const tx_buf_size {
Arg_string::find_arg(args, "tx_buf_size").ulong_value(0) };
if (ram_quota < tx_buf_size) {
throw Insufficient_ram_quota { };
}
Ram_dataspace_capability tx_ds { _env.ram().alloc(tx_buf_size) };
return new (md_alloc())
Usb_session { tx_ds, _env.ep(), _env.rm() };
Usb_session { _env,
session_label_from_args(args),
session_resources_from_args(args),
session_diag_from_args(args) };
}
public:

View File

@ -345,7 +345,7 @@ class Black_hole_test::Usb_test
Env &_env;
Allocator_avl _alloc;
Usb::Connection _connection { _env, &_alloc };
Usb::Connection _connection { _env };
bool _finished { false };
public:

View File

@ -0,0 +1,95 @@
USB host controller driver
##########################
This driver is capable to serve different controller types, which a platform
offers, like OHCI, UHCI, EHCI, and XHCI.
It can report the configuration it currently has, as well as a report
of all USB devices it has currently recognized. Both reports can be enabled
separatly via the config node of the driver:
! <start name="usb_host_drv">
! <binary name="pc_usb_host_drv"/>
! <resource name="RAM" quantum="10M"/>
! <provides><service name="Usb"/></provides>
! <config>
! <report config="yes" devices="yes"/>
! </config>
! </start>
The devices report contains most relevant information about an USB device,
beside of its product/vendor information, it also contains information
about configurations, interface, and endpoints available.
Example report:
! <devices>
! <device name="usb-2-2" speed="full" vendor_id="0x4e6" product_id="0x5116" class="0x0">
! <config active="true" value="0x1">
! <interface active="true" number="0x0" alt_setting="0x0" class="0xb" subclass="0x0" protocol="0x0">
! <endpoint address="0x83" attributes="0x3" max_packet_size="0x8"/>
! <endpoint address="0x5" attributes="0x2" max_packet_size="0x40"/>
! <endpoint address="0x84" attributes="0x2" max_packet_size="0x40"/>
! </interface>
! </config>
! </device>
! <device name="usb-3-1" speed="super" vendor_id="0x1d6b" product_id="0x3" class="0x9">
! <config active="true" value="0x1">
! <interface active="true" number="0x0" alt_setting="0x0" class="0x9" subclass="0x0" protocol="0x0">
! <endpoint address="0x81" attributes="0x3" max_packet_size="0x4"/>
! </interface>
! </config>
! </device>
! <device name="usb-2-1" speed="high" vendor_id="0x1d6b" product_id="0x2" class="0x9">
! <config active="true" value="0x1">
! <interface active="true" number="0x0" alt_setting="0x0" class="0x9" subclass="0x0" protocol="0x0">
! <endpoint address="0x81" attributes="0x3" max_packet_size="0x4"/>
! </interface>
! </config>
! </device>
! <device name="usb-1-1" speed="high" vendor_id="0x1d6b" product_id="0x2" class="0x9">
! <config active="true" value="0x1">
! <interface active="true" number="0x0" alt_setting="0x0" class="0x9" subclass="0x0" protocol="0x0">
! <endpoint address="0x81" attributes="0x3" max_packet_size="0x4"/>
! </interface>
! </config>
! </device>
! </devices>
An USB device can get assigned to a client request via policy nodes
within the configuration of the USB host controller driver. One can
assign devices based on their name, a vendor-product-tuple, or by
defining the class-value for all USB device interfaces that matches
that class. Here are some examples:
! <start name="usb_host_drv">
! <binary name="pc_usb_host_drv"/>
! <resource name="RAM" quantum="10M"/>
! <provides><service name="Usb"/></provides>
! <config>
! <policy label="usb_hid_drv -> "> <device class="0x3"/> </policy>
! <policy label="usb_block_drv -> "> <device name="usb-1-2"/> </policy>
! <policy label="usb_net_drv -> ">
! <device vendor_id="0x0b95" product_id="0x1790"/>
! </policy>
! </config>
! </start>
Currently, if an USB device is assigned to more than one client, only the first client
that acquires it gains access to the device. Once the device got acquired, it vanishs
from the devices ROM of the other clients.
BIOS Handoff
~~~~~~~~~~~~
Per default the driver performs a hand off of the USB controller from the
BIOS, since it still may access the controller when booting, for example, from
an USB device. The BIOS hand off induces the execution of BIOS/SMM USB driver
code and potentially DMA operations. Unfortunately, some ACPI tables report
wrong RMRR information, which implicates IOMMU faults on illegal DMA
operations and consequently the hand off may fail after noticeably long
timeouts. Therefore, the hand off can be disabled in the USB driver
configuration like follows.
! <config bios_handoff="no"/>

View File

@ -15,6 +15,7 @@
#include <base/env.h>
#include <lx_emul/init.h>
#include <lx_emul/shared_dma_buffer.h>
#include <lx_emul/usb.h>
#include <lx_kit/env.h>
#include <lx_kit/init.h>
@ -48,7 +49,6 @@ struct Main
Env & env;
Signal_handler<Main> signal_handler { env.ep(), *this,
&Main::handle_signal };
Sliced_heap sliced_heap { env.ram(), env.rm() };
void handle_signal()
{
@ -67,13 +67,11 @@ struct Main
}
Lx_kit::initialize(env, signal_handler);
env.exec_static_constructors();
genode_usb_init(genode_env_ptr(env),
genode_allocator_ptr(sliced_heap),
genode_signal_handler_ptr(signal_handler),
&lx_emul_usb_rpc_callbacks);
Genode_c_api::initialize_usb_service(env, signal_handler,
lx_emul_shared_dma_buffer_allocate,
lx_emul_shared_dma_buffer_free,
lx_emul_usb_release_device);
lx_emul_start_kernel(nullptr);
}
};

View File

@ -14,7 +14,6 @@
<rtc/>
<timer/>
<rom label="platform_info"/>
<rom label="usb_devices"/>
<usb/>
</requires>
@ -72,7 +71,6 @@
<service name="Audio_out"> <parent/> </service>
<service name="File_system" label="shared"> <parent label="shared"/> </service>
<service name="File_system"> <parent label="vm"/> </service>
<service name="ROM" label="usb_devices"> <parent label="usb_devices"/> </service>
<service name="ROM" label="capslock"> <parent label="capslock"/> </service>
<service name="ROM" label="platform_info">
<parent label="platform_info"/> </service>

View File

@ -13,7 +13,6 @@
<rm/>
<rtc/>
<timer/>
<rom label="usb_devices"/>
<usb/>
</requires>

View File

@ -17,7 +17,6 @@
<rom label="mesa_gpu_drv.lib.so"/>
<rm/>
<rtc/>
<rom label="usb_devices"/>
<usb/>
<audio_out/>
<audio_in/>
@ -81,7 +80,6 @@
<service name="Audio_out"> <parent/> </service>
<service name="File_system" label="shared"> <parent label="shared"/> </service>
<service name="File_system"> <parent label="vm"/> </service>
<service name="ROM" label="usb_devices"> <parent label="usb_devices"/> </service>
<service name="ROM" label="capslock"> <parent label="capslock"/> </service>
<service name="ROM" label="platform_info"> <parent label="platform_info"/> </service>
<service name="ROM" label="VBoxSharedClipboard.so">

View File

@ -16,7 +16,6 @@
<rom label="mesa_gpu_drv.lib.so"/>
<rm/>
<rtc/>
<rom label="usb_devices"/>
<usb/>
<audio_out/>
<audio_in/>
@ -78,7 +77,6 @@
<service name="Audio_out"> <parent/> </service>
<service name="File_system" label="shared"> <parent label="shared"/> </service>
<service name="File_system"> <parent label="vm"/> </service>
<service name="ROM" label="usb_devices"> <parent label="usb_devices"/> </service>
<service name="ROM" label="capslock"> <parent label="capslock"/> </service>
<service name="ROM" label="platform_info"> <parent label="platform_info"/> </service>
<service name="ROM" label="VBoxSharedClipboard.so">

View File

@ -38,7 +38,6 @@
<service name="Audio_out"> <parent/> </service>
<service name="File_system" label="shared"> <parent label="shared"/> </service>
<service name="File_system"> <parent label="vm"/> </service>
<service name="ROM" label="usb_devices"> <parent label="usb_devices"/> </service>
<service name="ROM" label="capslock"> <parent label="capslock"/> </service>
<service name="ROM" label="platform_info">
<parent label="platform_info"/> </service>

View File

@ -445,9 +445,13 @@ if { $use_usb_driver } {
set fd [open [run_dir]/genode/usb_host_drv.config w]
append usb_config {<config bios_handoff="yes">}
append_if [have_board rpi] usb_config {
<policy label_prefix="nic_drv" vendor_id="0x0424" product_id="0xec00"/> }
<policy label_prefix="nic_drv">
<device vendor_id="0x0424" product_id="0xec00"/>
</policy> }
append_if [have_spec x86] usb_config {
<policy label_prefix="nic_drv" vendor_id="0x0b95" product_id="0x1790"/> }
<policy label_prefix="nic_drv">
<device vendor_id="0x0b95" product_id="0x1790"/>
</policy> }
append usb_config {</config>}
puts $fd $usb_config
close $fd

View File

@ -13,8 +13,6 @@ if { [have_include "power_on/qemu"] || ![have_spec nova] || ![have_spec x86_64]}
exit 0
}
build { app/usb_report_filter }
create_boot_directory
import_from_depot [depot_user]/src/[base_src] \
[depot_user]/src/acpi_drv \
@ -61,13 +59,10 @@ install_config {
<resource name="RAM" quantum="1M"/>
<provides> <service name="Report"/> <service name="ROM"/> </provides>
<config>
<policy label="pci_decode -> system" report="acpi_drv -> acpi"/>
<policy label="platform_drv -> devices" report="pci_decode -> devices"/>
<policy label="pointer -> hover" report="nitpicker -> hover"/>
<policy label="pointer -> xray" report="nitpicker -> xray"/>
<policy label="usb_report_filter -> devices" report="usb_drv -> devices"/>
<policy label="usb_report_filter -> usb_drv_config" report="usb_drv -> config"/>
<policy label="virtualbox -> usb_devices" report="usb_report_filter -> usb_devices"/>
<policy label="pci_decode -> system" report="acpi_drv -> acpi"/>
<policy label="platform_drv -> devices" report="pci_decode -> devices"/>
<policy label="pointer -> hover" report="nitpicker -> hover"/>
<policy label="pointer -> xray" report="nitpicker -> xray"/>
</config>
</start>
@ -108,75 +103,17 @@ install_config {
<provides><service name="Timer"/></provides>
</start>
<start name="usb_config_fs" priority="-1">
<binary name="vfs"/>
<resource name="RAM" quantum="1M"/>
<provides><service name="File_system"/></provides>
<config verbose="yes">
<vfs>
<ram/>
<import>
<inline name="usb_drv.config">
<config>
<report devices="yes" config="yes"/>
<policy label_prefix="virtualbox" class="0x3"/>
</config>
</inline>
<inline name="usb_report_filter.config">
<config>
<vfs> <fs/> </vfs>
<!-- USB device whitelist -->
<client label="virtualbox"/>
<device vendor_id="0x03eb" product_id="0x204d"/> <!-- 'Pro Micro' test device -->
</config>
</inline>
</import>
</vfs>
<policy label_prefix="usb_report_filter" root="/" writeable="yes" />
<policy label_prefix="usb_config_rom" root="/"/>
</config>
</start>
<start name="usb_config_rom" priority="-1">
<binary name="fs_rom"/>
<resource name="RAM" quantum="1200K"/>
<provides><service name="ROM"/></provides>
<route>
<service name="File_system"><child name="usb_config_fs"/></service>
<any-service><parent/><any-child/></any-service>
</route>
</start>
<start name="usb_report_filter" priority="-1">
<resource name="RAM" quantum="1200K"/>
<route>
<service name="Report"><child name="report_rom" /></service>
<service name="ROM" label="config">
<child name="usb_config_rom" label="usb_report_filter.config"/>
</service>
<service name="ROM" label="devices">
<child name="report_rom"/>
</service>
<service name="ROM" label="usb_drv_config">
<child name="report_rom"/>
</service>
<service name="File_system" label="usb_drv.config">
<child name="usb_config_fs"/>
</service>
<any-service><parent/><any-child /></any-service>
</route>
</start>
<start name="usb_drv" priority="-1">
<binary name="pc_usb_host_drv"/>
<resource name="RAM" quantum="16M"/>
<provides> <service name="Usb"/> </provides>
<config>
<report devices="yes" config="yes"/>
<policy label_prefix="virtualbox"><device class="0x3"/></policy>
</config>
<route>
<service name="IRQ"><child name="acpi_drv" /></service>
<service name="Report"> <child name="report_rom" /> </service>
<service name="ROM" label="config">
<child name="usb_config_rom" label="usb_drv.config"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
@ -240,7 +177,6 @@ install_config {
</config>
<route>
<service name="Report"><child name="report_rom" /></service>
<service name="ROM" label="usb_devices"> <child name="report_rom"/> </service>
<any-service> <parent/> <any-child /> </any-service>
</route>
</start>
@ -275,7 +211,7 @@ exec -ignorestderr \
exec ln -sf ${genode_dir}/repos/ports/run/vm_genode_usb_hid_raw.vbox bin/
exec ln -sf ../../usb_hid_raw.iso bin/
build_boot_image { usb_report_filter usb_hid_raw.iso vm_genode_usb_hid_raw.vbox }
build_boot_image { usb_hid_raw.iso vm_genode_usb_hid_raw.vbox }
if { ![get_cmd_switch --autopilot] } { run_genode_until forever }
@ -291,10 +227,11 @@ run_genode_until {.*\[init -\> event_dump\] Input event #11.*\n} 60 [output_spaw
# pay only attention to the output of init and its children
grep_output {^\[init }
unify_output {(?n)^\[init -\> log_terminal\] \[init -\> usb_hid_drv\] usb usb-[0-9]-[0-9]: input irq status -19 received} ""
unify_output {(?n) on usb-usbbus.*$} ""
unify_output {(?n) at usb-usbbus.*\)} ")"
unify_output {(?n)hid-generic.*input:} "hid-generic: input:"
unify_output {(?n)usb-[0-9]-[0-9]} "usb-X-X"
unify_output {(?n)usb-[0-9]-[0-9]: USB disconnect, device number [0-9]} "usb-X-X: USB disconnect, device number X"
unify_output {(?n)device number [0-9]+} "device number X"
unify_output {(?n)input[0-9]} "inputX"
unify_output {(?n) as /devices/.*} ""
@ -313,13 +250,12 @@ compare_output_to {
[init -> log_terminal] [init -> usb_hid_drv] usb usb-X-X: USB disconnect, device number X
[init -> log_terminal] [init -> usb_hid_drv] Disconnected device: inputX
[init -> log_terminal] [init -> usb_hid_drv] Disconnected device: inputX
[init -> virtualbox] Attach USB device usb-X-X
[init -> log_terminal] [init -> usb_hid_drv] input: HID 03eb:204d
[init -> log_terminal] [init -> usb_hid_drv] Connected device: inputX (HID 03eb:204d)
[init -> log_terminal] [init -> usb_hid_drv] hid-generic: input: USB HID v1.11 Keyboard [HID 03eb:204d]
[init -> log_terminal] [init -> usb_hid_drv] input: HID 03eb:204d
[init -> log_terminal] [init -> usb_hid_drv] Connected device: inputX (HID 03eb:204d) MOUSE
[init -> log_terminal] [init -> usb_hid_drv] hid-generic: input: USB HID v1.11 Mouse [HID 03eb:204d]
[init -> log_terminal] [init -> usb_hid_drv] input: Dean Camera LUFA Mouse and Keyboard Demo
[init -> log_terminal] [init -> usb_hid_drv] Connected device: inputX (Dean Camera LUFA Mouse and Keyboard Demo)
[init -> log_terminal] [init -> usb_hid_drv] hid-generic: input: USB HID v1.11 Keyboard [Dean Camera LUFA Mouse and Keyboard Demo]
[init -> log_terminal] [init -> usb_hid_drv] input: Dean Camera LUFA Mouse and Keyboard Demo
[init -> log_terminal] [init -> usb_hid_drv] Connected device: inputX (Dean Camera LUFA Mouse and Keyboard Demo) MOUSE
[init -> log_terminal] [init -> usb_hid_drv] hid-generic: input: USB HID v1.11 Mouse [Dean Camera LUFA Mouse and Keyboard Demo]
[init -> log_terminal] [init -> event_dump] Input event #5 PRESS KEY_X 65534 key count: 1
[init -> log_terminal] [init -> event_dump] Input event #6 RELEASE KEY_X key count: 0
[init -> log_terminal] [init -> event_dump] Input event #7 REL_MOTION -1+1 key count: 0

View File

@ -275,9 +275,6 @@ set config_of_app {
<policy label="pointer -> hover" report="nitpicker -> hover"/>
<policy label="pointer -> xray" report="nitpicker -> xray"/>
<policy label="usb_hid_drv -> report" report="usb_drv -> devices"/>
<policy label="usb_report_filter -> devices" report="usb_drv -> devices"/>
<policy label="usb_report_filter -> usb_drv_config" report="usb_drv -> config"/>
<policy label="vbox1 -> usb_devices" report="usb_report_filter -> usb_devices"/>
</config>
</start>

View File

@ -144,9 +144,7 @@ set config_of_app {
<policy label="pointer -> xray" report="nitpicker -> xray"/>}
append config_of_app {
<policy label="usb_hid_drv -> report" report="usb_drv -> devices"/>
<policy label="usb_report_filter -> devices" report="usb_drv -> devices"/>
<policy label="usb_report_filter -> usb_drv_config" report="usb_drv -> config"/>
<policy label="vbox1 -> usb_devices" report="usb_report_filter -> usb_devices"/>}
}
append_if [expr $use_cpu_load] config_of_app {
<policy label="cpu_load_display -> trace_subjects"
report="trace_subject_reporter -> trace_subjects"/>}

View File

@ -47,6 +47,10 @@ if {$use_usb} {
[depot_user]/src/usb_hid_drv
}
if {!$use_usb} {
import_from_depot [depot_user]/src/black_hole
}
if {$use_rumpfs} {
import_from_depot [depot_user]/src/rump
}
@ -61,7 +65,6 @@ append build_components {
}
lappend_if [expr $use_serial] build_components server/log_terminal
lappend_if [expr $use_usb] build_components app/usb_report_filter
lappend_if [expr $use_ram_fs || $use_usb] build_components lib/vfs_import
lappend_if [expr $use_cpu_load] build_components app/trace_subject_reporter
lappend_if [expr $use_cpu_load] build_components app/cpu_load_display
@ -332,99 +335,43 @@ append_if [expr $use_cpu_load] config {
</start>}
append_if [expr $use_usb] config {
<start name="usb_config_fs" priority="-1">
<binary name="vfs"/>
<resource name="RAM" quantum="2M"/>
<provides><service name="File_system"/></provides>
<config verbose="yes">
<vfs>
<ram/>
<import>
<inline name="usb_drv.config">
<config>
<report devices="yes"/>
<policy label_prefix="usb_hid_drv" class="0x3"/>
</config>
</inline>
<inline name="usb_report_filter.config">
<config>
<vfs> <fs/> </vfs>
<!-- USB device whitelist -->
<client label="vbox1"/>
<device vendor_id="0x13fe" product_id="0x5200"/> <!-- platinum stick -->
<device vendor_id="0x148f" product_id="0x2573"/> <!-- ralink wifi -->
<device vendor_id="0x1f75" product_id="0x0917"/> <!-- intenso stick -->
<device vendor_id="0x04f9" product_id="0x0051"/> <!-- brother printer -->
<device vendor_id="0x090c" product_id="0x6000"/> <!-- hama sd/hc reader -->
<device vendor_id="0x1b1c" product_id="0x1a09"/> <!-- voyager gt stick -->
<device vendor_id="0x1b1c" product_id="0x1a03"/> <!-- voyager stick -->
<device vendor_id="0x04b3" product_id="0x310d"/> <!-- lenovo mouse -->
<device vendor_id="0x04b3" product_id="0x310c"/> <!-- lenovo mouse -->
<device vendor_id="0x04b3" product_id="0x3025"/> <!-- lenovo keyboard -->
<device vendor_id="0x046a" product_id="0x0001"/> <!-- cherry keyboard -->
<device vendor_id="0x0482" product_id="0x0015"/> <!-- kyo printer -->
<device vendor_id="0x04a9" product_id="0x2220"/> <!-- canon scanner -->
<device vendor_id="0x067b" product_id="0x2303"/> <!-- prolific serial -->
<device vendor_id="0x0583" product_id="0x2060"/> <!-- snes controller -->
<device vendor_id="0x045e" product_id="0x028e"/> <!-- x360 controller -->
<device vendor_id="0x046d" product_id="0xc00e"/> <!-- logitech mouse -->
<device vendor_id="0x0984" product_id="0x0066"/> <!-- lenovo DVDRW -->
<device vendor_id="0x174c" product_id="0x5106"/> <!-- delock SATA -->
</config>
</inline>
</import>
</vfs>
<policy label_prefix="usb_report_filter" root="/" writeable="yes"/>
<policy label_prefix="usb_config_rom" root="/"/>
</config>
</start>
<start name="usb_config_rom" priority="-1">
<binary name="fs_rom"/>
<resource name="RAM" quantum="1200K"/>
<provides><service name="ROM"/></provides>
<route>
<service name="File_system"><child name="usb_config_fs"/></service>
<any-service><parent/><any-child/></any-service>
</route>
</start>
<start name="usb_report_filter" priority="-1">
<resource name="RAM" quantum="1200K"/>
<route>
<service name="Report"><child name="report_rom"/></service>
<service name="ROM" label="config">
<child name="usb_config_rom" label="usb_report_filter.config"/>
</service>
<service name="ROM" label="devices">
<child name="report_rom"/>
</service>
<service name="ROM" label="usb_drv_config">
<child name="report_rom"/>
</service>
<service name="File_system" label="usb_drv.config">
<child name="usb_config_fs"/>
</service>
<any-service><parent/><any-child/></any-service>
</route>
</start>
<start name="usb_drv" caps="200">
<binary name="pc_usb_host_drv"/>
<resource name="RAM" quantum="20M"/>
<provides> <service name="Usb"/> </provides>
<route>
<service name="Report"> <child name="report_rom"/> </service>
<service name="ROM" label="config">
<child name="usb_config_rom" label="usb_drv.config"/> </service>
<any-service><parent/><any-child/></any-service>
</route>
<config>
<report devices="yes"/>
<policy label_prefix="usb_hid_drv"><device class="0x3"/></policy>
<policy label_prefix="vbox1">
<device vendor_id="0x13fe" product_id="0x5200"/> <!-- platinum stick -->
<device vendor_id="0x148f" product_id="0x2573"/> <!-- ralink wifi -->
<device vendor_id="0x1f75" product_id="0x0917"/> <!-- intenso stick -->
<device vendor_id="0x04f9" product_id="0x0051"/> <!-- brother printer -->
<device vendor_id="0x090c" product_id="0x6000"/> <!-- hama sd/hc reader -->
<device vendor_id="0x1b1c" product_id="0x1a09"/> <!-- voyager gt stick -->
<device vendor_id="0x1b1c" product_id="0x1a03"/> <!-- voyager stick -->
<device vendor_id="0x04b3" product_id="0x310d"/> <!-- lenovo mouse -->
<device vendor_id="0x04b3" product_id="0x310c"/> <!-- lenovo mouse -->
<device vendor_id="0x04b3" product_id="0x3025"/> <!-- lenovo keyboard -->
<device vendor_id="0x046a" product_id="0x0001"/> <!-- cherry keyboard -->
<device vendor_id="0x0482" product_id="0x0015"/> <!-- kyo printer -->
<device vendor_id="0x04a9" product_id="0x2220"/> <!-- canon scanner -->
<device vendor_id="0x067b" product_id="0x2303"/> <!-- prolific serial -->
<device vendor_id="0x0583" product_id="0x2060"/> <!-- snes controller -->
<device vendor_id="0x045e" product_id="0x028e"/> <!-- x360 controller -->
<device vendor_id="0x046d" product_id="0xc00e"/> <!-- logitech mouse -->
<device vendor_id="0x0984" product_id="0x0066"/> <!-- lenovo DVDRW -->
<device vendor_id="0x174c" product_id="0x5106"/> <!-- delock SATA -->
</policy>
</config>
</start>
<start name="usb_hid_drv" priority="-1" caps="140">
<resource name="RAM" quantum="11M"/>
<config use_report="yes"/>
<route>
<service name="Report"> <child name="report_rom"/> </service>
<service name="Event"> <child name="event_filter" label="usb_hid"/> </service>
@ -434,6 +381,15 @@ append_if [expr $use_usb] config {
</route>
</start>}
append_if [expr !$use_usb] config {
<start name="usb_drv" caps="200">
<binary name="black_hole"/>
<resource name="RAM" quantum="1M"/>
<provides> <service name="Usb"/> </provides>
<config> <usb/> </config>
</start>
}
append_if [expr $use_serial] config {
<start name="log_terminal" priority="-1">
<resource name="RAM" quantum="2M"/>
@ -453,6 +409,3 @@ install_config $config
lappend boot_modules {*}[build_artifacts]
lappend_if [expr $use_ram_fs && !$use_overlay_from_disk] boot_modules $overlay_image
# platform-specific modules
lappend_if [expr $use_usb] boot_modules usb_report_filter