diff --git a/repos/libports/lib/mk/vfs_libusb.mk b/repos/libports/lib/mk/vfs_libusb.mk
new file mode 100644
index 0000000000..6d7d7e734d
--- /dev/null
+++ b/repos/libports/lib/mk/vfs_libusb.mk
@@ -0,0 +1,7 @@
+SRC_CC = vfs_libusb.cc
+
+vpath %.cc $(REP_DIR)/src/lib/vfs/libusb
+
+SHARED_LIB = yes
+
+CC_CXX_WARN_STRICT =
diff --git a/repos/libports/recipes/pkg/usb_webcam/archives b/repos/libports/recipes/pkg/usb_webcam/archives
index 15a5624f8a..1b2091cf70 100644
--- a/repos/libports/recipes/pkg/usb_webcam/archives
+++ b/repos/libports/recipes/pkg/usb_webcam/archives
@@ -11,5 +11,5 @@ _/src/rom_filter
_/src/report_rom
_/src/stdcxx
_/src/vfs
+_/src/vfs_libusb
_/src/vfs_pipe
-
diff --git a/repos/libports/recipes/pkg/usb_webcam/runtime b/repos/libports/recipes/pkg/usb_webcam/runtime
index ea7354a3f7..aa1db16023 100644
--- a/repos/libports/recipes/pkg/usb_webcam/runtime
+++ b/repos/libports/recipes/pkg/usb_webcam/runtime
@@ -6,6 +6,7 @@
+
diff --git a/repos/libports/recipes/raw/usb_webcam/usb_webcam.config b/repos/libports/recipes/raw/usb_webcam/usb_webcam.config
index a017619f88..7becd5177a 100644
--- a/repos/libports/recipes/raw/usb_webcam/usb_webcam.config
+++ b/repos/libports/recipes/raw/usb_webcam/usb_webcam.config
@@ -75,7 +75,11 @@
- 2018-01-01 00:01
+
+
+ 2018-01-01 00:01
+
+
diff --git a/repos/libports/recipes/src/vfs_libusb/content.mk b/repos/libports/recipes/src/vfs_libusb/content.mk
new file mode 100644
index 0000000000..9b99967540
--- /dev/null
+++ b/repos/libports/recipes/src/vfs_libusb/content.mk
@@ -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 $@
diff --git a/repos/libports/recipes/src/vfs_libusb/hash b/repos/libports/recipes/src/vfs_libusb/hash
new file mode 100644
index 0000000000..6d1608f261
--- /dev/null
+++ b/repos/libports/recipes/src/vfs_libusb/hash
@@ -0,0 +1 @@
+2022-02-01 a4dec9e3717d7b06e20b057905b2c5e8c0608d93
diff --git a/repos/libports/recipes/src/vfs_libusb/used_apis b/repos/libports/recipes/src/vfs_libusb/used_apis
new file mode 100644
index 0000000000..5830357be3
--- /dev/null
+++ b/repos/libports/recipes/src/vfs_libusb/used_apis
@@ -0,0 +1,5 @@
+base
+os
+so
+usb_session
+vfs
diff --git a/repos/libports/run/smartcard.run b/repos/libports/run/smartcard.run
index 379ccffa08..6ba9f2ffca 100644
--- a/repos/libports/run/smartcard.run
+++ b/repos/libports/run/smartcard.run
@@ -26,6 +26,7 @@ set build_components {
core init timer
drivers/usb_host
test/smartcard
+ lib/vfs/libusb
lib/vfs/pipe
}
@@ -91,7 +92,11 @@ append config {
- 2018-01-01 00:01
+
+
+ 2018-01-01 00:01
+
+
@@ -116,7 +121,7 @@ set boot_modules {
core init timer test-smartcard
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
- Info.plist vfs_pipe.lib.so
+ Info.plist vfs_libusb.lib.so vfs_pipe.lib.so
}
lappend boot_modules [usb_host_drv_binary]
diff --git a/repos/libports/src/lib/libusb/README b/repos/libports/src/lib/libusb/README
index 97462f0452..8ff3c2b4b1 100644
--- a/repos/libports/src/lib/libusb/README
+++ b/repos/libports/src/lib/libusb/README
@@ -11,3 +11,9 @@ the application using libusb:
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 ''
+node in its VFS configuration and the 'vfs_libusb.lib.so' file loadable at
+runtime.
diff --git a/repos/libports/src/lib/libusb/genode_usb_raw.cc b/repos/libports/src/lib/libusb/genode_usb_raw.cc
index 6cb784d581..e2e960bc32 100644
--- a/repos/libports/src/lib/libusb/genode_usb_raw.cc
+++ b/repos/libports/src/lib/libusb/genode_usb_raw.cc
@@ -17,6 +17,7 @@
#include
#include
+#include
#include
#include
#include
@@ -36,66 +37,9 @@ static Genode::Env &genode_env()
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 _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 { };
-/*
- * 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 usbi_transfer *itransfer;
@@ -111,36 +55,95 @@ struct Usb_device
{
private:
- Genode::Allocator_avl _alloc { &libc_alloc };
-
- Genode::Io_signal_handler _state_changed_handler {
- genode_env().ep(), *this, &Usb_device::_handle_state_changed };
-
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)
{
- /*
- * The handler is installed only to receive state-change signals
- * from the USB connection using the 'Usb_device' constructor.
- */
+ 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);
}
- Genode::Io_signal_handler _ack_avail_handler {
- ep(), *this, &Usb_device::_handle_ack_avail };
+ ~Usb_device()
+ {
+ 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;
- while (usb_connection.source()->ack_avail()) {
+ while (usb_connection->source()->ack_avail()) {
Usb::Packet_descriptor p =
- usb_connection.source()->get_acked_packet();
+ usb_connection->source()->get_acked_packet();
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;
}
@@ -153,8 +156,7 @@ struct Usb_device
destroy(libc_alloc, completion);
if (_open == 0) {
- Genode::Mutex::Guard guard(usb_packet_allocator_mutex());
- usb_connection.source()->release_packet(p);
+ usb_connection->source()->release_packet(p);
continue;
}
@@ -162,15 +164,12 @@ struct Usb_device
if (!p.succeded)
Genode::error("USB transfer failed: ", (unsigned)p.type);
itransfer->transferred = 0;
- {
- Genode::Mutex::Guard guard(usb_packet_allocator_mutex());
- usb_connection.source()->release_packet(p);
- }
+ usb_connection->source()->release_packet(p);
usbi_signal_transfer_completion(itransfer);
continue;
}
- char *packet_content = usb_connection.source()->packet_content(p);
+ char *packet_content = usb_connection->source()->packet_content(p);
struct libusb_transfer *transfer =
USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
@@ -239,15 +238,11 @@ struct Usb_device
default:
Genode::error(__PRETTY_FUNCTION__,
": unsupported transfer type");
- Genode::Mutex::Guard guard(usb_packet_allocator_mutex());
- usb_connection.source()->release_packet(p);
+ usb_connection->source()->release_packet(p);
continue;
}
- {
- Genode::Mutex::Guard guard(usb_packet_allocator_mutex());
- usb_connection.source()->release_packet(p);
- }
+ usb_connection->source()->release_packet(p);
usbi_signal_transfer_completion(itransfer);
}
@@ -255,100 +250,38 @@ struct Usb_device
if (ctx != nullptr)
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)
{
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 {
Genode::error("tried to init genode usb context twice");
+ return LIBUSB_ERROR_OTHER;
}
+
return LIBUSB_SUCCESS;
}
@@ -358,6 +291,9 @@ static void genode_exit(void)
if (device_instance) {
destroy(libc_alloc, device_instance);
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)
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)
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;
try {
- usb_device->usb_connection.claim_interface(interface_number);
+ 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;
@@ -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;
try {
- usb_device->usb_connection.release_interface(interface_number);
+ 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;
@@ -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;
- if (!usb_device->usb_connection.source()->ready_to_submit())
+ if (!usb_device->usb_connection->source()->ready_to_submit())
return LIBUSB_ERROR_BUSY;
switch (transfer->type) {
@@ -577,8 +516,7 @@ static int genode_submit_transfer(struct usbi_transfer * itransfer)
Usb::Packet_descriptor p;
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) {
return LIBUSB_ERROR_BUSY;
}
@@ -596,14 +534,14 @@ static int genode_submit_transfer(struct usbi_transfer * itransfer)
LIBUSB_ENDPOINT_OUT) {
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 + LIBUSB_CONTROL_SETUP_SIZE,
setup->wLength);
}
- usb_device->usb_connection.source()->submit_packet(p);
+ usb_device->usb_connection->source()->submit_packet(p);
return LIBUSB_SUCCESS;
}
@@ -622,8 +560,7 @@ static int genode_submit_transfer(struct usbi_transfer * itransfer)
Usb::Packet_descriptor p;
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) {
return LIBUSB_ERROR_BUSY;
}
@@ -640,12 +577,12 @@ static int genode_submit_transfer(struct usbi_transfer * itransfer)
if (IS_XFEROUT(transfer)) {
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,
transfer->length);
}
- usb_device->usb_connection.source()->submit_packet(p);
+ usb_device->usb_connection->source()->submit_packet(p);
return LIBUSB_SUCCESS;
}
@@ -659,8 +596,7 @@ static int genode_submit_transfer(struct usbi_transfer * itransfer)
Usb::Packet_descriptor p;
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) {
return LIBUSB_ERROR_BUSY;
}
@@ -679,12 +615,12 @@ static int genode_submit_transfer(struct usbi_transfer * itransfer)
if (IS_XFEROUT(transfer)) {
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,
transfer->length);
}
- usb_device->usb_connection.source()->submit_packet(p);
+ usb_device->usb_connection->source()->submit_packet(p);
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 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)
{
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,
/*.clear_transfer_priv =*/ genode_clear_transfer_priv,
- /*.handle_events =*/ NULL,
+ /*.handle_events =*/ genode_handle_events,
/*.handle_transfer_completion =*/ genode_handle_transfer_completion,
/*.clock_gettime =*/ genode_clock_gettime,
@@ -808,3 +757,4 @@ void __attribute__((constructor)) init_libc_libusb(void)
{
static Plugin plugin;
}
+
diff --git a/repos/libports/src/lib/vfs/libusb/target.mk b/repos/libports/src/lib/vfs/libusb/target.mk
new file mode 100644
index 0000000000..7e63071cc8
--- /dev/null
+++ b/repos/libports/src/lib/vfs/libusb/target.mk
@@ -0,0 +1,4 @@
+TARGET = dummy-vfs_libusb
+LIBS = vfs_libusb
+
+CC_CXX_WARN_STRICT =
diff --git a/repos/libports/src/lib/vfs/libusb/vfs_libusb.cc b/repos/libports/src/lib/vfs/libusb/vfs_libusb.cc
new file mode 100644
index 0000000000..dde8a44b04
--- /dev/null
+++ b/repos/libports/src/lib/vfs/libusb/vfs_libusb.cc
@@ -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
+#include
+#include
+#include
+#include
+
+
+/*
+ * 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 _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 _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;
+}