diff --git a/repos/libports/include/qemu/usb.h b/repos/libports/include/qemu/usb.h
new file mode 100644
index 0000000000..6660002c0b
--- /dev/null
+++ b/repos/libports/include/qemu/usb.h
@@ -0,0 +1,129 @@
+/*
+ * \brief Qemu USB controller interface
+ * \author Josef Soentgen
+ * \author Sebastian Sumpf
+ * \date 2015-12-14
+ */
+
+/*
+ * Copyright (C) 2015 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU General Public License version 2.
+ */
+
+#ifndef _INCLUDE__QEMU__USB_H_
+#define _INCLUDE__QEMU__USB_H_
+
+#include
+#include
+
+namespace Qemu {
+
+ typedef Genode::size_t size_t;
+ typedef Genode::off_t off_t;
+ typedef Genode::int64_t int64_t;
+ typedef Genode::addr_t addr_t;
+
+
+ /************************************
+ ** Qemu library backend interface **
+ ************************************/
+
+ /*
+ * The backend interface needs to be provided the user of the library.
+ */
+
+ /**
+ * Timer_queue class
+ *
+ * The library uses the Timer_queue internally to schedule timeouts.
+ */
+ struct Timer_queue
+ {
+ virtual int64_t get_ns() = 0;
+ virtual void register_timer(void *qtimer, void (*cb)(void *data), void *data) = 0;
+ virtual void delete_timer(void *qtimer) = 0;
+ virtual void activate_timer(void *qtimer, long long int expires_abs) = 0;
+ virtual void deactivate_timer(void *qtimer) = 0;
+ };
+
+ /**
+ * Pci_device class
+ *
+ * The library uses the Pci_device to access physical DMA memory and to
+ * raise interrupts.
+ */
+ struct Pci_device
+ {
+ /**
+ * Raise interrupt
+ *
+ * \param assert 1 == raise, 0 == deassert interrupt
+ */
+ virtual void raise_interrupt(int assert) = 0;
+ virtual int read_dma(addr_t addr, void *buf, size_t size) = 0;
+ virtual int write_dma(addr_t addr, void const *buf, size_t size) = 0;
+ virtual void *map_dma(addr_t base, size_t size) = 0;
+ virtual void unmap_dma(void *addr, size_t size) = 0;
+ };
+
+
+ /*************************************
+ ** Qemu library frontend functions **
+ *************************************/
+
+ /**
+ * Controller class to access MMIO register of the xHCI device model
+ *
+ * This class is implemented by the library.
+ */
+ struct Controller
+ {
+ /**
+ * Size of the MMIO region of the controller
+ */
+ virtual size_t mmio_size() const = 0;
+
+ /**
+ * Read/write MMIO offset in the MMIO region of the controller
+ */
+ virtual int mmio_read(off_t offset, void *buf, size_t size) = 0;
+ virtual int mmio_write(off_t offset, void const *buf, size_t size) = 0;
+ };
+
+ /**
+ * Initialize USB library
+ *
+ * \param tq Timer_queue instance provided by the user of the library
+ * \param pd Pci_device instance provided by the user of the library
+ * \param sr Signal_receiver used by the library to install signals
+ *
+ * \return Pointer to Controller object that is used to access the xHCI device state
+ */
+ Controller *usb_init(Timer_queue &tq, Pci_device &pd, Genode::Signal_receiver &sr);
+
+ /**
+ * Reset USB libray
+ */
+ void usb_reset();
+
+ /**
+ * Update USB devices list
+ *
+ * Needs to be called after a library reset.
+ */
+ void usb_update_devices();
+
+ /**
+ * Library timer callback
+ *
+ * Needs to be called when a timer triggers (see Timer_queue interface).
+ *
+ * \param cb Callback installed by Timer_queue::register_timer()
+ * \param data Data pointer given in Timer_queue::register_timer()
+ */
+ void usb_timer_callback(void (*cb)(void *data), void *data);
+}
+
+#endif /* _INCLUDE__QEMU__USB_H_ */
diff --git a/repos/libports/lib/import/import-qemu-usb_include.mk b/repos/libports/lib/import/import-qemu-usb_include.mk
new file mode 100644
index 0000000000..a81e8e590d
--- /dev/null
+++ b/repos/libports/lib/import/import-qemu-usb_include.mk
@@ -0,0 +1,11 @@
+QEMU_CONTRIB_DIR := $(call select_from_ports,qemu-usb)/src/lib/qemu
+
+LIB_DIR := $(REP_DIR)/src/lib/qemu-usb
+LIB_INC_DIR := $(LIB_DIR)/include
+
+#
+# The order of include-search directories is important, we need to look into
+# 'contrib' before falling back to our custom 'qemu_emul.h' header.
+INC_DIR += $(LIB_INC_DIR)
+INC_DIR += $(QEMU_CONTRIB_DIR)/include
+INC_DIR += $(LIB_CACHE_DIR)/qemu-usb_include/include
diff --git a/repos/libports/lib/mk/qemu-usb.mk b/repos/libports/lib/mk/qemu-usb.mk
new file mode 100644
index 0000000000..2acc67e5ca
--- /dev/null
+++ b/repos/libports/lib/mk/qemu-usb.mk
@@ -0,0 +1,19 @@
+LIB_DIR = $(REP_DIR)/src/lib/qemu-usb
+QEMU_USB_DIR = $(call select_from_ports,qemu-usb)/src/lib/qemu/hw/usb
+
+CC_WARN=
+
+INC_DIR += $(LIB_DIR) $(QEMU_USB_DIR)
+
+LIBS = qemu-usb_include
+
+SRC_CC = dummies.cc qemu_emul.cc host.cc
+
+SRC_C = hcd-xhci.c core.c bus.c
+
+SHARED_LIB = yes
+
+LD_OPT += --version-script=$(LIB_DIR)/symbol.map
+
+vpath %.c $(QEMU_USB_DIR)
+vpath %.cc $(LIB_DIR)
diff --git a/repos/libports/lib/mk/qemu-usb_include.mk b/repos/libports/lib/mk/qemu-usb_include.mk
new file mode 100644
index 0000000000..ab3e0d1cd2
--- /dev/null
+++ b/repos/libports/lib/mk/qemu-usb_include.mk
@@ -0,0 +1,24 @@
+ifeq ($(called_from_lib_mk),yes)
+
+QEMU_CONTRIB_DIR := $(call select_from_ports,qemu-usb)/src/lib/qemu
+QEMU_EMUL_H := $(REP_DIR)/src/lib/qemu-usb/include/qemu_emul.h
+
+#
+# Determine the header files included by the contrib code. For each
+# of these header files we create a symlink to 'qemu_emul.h'.
+#
+GEN_INCLUDES := $(shell grep -rh "^\#include .*" $(QEMU_CONTRIB_DIR) |\
+ sed "s/^\#include [^<\"]*[<\"]\([^>\"]*\)[>\"].*/\1/" | sort | uniq)
+#
+# Put Qemu headers in 'GEN_INC' dir
+#
+GEN_INC := $(shell pwd)/include
+GEN_INCLUDES := $(addprefix $(GEN_INC)/,$(GEN_INCLUDES))
+
+all: $(GEN_INCLUDES)
+
+$(GEN_INCLUDES):
+ $(VERBOSE)mkdir -p $(dir $@)
+ $(VERBOSE)ln -s $(QEMU_EMUL_H) $@
+
+endif
diff --git a/repos/libports/ports/qemu-usb.hash b/repos/libports/ports/qemu-usb.hash
new file mode 100644
index 0000000000..6ea380208d
--- /dev/null
+++ b/repos/libports/ports/qemu-usb.hash
@@ -0,0 +1 @@
+cf9157628466843e495e600f15a40e64993dd87f
diff --git a/repos/libports/ports/qemu-usb.port b/repos/libports/ports/qemu-usb.port
new file mode 100644
index 0000000000..3604aa8a86
--- /dev/null
+++ b/repos/libports/ports/qemu-usb.port
@@ -0,0 +1,13 @@
+LICENSE := GPLv2
+VERSION := 2.4.1
+DOWNLOADS := qemu.archive
+
+URL(qemu) := http://wiki.qemu-project.org/download/qemu-$(VERSION).tar.bz2
+SHA(qemu) := 629fb77fc03713b1267c1d51a8df6c0d9c7fd39b
+DIR(qemu) := src/lib/qemu
+TAR_OPT(qemu) := --strip-components=1 --files-from $(REP_DIR)/src/lib/qemu-usb/files.list
+HASH_INPUT += $(REP_DIR)/src/lib/qemu-usb/files.list
+
+PATCHES := src/lib/qemu-usb/patches/xhci_state.patch \
+ src/lib/qemu-usb/patches/usb_bus_nfree.patch
+PATCH_OPT:= -p1
diff --git a/repos/libports/src/lib/qemu-usb/README b/repos/libports/src/lib/qemu-usb/README
new file mode 100644
index 0000000000..d37cba9811
--- /dev/null
+++ b/repos/libports/src/lib/qemu-usb/README
@@ -0,0 +1,30 @@
+This library makes the xHCI device model of Qemu available on Genode
+and is used as a back end for such for device models in existing VMMs.
+
+Usage
+~~~~~
+
+The user of this library is required to provide certain back end
+functionality, namely a Timer_queue to handle timer events and a Pci_device
+that handles access to the PCI bus (raise interrupts, (un)map DMA memory)
+within the VMM device model.
+
+To use this library the user calls 'Qemu::usb_init' and passes
+pointers to the back end objects. In addition, a Signal_receiver
+reference has also to be handed over. It will receive all signals
+required by this library.
+
+'Qemu::usb_init' returns a pointer to a Controller object. MMIO
+access must be forwarded to this object when the device model in the VMM
+wants to access the MMIO regions of the xHCI device.
+
+Whenever the VMM requests a device reset the 'Qemu::usb_reset'
+function has to be called. It will remove and free all attached
+USB devices and will reset the state of the xHCI device model.
+
+After the xHCI device model has been reset 'Qemu::usb_update_devices'
+needs to be called to reattach USB devices.
+
+Timer callbacks that have been registered using the Timer_queue
+interface have to be executed by calling 'Qemu::usb_timer_callback'
+when the timer triggers.
diff --git a/repos/libports/src/lib/qemu-usb/dummies.cc b/repos/libports/src/lib/qemu-usb/dummies.cc
new file mode 100644
index 0000000000..789b064515
--- /dev/null
+++ b/repos/libports/src/lib/qemu-usb/dummies.cc
@@ -0,0 +1,202 @@
+/*
+ * \brief Qemu USB controller interface
+ * \author Josef Soentgen
+ * \author Sebastian Sumpf
+ * \date 2015-12-14
+ */
+
+/*
+ * Copyright (C) 2015 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU General Public License version 2.
+ */
+
+/* Genode includes */
+#include
+#include
+
+/* local includes */
+#include
+#include
+#include
+
+
+extern "C" {
+
+enum {
+ SHOW_TRACE = 0,
+};
+
+#define TRACE_AND_STOP \
+ do { \
+ PWRN("%s not implemented called from: %p", __func__, __builtin_return_address(0)); \
+ Genode::sleep_forever(); \
+ } while (0)
+
+#define TRACE \
+ do { \
+ if (SHOW_TRACE) \
+ PWRN("%s not implemented", __func__); \
+ } while (0)
+
+
+/****************
+ ** hcd-xhci.c **
+ ****************/
+
+void memory_region_del_subregion(MemoryRegion*, MemoryRegion*)
+{
+ TRACE_AND_STOP;
+}
+
+
+void msix_vector_unuse(PCIDevice*, unsigned int)
+{
+ TRACE;
+}
+
+
+int msix_vector_use(PCIDevice*, unsigned int)
+{
+ TRACE;
+ return 0;
+}
+
+
+ObjectClass* object_class_dynamic_cast_assert(ObjectClass*, const char*, const char*, int,
+ const char*)
+{
+ TRACE_AND_STOP;
+ return nullptr;
+}
+
+
+Object* object_dynamic_cast_assert(Object*, const char*, const char*, int, const char*)
+{
+ TRACE_AND_STOP;
+ return nullptr;
+}
+
+
+bool pci_bus_is_express(PCIBus*)
+{
+ TRACE;
+ return false;
+}
+
+
+void pci_register_bar(PCIDevice*, int, uint8_t, MemoryRegion*)
+{
+ TRACE;
+}
+
+
+int pcie_endpoint_cap_init(PCIDevice*, uint8_t)
+{
+ TRACE_AND_STOP;
+ return -1;
+}
+
+
+/***********
+ ** bus.c **
+ ***********/
+
+static Error _error;
+Error *error_abort = &_error;
+
+
+ObjectClass* object_get_class(Object*)
+{
+ TRACE_AND_STOP;
+ return nullptr;
+}
+
+const char* object_get_typename(Object*)
+{
+ TRACE;
+ return nullptr;
+}
+
+
+void qbus_set_bus_hotplug_handler(BusState *state, Error **error)
+{
+ TRACE;
+}
+
+
+gchar* g_strdup_printf(const gchar*, ...)
+{
+ TRACE;
+ return 0;
+}
+
+
+void pstrcpy(char*, int, const char*)
+{
+ TRACE;
+}
+
+
+long int strtol(const char*, char**, int)
+{
+ TRACE;
+ return -1;
+}
+
+
+DeviceState* qdev_try_create(BusState*, const char*)
+{
+ TRACE_AND_STOP;
+ return nullptr;
+}
+
+
+void monitor_printf(Monitor*, const char*, ...)
+{
+ TRACE;
+}
+
+
+void qdev_simple_device_unplug_cb(HotplugHandler*, DeviceState*, Error**)
+{
+ TRACE_AND_STOP;
+}
+
+
+char* qdev_get_dev_path(DeviceState*)
+{
+ TRACE_AND_STOP;
+ return 0;
+}
+
+
+const char* qdev_fw_name(DeviceState*)
+{
+ TRACE;
+ return 0;
+}
+
+
+gchar* g_strdup(const gchar*)
+{
+ TRACE;
+ return 0;
+}
+
+
+size_t strlen(const char*)
+{
+ TRACE_AND_STOP;
+ return 0;
+}
+
+
+/**********
+ ** libc **
+ **********/
+
+void abort() { TRACE_AND_STOP; }
+
+} /* extern "C" */
diff --git a/repos/libports/src/lib/qemu-usb/files.list b/repos/libports/src/lib/qemu-usb/files.list
new file mode 100644
index 0000000000..f501ae6ec4
--- /dev/null
+++ b/repos/libports/src/lib/qemu-usb/files.list
@@ -0,0 +1,6 @@
+qemu-2.4.1/include/hw/usb.h
+qemu-2.4.1/include/qemu/queue.h
+qemu-2.4.1/include/qom/object.h
+qemu-2.4.1/hw/usb/bus.c
+qemu-2.4.1/hw/usb/core.c
+qemu-2.4.1/hw/usb/hcd-xhci.c
diff --git a/repos/libports/src/lib/qemu-usb/host.cc b/repos/libports/src/lib/qemu-usb/host.cc
new file mode 100644
index 0000000000..e0ec56f711
--- /dev/null
+++ b/repos/libports/src/lib/qemu-usb/host.cc
@@ -0,0 +1,658 @@
+/**
+ * \brief USB session back end
+ * \author Josef Soentgen
+ * \author Sebastian Sumpf
+ * \date 2015-12-18
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+
+using namespace Genode;
+
+static bool const verbose_devices = false;
+static bool const verbose_host = false;
+Lock _lock;
+
+
+static void update_ep(USBDevice *);
+static bool claim_interfaces(USBDevice *dev);
+
+
+struct Completion : Usb::Completion
+{
+ USBPacket *p = nullptr;
+ USBDevice *dev = nullptr;
+ uint8_t *data = nullptr;
+ enum State { VALID, FREE, CANCELED };
+ State state = FREE;
+
+ void complete(Usb::Packet_descriptor &p) override { }
+
+ void complete(Usb::Packet_descriptor &packet, char *content)
+ {
+ if (state != VALID)
+ return;
+
+ int actual_size = 0;
+
+ switch (packet.type) {
+ case Usb::Packet_descriptor::CTRL:
+ actual_size = packet.control.actual_size;
+ break;
+ case Usb::Packet_descriptor::BULK:
+ case Usb::Packet_descriptor::IRQ:
+ actual_size = packet.transfer.actual_size;
+ default:
+ break;
+ }
+
+ if (actual_size < 0) actual_size = 0;
+
+ if (verbose_host)
+ PDBG("packet.type: %u actual_size: 0x%x", packet.type, actual_size);
+
+ p->actual_length = 0;
+
+ if (p->pid == USB_TOKEN_IN && actual_size > 0) {
+ if (data) Genode::memcpy(data, content, actual_size);
+ else usb_packet_copy(p, content, actual_size);
+ }
+
+ p->actual_length = actual_size;
+
+ if (packet.succeded)
+ p->status = USB_RET_SUCCESS;
+ else
+ p->status = USB_RET_IOERROR;
+
+ switch (packet.type) {
+ case Usb::Packet_descriptor::CONFIG:
+ if (!claim_interfaces(dev))
+ p->status = USB_RET_IOERROR;
+ case Usb::Packet_descriptor::ALT_SETTING:
+ update_ep(dev);
+ case Usb::Packet_descriptor::CTRL:
+ usb_generic_async_ctrl_complete(dev, p);
+ break;
+ case Usb::Packet_descriptor::BULK:
+ case Usb::Packet_descriptor::IRQ:
+ usb_packet_complete(dev, p);
+ break;
+ default:
+ break;
+ }
+ }
+};
+
+
+struct Usb_host_device : List::Element
+{
+ struct Could_not_create_device : Genode::Exception { };
+
+ bool deleted = false;
+ char const *label = nullptr;
+ unsigned bus = 0;
+ unsigned dev = 0;
+
+ USBHostDevice *qemu_dev;
+ Completion completion[Usb::Session::TX_QUEUE_SIZE];
+
+ Signal_receiver &sig_rec;
+ Signal_dispatcher state_dispatcher { sig_rec, *this, &Usb_host_device::state_change };
+
+ Allocator_avl alloc { env()->heap() };
+ Usb::Connection usb_raw { &alloc, label, 1024*1024, state_dispatcher };
+
+ Signal_dispatcher ack_avail_dispatcher { sig_rec, *this, &Usb_host_device::ack_avail };
+
+ void _release_interfaces()
+ {
+ Usb::Config_descriptor cdescr;
+ Usb::Device_descriptor ddescr;
+
+ usb_raw.config_descriptor(&ddescr, &cdescr);
+
+ for (unsigned i = 0; i < cdescr.num_interfaces; i++) {
+ usb_raw.release_interface(i);
+ }
+ }
+
+ bool _claim_interfaces()
+ {
+ Usb::Config_descriptor cdescr;
+ Usb::Device_descriptor ddescr;
+
+ usb_raw.config_descriptor(&ddescr, &cdescr);
+
+ bool result = true;
+ for (unsigned i = 0; i < cdescr.num_interfaces; i++) {
+ try {
+ usb_raw.claim_interface(i);
+ } catch (Usb::Session::Interface_already_claimed) {
+ result = false;
+ }
+ }
+
+ if (!result) PERR("Device already claimed");
+
+ return result;
+ }
+
+ Usb_host_device(Signal_receiver &sig_rec, char const *label,
+ unsigned bus, unsigned dev)
+ : label(label), bus(bus), dev(dev), sig_rec(sig_rec)
+ {
+ usb_raw.tx_channel()->sigh_ack_avail(ack_avail_dispatcher);
+
+ if (!_claim_interfaces())
+ throw Could_not_create_device();
+
+ qemu_dev = create_usbdevice(this);
+
+ if (!qemu_dev)
+ throw Could_not_create_device();
+ }
+
+ static int to_qemu_speed(unsigned speed)
+ {
+ switch (speed) {
+ case Usb::Device::SPEED_LOW: return USB_SPEED_LOW;
+ case Usb::Device::SPEED_FULL: return USB_SPEED_FULL;
+ case Usb::Device::SPEED_HIGH: return USB_SPEED_HIGH;
+ case Usb::Device::SPEED_SUPER: return USB_SPEED_SUPER;
+ default: return 0;
+ }
+ }
+
+ void ack_avail(unsigned)
+ {
+ Lock::Guard g(_lock);
+
+ /* we are already dead, do nothing */
+ if (deleted == true) return;
+
+ while (usb_raw.source()->ack_avail()) {
+ Usb::Packet_descriptor packet = usb_raw.source()->get_acked_packet();
+
+ char *packet_content = usb_raw.source()->packet_content(packet);
+ dynamic_cast(packet.completion)->complete(packet, packet_content);
+ free_packet(packet);
+ }
+ }
+
+ void _destroy()
+ {
+ /* mark delete before removing */
+ deleted = true;
+
+ /* remove from USB bus */
+ remove_usbdevice(qemu_dev);
+ qemu_dev = nullptr;
+ }
+
+ void state_change(unsigned)
+ {
+ Lock::Guard g(_lock);
+ if (usb_raw.plugged())
+ return;
+
+ _destroy();
+ }
+
+ void destroy()
+ {
+ Lock::Guard g(_lock);
+
+ _release_interfaces();
+
+ _destroy();
+ }
+
+ Usb::Packet_descriptor alloc_packet(int length)
+ {
+
+ if (!usb_raw.source()->ready_to_submit())
+ throw -1;
+
+ Usb::Packet_descriptor packet = usb_raw.source()->alloc_packet(length);
+ packet.completion = alloc_completion();
+ return packet;
+ }
+
+ void free_packet(Usb::Packet_descriptor &packet)
+ {
+ dynamic_cast(packet.completion)->state = Completion::FREE;
+ usb_raw.source()->release_packet(packet);
+ }
+
+ Completion *alloc_completion()
+ {
+ for (unsigned i = 0; i < Usb::Session::TX_QUEUE_SIZE; i++)
+ if (completion[i].state == Completion::FREE) {
+ completion[i]. state = Completion::VALID;
+ return &completion[i];
+ }
+
+ return nullptr;
+ }
+
+ Completion *find_completion(USBPacket *p)
+ {
+ for (unsigned i = 0; i < Usb::Session::TX_QUEUE_SIZE; i++)
+ if (completion[i].p == p)
+ return &completion[i];
+
+ return nullptr;
+ }
+
+ void submit(Usb::Packet_descriptor p) {
+ usb_raw.source()->submit_packet(p); }
+
+ bool claim_interfaces() { return _claim_interfaces(); }
+
+ void set_configuration(uint8_t value, USBPacket *p)
+ {
+ _release_interfaces();
+
+ Usb::Packet_descriptor packet = alloc_packet(0);
+ packet.type = Usb::Packet_descriptor::CONFIG;
+ packet.number = value;
+
+ Completion *c = dynamic_cast(packet.completion);
+ c->p = p;
+ c->dev = cast_USBDevice(qemu_dev);
+ submit(packet);
+ p->status = USB_RET_ASYNC;
+ }
+
+ void set_interface(int index, uint8_t value, USBPacket *p)
+ {
+ Usb::Packet_descriptor packet = alloc_packet(0);
+ packet.type = Usb::Packet_descriptor::ALT_SETTING;
+ packet.interface.number = index;
+ packet.interface.alt_setting = value;
+
+ Completion *c = dynamic_cast(packet.completion);
+ c->p = p;
+ c->dev = cast_USBDevice(qemu_dev);
+ submit(packet);
+ p->status = USB_RET_ASYNC;
+ }
+
+ void update_ep(USBDevice *udev)
+ {
+ usb_ep_reset(udev);
+
+ /* retrieve device speed */
+ Usb::Config_descriptor cdescr;
+ Usb::Device_descriptor ddescr;
+
+ usb_raw.config_descriptor(&ddescr, &cdescr);
+
+ for (unsigned i = 0; i < cdescr.num_interfaces; i++) {
+ udev->altsetting[i] = usb_raw.alt_settings(i);
+ }
+
+ for (unsigned i = 0; i < cdescr.num_interfaces; i++) {
+ for (int j = 0; j < udev->altsetting[i]; j++) {
+ Usb::Interface_descriptor iface;
+ usb_raw.interface_descriptor(i, j, &iface);
+ for (unsigned k = 0; k < iface.num_endpoints; k++) {
+ Usb::Endpoint_descriptor endp;
+ usb_raw.endpoint_descriptor(i, j, k, &endp);
+
+ int const pid = (endp.address & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT;
+ int const ep = (endp.address & 0xf);
+ uint8_t const type = (endp.attributes & 0x3);
+
+ usb_ep_set_max_packet_size(udev, pid, ep, endp.max_packet_size);
+ usb_ep_set_type(udev, pid, ep, type);
+ usb_ep_set_ifnum(udev, pid, ep, i);
+ usb_ep_set_halted(udev, pid, ep, 0);
+ }
+ }
+ }
+ }
+};
+
+
+/********************
+ ** Qemu interface **
+ ********************/
+
+#define TRACE_AND_STOP do { PDBG("not implemented"); } while(false)
+
+#define USB_HOST_DEVICE(obj) \
+ OBJECT_CHECK(USBHostDevice, (obj), TYPE_USB_HOST_DEVICE)
+
+
+static void update_ep(USBDevice *udev)
+{
+ USBHostDevice *d = USB_HOST_DEVICE(udev);
+ Usb_host_device *dev = (Usb_host_device *)d->data;
+
+ dev->update_ep(udev);
+}
+
+
+static bool claim_interfaces(USBDevice *udev)
+{
+ USBHostDevice *d = USB_HOST_DEVICE(udev);
+ Usb_host_device *dev = (Usb_host_device *)d->data;
+
+ return dev->claim_interfaces();
+}
+
+
+static void usb_host_realize(USBDevice *udev, Error **errp)
+{
+ USBHostDevice *d = USB_HOST_DEVICE(udev);
+ Usb_host_device *dev = (Usb_host_device *)d->data;
+
+ /* retrieve device speed */
+ Usb::Config_descriptor cdescr;
+ Usb::Device_descriptor ddescr;
+
+ dev->usb_raw.config_descriptor(&ddescr, &cdescr);
+
+ if (verbose_host)
+ PDBG("set udev->speed to %d", Usb_host_device::to_qemu_speed(ddescr.speed));
+
+ udev->speed = Usb_host_device::to_qemu_speed(ddescr.speed);
+ udev->speedmask = (1 << udev->speed);
+
+ udev->flags |= (1 << USB_DEV_FLAG_IS_HOST);
+
+ dev->update_ep(udev);
+}
+
+
+static void usb_host_cancel_packet(USBDevice *udev, USBPacket *p)
+{
+ USBHostDevice *d = USB_HOST_DEVICE(udev);
+ Usb_host_device *dev = (Usb_host_device *)d->data;
+ Completion *c = dev->find_completion(p);
+ c->state = Completion::CANCELED;
+}
+
+
+static void usb_host_handle_data(USBDevice *udev, USBPacket *p)
+{
+ USBHostDevice *d = USB_HOST_DEVICE(udev);
+ Usb_host_device *dev = (Usb_host_device *)d->data;
+
+ size_t size = 0;
+ unsigned timeout = 0;
+ Usb::Packet_descriptor::Type type = Usb::Packet_descriptor::BULK;
+
+ switch (usb_ep_get_type(udev, p->pid, p->ep->nr)) {
+ case USB_ENDPOINT_XFER_BULK:
+ type = Usb::Packet_descriptor::BULK;
+ size = usb_packet_size(p);
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ type = Usb::Packet_descriptor::IRQ;
+ size = p->iov.size;
+
+ /* values match usb_drv */
+ switch (udev->speed) {
+ case USB_SPEED_SUPER:
+ timeout = 1<<15;
+ break;
+ case USB_SPEED_HIGH:
+ timeout = 1<<13;
+ break;
+ case USB_SPEED_FULL:
+ case USB_SPEED_LOW:
+ timeout = 1<<7;
+ break;
+ default: break;
+ }
+ break;
+ default:
+ PERR("not supported data request");
+ break;
+ }
+
+ bool const in = p->pid == USB_TOKEN_IN;
+
+ Usb::Packet_descriptor packet = dev->alloc_packet(size);
+ packet.type = type;
+ packet.transfer.ep = p->ep->nr | (in ? USB_DIR_IN : 0);
+ packet.transfer.timeout = timeout;
+
+ if (!in) {
+ char * const content = dev->usb_raw.source()->packet_content(packet);
+ usb_packet_copy(p, content, size);
+ }
+
+ Completion *c = dynamic_cast(packet.completion);
+ c->p = p;
+ c->dev = udev;
+ c->data = nullptr;
+
+ dev->submit(packet);
+ p->status = USB_RET_ASYNC;
+}
+
+
+static void usb_host_handle_control(USBDevice *udev, USBPacket *p,
+ int request, int value, int index,
+ int length, uint8_t *data)
+{
+ USBHostDevice *d = USB_HOST_DEVICE(udev);
+ Usb_host_device *dev = (Usb_host_device *)d->data;
+
+ if (verbose_host)
+ PDBG("r: %x v: %x i: %x length: %d", request, value, index, length);
+
+ switch (request) {
+ case DeviceOutRequest | USB_REQ_SET_ADDRESS:
+ udev->addr = value;
+ return;
+ case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
+ dev->set_configuration(value & 0xff, p);
+ return;
+ case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
+ dev->set_interface(index, value, p);
+ return;
+ }
+
+ if (udev->speed == USB_SPEED_SUPER &&
+ !(udev->port->speedmask & USB_SPEED_MASK_SUPER) &&
+ request == 0x8006 && value == 0x100 && index == 0) {
+ PERR("r->usb3ep0quirk = true");
+ }
+
+ Usb::Packet_descriptor packet;
+ try {
+ packet = dev->alloc_packet(length);
+ } catch (...) { PERR("Packet allocation failed"); return; }
+
+ packet.type = Usb::Packet_descriptor::CTRL;
+ packet.control.request_type = request >> 8;
+ packet.control.request = request & 0xff;
+ packet.control.index = index;
+ packet.control.value = value;
+
+ Completion *c = dynamic_cast(packet.completion);
+ c->p = p;
+ c->dev = udev;
+ c->data = data;
+
+ if (!(packet.control.request_type & USB_DIR_IN) && length) {
+ char *packet_content = dev->usb_raw.source()->packet_content(packet);
+ Genode::memcpy(packet_content, data, length);
+ }
+
+ dev->submit(packet);
+ p->status = USB_RET_ASYNC;
+}
+
+
+static Property usb_host_dev_properties[] = {
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+
+static void usb_host_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+ uc->realize = usb_host_realize;
+ uc->product_desc = "USB Host Device";
+ uc->cancel_packet = usb_host_cancel_packet;
+ uc->handle_data = usb_host_handle_data;
+ uc->handle_control = usb_host_handle_control;
+ dc->props = usb_host_dev_properties;
+}
+
+
+static TypeInfo usb_host_dev_info;
+
+
+static void usb_host_register_types(void)
+{
+ usb_host_dev_info.name = TYPE_USB_HOST_DEVICE;
+ usb_host_dev_info.parent = TYPE_USB_DEVICE;
+ usb_host_dev_info.instance_size = sizeof(USBHostDevice);
+ usb_host_dev_info.class_init = usb_host_class_initfn;
+
+ type_register_static(&usb_host_dev_info);
+}
+
+
+struct Usb_devices : List
+{
+ Signal_receiver &_sig_rec;
+ Signal_dispatcher _device_dispatcher { _sig_rec, *this, &Usb_devices::_devices_update };
+ Attached_rom_dataspace _devices_rom { "usb_devices" };
+
+ void _garbage_collect()
+ {
+ for (Usb_host_device *d = first(); d; d = d->next()) {
+ if (d->deleted == false)
+ continue;
+
+ remove(d);
+ Genode::destroy(env()->heap(), d);
+ }
+ }
+
+ Usb_host_device *_find_usb_device(unsigned bus, unsigned dev)
+ {
+ for (Usb_host_device *d = first(); d; d = d->next())
+ if (d->bus == bus && d->dev == dev)
+ return d;
+
+ return nullptr;
+ }
+
+ void _devices_update(unsigned)
+ {
+ Lock::Guard g(_lock);
+
+ _garbage_collect();
+
+ _devices_rom.update();
+ if (!_devices_rom.is_valid())
+ return;
+
+ if (verbose_devices)
+ PINF("%s", _devices_rom.local_addr());
+
+ Xml_node devices_node(_devices_rom.local_addr(), _devices_rom.size());
+ devices_node.for_each_sub_node("device", [&] (Xml_node const &node) {
+
+ unsigned product = node.attribute_value("product_id", 0);
+ unsigned vendor = node.attribute_value("vendor_id", 0);
+ unsigned bus = node.attribute_value("bus", 0);
+ unsigned dev = node.attribute_value("dev", 0);
+
+ Genode::String<128> label;
+ try {
+ node.attribute("label").value(&label);
+ } catch (Genode::Xml_attribute::Nonexistent_attribute) {
+ PERR("No label found for device %03x:%03x", bus, dev);
+ return;
+ }
+
+ /* ignore if already created */
+ if (_find_usb_device(bus, dev)) return;
+
+ try {
+ Usb_host_device *new_device = new (env()->heap())
+ Usb_host_device(_sig_rec, label.string(), bus, dev);
+
+ insert(new_device);
+
+ PINF("Attach USB device %03x:%03x (%x:%x)",
+ bus, dev, vendor, product);
+
+ } catch (...) {
+ PERR("Could not attach USB device %03x:%03x (%x:%x)",
+ bus, dev, vendor, product);
+ }
+ });
+ }
+
+ Usb_devices(Signal_receiver *sig_rec)
+ : _sig_rec(*sig_rec)
+ {
+ _devices_rom.sigh(_device_dispatcher);
+ }
+
+ void destroy()
+ {
+ for (Usb_host_device *d = first(); d; d = d->next())
+ d->destroy();
+
+ _garbage_collect();
+ }
+};
+
+
+static Usb_devices *_devices;
+
+
+extern "C" void usb_host_destroy()
+{
+ if (_devices == nullptr) return;
+
+ _devices->destroy();
+}
+
+
+extern "C" void usb_host_update_devices()
+{
+ if (_devices == nullptr) return;
+
+ _devices->_devices_update(0);
+}
+
+
+/*
+ * Do not use type_init macro because of name mangling
+ */
+extern "C" void _type_init_usb_host_register_types(Genode::Signal_receiver *sig_rec)
+{
+ usb_host_register_types();
+
+ static Usb_devices devices(sig_rec);
+ _devices = &devices;
+}
diff --git a/repos/libports/src/lib/qemu-usb/include/extern_c_begin.h b/repos/libports/src/lib/qemu-usb/include/extern_c_begin.h
new file mode 100644
index 0000000000..18f2694a9b
--- /dev/null
+++ b/repos/libports/src/lib/qemu-usb/include/extern_c_begin.h
@@ -0,0 +1,27 @@
+/*
+ * \brief Include before including Linux headers in C++
+ * \author Christian Helmuth
+ * \date 2014-08-21
+ */
+
+/*
+ * Copyright (C) 2014 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU General Public License version 2.
+ */
+
+#define extern_c_begin
+
+extern "C" {
+
+/* some warnings should only be switched of for Linux headers */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpointer-arith"
+#pragma GCC diagnostic ignored "-Wsign-compare"
+
+/* deal with C++ keywords used for identifiers etc. */
+#define private private_
+#define class class_
+#define new new_
+#define typename typename_
diff --git a/repos/libports/src/lib/qemu-usb/include/extern_c_end.h b/repos/libports/src/lib/qemu-usb/include/extern_c_end.h
new file mode 100644
index 0000000000..87094bc936
--- /dev/null
+++ b/repos/libports/src/lib/qemu-usb/include/extern_c_end.h
@@ -0,0 +1,21 @@
+/*
+ * \brief Include after including Linux headers in C++
+ * \author Christian Helmuth
+ * \date 2014-08-21
+ */
+
+/*
+ * Copyright (C) 2014 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU General Public License version 2.
+ */
+
+#undef typename
+#undef new
+#undef class
+#undef private
+
+#pragma GCC diagnostic pop
+
+} /* extern "C" */
diff --git a/repos/libports/src/lib/qemu-usb/include/qemu_emul.h b/repos/libports/src/lib/qemu-usb/include/qemu_emul.h
new file mode 100644
index 0000000000..c5104d5c19
--- /dev/null
+++ b/repos/libports/src/lib/qemu-usb/include/qemu_emul.h
@@ -0,0 +1,728 @@
+/*
+ * \brief Qemu emulation environment
+ * \author Josef Soentgen
+ * \author Sebastian Sumpf
+ * \date 2015-12-14
+ */
+
+/*
+ * Copyright (C) 2015 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU General Public License version 2.
+ */
+
+#ifndef _INCLUDE__QEMU_EMUL_H_
+#define _INCLUDE__QEMU_EMUL_H_
+
+#include
+#include
+
+void q_printf(char const *, ...) __attribute__((format(printf, 1, 2)));
+void q_vprintf(char const *, va_list);
+
+typedef genode_uint8_t uint8_t;
+typedef genode_uint16_t uint16_t;
+typedef genode_uint32_t uint32_t;
+typedef genode_uint64_t uint64_t;
+
+typedef genode_int32_t int32_t;
+typedef genode_int64_t int64_t;
+typedef signed long ssize_t;
+
+#ifndef __cplusplus
+typedef _Bool bool;
+enum { false = 0, true = 1 };
+#endif
+typedef __SIZE_TYPE__ size_t;
+typedef unsigned long dma_addr_t;
+typedef uint64_t hwaddr;
+
+typedef struct uint16List
+{
+ union {
+ uint16_t value;
+ uint64_t padding;
+ };
+ struct uint16List *next;
+} uint16List;
+
+
+/**********
+ ** libc **
+ **********/
+
+enum {
+ EINVAL = 22,
+};
+
+void *malloc(size_t size);
+void *memset(void *s, int c, size_t n);
+void *memcpy(void *dest, const void *src, size_t n);
+void free(void *p);
+
+void abort();
+
+#define fprintf(fd, fmt, ...) q_printf(fmt, ##__VA_ARGS__)
+int snprintf(char *buf, size_t size, const char *fmt, ...);
+int strcmp(const char *s1, const char *s2);
+size_t strlen(char const *s);
+long int strtol(const char *nptr, char **endptr, int base);
+char *strchr(const char *s, int c);
+
+
+/*************
+ ** defines **
+ *************/
+
+#define NULL (void *)0
+#define QEMU_SENTINEL
+
+#define le32_to_cpu(x) (x)
+#define cpu_to_le32(x) (x)
+#define cpu_to_le64(x) (x)
+
+#define le32_to_cpus(x)
+#define le64_to_cpus(x)
+
+/**
+ * Forward declarations
+ */
+
+typedef struct Monitor Monitor;
+typedef struct QDict QDict;
+
+typedef struct CPUReadMemoryFunc CPUReadMemoryFunc;
+typedef struct CPUWriteMemoryFunc CPUWriteMemoryFunc;
+
+typedef struct MemoryRegion { unsigned dummy; } MemoryRegion;
+
+struct tm;
+
+
+/******************
+ ** qapi/error.h **
+ ******************/
+
+typedef struct Error { char string[256]; } Error;
+
+void error_setg(Error **errp, const char *fmt, ...);
+
+const char *error_get_pretty(Error *err);
+void error_report(const char *fmt, ...);
+void error_free(Error *err);
+void error_propagate(Error **dst_errp, Error *local_err);
+
+extern Error *error_abort;
+
+
+/*******************
+ ** qemu/bitops.h **
+ *******************/
+
+#define BITS_PER_BYTE 8
+#define BITS_PER_LONG (sizeof (unsigned long) * BITS_PER_BYTE)
+
+#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
+#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
+#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+
+#define DECLARE_BITMAP(name,bits) \
+ unsigned long name[BITS_TO_LONGS(bits)]
+
+static inline void set_bit(long nr, unsigned long *addr)
+{
+ unsigned long mask = BIT_MASK(nr);
+ unsigned long *p = addr + BIT_WORD(nr);
+
+ *p |= mask;
+}
+
+
+/*******************
+ ** qemu-common.h **
+ *******************/
+
+struct iovec
+{
+ void *iov_base;
+ size_t iov_len;
+};
+
+typedef struct QEMUIOVector
+{
+ struct iovec *iov;
+ int niov;
+ size_t size;
+ int alloc_hint;
+} QEMUIOVector;
+
+void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint);
+void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len);
+void qemu_iovec_reset(QEMUIOVector *qiov);
+void qemu_iovec_destroy(QEMUIOVector *qiov);
+
+void pstrcpy(char *buf, int buf_size, const char *str);
+
+
+/****************
+ ** qemu/iov.h **
+ ****************/
+
+size_t iov_from_buf(const struct iovec *iov, unsigned int iov_cnt,
+ size_t offset, const void *buf, size_t bytes);
+size_t iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt,
+ size_t offset, void *buf, size_t bytes);
+size_t iov_memset(const struct iovec *iov, const unsigned int iov_cnt,
+ size_t offset, int fillc, size_t bytes);
+
+/******************
+ ** qom/object.h **
+ ******************/
+
+typedef struct Object { unsigned dummy; } Object;
+typedef struct ObjectClass { unsigned dummy; } ObjectClass;
+
+struct DeviceState;
+struct PCIDevice;
+struct XHCIState;
+
+struct PCIDevice *cast_PCIDevice(void *);
+struct XHCIState *cast_XHCIState(void *);
+struct DeviceState *cast_DeviceState(void *);
+struct BusState *cast_BusState(void *);
+struct Object *cast_object(void *);
+struct USBDevice *cast_USBDevice(void *);
+struct USBHostDevice *cast_USBHostDevice(void *);
+
+struct PCIDeviceClass *cast_PCIDeviceClass(void *);
+struct DeviceClass *cast_DeviceClass(void *);
+struct BusClass *cast_BusClass(void *);
+struct HotplugHandlerClass *cast_HotplugHandlerClass(void *);
+
+struct USBDeviceClass *cast_USBDeviceClass(void *);
+
+#define OBJECT_CHECK(type, obj, str) \
+ cast_##type((void *)obj)
+
+#define OBJECT_CLASS_CHECK(type, klass, str) \
+ OBJECT_CHECK(type, (klass), str)
+
+#define OBJECT(obj) \
+ cast_object(obj)
+
+#define OBJECT_GET_CLASS(klass, obj, str) \
+ OBJECT_CHECK(klass, obj, str)
+
+
+typedef struct InterfaceInfo {
+ const char *type;
+} InterfaceInfo;
+
+
+typedef struct TypeInfo
+{
+ char const *name;
+ char const *parent;
+ size_t instance_size;
+
+ bool abstract;
+ size_t class_size;
+ void (*class_init)(ObjectClass *klass, void *data);
+ InterfaceInfo *interfaces;
+} TypeInfo;
+
+struct Type_impl { unsigned dummy; };
+typedef struct Type_impl *Type;
+
+Type type_register_static(const TypeInfo *info);
+
+#define object_property_set_bool(...)
+#define object_unparent(...)
+
+const char *object_get_typename(Object *obj);
+
+/********************
+ ** glib emulation **
+ ********************/
+
+#define g_new0(type, count)({ \
+ typeof(type) *t = (typeof(type)*)malloc(sizeof(type) * count); \
+ memset(t, 0, sizeof(type) * count); \
+ t; \
+ })
+
+#define g_free(p) free(p)
+#define g_malloc malloc
+
+#define g_malloc0(size) ({ \
+ void *t = malloc((size)); \
+ memset(t, 0, (size)); \
+ t; \
+ })
+
+typedef void* gpointer;
+typedef struct GSList GSList;
+
+struct GSList
+{
+ gpointer data;
+ GSList *next;
+};
+
+GSList *g_slist_append(GSList *list, gpointer data);
+
+typedef char gchar;
+gchar *g_strdup(gchar const *str);
+gchar *g_strdup_printf(gchar const *fmt, ...);
+
+
+/********************
+ ** hw/qdev-core.h **
+ ********************/
+
+typedef enum DeviceCategory {
+ DEVICE_CATEGORY_USB = 1,
+ DEVICE_CATEGORY_MAX
+} DeviceCategory;
+
+typedef struct BusState BusState;
+
+typedef struct DeviceState
+{
+ BusState *parent_bus;
+} DeviceState;
+
+struct VMStateDescription;
+struct Property;
+
+typedef void (*DeviceRealize)(DeviceState *dev, Error **errp);
+typedef void (*DeviceUnrealize)(DeviceState *dev, Error **errp);
+
+typedef struct DeviceClass
+{
+ DECLARE_BITMAP(categories, DEVICE_CATEGORY_MAX);
+ struct Property *props;
+ void (*reset)(DeviceState *dev);
+ DeviceRealize realize;
+ DeviceUnrealize unrealize;
+
+ const struct VMStateDescription *vmsd;
+ const char *bus_type;
+} DeviceClass;
+
+#define DEVICE_CLASS(klass) OBJECT_CHECK(DeviceClass, (klass), "device")
+
+
+typedef struct BusState
+{
+ DeviceState *parent;
+ char *name;
+} BusState;
+
+typedef struct BusClass
+{
+ void (*print_dev)(Monitor *mon, DeviceState *dev, int indent);
+ char *(*get_dev_path)(DeviceState *dev);
+ char *(*get_fw_dev_path)(DeviceState *dev);
+
+} BusClass;
+
+#define TYPE_BUS "bus"
+#define BUS(obj) OBJECT_CHECK(BusState, (obj), TYPE_BUS)
+#define BUS_CLASS(klass) OBJECT_CLASS_CHECK(BusClass, (klass), TYPE_BUS)
+
+#define TYPE_DEVICE "device"
+#define DEVICE(obj) OBJECT_CHECK(DeviceState, (obj), TYPE_DEVICE)
+
+enum Prop_type
+{
+ BIT, UINT32, END
+};
+
+typedef struct Property
+{
+ enum Prop_type type;
+ unsigned offset;
+ unsigned long value;
+} Property;
+
+
+#define DEFINE_PROP_BIT(_name, _state, _field, _bit, _bool) \
+{ .type = BIT, .offset = offsetof(_state, _field), .value = (_bool << _bit) }
+#define DEFINE_PROP_UINT32(_name, _state, _field, _value) \
+{ .type = UINT32, .offset = offsetof(_state, _field), .value = _value }
+#define DEFINE_PROP_END_OF_LIST() { .type = END }
+#define DEFINE_PROP_STRING(...) {}
+
+
+/* forward */
+typedef struct DeviceState DeviceState;
+typedef struct HotplugHandler HotplugHandler;
+
+void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp);
+void qbus_create_inplace(void *bus, size_t size, const char *typename,
+ DeviceState *parent, const char *name);
+void qbus_set_bus_hotplug_handler(BusState *bus, Error **errp);
+DeviceState *qdev_create(BusState *bus, const char *name);
+DeviceState *qdev_try_create(BusState *bus, const char *name);
+char *qdev_get_dev_path(DeviceState *dev);
+const char *qdev_fw_name(DeviceState *dev);
+
+/******************
+ ** hw/hotplug.h **
+ ******************/
+
+typedef struct HotplugHandler { unsigned dummy; } HotplugHandler;
+
+typedef void (*hotplug_fn)(HotplugHandler *plug_handler,
+ DeviceState *plugged_dev, Error **errp);
+
+typedef struct HotplugHandlerClass
+{
+ hotplug_fn unplug;
+} HotplugHandlerClass;
+
+#define TYPE_HOTPLUG_HANDLER "hotplug-handler"
+#define HOTPLUG_HANDLER_CLASS(klass) \
+ OBJECT_CLASS_CHECK(HotplugHandlerClass, (klass), TYPE_HOTPLUG_HANDLER)
+
+
+/****************
+ ** hw/osdep.h **
+ ****************/
+
+#define offsetof(type, member) ((size_t) &((type *)0)->member)
+
+
+#define container_of(ptr, type, member) ({ \
+ const typeof(((type *) 0)->member) *__mptr = (ptr); \
+ (type *) ((char *) __mptr - offsetof(type, member));})
+
+#define DO_UPCAST(type, field, dev) cast_DeviceStateToUSBBus()
+
+struct USBBus *cast_DeviceStateToUSBBus(void);
+
+#define MAX(a, b) ((a) < (b) ? (b) : (a))
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+
+/******************
+ ** qemu/timer.h **
+ ******************/
+
+enum QEMUClockType
+{
+ QEMU_CLOCK_VIRTUAL = 1,
+};
+
+typedef enum QEMUClockType QEMUClockType;
+typedef struct QEMUTimer { unsigned dummy; } QEMUTimer;
+typedef void QEMUTimerCB(void *opaque);
+
+QEMUTimer *timer_new_ns(QEMUClockType type, QEMUTimerCB *cb, void *opaque);
+void timer_mod(QEMUTimer *ts, int64_t expire_timer);
+void timer_del(QEMUTimer *ts);
+void timer_free(QEMUTimer *ts);
+
+int64_t qemu_clock_get_ns(QEMUClockType type);
+
+
+/***********************
+ ** exec/cpu-common.h **
+ ***********************/
+
+enum device_endian { DEVICE_LITTLE_ENDIAN = 2 };
+
+
+/*******************
+ ** exec/memory.h **
+ *******************/
+
+typedef struct AddressSpace { unsigned dummy; } AddressSpace;
+
+typedef struct MemoryRegionOps {
+ uint64_t (*read)(void *opaque, hwaddr addr, unsigned size);
+ void (*write)(void *opaque, hwaddr addr, uint64_t data, unsigned size);
+
+ enum device_endian endianness;
+
+ struct {
+ unsigned min_access_size;
+ unsigned max_access_size;
+ } valid;
+
+ struct {
+ unsigned min_access_size;
+ unsigned max_access_size;
+ } impl;
+} MemoryRegionOps;
+
+void memory_region_init(MemoryRegion *mr,
+ struct Object *owner,
+ const char *name,
+ uint64_t size);
+
+void memory_region_init_io(MemoryRegion *mr,
+ struct Object *owner,
+ const MemoryRegionOps *ops,
+ void *opaque,
+ const char *name,
+ uint64_t size);
+
+void memory_region_add_subregion(MemoryRegion *mr,
+ hwaddr offset,
+ MemoryRegion *subregion);
+
+void memory_region_del_subregion(MemoryRegion *mr,
+ MemoryRegion *subregion);
+
+/******************
+ ** sysemu/dma.h **
+ ******************/
+
+typedef struct QEMUIOVector QEMUSGList;
+
+void qemu_sglist_add(QEMUSGList *qsg, dma_addr_t base, dma_addr_t len);
+void qemu_sglist_destroy(QEMUSGList *qsg);
+
+int dma_memory_read(AddressSpace *as, dma_addr_t addr, void *buf, dma_addr_t len);
+
+static inline uint64_t ldq_le_dma(AddressSpace *as, dma_addr_t addr)
+{
+ uint64_t val;
+ dma_memory_read(as, addr, &val, 8);
+ return val;
+}
+
+static inline uint64_t ldq_le_pci_dma(void *dev, dma_addr_t addr)
+{
+ return ldq_le_dma(0, addr);
+}
+
+
+/**************
+ ** hw/pci.h **
+ **************/
+
+enum Pci_regs {
+ PCI_BASE_ADDRESS_SPACE_MEMORY = 0,
+ PCI_BASE_ADDRESS_MEM_TYPE_64 = 0x04,
+ PCI_CLASS_PROG = 0x09,
+ PCI_CACHE_LINE_SIZE = 0x0c,
+ PCI_INTERRUPT_PIN = 0x3d,
+};
+
+enum Pci_ids {
+ PCI_CLASS_SERIAL_USB = 0x0c03,
+ PCI_VENDOR_ID_NEC = 0x1033,
+ PCI_DEVICE_ID_NEC_UPD720200 = 0x0194,
+};
+
+typedef struct PCIBus { unsigned dummy; } PCIBus;
+
+typedef struct PCIDevice
+{
+ uint8_t config[0x1000]; /* PCIe config space */
+ PCIBus *bus;
+
+ uint8_t *msix_table;
+ uint8_t *msix_pba;
+
+ MemoryRegion msix_table_mmio;
+ MemoryRegion msix_pba_mmio;
+
+ unsigned *msix_entry_used;
+} PCIDevice;
+
+typedef void PCIUnregisterFunc(PCIDevice *pci_dev);
+
+typedef struct PCIDeviceClass
+{
+ void (*realize)(PCIDevice *dev, Error **errp);
+ PCIUnregisterFunc *exit;
+
+ uint16_t vendor_id;
+ uint16_t device_id;
+ uint8_t revision;
+ uint16_t class_id;
+
+ int is_express;
+
+} PCIDeviceClass;
+
+#define TYPE_PCI_DEVICE "pci-device"
+#define PCI_DEVICE(obj) \
+ OBJECT_CHECK(PCIDevice, (obj), TYPE_PCI_DEVICE)
+#define PCI_DEVICE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(PCIDeviceClass, (klass), TYPE_PCI_DEVICE)
+
+int pci_dma_read(PCIDevice *dev, dma_addr_t addr,
+ void *buf, dma_addr_t len);
+
+int pci_dma_write(PCIDevice *dev, dma_addr_t addr,
+ const void *buf, dma_addr_t len);
+
+void pci_set_irq(PCIDevice *pci_dev, int level);
+void pci_irq_assert(PCIDevice *pci_dev);
+void pci_dma_sglist_init(QEMUSGList *qsg, PCIDevice *dev,
+ int alloc_hint);
+AddressSpace *pci_get_address_space(PCIDevice *dev);
+
+void pci_register_bar(PCIDevice *pci_dev, int region_num,
+ uint8_t attr, MemoryRegion *memory);
+bool pci_bus_is_express(PCIBus *bus);
+
+int pcie_endpoint_cap_init(PCIDevice *dev, uint8_t offset);
+
+
+/*********************
+ ** hw/pci/msi(x).h **
+ *********************/
+
+int msi_init(struct PCIDevice *dev, uint8_t offset,
+ unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask);
+
+int msix_init(PCIDevice *dev, unsigned short nentries,
+ MemoryRegion *table_bar, uint8_t table_bar_nr,
+ unsigned table_offset, MemoryRegion *pba_bar,
+ uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos);
+
+bool msi_enabled(const PCIDevice *dev);
+int msix_enabled(PCIDevice *dev);
+
+int msix_vector_use(PCIDevice *dev, unsigned vector);
+void msix_vector_unuse(PCIDevice *dev, unsigned vector);
+
+void msi_notify(PCIDevice *dev, unsigned int vector);
+void msix_notify(PCIDevice *dev, unsigned vector);
+
+
+/*************************
+ ** migration/vmstate.h **
+ *************************/
+
+#define VMSTATE_BOOL(...) {}
+#define VMSTATE_UINT8(...) {}
+#define VMSTATE_UINT32(...) {}
+#define VMSTATE_UINT32_TEST(...) {}
+#define VMSTATE_UINT64(...) {}
+#define VMSTATE_INT32(...) {}
+#define VMSTATE_INT64(...) {}
+#define VMSTATE_STRUCT_ARRAY_TEST(...) {}
+#define VMSTATE_UINT8_ARRAY(...) {}
+#define VMSTATE_STRUCT_VARRAY_UINT32(...) {}
+#define VMSTATE_PCIE_DEVICE(...) {}
+#define VMSTATE_MSIX(...) {}
+#define VMSTATE_TIMER_PTR(...) {}
+#define VMSTATE_STRUCT(...) {}
+#define VMSTATE_END_OF_LIST() {}
+
+typedef struct VMStateField { unsigned dummy; } VMStateField;
+typedef struct VMStateDescription
+{
+ char const *name;
+ int version_id;
+ int minimum_version_id;
+ int (*post_load)(void *opaque, int version_id);
+ VMStateField *fields;
+} VMStateDescription;
+
+
+/**************
+ ** assert.h **
+ **************/
+
+#define assert(cond) do { \
+ if (!(cond)) { \
+ q_printf("assertion faied: %s:%d\n", __FILE__, __LINE__); \
+ int *d = (int *)0x0; \
+ *d = 1; \
+ }} while (0)
+
+
+/************
+ ** traces **
+ ************/
+
+#define trace_usb_xhci_irq_msix_use(v)
+#define trace_usb_xhci_irq_msix_unuse(v)
+#define trace_usb_xhci_irq_msix(v)
+#define trace_usb_xhci_irq_msi(v)
+#define trace_usb_xhci_queue_event(...)
+#define trace_usb_xhci_fetch_trb(...)
+#define trace_usb_xhci_run(...)
+#define trace_usb_xhci_stop(...)
+#define trace_usb_xhci_ep_state(...)
+#define trace_usb_xhci_ep_enable(...)
+#define trace_usb_xhci_ep_disable(...)
+#define trace_usb_xhci_ep_stop(...)
+#define trace_usb_xhci_ep_reset(...)
+#define trace_usb_xhci_ep_set_dequeue(...)
+#define trace_usb_xhci_xfer_async(...)
+#define trace_usb_xhci_xfer_nak(...)
+#define trace_usb_xhci_xfer_success(...)
+#define trace_usb_xhci_xfer_error(...)
+#define trace_usb_xhci_xfer_start(...)
+#define trace_usb_xhci_unimplemented(...)
+#define trace_usb_xhci_ep_kick(...)
+#define trace_usb_xhci_xfer_retry(...)
+#define trace_usb_xhci_slot_enable(...)
+#define trace_usb_xhci_slot_disable(...)
+#define trace_usb_xhci_slot_address(...)
+#define trace_usb_xhci_slot_configure(...)
+#define trace_usb_xhci_irq_intx(...)
+#define trace_usb_xhci_slot_reset(...)
+#define trace_usb_xhci_slot_evaluate(...)
+#define trace_usb_xhci_port_notify(...)
+#define trace_usb_xhci_port_link(...)
+#define trace_usb_xhci_port_reset(...)
+#define trace_usb_xhci_reset(...)
+#define trace_usb_xhci_cap_read(...)
+#define trace_usb_xhci_port_read(...)
+#define trace_usb_xhci_port_write(...)
+#define trace_usb_xhci_oper_read(...)
+#define trace_usb_xhci_oper_write(...)
+#define trace_usb_xhci_runtime_read(...)
+#define trace_usb_xhci_runtime_write(...)
+#define trace_usb_xhci_doorbell_read(...)
+#define trace_usb_xhci_doorbell_write(...)
+#define trace_usb_xhci_exit(...)
+#define trace_usb_port_claim(...)
+#define trace_usb_port_release(...)
+#define trace_usb_port_attach(...)
+#define trace_usb_port_detach(...)
+#define trace_usb_packet_state_fault(...)
+#define trace_usb_packet_state_change(...)
+
+/***********************
+ ** library interface **
+ ***********************/
+
+#define type_init(func) void _type_init_##func(void) { func(); }
+
+#define TYPE_USB_HOST_DEVICE "usb-host"
+
+typedef struct USBHostDevice
+{
+ void *data;
+} USBHostDevice;
+
+
+USBHostDevice *create_usbdevice(void *data);
+void remove_usbdevice(USBHostDevice *device);
+
+void usb_host_destroy();
+void usb_host_update_devices();
+
+
+/***********************
+ ** monitor/monitor.h **
+ ***********************/
+
+void monitor_printf(Monitor *mon, const char *fmt, ...);
+
+
+#endif /* _INCLUDE__QEMU_EMUL_H_ */
diff --git a/repos/libports/src/lib/qemu-usb/patches/usb_bus_nfree.patch b/repos/libports/src/lib/qemu-usb/patches/usb_bus_nfree.patch
new file mode 100644
index 0000000000..b7677728d0
--- /dev/null
+++ b/repos/libports/src/lib/qemu-usb/patches/usb_bus_nfree.patch
@@ -0,0 +1,19 @@
+diff --git a/src/lib/qemu/hw/usb/bus.c b/src/lib/qemu/hw/usb/bus.c
+index 5f39e1e..b94f3af 100644
+--- a/src/lib/qemu/hw/usb/bus.c
++++ b/src/lib/qemu/hw/usb/bus.c
+@@ -433,10 +433,10 @@ void usb_claim_port(USBDevice *dev, Error **errp)
+ return;
+ }
+ } else {
+- if (bus->nfree == 1 && strcmp(object_get_typename(OBJECT(dev)), "usb-hub") != 0) {
+- /* Create a new hub and chain it on */
+- usb_try_create_simple(bus, "usb-hub", NULL);
+- }
++ // if (bus->nfree == 1 && strcmp(object_get_typename(OBJECT(dev)), "usb-hub") != 0) {
++ // /* Create a new hub and chain it on */
++ // usb_try_create_simple(bus, "usb-hub", NULL);
++ // }
+ if (bus->nfree == 0) {
+ error_setg(errp, "tried to attach usb device %s to a bus "
+ "with no free ports", dev->product_desc);
diff --git a/repos/libports/src/lib/qemu-usb/patches/xhci_state.patch b/repos/libports/src/lib/qemu-usb/patches/xhci_state.patch
new file mode 100644
index 0000000000..b9c57f61d7
--- /dev/null
+++ b/repos/libports/src/lib/qemu-usb/patches/xhci_state.patch
@@ -0,0 +1,27 @@
+diff --git a/src/lib/qemu/hw/usb/hcd-xhci.c b/src/lib/qemu/hw/usb/hcd-xhci.c
+index c673bed..b2a8939 100644
+--- a/src/lib/qemu/hw/usb/hcd-xhci.c
++++ b/src/lib/qemu/hw/usb/hcd-xhci.c
+@@ -486,6 +486,8 @@ struct XHCIState {
+
+ #define TYPE_XHCI "nec-usb-xhci"
+
++#ifndef __cplusplus
++
+ #define XHCI(obj) \
+ OBJECT_CHECK(XHCIState, (obj), TYPE_XHCI)
+
+@@ -2361,6 +2363,7 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
+
+ if (bsr) {
+ slot_ctx[3] = SLOT_DEFAULT << SLOT_STATE_SHIFT;
++ usb_device_reset(dev);
+ } else {
+ USBPacket p;
+ uint8_t buf[1];
+@@ -3914,3 +3917,5 @@ static void xhci_register_types(void)
+ }
+
+ type_init(xhci_register_types)
++
++#endif /* __cplusplus */
diff --git a/repos/libports/src/lib/qemu-usb/qemu_emul.cc b/repos/libports/src/lib/qemu-usb/qemu_emul.cc
new file mode 100644
index 0000000000..68549eab33
--- /dev/null
+++ b/repos/libports/src/lib/qemu-usb/qemu_emul.cc
@@ -0,0 +1,896 @@
+/*
+ * \brief Qemu USB controller interface
+ * \author Josef Soentgen
+ * \author Sebastian Sumpf
+ * \date 2015-12-14
+ */
+
+/*
+ * Copyright (C) 2015 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU General Public License version 2.
+ */
+
+/* Genode includes */
+#include
+#include
+#include
+
+/* local includes */
+#include
+#include
+/* XHCIState is defined in this file */
+#include
+#include
+
+#include
+
+/*******************
+ ** USB interface **
+ *******************/
+
+static bool const verbose_irq = false;
+static bool const verbose_iov = false;
+static bool const verbose_mmio = false;
+
+extern "C" void _type_init_usb_register_types();
+extern "C" void _type_init_usb_host_register_types(Genode::Signal_receiver*);
+extern "C" void _type_init_xhci_register_types();
+
+extern Genode::Lock _lock;
+
+Qemu::Controller *qemu_controller();
+
+
+static Qemu::Timer_queue* _timer_queue;
+static Qemu::Pci_device* _pci_device;
+
+
+Qemu::Controller *Qemu::usb_init(Timer_queue &tq, Pci_device &pci, Genode::Signal_receiver &sig_rec)
+{
+ _timer_queue = &tq;
+ _pci_device = &pci;
+
+ _type_init_usb_register_types();
+ _type_init_xhci_register_types();
+ _type_init_usb_host_register_types(&sig_rec);
+
+ return qemu_controller();
+}
+
+void reset_controller();
+
+void Qemu::usb_reset()
+{
+ usb_host_destroy();
+
+ reset_controller();
+}
+
+
+void Qemu::usb_update_devices() {
+ usb_host_update_devices(); }
+
+
+void Qemu::usb_timer_callback(void (*cb)(void*), void *data)
+{
+ Genode::Lock::Guard g(_lock);
+
+ cb(data);
+}
+
+
+/**********
+ ** libc **
+ **********/
+
+void *malloc(size_t size) {
+ return Genode::env()->heap()->alloc(size); }
+
+
+void *memset(void *s, int c, size_t n) {
+ return Genode::memset(s, c, n); }
+
+
+void free(void *p) {
+ Genode::env()->heap()->free(p, 0); }
+
+
+void q_printf(char const *fmt, ...)
+{
+ va_list va;
+ va_start(va, fmt);
+ Genode::vprintf(fmt, va);
+ va_end(va);
+}
+
+
+int snprintf(char *buf, size_t size, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ Genode::String_console sc(buf, size);
+ sc.vprintf(fmt, args);
+ va_end(args);
+
+ return sc.len();
+}
+
+
+int strcmp(const char *s1, const char *s2)
+{
+ return Genode::strcmp(s1, s2);
+}
+
+
+/********************
+ ** Qemu emulation **
+ ********************/
+
+/**
+ * Set properties of objects
+ */
+template
+void properties_apply(T *state, DeviceClass *klass)
+{
+ Property *p = klass->props;
+
+ if (!p)
+ return;
+
+ while (p->type != END) {
+ char *s = (char *)state;
+ s += p->offset;
+ uint32_t *member = (uint32_t *)s;
+ if (p->type == BIT)
+ *member |= p->value;
+ if (p->type == UINT32)
+ *member = p->value;
+
+ p++;
+ }
+}
+
+
+/**
+ * Class and objects wrapper
+ */
+struct Wrapper
+{
+ unsigned long _start;
+ Object _object;
+ DeviceState _device_state;
+ PCIDevice _pci_device;
+ USBDevice _usb_device;
+ BusState _bus_state;
+ XHCIState *_xhci_state = nullptr;
+ USBHostDevice _usb_host_device;
+
+ ObjectClass _object_class;
+ DeviceClass _device_class;
+ PCIDeviceClass _pci_device_class;
+ BusClass _bus_class;
+ USBDeviceClass _usb_device_class;
+ HotplugHandlerClass _hotplug_handler_class;
+ unsigned long _end;
+
+ Wrapper() { }
+
+ bool in_object(void * ptr)
+ {
+ /*
+ * XHCIState is roughly 3 MiB large so we only create on instance
+ * (see below) and have to do this pointer check shenanigans.
+ */
+ if (_xhci_state != nullptr
+ && ptr >= _xhci_state
+ && ptr < ((char*)_xhci_state + sizeof(XHCIState)))
+ return true;
+
+ using addr_t = Genode::addr_t;
+
+ addr_t p = (addr_t)ptr;
+
+ if (p > (addr_t)&_start && p < (addr_t)&_end)
+ return true;
+
+ return false;
+ }
+};
+
+
+struct Object_pool
+{
+ enum {
+ XHCI, /* XHCI controller */
+ USB_BUS, /* bus driver */
+ USB_DEVICE, /* USB device driver */
+ USB_HOST_DEVICE, /* USB host device driver */
+ MAX = 8 /* host devices (USB_HOST_DEVICE - MAX) */
+ };
+
+ bool used[MAX];
+ Wrapper obj[MAX];
+
+ Wrapper *create_object()
+ {
+ for (unsigned i = USB_HOST_DEVICE + 1; i < MAX; i++) {
+ if (used[i] == false) {
+ used[i] = true;
+ return &obj[i];
+ }
+ }
+ return nullptr;
+ }
+
+ void free_object(Wrapper *w)
+ {
+ for (unsigned i = USB_HOST_DEVICE + 1; i < MAX; i++)
+ if (w == &obj[i]) {
+ used[i] = false;
+ break;
+ }
+ }
+
+ Wrapper * find_object(void *ptr)
+ {
+ for (Wrapper &w : obj) {
+ if(w.in_object(ptr))
+ return &w;
+ }
+
+ PERR("object for pointer not found called from: %p", __builtin_return_address(0));
+ throw -1;
+ }
+
+ XHCIState *xhci_state() {
+ return obj[XHCI]._xhci_state; }
+
+ BusState *bus() {
+ return &obj[USB_BUS]._bus_state; }
+
+ static Object_pool *p()
+ {
+ static Object_pool _p;
+ return &_p;
+ }
+};
+
+
+/***********
+ ** casts **
+ ***********/
+
+struct PCIDevice *cast_PCIDevice(void *ptr) {
+ return &Object_pool::p()->find_object(ptr)->_pci_device; }
+
+
+struct XHCIState *cast_XHCIState(void *ptr) {
+ return Object_pool::p()->find_object(ptr)->_xhci_state; }
+
+
+struct DeviceState *cast_DeviceState(void *ptr) {
+ return &Object_pool::p()->find_object(ptr)->_device_state; }
+
+
+struct BusState *cast_BusState(void *ptr) {
+ return &Object_pool::p()->find_object(ptr)->_bus_state; }
+
+
+struct USBDevice *cast_USBDevice(void *ptr) {
+ return &Object_pool::p()->find_object(ptr)->_usb_device; }
+
+
+struct Object *cast_object(void *ptr) {
+ return &Object_pool::p()->find_object(ptr)->_object; }
+
+
+struct PCIDeviceClass *cast_PCIDeviceClass(void *ptr) {
+ return &Object_pool::p()->find_object(ptr)->_pci_device_class; }
+
+
+struct DeviceClass *cast_DeviceClass(void *ptr) {
+ return &Object_pool::p()->find_object(ptr)->_device_class; }
+
+
+struct USBDeviceClass *cast_USBDeviceClass(void *ptr) {
+ return &Object_pool::p()->find_object(ptr)->_usb_device_class; }
+
+
+struct BusClass *cast_BusClass(void *ptr) {
+ return &Object_pool::p()->find_object(ptr)->_bus_class; }
+
+
+struct HotplugHandlerClass *cast_HotplugHandlerClass(void *ptr) {
+ return &Object_pool::p()->find_object(ptr)->_hotplug_handler_class; }
+
+
+struct USBHostDevice *cast_USBHostDevice(void *ptr) {
+ return &Object_pool::p()->find_object(ptr)->_usb_host_device; }
+
+
+struct USBBus *cast_DeviceStateToUSBBus(void) {
+ return &Object_pool::p()->xhci_state()->bus; }
+
+
+USBHostDevice *create_usbdevice(void *data)
+{
+ Wrapper *obj = Object_pool::p()->create_object();
+ if (!obj) {
+ PERR("could not create new object");
+ return nullptr;
+ }
+
+ obj->_usb_device_class = Object_pool::p()->obj[Object_pool::USB_HOST_DEVICE]._usb_device_class;
+
+ /*
+ * Set parent bus object
+ */
+ DeviceState *dev_state = &obj->_device_state;
+ dev_state->parent_bus = Object_pool::p()->bus();
+
+ /* set data pointer */
+ obj->_usb_host_device.data = data;
+
+ /*
+ * Attach new USB host device to USB device driver
+ */
+ Error *e = nullptr;
+ DeviceClass *usb_device_class = &Object_pool::p()->obj[Object_pool::USB_DEVICE]._device_class;
+ usb_device_class->realize(dev_state, &e);
+ if (e) {
+ error_free(e);
+ e = nullptr;
+
+ usb_device_class->unrealize(dev_state, &e);
+ Object_pool::p()->free_object(obj);
+
+ return nullptr;
+ }
+
+ return &obj->_usb_host_device;
+}
+
+
+void remove_usbdevice(USBHostDevice *device)
+{
+ DeviceClass *usb_device_class = &Object_pool::p()->obj[Object_pool::USB_DEVICE]._device_class;
+ DeviceState *usb_device_state = cast_DeviceState(device);
+
+ if (usb_device_class == nullptr)
+ PERR("usb_device_class null");
+
+ if (usb_device_state == nullptr)
+ PERR("usb_device_class null");
+
+ Error *e = nullptr;
+ usb_device_class->unrealize(usb_device_state, &e);
+
+ Wrapper *obj = Object_pool::p()->find_object(device);
+ Object_pool::p()->free_object(obj);
+}
+
+
+void reset_controller()
+{
+ Wrapper *w = &Object_pool::p()->obj[Object_pool::XHCI];
+ DeviceClass *dc = &w->_device_class;
+
+ dc->reset(&w->_device_state);
+}
+
+
+/***********************************
+ ** Qemu interface implementation **
+ ***********************************/
+
+Type type_register_static(TypeInfo const *t)
+{
+ if (!Genode::strcmp(t->name, TYPE_XHCI)) {
+ Wrapper *w = &Object_pool::p()->obj[Object_pool::XHCI];
+ w->_xhci_state = (XHCIState*) malloc(sizeof(XHCIState));
+ Genode::memset(w->_xhci_state, 0, sizeof(XHCIState));
+
+ t->class_init(&w->_object_class, 0);
+
+ properties_apply(w->_xhci_state, &w->_device_class);
+
+ PCIDevice *pci = &w->_pci_device;
+ PCIDeviceClass *pci_class = &w->_pci_device_class;
+ Error *e;
+ pci_class->realize(pci, &e);
+ }
+
+ if (!Genode::strcmp(t->name, TYPE_USB_DEVICE)) {
+ Wrapper *w = &Object_pool::p()->obj[Object_pool::USB_DEVICE];
+ t->class_init(&w->_object_class, 0);
+ }
+
+ if (!Genode::strcmp(t->name, TYPE_USB_HOST_DEVICE)) {
+ Wrapper *w = &Object_pool::p()->obj[Object_pool::USB_HOST_DEVICE];
+ t->class_init(&w->_object_class, 0);
+ }
+
+ if (!Genode::strcmp(t->name, TYPE_USB_BUS)) {
+ Wrapper *w = &Object_pool::p()->obj[Object_pool::USB_BUS];
+ ObjectClass *c = &w->_object_class;
+ t->class_init(c, 0);
+ }
+
+ return nullptr;
+}
+
+
+void qbus_create_inplace(void* bus, size_t size , const char* type,
+ DeviceState *parent, const char *name)
+{
+ Wrapper *w = &Object_pool::p()->obj[Object_pool::USB_BUS];
+ BusState *b = &w->_bus_state;
+ char const *n = "xhci.0";
+ b->name = (char *)malloc(Genode::strlen(n) + 1);
+ Genode::strncpy(b->name, n, Genode::strlen(n) + 1);
+}
+
+
+void timer_del(QEMUTimer *t)
+{
+ _timer_queue->deactivate_timer(t);
+}
+
+
+void timer_free(QEMUTimer *t)
+{
+ _timer_queue->delete_timer(t);
+ free(t);
+}
+
+
+void timer_mod(QEMUTimer *t, int64_t expire)
+{
+ _timer_queue->activate_timer(t, expire);
+}
+
+
+QEMUTimer* timer_new_ns(QEMUClockType, void (*cb)(void*), void *opaque)
+{
+ QEMUTimer *t = (QEMUTimer*)malloc(sizeof(QEMUTimer));
+ if (t == nullptr) {
+ PERR("could not create QEMUTimer");
+ return nullptr;
+ }
+
+ _timer_queue->register_timer(t, cb, opaque);
+
+ return t;
+}
+
+
+int64_t qemu_clock_get_ns(QEMUClockType) {
+ return _timer_queue->get_ns(); }
+
+
+struct Controller : public Qemu::Controller
+{
+ struct Mmio
+ {
+ Genode::addr_t id;
+ Genode::size_t size;
+ Genode::off_t offset;
+
+ MemoryRegionOps const *ops;
+ } mmio_regions [16];
+
+ uint64_t _mmio_size;
+
+ Controller()
+ {
+ Genode::memset(mmio_regions, 0, sizeof(mmio_regions));
+ }
+
+ void mmio_add_region(uint64_t size) { _mmio_size = size; }
+
+ void mmio_add_region_io(Genode::addr_t id, uint64_t size, MemoryRegionOps const *ops)
+ {
+ for (Mmio &mmio : mmio_regions) {
+ if (mmio.id != 0) continue;
+
+ mmio.id = id;
+ mmio.size = size;
+ mmio.ops = ops;
+ return;
+ }
+ }
+
+ Mmio &find_region(Genode::off_t offset)
+ {
+ for (Mmio &mmio : mmio_regions) {
+ if (offset >= mmio.offset
+ && (offset < mmio.offset + (Genode::off_t)mmio.size))
+ return mmio;
+ }
+
+ PERR("could not find MMIO region for offset: %lx", offset);
+ throw -1;
+ }
+
+ void mmio_add_sub_region(Genode::addr_t id, Genode::off_t offset)
+ {
+ for (Mmio &mmio : mmio_regions) {
+ if (mmio.id != id) continue;
+
+ mmio.offset = offset;
+ return;
+ }
+ }
+
+ size_t mmio_size() const { return _mmio_size; }
+
+ int mmio_read(Genode::off_t offset, void *buf, size_t size)
+ {
+ Genode::Lock::Guard g(_lock);
+ Mmio &mmio = find_region(offset);
+ Genode::off_t reg = offset - mmio.offset;
+
+ void *ptr = Object_pool::p()->xhci_state();
+
+ /*
+ * Handle port access
+ */
+ if (offset >= (OFF_OPER + 0x400) && offset < OFF_RUNTIME) {
+ uint32_t port = (offset - 0x440) / 0x10;
+ ptr = (void*)&Object_pool::p()->xhci_state()->ports[port];
+ }
+
+ uint64_t v = mmio.ops->read(ptr, reg, size);
+ *((uint32_t*)buf) = v;
+
+ if (verbose_mmio)
+ PDBG("mmio: %lx offset: %lx reg: %lx v: %llx", mmio.id, offset, reg, v);
+
+ return 0;
+ }
+
+ int mmio_write(Genode::off_t offset, void const *buf, size_t size)
+ {
+ Genode::Lock::Guard g(_lock);
+ Mmio &mmio = find_region(offset);
+ Genode::off_t reg = offset - mmio.offset;
+ uint64_t v = *((uint64_t*)buf);
+
+ void *ptr = Object_pool::p()->xhci_state();
+
+ /*
+ * Handle port access
+ */
+ if (offset >= (OFF_OPER + 0x400) && offset < OFF_RUNTIME) {
+ uint32_t port = (offset - 0x440) / 0x10;
+ ptr = (void*)&Object_pool::p()->xhci_state()->ports[port];
+ }
+
+ mmio.ops->write(ptr, reg, v, size);
+
+ if (verbose_mmio)
+ PDBG("mmio: %lx offset: %lx reg: %lx v: %llx", mmio.id, offset, reg, v);
+
+ return 0;
+ }
+};
+
+
+static Controller *controller()
+{
+ static Controller _inst;
+ return &_inst;
+}
+
+Qemu::Controller *qemu_controller()
+{
+ return controller();
+}
+
+
+/**********
+ ** MMIO **
+ **********/
+
+void memory_region_init(MemoryRegion *mr, Object *obj, const char *name, uint64_t size) {
+ controller()->mmio_add_region(size); }
+
+
+void memory_region_init_io(MemoryRegion* mr, Object* obj, const MemoryRegionOps* ops,
+ void *, const char * name, uint64_t size) {
+ controller()->mmio_add_region_io((Genode::addr_t)mr, size, ops); }
+
+
+void memory_region_add_subregion(MemoryRegion *mr, hwaddr offset, MemoryRegion *sr) {
+ controller()->mmio_add_sub_region((Genode::addr_t)sr, offset); }
+
+
+/*********
+ ** DMA **
+ *********/
+
+int pci_dma_read(PCIDevice*, dma_addr_t addr, void *buf, dma_addr_t size)
+{
+ return _pci_device->read_dma(addr, buf, size);
+}
+
+
+int pci_dma_write(PCIDevice*, dma_addr_t addr, const void *buf, dma_addr_t size)
+{
+ return _pci_device->write_dma(addr, buf, size);
+}
+
+
+int dma_memory_read(AddressSpace*, dma_addr_t addr, void *buf, dma_addr_t size)
+{
+ return _pci_device->read_dma(addr, buf, size);
+}
+
+
+/****************
+ ** Interrupts **
+ ****************/
+
+void pci_set_irq(PCIDevice*, int level)
+{
+ if (verbose_irq)
+ PDBG("IRQ level: %d", level);
+ _pci_device->raise_interrupt(level);
+}
+
+
+void pci_irq_assert(PCIDevice*)
+{
+ pci_set_irq(nullptr, 1);
+}
+
+
+int msi_init(PCIDevice *pdev, uint8_t offset, unsigned int nr_vectors, bool msi64bit,
+ bool msi_per_vector_mask)
+{
+ return 0;
+}
+
+
+int msix_init(PCIDevice*, short unsigned int, MemoryRegion*, uint8_t, unsigned int, MemoryRegion*,
+ uint8_t, unsigned int, uint8_t)
+{
+ return 0;
+}
+
+
+bool msi_enabled(const PCIDevice *pdev)
+{
+ return false;
+}
+
+
+int msix_enabled(PCIDevice *pdev)
+{
+ return 0;
+}
+
+
+void msi_notify(PCIDevice *pdev, unsigned int level) { }
+
+
+void msix_notify(PCIDevice *pdev , unsigned int level) { }
+
+
+/*************************************
+ ** IO vector / scatter-gatter list **
+ *************************************/
+
+void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len)
+{
+ int niov = qiov->niov;
+
+ if (qiov->alloc_hint <= niov) {
+ if (verbose_iov)
+ PDBG("alloc_hint %d <= niov: %d", qiov->alloc_hint, niov);
+
+ qiov->alloc_hint += 64;
+ iovec *new_iov = (iovec*) malloc(sizeof(iovec) * qiov->alloc_hint);
+ if (new_iov == nullptr) {
+ PERR("Could not reallocate iov");
+ throw -1;
+ }
+
+ for (int i = 0; i < niov; i++) {
+ new_iov[i].iov_base = qiov->iov[i].iov_base;
+ new_iov[i].iov_len = qiov->iov[i].iov_len;
+ }
+
+ free(qiov->iov);
+ qiov->iov = new_iov;
+ }
+
+ if (verbose_iov)
+ PDBG("niov: %u iov_base: %p base: %p len: %zu",
+ niov, &qiov->iov[niov].iov_base, base, len);
+
+ qiov->iov[niov].iov_base = base;
+ qiov->iov[niov].iov_len = len;
+ qiov->size += len;
+ qiov->niov++;
+}
+
+
+void qemu_iovec_destroy(QEMUIOVector *qiov)
+{
+ qemu_iovec_reset(qiov);
+
+ free(qiov->iov);
+ qiov->iov = nullptr;
+}
+
+
+void qemu_iovec_reset(QEMUIOVector *qiov)
+{
+ qiov->size = 0;
+ qiov->niov = 0;
+}
+
+
+void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint)
+{
+ if (verbose_iov)
+ PDBG("iov: %p alloc_hint: %d", qiov->iov, alloc_hint);
+
+ iovec *iov = qiov->iov;
+ if (iov != nullptr) {
+ if (alloc_hint > qiov->alloc_hint)
+ PERR("iov already initialized: %p and alloc_hint smaller", iov);
+
+ qemu_iovec_reset(qiov);
+ return;
+ }
+
+ if (alloc_hint <= 0) alloc_hint = 1;
+
+ qiov->alloc_hint = alloc_hint;
+
+ qiov->iov = (iovec*) malloc(sizeof(iovec) * alloc_hint);
+ if (qiov->iov == nullptr) {
+ PERR("Could not allocate iov");
+ throw -1;
+ }
+
+ Genode::memset(qiov->iov, 0, sizeof(iovec) * alloc_hint);
+
+ qemu_iovec_reset(qiov);
+}
+
+
+/* taken from util/iov.c */
+size_t iov_from_buf(const struct iovec *iov, unsigned int iov_cnt,
+ size_t offset, const void *buf, size_t bytes)
+{
+ size_t done;
+ unsigned int i;
+ for (i = 0, done = 0; (offset || done < bytes) && i < iov_cnt; i++) {
+ if (offset < iov[i].iov_len) {
+ size_t len = Genode::min(iov[i].iov_len - offset, bytes - done);
+ memcpy((char*)iov[i].iov_base + offset, (char*)buf + done, len);
+ done += len;
+ offset = 0;
+ } else {
+ offset -= iov[i].iov_len;
+ }
+ }
+
+ assert(offset == 0);
+ return done;
+}
+
+
+/* taken from util/iov.c */
+size_t iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt,
+ size_t offset, void *buf, size_t bytes)
+{
+ size_t done;
+ unsigned int i;
+ for (i = 0, done = 0; (offset || done < bytes) && i < iov_cnt; i++) {
+ if (offset < iov[i].iov_len) {
+ size_t len = Genode::min(iov[i].iov_len - offset, bytes - done);
+ memcpy((char*)buf + done, (char*)iov[i].iov_base + offset, len);
+ done += len;
+ offset = 0;
+ } else {
+ offset -= iov[i].iov_len;
+ }
+ }
+
+ assert(offset == 0);
+ return done;
+}
+
+
+void pci_dma_sglist_init(QEMUSGList *sgl, PCIDevice*, int alloc_hint) {
+ qemu_iovec_init(sgl, alloc_hint); }
+
+
+void qemu_sglist_add(QEMUSGList *sgl, dma_addr_t base, dma_addr_t len) {
+ qemu_iovec_add(sgl, (void*)base, len); }
+
+
+void qemu_sglist_destroy(QEMUSGList *sgl) {
+ qemu_iovec_destroy(sgl); }
+
+
+int usb_packet_map(USBPacket *p, QEMUSGList *sgl)
+{
+ void *mem;
+
+ for (int i = 0; i < sgl->niov; i++) {
+ dma_addr_t base = (dma_addr_t) sgl->iov[i].iov_base;
+ dma_addr_t len = sgl->iov[i].iov_len;
+
+ while (len) {
+ dma_addr_t xlen = len;
+ mem = _pci_device->map_dma(base, xlen);
+ if (verbose_iov)
+ PDBG("mem: 0x%p base: 0x%p len: 0x%lx", mem, (void*)base, len);
+
+ if (!mem) {
+ goto err;
+ }
+ if (xlen > len) {
+ xlen = len;
+ }
+ qemu_iovec_add(&p->iov, mem, xlen);
+ len -= xlen;
+ base += xlen;
+ }
+ }
+ return 0;
+
+err:
+ PERR("could not map dma");
+ usb_packet_unmap(p, sgl);
+ return -1;
+}
+
+
+void usb_packet_unmap(USBPacket *p, QEMUSGList *sgl)
+{
+ for (int i = 0; i < p->iov.niov; i++) {
+ _pci_device->unmap_dma(p->iov.iov[i].iov_base,
+ p->iov.iov[i].iov_len);
+ }
+}
+
+
+/******************
+ ** qapi/error.h **
+ ******************/
+
+void error_setg(Error **errp, const char *fmt, ...)
+{
+ assert(*errp == nullptr);
+
+ *errp = (Error*) malloc(sizeof(Error));
+ if (*errp == nullptr) {
+ PERR("Could not allocate Error");
+ return;
+ }
+
+ Error *e = *errp;
+
+ va_list args;
+
+ va_start(args, fmt);
+ Genode::String_console sc(e->string, sizeof(e->string));
+ sc.vprintf(fmt, args);
+ va_end(args);
+}
+
+
+void error_propagate(Error **dst_errp, Error *local_err) {
+ *dst_errp = local_err; }
+
+
+void error_free(Error *err) { free(err); }
diff --git a/repos/libports/src/lib/qemu-usb/symbol.map b/repos/libports/src/lib/qemu-usb/symbol.map
new file mode 100644
index 0000000000..f3aea3ca8a
--- /dev/null
+++ b/repos/libports/src/lib/qemu-usb/symbol.map
@@ -0,0 +1,14 @@
+/*
+ *
+ */
+{
+ global:
+
+ extern "C++" {
+ Qemu::*;
+ };
+
+ local:
+
+ *;
+};