mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-21 10:01:57 +00:00
parent
cf0d007fd4
commit
d4d875f2e6
7
repos/libports/lib/mk/vfs_libusb.mk
Normal file
7
repos/libports/lib/mk/vfs_libusb.mk
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
SRC_CC = vfs_libusb.cc
|
||||||
|
|
||||||
|
vpath %.cc $(REP_DIR)/src/lib/vfs/libusb
|
||||||
|
|
||||||
|
SHARED_LIB = yes
|
||||||
|
|
||||||
|
CC_CXX_WARN_STRICT =
|
@ -11,5 +11,5 @@ _/src/rom_filter
|
|||||||
_/src/report_rom
|
_/src/report_rom
|
||||||
_/src/stdcxx
|
_/src/stdcxx
|
||||||
_/src/vfs
|
_/src/vfs
|
||||||
|
_/src/vfs_libusb
|
||||||
_/src/vfs_pipe
|
_/src/vfs_pipe
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
<rom label="init"/>
|
<rom label="init"/>
|
||||||
<rom label="jpeg.lib.so"/>
|
<rom label="jpeg.lib.so"/>
|
||||||
<rom label="vfs.lib.so"/>
|
<rom label="vfs.lib.so"/>
|
||||||
|
<rom label="vfs_libusb.lib.so"/>
|
||||||
<rom label="vfs_pipe.lib.so"/>
|
<rom label="vfs_pipe.lib.so"/>
|
||||||
<rom label="libc.lib.so"/>
|
<rom label="libc.lib.so"/>
|
||||||
<rom label="libm.lib.so"/>
|
<rom label="libm.lib.so"/>
|
||||||
|
@ -75,7 +75,11 @@
|
|||||||
<resource name="RAM" quantum="48M"/>
|
<resource name="RAM" quantum="48M"/>
|
||||||
<config ld_verbose="no" enabled="yes" width="640" height="480" format="yuv" fps="15">
|
<config ld_verbose="no" enabled="yes" width="640" height="480" format="yuv" fps="15">
|
||||||
<vfs>
|
<vfs>
|
||||||
<dir name="dev"> <log/> <inline name="rtc">2018-01-01 00:01</inline> </dir>
|
<dir name="dev">
|
||||||
|
<log/>
|
||||||
|
<inline name="rtc">2018-01-01 00:01</inline>
|
||||||
|
<libusb/>
|
||||||
|
</dir>
|
||||||
<dir name="pipe"> <pipe/> </dir>
|
<dir name="pipe"> <pipe/> </dir>
|
||||||
</vfs>
|
</vfs>
|
||||||
<libc stdout="/dev/log" stderr="/dev/log" rtc="/dev/rtc" pipe="/pipe"/>
|
<libc stdout="/dev/log" stderr="/dev/log" rtc="/dev/rtc" pipe="/pipe"/>
|
||||||
|
9
repos/libports/recipes/src/vfs_libusb/content.mk
Normal file
9
repos/libports/recipes/src/vfs_libusb/content.mk
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
MIRROR_FROM_REP_DIR := lib/mk/vfs_libusb.mk src/lib/vfs/libusb
|
||||||
|
|
||||||
|
content: $(MIRROR_FROM_REP_DIR) LICENSE
|
||||||
|
|
||||||
|
$(MIRROR_FROM_REP_DIR):
|
||||||
|
$(mirror_from_rep_dir)
|
||||||
|
|
||||||
|
LICENSE:
|
||||||
|
cp $(GENODE_DIR)/LICENSE $@
|
1
repos/libports/recipes/src/vfs_libusb/hash
Normal file
1
repos/libports/recipes/src/vfs_libusb/hash
Normal file
@ -0,0 +1 @@
|
|||||||
|
2022-02-01 a4dec9e3717d7b06e20b057905b2c5e8c0608d93
|
5
repos/libports/recipes/src/vfs_libusb/used_apis
Normal file
5
repos/libports/recipes/src/vfs_libusb/used_apis
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
base
|
||||||
|
os
|
||||||
|
so
|
||||||
|
usb_session
|
||||||
|
vfs
|
@ -26,6 +26,7 @@ set build_components {
|
|||||||
core init timer
|
core init timer
|
||||||
drivers/usb_host
|
drivers/usb_host
|
||||||
test/smartcard
|
test/smartcard
|
||||||
|
lib/vfs/libusb
|
||||||
lib/vfs/pipe
|
lib/vfs/pipe
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,7 +92,11 @@ append config {
|
|||||||
<resource name="RAM" quantum="4M"/>
|
<resource name="RAM" quantum="4M"/>
|
||||||
<config>
|
<config>
|
||||||
<vfs>
|
<vfs>
|
||||||
<dir name="dev"> <log/> <inline name="rtc">2018-01-01 00:01</inline> </dir>
|
<dir name="dev">
|
||||||
|
<log/>
|
||||||
|
<inline name="rtc">2018-01-01 00:01</inline>
|
||||||
|
<libusb/>
|
||||||
|
</dir>
|
||||||
<dir name="pipe"> <pipe/> </dir>
|
<dir name="pipe"> <pipe/> </dir>
|
||||||
<dir name="ifd-ccid.bundle">
|
<dir name="ifd-ccid.bundle">
|
||||||
<dir name="Contents">
|
<dir name="Contents">
|
||||||
@ -116,7 +121,7 @@ set boot_modules {
|
|||||||
core init timer test-smartcard
|
core init timer test-smartcard
|
||||||
ld.lib.so pcsc-lite.lib.so ccid.lib.so libusb.lib.so
|
ld.lib.so pcsc-lite.lib.so ccid.lib.so libusb.lib.so
|
||||||
libc.lib.so vfs.lib.so libm.lib.so posix.lib.so
|
libc.lib.so vfs.lib.so libm.lib.so posix.lib.so
|
||||||
Info.plist vfs_pipe.lib.so
|
Info.plist vfs_libusb.lib.so vfs_pipe.lib.so
|
||||||
}
|
}
|
||||||
|
|
||||||
lappend boot_modules [usb_host_drv_binary]
|
lappend boot_modules [usb_host_drv_binary]
|
||||||
|
@ -11,3 +11,9 @@ the application using libusb:
|
|||||||
</config>
|
</config>
|
||||||
|
|
||||||
See also the README file of the USB driver for additional policy attributes.
|
See also the README file of the USB driver for additional policy attributes.
|
||||||
|
|
||||||
|
The Genode USB connection object resides in a VFS plugin named 'vfs_libusb',
|
||||||
|
which is necessary to handle the 'ack_avail' signal in the libc kernel context.
|
||||||
|
So, an application using libusb needs to have a '<dir name="dev"><libusb/></dev>'
|
||||||
|
node in its VFS configuration and the 'vfs_libusb.lib.so' file loadable at
|
||||||
|
runtime.
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include <usb/usb.h>
|
#include <usb/usb.h>
|
||||||
#include <usb_session/connection.h>
|
#include <usb_session/connection.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <libc/allocator.h>
|
#include <libc/allocator.h>
|
||||||
#include <libc-plugin/plugin.h>
|
#include <libc-plugin/plugin.h>
|
||||||
@ -36,66 +37,9 @@ static Genode::Env &genode_env()
|
|||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct Usb_ep
|
|
||||||
{
|
|
||||||
Genode::Entrypoint _ep;
|
|
||||||
pthread_t _pthread;
|
|
||||||
|
|
||||||
void _handle_pthread_registration()
|
|
||||||
{
|
|
||||||
Genode::Thread *myself = Genode::Thread::myself();
|
|
||||||
if (!myself || Libc::pthread_create_from_thread(&_pthread, *myself, &myself)) {
|
|
||||||
Genode::error("cannot register thread for pthread");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Genode::Io_signal_handler<Usb_ep> _pthread_reg_sigh {
|
|
||||||
_ep, *this, &Usb_ep::_handle_pthread_registration };
|
|
||||||
|
|
||||||
Usb_ep(Genode::Env &env, size_t stack_size, char const *name,
|
|
||||||
Genode::Affinity::Location location)
|
|
||||||
: _ep { env, stack_size, name, location }
|
|
||||||
{
|
|
||||||
Genode::Signal_transmitter(_pthread_reg_sigh).submit();
|
|
||||||
}
|
|
||||||
|
|
||||||
Genode::Entrypoint &ep() { return _ep; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Entrypoint for handling 'ack avail' signals from the USB driver.
|
|
||||||
*
|
|
||||||
* The entrypoint is needed because the main thread of an application
|
|
||||||
* using libusb might be blocking on a pthread locking function, which
|
|
||||||
* currently do not dispatch signals while blocking.
|
|
||||||
*/
|
|
||||||
static Genode::Entrypoint &ep()
|
|
||||||
{
|
|
||||||
static Usb_ep instance(genode_env(),
|
|
||||||
2*1024*sizeof(Genode::addr_t),
|
|
||||||
"usb_ack_ep",
|
|
||||||
Genode::Affinity::Location());
|
|
||||||
return instance.ep();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static Libc::Allocator libc_alloc { };
|
static Libc::Allocator libc_alloc { };
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Prevent modification of packet allocator
|
|
||||||
* by multiple threads.
|
|
||||||
*/
|
|
||||||
static Genode::Mutex &usb_packet_allocator_mutex()
|
|
||||||
{
|
|
||||||
static Genode::Mutex instance;
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct Completion : Usb::Completion
|
struct Completion : Usb::Completion
|
||||||
{
|
{
|
||||||
struct usbi_transfer *itransfer;
|
struct usbi_transfer *itransfer;
|
||||||
@ -111,36 +55,95 @@ struct Usb_device
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Genode::Allocator_avl _alloc { &libc_alloc };
|
|
||||||
|
|
||||||
Genode::Io_signal_handler<Usb_device> _state_changed_handler {
|
|
||||||
genode_env().ep(), *this, &Usb_device::_handle_state_changed };
|
|
||||||
|
|
||||||
unsigned _open { 0 };
|
unsigned _open { 0 };
|
||||||
|
|
||||||
void _handle_state_changed()
|
public:
|
||||||
|
|
||||||
|
Usb::Connection *usb_connection;
|
||||||
|
|
||||||
|
Usb::Device_descriptor device_descriptor;
|
||||||
|
Usb::Config_descriptor config_descriptor;
|
||||||
|
char *raw_config_descriptor = nullptr;
|
||||||
|
|
||||||
|
Usb_device(Usb::Connection *usb)
|
||||||
|
: usb_connection(usb)
|
||||||
{
|
{
|
||||||
/*
|
Genode::log("libusb: waiting until device is plugged...");
|
||||||
* The handler is installed only to receive state-change signals
|
while (!usb_connection->plugged())
|
||||||
* from the USB connection using the 'Usb_device' constructor.
|
genode_env().ep().wait_and_dispatch_one_io_signal();
|
||||||
*/
|
Genode::log("libusb: device is plugged");
|
||||||
|
|
||||||
|
usb_connection->config_descriptor(&device_descriptor, &config_descriptor);
|
||||||
|
|
||||||
|
raw_config_descriptor = (char*)malloc(config_descriptor.total_length);
|
||||||
|
|
||||||
|
Usb::Packet_descriptor p =
|
||||||
|
usb_connection->source()->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;
|
||||||
|
|
||||||
|
usb_connection->source()->submit_packet(p);
|
||||||
|
|
||||||
|
while (!usb_connection->source()->ack_avail())
|
||||||
|
genode_env().ep().wait_and_dispatch_one_io_signal();
|
||||||
|
|
||||||
|
p = usb_connection->source()->get_acked_packet();
|
||||||
|
|
||||||
|
if (!p.succeded)
|
||||||
|
Genode::error(__PRETTY_FUNCTION__,
|
||||||
|
": could not read raw configuration descriptor");
|
||||||
|
|
||||||
|
if (p.control.actual_size != config_descriptor.total_length)
|
||||||
|
Genode::error(__PRETTY_FUNCTION__,
|
||||||
|
": received configuration descriptor of unexpected size");
|
||||||
|
|
||||||
|
char *packet_content = usb_connection->source()->packet_content(p);
|
||||||
|
Genode::memcpy(raw_config_descriptor, packet_content,
|
||||||
|
config_descriptor.total_length);
|
||||||
|
|
||||||
|
usb_connection->source()->release_packet(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
Genode::Io_signal_handler<Usb_device> _ack_avail_handler {
|
~Usb_device()
|
||||||
ep(), *this, &Usb_device::_handle_ack_avail };
|
{
|
||||||
|
free(raw_config_descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
void _handle_ack_avail()
|
bool altsetting(int number, int alt_setting)
|
||||||
|
{
|
||||||
|
if (!usb_connection->source()->ready_to_submit())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Usb::Packet_descriptor p =
|
||||||
|
usb_connection->source()->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;
|
struct libusb_context *ctx = nullptr;
|
||||||
|
|
||||||
while (usb_connection.source()->ack_avail()) {
|
while (usb_connection->source()->ack_avail()) {
|
||||||
|
|
||||||
Usb::Packet_descriptor p =
|
Usb::Packet_descriptor p =
|
||||||
usb_connection.source()->get_acked_packet();
|
usb_connection->source()->get_acked_packet();
|
||||||
|
|
||||||
if (p.type == Usb::Packet_descriptor::ALT_SETTING) {
|
if (p.type == Usb::Packet_descriptor::ALT_SETTING) {
|
||||||
Genode::Mutex::Guard guard(usb_packet_allocator_mutex());
|
usb_connection->source()->release_packet(p);
|
||||||
usb_connection.source()->release_packet(p);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,8 +156,7 @@ struct Usb_device
|
|||||||
destroy(libc_alloc, completion);
|
destroy(libc_alloc, completion);
|
||||||
|
|
||||||
if (_open == 0) {
|
if (_open == 0) {
|
||||||
Genode::Mutex::Guard guard(usb_packet_allocator_mutex());
|
usb_connection->source()->release_packet(p);
|
||||||
usb_connection.source()->release_packet(p);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,15 +164,12 @@ struct Usb_device
|
|||||||
if (!p.succeded)
|
if (!p.succeded)
|
||||||
Genode::error("USB transfer failed: ", (unsigned)p.type);
|
Genode::error("USB transfer failed: ", (unsigned)p.type);
|
||||||
itransfer->transferred = 0;
|
itransfer->transferred = 0;
|
||||||
{
|
usb_connection->source()->release_packet(p);
|
||||||
Genode::Mutex::Guard guard(usb_packet_allocator_mutex());
|
|
||||||
usb_connection.source()->release_packet(p);
|
|
||||||
}
|
|
||||||
usbi_signal_transfer_completion(itransfer);
|
usbi_signal_transfer_completion(itransfer);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *packet_content = usb_connection.source()->packet_content(p);
|
char *packet_content = usb_connection->source()->packet_content(p);
|
||||||
|
|
||||||
struct libusb_transfer *transfer =
|
struct libusb_transfer *transfer =
|
||||||
USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
||||||
@ -239,15 +238,11 @@ struct Usb_device
|
|||||||
default:
|
default:
|
||||||
Genode::error(__PRETTY_FUNCTION__,
|
Genode::error(__PRETTY_FUNCTION__,
|
||||||
": unsupported transfer type");
|
": unsupported transfer type");
|
||||||
Genode::Mutex::Guard guard(usb_packet_allocator_mutex());
|
usb_connection->source()->release_packet(p);
|
||||||
usb_connection.source()->release_packet(p);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
usb_connection->source()->release_packet(p);
|
||||||
Genode::Mutex::Guard guard(usb_packet_allocator_mutex());
|
|
||||||
usb_connection.source()->release_packet(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
usbi_signal_transfer_completion(itransfer);
|
usbi_signal_transfer_completion(itransfer);
|
||||||
}
|
}
|
||||||
@ -255,100 +250,38 @@ struct Usb_device
|
|||||||
if (ctx != nullptr)
|
if (ctx != nullptr)
|
||||||
usbi_signal_event(ctx);
|
usbi_signal_event(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Usb::Connection usb_connection { genode_env(),
|
|
||||||
&_alloc,
|
|
||||||
"usb_device",
|
|
||||||
1024*1024,
|
|
||||||
_state_changed_handler };
|
|
||||||
|
|
||||||
Usb::Device_descriptor device_descriptor;
|
|
||||||
Usb::Config_descriptor config_descriptor;
|
|
||||||
char *raw_config_descriptor = nullptr;
|
|
||||||
|
|
||||||
Usb_device()
|
|
||||||
{
|
|
||||||
Genode::log("libusb: waiting until device is plugged...");
|
|
||||||
while (!usb_connection.plugged())
|
|
||||||
genode_env().ep().wait_and_dispatch_one_io_signal();
|
|
||||||
Genode::log("libusb: device is plugged");
|
|
||||||
|
|
||||||
usb_connection.config_descriptor(&device_descriptor, &config_descriptor);
|
|
||||||
|
|
||||||
raw_config_descriptor = (char*)malloc(config_descriptor.total_length);
|
|
||||||
|
|
||||||
Usb::Packet_descriptor p =
|
|
||||||
usb_connection.source()->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;
|
|
||||||
|
|
||||||
usb_connection.source()->submit_packet(p);
|
|
||||||
|
|
||||||
while (!usb_connection.source()->ack_avail())
|
|
||||||
genode_env().ep().wait_and_dispatch_one_io_signal();
|
|
||||||
|
|
||||||
p = usb_connection.source()->get_acked_packet();
|
|
||||||
|
|
||||||
if (!p.succeded)
|
|
||||||
Genode::error(__PRETTY_FUNCTION__,
|
|
||||||
": could not read raw configuration descriptor");
|
|
||||||
|
|
||||||
if (p.control.actual_size != config_descriptor.total_length)
|
|
||||||
Genode::error(__PRETTY_FUNCTION__,
|
|
||||||
": received configuration descriptor of unexpected size");
|
|
||||||
|
|
||||||
char *packet_content = usb_connection.source()->packet_content(p);
|
|
||||||
Genode::memcpy(raw_config_descriptor, packet_content,
|
|
||||||
config_descriptor.total_length);
|
|
||||||
|
|
||||||
usb_connection.source()->release_packet(p);
|
|
||||||
|
|
||||||
usb_connection.tx_channel()->sigh_ack_avail(_ack_avail_handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
~Usb_device()
|
|
||||||
{
|
|
||||||
free(raw_config_descriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool altsetting(int number, int alt_setting)
|
|
||||||
{
|
|
||||||
Genode::Mutex::Guard guard(usb_packet_allocator_mutex());
|
|
||||||
|
|
||||||
if (!usb_connection.source()->ready_to_submit())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Usb::Packet_descriptor p =
|
|
||||||
usb_connection.source()->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++; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static Usb_device *device_instance;
|
|
||||||
|
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_connection = usb;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int genode_init(struct libusb_context* ctx)
|
static int genode_init(struct libusb_context* ctx)
|
||||||
{
|
{
|
||||||
if (!device_instance) {
|
if (!device_instance) {
|
||||||
device_instance = new (libc_alloc) Usb_device;
|
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);
|
||||||
} else {
|
} else {
|
||||||
Genode::error("tried to init genode usb context twice");
|
Genode::error("tried to init genode usb context twice");
|
||||||
|
return LIBUSB_ERROR_OTHER;
|
||||||
}
|
}
|
||||||
|
|
||||||
return LIBUSB_SUCCESS;
|
return LIBUSB_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,6 +291,9 @@ static void genode_exit(void)
|
|||||||
if (device_instance) {
|
if (device_instance) {
|
||||||
destroy(libc_alloc, device_instance);
|
destroy(libc_alloc, device_instance);
|
||||||
device_instance = nullptr;
|
device_instance = nullptr;
|
||||||
|
close(vfs_libusb_fd);
|
||||||
|
usb_connection = nullptr;
|
||||||
|
vfs_libusb_fd = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -436,7 +372,8 @@ static int genode_open(struct libusb_device_handle *dev_handle)
|
|||||||
if (device_instance)
|
if (device_instance)
|
||||||
device_instance->open();
|
device_instance->open();
|
||||||
|
|
||||||
return LIBUSB_SUCCESS;
|
return usbi_add_pollfd(HANDLE_CTX(dev_handle), vfs_libusb_fd,
|
||||||
|
POLLIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -444,6 +381,8 @@ static void genode_close(struct libusb_device_handle *dev_handle)
|
|||||||
{
|
{
|
||||||
if (device_instance)
|
if (device_instance)
|
||||||
device_instance->close();
|
device_instance->close();
|
||||||
|
|
||||||
|
usbi_remove_pollfd(HANDLE_CTX(dev_handle), vfs_libusb_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -511,7 +450,7 @@ static int genode_claim_interface(struct libusb_device_handle *dev_handle,
|
|||||||
Usb_device *usb_device = *(Usb_device**)dev_handle->dev->os_priv;
|
Usb_device *usb_device = *(Usb_device**)dev_handle->dev->os_priv;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
usb_device->usb_connection.claim_interface(interface_number);
|
usb_device->usb_connection->claim_interface(interface_number);
|
||||||
} catch (Usb::Session::Interface_not_found) {
|
} catch (Usb::Session::Interface_not_found) {
|
||||||
Genode::error(__PRETTY_FUNCTION__, ": interface not found");
|
Genode::error(__PRETTY_FUNCTION__, ": interface not found");
|
||||||
return LIBUSB_ERROR_NOT_FOUND;
|
return LIBUSB_ERROR_NOT_FOUND;
|
||||||
@ -533,7 +472,7 @@ static int genode_release_interface(struct libusb_device_handle *dev_handle,
|
|||||||
Usb_device *usb_device = *(Usb_device**)dev_handle->dev->os_priv;
|
Usb_device *usb_device = *(Usb_device**)dev_handle->dev->os_priv;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
usb_device->usb_connection.release_interface(interface_number);
|
usb_device->usb_connection->release_interface(interface_number);
|
||||||
} catch (Usb::Session::Interface_not_found) {
|
} catch (Usb::Session::Interface_not_found) {
|
||||||
Genode::error(__PRETTY_FUNCTION__, ": interface not found");
|
Genode::error(__PRETTY_FUNCTION__, ": interface not found");
|
||||||
return LIBUSB_ERROR_NOT_FOUND;
|
return LIBUSB_ERROR_NOT_FOUND;
|
||||||
@ -564,7 +503,7 @@ static int genode_submit_transfer(struct usbi_transfer * itransfer)
|
|||||||
|
|
||||||
Usb_device *usb_device = *(Usb_device**)transfer->dev_handle->dev->os_priv;
|
Usb_device *usb_device = *(Usb_device**)transfer->dev_handle->dev->os_priv;
|
||||||
|
|
||||||
if (!usb_device->usb_connection.source()->ready_to_submit())
|
if (!usb_device->usb_connection->source()->ready_to_submit())
|
||||||
return LIBUSB_ERROR_BUSY;
|
return LIBUSB_ERROR_BUSY;
|
||||||
|
|
||||||
switch (transfer->type) {
|
switch (transfer->type) {
|
||||||
@ -577,8 +516,7 @@ static int genode_submit_transfer(struct usbi_transfer * itransfer)
|
|||||||
Usb::Packet_descriptor p;
|
Usb::Packet_descriptor p;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Genode::Mutex::Guard guard(usb_packet_allocator_mutex());
|
p = usb_device->usb_connection->source()->alloc_packet(setup->wLength);
|
||||||
p = usb_device->usb_connection.source()->alloc_packet(setup->wLength);
|
|
||||||
} catch (Usb::Session::Tx::Source::Packet_alloc_failed) {
|
} catch (Usb::Session::Tx::Source::Packet_alloc_failed) {
|
||||||
return LIBUSB_ERROR_BUSY;
|
return LIBUSB_ERROR_BUSY;
|
||||||
}
|
}
|
||||||
@ -596,14 +534,14 @@ static int genode_submit_transfer(struct usbi_transfer * itransfer)
|
|||||||
LIBUSB_ENDPOINT_OUT) {
|
LIBUSB_ENDPOINT_OUT) {
|
||||||
|
|
||||||
char *packet_content =
|
char *packet_content =
|
||||||
usb_device->usb_connection.source()->packet_content(p);
|
usb_device->usb_connection->source()->packet_content(p);
|
||||||
|
|
||||||
Genode::memcpy(packet_content,
|
Genode::memcpy(packet_content,
|
||||||
transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE,
|
transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE,
|
||||||
setup->wLength);
|
setup->wLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
usb_device->usb_connection.source()->submit_packet(p);
|
usb_device->usb_connection->source()->submit_packet(p);
|
||||||
|
|
||||||
return LIBUSB_SUCCESS;
|
return LIBUSB_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -622,8 +560,7 @@ static int genode_submit_transfer(struct usbi_transfer * itransfer)
|
|||||||
Usb::Packet_descriptor p;
|
Usb::Packet_descriptor p;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Genode::Mutex::Guard guard(usb_packet_allocator_mutex());
|
p = usb_device->usb_connection->source()->alloc_packet(transfer->length);
|
||||||
p = usb_device->usb_connection.source()->alloc_packet(transfer->length);
|
|
||||||
} catch (Usb::Session::Tx::Source::Packet_alloc_failed) {
|
} catch (Usb::Session::Tx::Source::Packet_alloc_failed) {
|
||||||
return LIBUSB_ERROR_BUSY;
|
return LIBUSB_ERROR_BUSY;
|
||||||
}
|
}
|
||||||
@ -640,12 +577,12 @@ static int genode_submit_transfer(struct usbi_transfer * itransfer)
|
|||||||
|
|
||||||
if (IS_XFEROUT(transfer)) {
|
if (IS_XFEROUT(transfer)) {
|
||||||
char *packet_content =
|
char *packet_content =
|
||||||
usb_device->usb_connection.source()->packet_content(p);
|
usb_device->usb_connection->source()->packet_content(p);
|
||||||
Genode::memcpy(packet_content, transfer->buffer,
|
Genode::memcpy(packet_content, transfer->buffer,
|
||||||
transfer->length);
|
transfer->length);
|
||||||
}
|
}
|
||||||
|
|
||||||
usb_device->usb_connection.source()->submit_packet(p);
|
usb_device->usb_connection->source()->submit_packet(p);
|
||||||
|
|
||||||
return LIBUSB_SUCCESS;
|
return LIBUSB_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -659,8 +596,7 @@ static int genode_submit_transfer(struct usbi_transfer * itransfer)
|
|||||||
|
|
||||||
Usb::Packet_descriptor p;
|
Usb::Packet_descriptor p;
|
||||||
try {
|
try {
|
||||||
Genode::Mutex::Guard guard(usb_packet_allocator_mutex());
|
p = usb_device->usb_connection->source()->alloc_packet(total_length);
|
||||||
p = usb_device->usb_connection.source()->alloc_packet(total_length);
|
|
||||||
} catch (Usb::Session::Tx::Source::Packet_alloc_failed) {
|
} catch (Usb::Session::Tx::Source::Packet_alloc_failed) {
|
||||||
return LIBUSB_ERROR_BUSY;
|
return LIBUSB_ERROR_BUSY;
|
||||||
}
|
}
|
||||||
@ -679,12 +615,12 @@ static int genode_submit_transfer(struct usbi_transfer * itransfer)
|
|||||||
|
|
||||||
if (IS_XFEROUT(transfer)) {
|
if (IS_XFEROUT(transfer)) {
|
||||||
char *packet_content =
|
char *packet_content =
|
||||||
usb_device->usb_connection.source()->packet_content(p);
|
usb_device->usb_connection->source()->packet_content(p);
|
||||||
Genode::memcpy(packet_content, transfer->buffer,
|
Genode::memcpy(packet_content, transfer->buffer,
|
||||||
transfer->length);
|
transfer->length);
|
||||||
}
|
}
|
||||||
|
|
||||||
usb_device->usb_connection.source()->submit_packet(p);
|
usb_device->usb_connection->source()->submit_packet(p);
|
||||||
|
|
||||||
return LIBUSB_SUCCESS;
|
return LIBUSB_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -706,6 +642,19 @@ static int genode_cancel_transfer(struct usbi_transfer * itransfer)
|
|||||||
static void genode_clear_transfer_priv(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)
|
||||||
|
{
|
||||||
|
if (device_instance) {
|
||||||
|
device_instance->handle_events();
|
||||||
|
return LIBUSB_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LIBUSB_ERROR_NO_DEVICE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int genode_handle_transfer_completion(struct usbi_transfer * itransfer)
|
static int genode_handle_transfer_completion(struct usbi_transfer * itransfer)
|
||||||
{
|
{
|
||||||
enum libusb_transfer_status status = LIBUSB_TRANSFER_COMPLETED;
|
enum libusb_transfer_status status = LIBUSB_TRANSFER_COMPLETED;
|
||||||
@ -768,7 +717,7 @@ const struct usbi_os_backend genode_usb_raw_backend = {
|
|||||||
/*.cancel_transfer =*/ genode_cancel_transfer,
|
/*.cancel_transfer =*/ genode_cancel_transfer,
|
||||||
/*.clear_transfer_priv =*/ genode_clear_transfer_priv,
|
/*.clear_transfer_priv =*/ genode_clear_transfer_priv,
|
||||||
|
|
||||||
/*.handle_events =*/ NULL,
|
/*.handle_events =*/ genode_handle_events,
|
||||||
/*.handle_transfer_completion =*/ genode_handle_transfer_completion,
|
/*.handle_transfer_completion =*/ genode_handle_transfer_completion,
|
||||||
|
|
||||||
/*.clock_gettime =*/ genode_clock_gettime,
|
/*.clock_gettime =*/ genode_clock_gettime,
|
||||||
@ -808,3 +757,4 @@ void __attribute__((constructor)) init_libc_libusb(void)
|
|||||||
{
|
{
|
||||||
static Plugin plugin;
|
static Plugin plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
4
repos/libports/src/lib/vfs/libusb/target.mk
Normal file
4
repos/libports/src/lib/vfs/libusb/target.mk
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
TARGET = dummy-vfs_libusb
|
||||||
|
LIBS = vfs_libusb
|
||||||
|
|
||||||
|
CC_CXX_WARN_STRICT =
|
144
repos/libports/src/lib/vfs/libusb/vfs_libusb.cc
Normal file
144
repos/libports/src/lib/vfs/libusb/vfs_libusb.cc
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
/*
|
||||||
|
* \brief libusb file system
|
||||||
|
* \author Christian Prochaska
|
||||||
|
* \date 2022-01-31
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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/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>
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function is implemented in the Genode backend
|
||||||
|
* of libusb.
|
||||||
|
*/
|
||||||
|
extern void libusb_genode_usb_connection(Usb::Connection *);
|
||||||
|
|
||||||
|
class Libusb_file_system : public Vfs::Single_file_system
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
Vfs::Env &_env;
|
||||||
|
|
||||||
|
class Libusb_vfs_handle : public Single_vfs_handle
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
Genode::Env &_env;
|
||||||
|
Genode::Allocator_avl _alloc_avl;
|
||||||
|
Usb::Connection _usb_connection;
|
||||||
|
|
||||||
|
Genode::Io_signal_handler<Libusb_vfs_handle> _state_changed_handler {
|
||||||
|
_env.ep(), *this, &Libusb_vfs_handle::_handle_state_changed };
|
||||||
|
|
||||||
|
void _handle_state_changed()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The handler is installed only to receive state-change
|
||||||
|
* signals from the USB connection using the 'Usb_device'
|
||||||
|
* constructor.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
Genode::Io_signal_handler<Libusb_vfs_handle> _ack_avail_handler {
|
||||||
|
_env.ep(), *this, &Libusb_vfs_handle::_handle_ack_avail };
|
||||||
|
|
||||||
|
void _handle_ack_avail()
|
||||||
|
{
|
||||||
|
io_progress_response();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Libusb_vfs_handle(Directory_service &ds,
|
||||||
|
File_io_service &fs,
|
||||||
|
Genode::Allocator &alloc,
|
||||||
|
Genode::Env &env)
|
||||||
|
: Single_vfs_handle(ds, fs, alloc, 0),
|
||||||
|
_env(env), _alloc_avl(&alloc),
|
||||||
|
_usb_connection(_env, &_alloc_avl,
|
||||||
|
"usb_device",
|
||||||
|
1024*1024,
|
||||||
|
_state_changed_handler)
|
||||||
|
{
|
||||||
|
_usb_connection.tx_channel()->sigh_ack_avail(_ack_avail_handler);
|
||||||
|
libusb_genode_usb_connection(&_usb_connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool read_ready() override
|
||||||
|
{
|
||||||
|
return _usb_connection.source()->ack_avail();
|
||||||
|
}
|
||||||
|
|
||||||
|
Read_result read(char *dst, Vfs::file_size count,
|
||||||
|
Vfs::file_size &out_count) override
|
||||||
|
{
|
||||||
|
return READ_ERR_IO;
|
||||||
|
}
|
||||||
|
|
||||||
|
Write_result write(char const *src, Vfs::file_size count,
|
||||||
|
Vfs::file_size &out_count) override
|
||||||
|
{
|
||||||
|
return WRITE_ERR_IO;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Libusb_file_system(Vfs::Env &env,
|
||||||
|
Genode::Xml_node config)
|
||||||
|
:
|
||||||
|
Single_file_system(Vfs::Node_type::CONTINUOUS_FILE, name(),
|
||||||
|
Vfs::Node_rwx::ro(), config),
|
||||||
|
_env(env) { }
|
||||||
|
|
||||||
|
~Libusb_file_system() { }
|
||||||
|
|
||||||
|
static char const *name() { return "libusb"; }
|
||||||
|
char const *type() override { return "libusb"; }
|
||||||
|
|
||||||
|
/*********************************
|
||||||
|
** Directory service interface **
|
||||||
|
*********************************/
|
||||||
|
|
||||||
|
Open_result open(char const *path, unsigned,
|
||||||
|
Vfs::Vfs_handle **out_handle,
|
||||||
|
Genode::Allocator &alloc) override
|
||||||
|
{
|
||||||
|
if (!_single_file(path))
|
||||||
|
return OPEN_ERR_UNACCESSIBLE;
|
||||||
|
|
||||||
|
*out_handle = new (alloc)
|
||||||
|
Libusb_vfs_handle(*this, *this, alloc, _env.env());
|
||||||
|
return OPEN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Libusb_factory : Vfs::File_system_factory
|
||||||
|
{
|
||||||
|
Vfs::File_system *create(Vfs::Env &env, Genode::Xml_node node) override
|
||||||
|
{
|
||||||
|
return new (env.alloc()) Libusb_file_system(env, node);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" Vfs::File_system_factory *vfs_file_system_factory(void)
|
||||||
|
{
|
||||||
|
static Libusb_factory factory;
|
||||||
|
return &factory;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user