Index: uspace/lib/usbhost/Makefile
===================================================================
--- uspace/lib/usbhost/Makefile	(revision cecba66ea48d60cfa59865e98aeda663808e42c7)
+++ uspace/lib/usbhost/Makefile	(revision 6cad7765736ec29f90dd2a80f7df7d0dd4857b9d)
@@ -37,5 +37,7 @@
 	src/endpoint.c \
 	src/hcd.c \
-	src/usb_bus.c \
+	src/bus.c \
+	src/usb2_bus.c \
+	src/bandwidth.c \
 	src/usb_transfer_batch.c
 
Index: uspace/lib/usbhost/include/usb/host/bandwidth.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/bandwidth.h	(revision 6cad7765736ec29f90dd2a80f7df7d0dd4857b9d)
+++ uspace/lib/usbhost/include/usb/host/bandwidth.h	(revision 6cad7765736ec29f90dd2a80f7df7d0dd4857b9d)
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/**  @addtogroup libusbhost
+ * @{
+ */
+/** @file
+ *
+ * Bandwidth calculation functions. Shared among uhci, ohci and ehci drivers.
+ */
+
+#ifndef LIBUSBHOST_HOST_BANDWIDTH_H
+#define LIBUSBHOST_HOST_BANDWIDTH_H
+
+#include <usb/usb.h>
+
+#include <stddef.h>
+
+/** Bytes per second in FULL SPEED */
+#define BANDWIDTH_TOTAL_USB11 (12000000 / 8)
+/** 90% of total bandwidth is available for periodic transfers */
+#define BANDWIDTH_AVAILABLE_USB11 ((BANDWIDTH_TOTAL_USB11 / 10) * 9)
+
+//TODO: Implement
+#define BANDWIDTH_AVAILABLE_USB20  1
+
+typedef struct endpoint endpoint_t;
+
+extern size_t bandwidth_count_usb11(endpoint_t *, size_t);
+
+extern size_t bandwidth_count_usb20(endpoint_t *, size_t);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbhost/include/usb/host/bus.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/bus.h	(revision 6cad7765736ec29f90dd2a80f7df7d0dd4857b9d)
+++ uspace/lib/usbhost/include/usb/host/bus.h	(revision 6cad7765736ec29f90dd2a80f7df7d0dd4857b9d)
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2017 Ondrej Hlavaty <aearsis@eideo.cz>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup libusbhost
+ * @{
+ */
+/** @file
+ * Virtual base for usb bus implementations.
+ *
+ * The purpose of this structure is to keep information about connected devices
+ * and endpoints, manage available bandwidth and the toggle bit flipping.
+ *
+ * The generic implementation is provided for USB 1 and 2 in usb2_bus.c. Some
+ * details in [OUE]HCI are solved through overriding some functions. XHCI does
+ * not need the bookkeeping functionality, because addresses are managed by HC
+ * itself.
+ */
+#ifndef LIBUSBHOST_HOST_BUS_H
+#define LIBUSBHOST_HOST_BUS_H
+
+#include <usb/usb.h>
+#include <usb/request.h>
+
+#include <assert.h>
+#include <fibril_synch.h>
+#include <stdbool.h>
+
+typedef struct hcd hcd_t;
+typedef struct endpoint endpoint_t;
+typedef struct bus bus_t;
+typedef struct ddf_fun ddf_fun_t;
+typedef struct usb_transfer_batch usb_transfer_batch_t;
+
+typedef struct device {
+	/* Device tree keeping */
+	link_t link;
+	list_t devices;
+	fibril_mutex_t guard;
+
+	/* Associated DDF function, if any */
+	ddf_fun_t *fun;
+
+	/* Invalid for the roothub device */
+	unsigned port;
+	struct device *hub;
+
+	/* Transaction translator */
+	usb_tt_address_t tt;
+
+	/* The following are not set by the library */
+	usb_speed_t speed;
+	usb_address_t address;
+
+	/* This structure is meant to be extended by overriding. */
+} device_t;
+
+typedef struct {
+	int (*enumerate_device)(bus_t *, hcd_t *, device_t *);
+	int (*remove_device)(bus_t *, hcd_t *, device_t *);
+
+	int (*online_device)(bus_t *, hcd_t *, device_t *);			/**< Optional */
+	int (*offline_device)(bus_t *, hcd_t *, device_t *);			/**< Optional */
+
+	/* The following operations are protected by a bus guard. */
+	endpoint_t *(*create_endpoint)(bus_t *);
+	int (*register_endpoint)(bus_t *, device_t *, endpoint_t *, const usb_endpoint_desc_t *);
+	int (*unregister_endpoint)(bus_t *, endpoint_t *);
+	endpoint_t *(*find_endpoint)(bus_t *, device_t*, usb_target_t, usb_direction_t);
+	void (*destroy_endpoint)(endpoint_t *);			/**< Optional */
+	bool (*endpoint_get_toggle)(endpoint_t *);		/**< Optional */
+	void (*endpoint_set_toggle)(endpoint_t *, bool);	/**< Optional */
+
+	int (*request_address)(bus_t *, usb_address_t*, bool, usb_speed_t);
+	int (*release_address)(bus_t *, usb_address_t);
+
+	int (*reset_toggle)(bus_t *, usb_target_t, toggle_reset_mode_t);
+
+	size_t (*count_bw) (endpoint_t *, size_t);
+
+	usb_transfer_batch_t *(*create_batch)(bus_t *, endpoint_t *); /**< Optional */
+	void (*destroy_batch)(usb_transfer_batch_t *);	/**< Optional */
+} bus_ops_t;
+
+/** Endpoint management structure */
+typedef struct bus {
+	/* Synchronization of ops */
+	fibril_mutex_t guard;
+
+	size_t device_size;
+
+	/* Do not call directly, ops are synchronized. */
+	bus_ops_t ops;
+
+	/* This structure is meant to be extended by overriding. */
+} bus_t;
+
+void bus_init(bus_t *, size_t);
+int device_init(device_t *);
+
+int device_set_default_name(device_t *);
+
+int bus_enumerate_device(bus_t *, hcd_t *, device_t *);
+int bus_remove_device(bus_t *, hcd_t *, device_t *);
+
+int bus_online_device(bus_t *, hcd_t *, device_t *);
+int bus_offline_device(bus_t *, hcd_t *, device_t *);
+
+int bus_add_endpoint(bus_t *, device_t *, const usb_endpoint_desc_t *, endpoint_t **);
+endpoint_t *bus_find_endpoint(bus_t *, device_t *, usb_target_t, usb_direction_t);
+int bus_remove_endpoint(bus_t *, endpoint_t *);
+
+size_t bus_count_bw(endpoint_t *, size_t);
+
+int bus_request_address(bus_t *, usb_address_t *, bool, usb_speed_t);
+int bus_release_address(bus_t *, usb_address_t);
+
+
+static inline int bus_reserve_default_address(bus_t *bus, usb_speed_t speed) {
+	usb_address_t addr = USB_ADDRESS_DEFAULT;
+
+	const int r = bus_request_address(bus, &addr, true, speed);
+	assert(addr == USB_ADDRESS_DEFAULT);
+	return r;
+}
+
+static inline int bus_release_default_address(bus_t *bus) {
+	return bus_release_address(bus, USB_ADDRESS_DEFAULT);
+}
+
+int bus_reset_toggle(bus_t *, usb_target_t, bool);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbhost/include/usb/host/ddf_helpers.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/ddf_helpers.h	(revision cecba66ea48d60cfa59865e98aeda663808e42c7)
+++ uspace/lib/usbhost/include/usb/host/ddf_helpers.h	(revision 6cad7765736ec29f90dd2a80f7df7d0dd4857b9d)
@@ -38,5 +38,5 @@
 
 #include <usb/host/hcd.h>
-#include <usb/host/usb_bus.h>
+#include <usb/host/bus.h>
 #include <usb/usb.h>
 
@@ -45,26 +45,46 @@
 #include <device/hw_res_parsed.h>
 
-typedef int (*driver_init_t)(hcd_t *, const hw_res_list_parsed_t *, bool);
+typedef int (*driver_init_t)(hcd_t *, const hw_res_list_parsed_t *, ddf_dev_t *);
+typedef int (*irq_code_gen_t)(irq_code_t *, hcd_t *, const hw_res_list_parsed_t *);
+typedef int (*claim_t)(hcd_t *, ddf_dev_t *);
+typedef int (*driver_start_t)(hcd_t *, bool irq);
+typedef int (*setup_root_hub_t)(hcd_t *, ddf_dev_t *);
+
+typedef void (*driver_stop_t)(hcd_t *);
 typedef void (*driver_fini_t)(hcd_t *);
-typedef int (*claim_t)(ddf_dev_t *);
-typedef int (*irq_code_gen_t)(irq_code_t *, const hw_res_list_parsed_t *);
 
+/**
+ * All callbacks are optional.
+ */
 typedef struct {
 	hcd_ops_t ops;
-	claim_t claim;
-	usb_speed_t hc_speed;
-	driver_init_t init;
-	driver_fini_t fini;
-	interrupt_handler_t *irq_handler;
-	irq_code_gen_t irq_code_gen;
 	const char *name;
+
+	interrupt_handler_t *irq_handler;  /**< Handler of IRQ. Do have generic implementation. */
+
+	/* Initialization sequence: */
+	driver_init_t init;                /**< Initialize internal structures, memory */
+	claim_t claim;                     /**< Claim device from BIOS */
+	irq_code_gen_t irq_code_gen;       /**< Generate IRQ handling code */
+	driver_start_t start;              /**< Start the HC */
+	setup_root_hub_t setup_root_hub;   /**< Setup the root hub */
+
+	/* Destruction sequence: */
+	driver_stop_t stop;                /**< Stop the HC (counterpart of start) */
+	driver_fini_t fini;                /**< Destroy internal structures (counterpart of init) */
 } ddf_hc_driver_t;
 
 int hcd_ddf_add_hc(ddf_dev_t *device, const ddf_hc_driver_t *driver);
 
-int hcd_ddf_setup_hc(ddf_dev_t *device, usb_speed_t max_speed,
-    size_t bw, bw_count_func_t bw_count);
+int hcd_ddf_setup_hc(ddf_dev_t *device);
 void hcd_ddf_clean_hc(ddf_dev_t *device);
-int hcd_ddf_setup_root_hub(ddf_dev_t *device);
+
+int hcd_setup_virtual_root_hub(hcd_t *, ddf_dev_t *);
+
+device_t *hcd_ddf_device_create(ddf_dev_t *, size_t);
+void hcd_ddf_device_destroy(device_t *);
+int hcd_ddf_device_explore(hcd_t *, device_t *);
+int hcd_ddf_device_online(ddf_fun_t *);
+int hcd_ddf_device_offline(ddf_fun_t *);
 
 hcd_t *dev_to_hcd(ddf_dev_t *dev);
@@ -75,5 +95,5 @@
     const hw_res_list_parsed_t *hw_res,
     interrupt_handler_t handler,
-    int (*gen_irq_code)(irq_code_t *, const hw_res_list_parsed_t *));
+    irq_code_gen_t gen_irq_code);
 void ddf_hcd_gen_irq_handler(ipc_callid_t iid, ipc_call_t *call, ddf_dev_t *dev);
 
Index: uspace/lib/usbhost/include/usb/host/endpoint.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/endpoint.h	(revision cecba66ea48d60cfa59865e98aeda663808e42c7)
+++ uspace/lib/usbhost/include/usb/host/endpoint.h	(revision 6cad7765736ec29f90dd2a80f7df7d0dd4857b9d)
@@ -32,4 +32,8 @@
 /** @file
  *
+ * Endpoint structure is tightly coupled to the bus. The bus controls the
+ * life-cycle of endpoint. In order to keep endpoints lightweight, operations
+ * on endpoints are part of the bus structure.
+ *
  */
 #ifndef LIBUSBHOST_HOST_ENDPOINT_H
@@ -42,13 +46,19 @@
 #include <atomic.h>
 
+typedef struct bus bus_t;
+typedef struct device device_t;
+typedef struct usb_transfer_batch usb_transfer_batch_t;
+
 /** Host controller side endpoint structure. */
 typedef struct endpoint {
-	/** Reference count. */
-	atomic_t refcnt;	
 	/** Part of linked list. */
 	link_t link;
-	/** USB address. */
-	usb_address_t address;
-	/** USB endpoint number. */
+	/** Managing bus */
+	bus_t *bus;
+	/** Reference count. */
+	atomic_t refcnt;
+	/** USB device */
+	device_t *device;
+	/** Enpoint number */
 	usb_endpoint_t endpoint;
 	/** Communication direction. */
@@ -62,47 +72,39 @@
 	/** Additional opportunities per uframe */
 	unsigned packets;
-	/** Necessary bandwidth. */
+	/** Reserved bandwidth. */
 	size_t bandwidth;
 	/** Value of the toggle bit. */
 	unsigned toggle:1;
-	/** True if there is a batch using this scheduled for this endpoint. */
-	volatile bool active;
+	/** The currently active transfer batch. Write using methods, read under guard. */
+	usb_transfer_batch_t *active_batch;
 	/** Protects resources and active status changes. */
 	fibril_mutex_t guard;
 	/** Signals change of active status. */
 	fibril_condvar_t avail;
-	/** High speed TT data */
-	struct {
-		usb_address_t address;
-		unsigned port;
-	} tt;
-	/** Optional device specific data. */
-	struct {
-		/** Device specific data. */
-		void *data;
-		/** Callback to get the value of toggle bit. */
-		int (*toggle_get)(void *);
-		/** Callback to set the value of toggle bit. */
-		void (*toggle_set)(void *, int);
-	} hc_data;
+
+	/* This structure is meant to be extended by overriding. */
 } endpoint_t;
 
-extern endpoint_t *endpoint_create(usb_address_t, usb_endpoint_t,
-    usb_direction_t, usb_transfer_type_t, usb_speed_t, size_t, unsigned int,
-    size_t, usb_address_t, unsigned int);
-extern void endpoint_destroy(endpoint_t *);
+extern void endpoint_init(endpoint_t *, bus_t *);
 
 extern void endpoint_add_ref(endpoint_t *);
 extern void endpoint_del_ref(endpoint_t *);
 
-extern void endpoint_set_hc_data(endpoint_t *, void *, int (*)(void *),
-    void (*)(void *, int));
-extern void endpoint_clear_hc_data(endpoint_t *);
+/* Pay atention to synchronization of batch access wrt to aborting & finishing from another fibril. */
 
-extern void endpoint_use(endpoint_t *);
-extern void endpoint_release(endpoint_t *);
+/* Set currently active batch. The common case is to activate in the same
+ * critical section as scheduling to HW.
+ */
+extern void endpoint_activate_locked(endpoint_t *, usb_transfer_batch_t *);
+
+/* Deactivate the endpoint, allowing others to activate it again. Batch shall
+ * already have an error set. */
+extern void endpoint_deactivate_locked(endpoint_t *);
+
+/* Abort the currenty active batch. */
+void endpoint_abort(endpoint_t *);
 
 extern int endpoint_toggle_get(endpoint_t *);
-extern void endpoint_toggle_set(endpoint_t *, int);
+extern void endpoint_toggle_set(endpoint_t *, bool);
 
 /** list_get_instance wrapper.
@@ -117,4 +119,5 @@
 	return item ? list_get_instance(item, endpoint_t, link) : NULL;
 }
+
 #endif
 
Index: uspace/lib/usbhost/include/usb/host/hcd.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/hcd.h	(revision cecba66ea48d60cfa59865e98aeda663808e42c7)
+++ uspace/lib/usbhost/include/usb/host/hcd.h	(revision 6cad7765736ec29f90dd2a80f7df7d0dd4857b9d)
@@ -38,32 +38,30 @@
 
 #include <usb/host/endpoint.h>
-#include <usb/host/usb_bus.h>
+#include <usb/host/bus.h>
 #include <usb/host/usb_transfer_batch.h>
 #include <usb/usb.h>
 
 #include <assert.h>
-#include <usbhc_iface.h>
+#include <mem.h>
 #include <stddef.h>
 #include <stdint.h>
+#include <usbhc_iface.h>
 
 typedef struct hcd hcd_t;
 
 typedef int (*schedule_hook_t)(hcd_t *, usb_transfer_batch_t *);
-typedef int (*ep_add_hook_t)(hcd_t *, endpoint_t *);
-typedef void (*ep_remove_hook_t)(hcd_t *, endpoint_t *);
 typedef void (*interrupt_hook_t)(hcd_t *, uint32_t);
 typedef int (*status_hook_t)(hcd_t *, uint32_t *);
+typedef int (*address_device_hook_t)(hcd_t *, usb_speed_t, usb_tt_address_t, usb_address_t *);
 
 typedef struct {
 	/** Transfer scheduling, implement in device driver. */
 	schedule_hook_t schedule;
-	/** Hook called upon registering new endpoint. */
-	ep_add_hook_t ep_add_hook;
-	/** Hook called upon removing of an endpoint. */
-	ep_remove_hook_t ep_remove_hook;
 	/** Hook to be called on device interrupt, passes ARG1 */
 	interrupt_hook_t irq_hook;
 	/** Periodic polling hook */
 	status_hook_t status_hook;
+	/** Hook to setup device address */
+	address_device_hook_t address_device;
 } hcd_ops_t;
 
@@ -71,5 +69,5 @@
 struct hcd {
 	/** Endpoint manager. */
-	usb_bus_t bus;
+	bus_t *bus;
 
 	/** Interrupt replacement fibril */
@@ -78,12 +76,13 @@
 	/** Driver implementation */
 	hcd_ops_t ops;
+
 	/** Device specific driver data. */
 	void * driver_data;
 };
 
-extern void hcd_init(hcd_t *, usb_speed_t, size_t, bw_count_func_t);
+extern void hcd_init(hcd_t *);
 
 static inline void hcd_set_implementation(hcd_t *hcd, void *data,
-    const hcd_ops_t *ops)
+    const hcd_ops_t *ops, bus_t *bus)
 {
 	assert(hcd);
@@ -91,4 +90,5 @@
 		hcd->driver_data = data;
 		hcd->ops = *ops;
+		hcd->bus = bus;
 	} else {
 		memset(&hcd->ops, 0, sizeof(hcd->ops));
@@ -104,25 +104,16 @@
 extern usb_address_t hcd_request_address(hcd_t *, usb_speed_t);
 
-extern int hcd_release_address(hcd_t *, usb_address_t);
-
-extern int hcd_reserve_default_address(hcd_t *, usb_speed_t);
-
-static inline int hcd_release_default_address(hcd_t *hcd)
-{
-	return hcd_release_address(hcd, USB_ADDRESS_DEFAULT);
-}
-
 extern int hcd_add_ep(hcd_t *, usb_target_t, usb_direction_t,
-    usb_transfer_type_t, size_t, unsigned int, size_t, usb_address_t,
-    unsigned int);
+    usb_transfer_type_t, size_t, unsigned int, size_t, usb_tt_address_t);
 
 extern int hcd_remove_ep(hcd_t *, usb_target_t, usb_direction_t);
 
-extern int hcd_send_batch(hcd_t *, usb_target_t, usb_direction_t, void *,
-    size_t, uint64_t, usbhc_iface_transfer_in_callback_t,
-    usbhc_iface_transfer_out_callback_t, void *, const char *);
+extern int hcd_send_batch(hcd_t *, device_t *, usb_target_t,
+    usb_direction_t direction, char *, size_t, uint64_t,
+    usbhc_iface_transfer_callback_t, void *, const char *);
 
-extern ssize_t hcd_send_batch_sync(hcd_t *, usb_target_t, usb_direction_t,
-    void *, size_t, uint64_t, const char *);
+extern ssize_t hcd_send_batch_sync(hcd_t *, device_t *, usb_target_t,
+    usb_direction_t direction, char *, size_t, uint64_t,
+    const char *);
 
 #endif
Index: uspace/lib/usbhost/include/usb/host/usb2_bus.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/usb2_bus.h	(revision 6cad7765736ec29f90dd2a80f7df7d0dd4857b9d)
+++ uspace/lib/usbhost/include/usb/host/usb2_bus.h	(revision 6cad7765736ec29f90dd2a80f7df7d0dd4857b9d)
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * Copyright (c) 2017 Ondrej Hlavaty <aearsis@eideo.cz>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup libusbhost
+ * @{
+ */
+/** @file
+ *
+ * Bus implementation common for OHCI, UHCI and EHCI.
+ */
+#ifndef LIBUSBHOST_HOST_USB2_BUS_H
+#define LIBUSBHOST_HOST_USB2_BUS_H
+
+#include <usb/usb.h>
+#include <usb/host/bus.h>
+
+#include <adt/list.h>
+#include <stdbool.h>
+
+typedef struct usb2_bus usb2_bus_t;
+typedef struct endpoint endpoint_t;
+
+typedef size_t (*count_bw_func_t)(endpoint_t *, size_t);
+
+/** Endpoint management structure */
+typedef struct usb2_bus {
+	bus_t base;			/**< Inheritance - keep this first */
+
+	/* Device bookkeeping */
+	struct {
+		usb_speed_t speed;      /**< Device speed */
+		bool occupied;          /**< The address is in use. */
+		// TODO: This can be stored in usb2_bus-specific device_t
+		list_t endpoint_list;   /**< Store endpoint_t instances */
+	} devices[USB_ADDRESS_COUNT];
+
+	/** Size of the bandwidth pool */
+	size_t free_bw;
+	/** The last reserved address */
+	usb_address_t last_address;
+} usb2_bus_t;
+
+extern int usb2_bus_init(usb2_bus_t *, size_t, count_bw_func_t);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbhost/include/usb/host/usb_bus.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/usb_bus.h	(revision cecba66ea48d60cfa59865e98aeda663808e42c7)
+++ 	(revision )
@@ -1,120 +1,0 @@
-/*
- * Copyright (c) 2011 Jan Vesely
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-/** @addtogroup libusbhost
- * @{
- */
-/** @file
- * Device keeper structure and functions.
- *
- * Typical USB host controller needs to keep track of various settings for
- * each device that is connected to it.
- * State of toggle bit, device speed etc. etc.
- * This structure shall simplify the management.
- */
-#ifndef LIBUSBHOST_HOST_USB_ENDPOINT_MANAGER_H
-#define LIBUSBHOST_HOST_USB_ENDPOINT_MANAGER_H
-
-#include <usb/host/endpoint.h>
-#include <usb/usb.h>
-
-#include <adt/list.h>
-#include <fibril_synch.h>
-#include <stdbool.h>
-
-
-/** Bytes per second in FULL SPEED */
-#define BANDWIDTH_TOTAL_USB11 (12000000 / 8)
-/** 90% of total bandwidth is available for periodic transfers */
-#define BANDWIDTH_AVAILABLE_USB11 ((BANDWIDTH_TOTAL_USB11 / 10) * 9)
-
-//TODO: Implement
-#define BANDWIDTH_AVAILABLE_USB20  1
-
-typedef size_t (*bw_count_func_t)(usb_speed_t, usb_transfer_type_t, size_t, size_t);
-typedef void (*ep_remove_callback_t)(endpoint_t *, void *);
-typedef int (*ep_add_callback_t)(endpoint_t *, void *);
-
-/** Endpoint management structure */
-typedef struct usb_bus {
-	struct {
-		usb_speed_t speed;      /**< Device speed */
-		bool occupied;          /**< The address is in use. */
-		list_t endpoint_list;   /**< Store endpoint_t instances */
-	} devices[USB_ADDRESS_COUNT];
-	/** Prevents races accessing lists */
-	fibril_mutex_t guard;
-	/** Size of the bandwidth pool */
-	size_t free_bw;
-	/** Use this function to count bw required by EP */
-	bw_count_func_t bw_count;
-	/** Maximum speed allowed. */
-	usb_speed_t max_speed;
-	/** The last reserved address */
-	usb_address_t last_address;
-} usb_bus_t;
-
-
-size_t bandwidth_count_usb11(usb_speed_t speed, usb_transfer_type_t type,
-    size_t size, size_t max_packet_size);
-size_t bandwidth_count_usb20(usb_speed_t speed, usb_transfer_type_t type,
-    size_t size, size_t max_packet_size);
-
-int usb_bus_init(usb_bus_t *instance,
-    size_t available_bandwidth, bw_count_func_t bw_count, usb_speed_t max_speed);
-
-int usb_bus_register_ep(usb_bus_t *instance, endpoint_t *ep, size_t data_size);
-
-int usb_bus_unregister_ep(usb_bus_t *instance, endpoint_t *ep);
-
-endpoint_t * usb_bus_find_ep(usb_bus_t *instance,
-    usb_address_t address, usb_endpoint_t ep, usb_direction_t direction);
-
-int usb_bus_add_ep(usb_bus_t *instance,
-    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction,
-    usb_transfer_type_t type, size_t max_packet_size, unsigned packets,
-    size_t data_size, ep_add_callback_t callback, void *arg,
-    usb_address_t tt_address, unsigned tt_port);
-
-int usb_bus_remove_ep(usb_bus_t *instance,
-    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction,
-    ep_remove_callback_t callback, void *arg);
-
-int usb_bus_reset_toggle(usb_bus_t *instance, usb_target_t target, bool all);
-
-int usb_bus_remove_address(usb_bus_t *instance,
-    usb_address_t address, ep_remove_callback_t callback, void *arg);
-
-int usb_bus_request_address(usb_bus_t *instance,
-    usb_address_t *address, bool strict, usb_speed_t speed);
-
-int usb_bus_get_speed(usb_bus_t *instance,
-    usb_address_t address, usb_speed_t *speed);
-#endif
-/**
- * @}
- */
Index: uspace/lib/usbhost/include/usb/host/usb_transfer_batch.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/usb_transfer_batch.h	(revision cecba66ea48d60cfa59865e98aeda663808e42c7)
+++ uspace/lib/usbhost/include/usb/host/usb_transfer_batch.h	(revision 6cad7765736ec29f90dd2a80f7df7d0dd4857b9d)
@@ -37,46 +37,55 @@
 #define LIBUSBHOST_HOST_USB_TRANSFER_BATCH_H
 
-#include <usb/host/endpoint.h>
 #include <usb/usb.h>
+#include <usb/request.h>
+#include <usbhc_iface.h>
 
-#include <assert.h>
+#include <atomic.h>
 #include <stddef.h>
+#include <errno.h>
 #include <stdint.h>
-#include <usbhc_iface.h>
 
 #define USB_SETUP_PACKET_SIZE 8
 
+typedef struct endpoint endpoint_t;
+typedef struct bus bus_t;
+
 /** Structure stores additional data needed for communication with EP */
 typedef struct usb_transfer_batch {
+	/** Target for communication */
+	usb_target_t target;
+
 	/** Endpoint used for communication */
 	endpoint_t *ep;
-	/** Function called on completion (IN version) */
-	usbhc_iface_transfer_in_callback_t callback_in;
-	/** Function called on completion (OUT version) */
-	usbhc_iface_transfer_out_callback_t callback_out;
-	/** Argument to pass to the completion function */
-	void *arg;
+
+	/** Size reported to be sent */
+	size_t expected_size;
+
+	/** Direction of the transfer */
+	usb_direction_t dir;
+
+	/** Function called on completion */
+	usbhc_iface_transfer_callback_t on_complete;
+	/** Arbitrary data for the handler */
+	void *on_complete_data;
+
+	/** Place to store SETUP data needed by control transfers */
+	union {
+		char buffer [USB_SETUP_PACKET_SIZE];
+		usb_device_request_setup_packet_t packet;
+		uint64_t packed;
+	} setup;
+
+	/** Resetting the Toggle */
+	toggle_reset_mode_t toggle_reset_mode;
+
 	/** Place for data to send/receive */
 	char *buffer;
 	/** Size of memory pointed to by buffer member */
 	size_t buffer_size;
-	/** Place to store SETUP data needed by control transfers */
-	char setup_buffer[USB_SETUP_PACKET_SIZE];
-	/** Used portion of setup_buffer member
-	 *
-	 * SETUP buffer must be 8 bytes for control transfers and is left
-	 * unused for all other transfers. Thus, this field is either 0 or 8.
-	 */
-	size_t setup_size;
+	/** Actually used portion of the buffer */
+	size_t transfered_size;
 
-	/** Actually used portion of the buffer
-	 * This member is never accessed by functions provided in this header,
-	 * with the exception of usb_transfer_batch_finish. For external use.
-	 */
-	size_t transfered_size;
-	/** Indicates success/failure of the communication
-	 * This member is never accessed by functions provided in this header,
-	 * with the exception of usb_transfer_batch_finish. For external use.
-	 */
+	/** Indicates success/failure of the communication */
 	int error;
 } usb_transfer_batch_t;
@@ -89,5 +98,5 @@
  */
 #define USB_TRANSFER_BATCH_ARGS(batch) \
-	(batch).ep->address, (batch).ep->endpoint, \
+	(batch).target.address, (batch).target.endpoint, \
 	usb_str_speed((batch).ep->speed), \
 	usb_str_transfer_type_short((batch).ep->transfer_type), \
@@ -95,56 +104,21 @@
 	(batch).buffer_size, (batch).ep->max_packet_size
 
+/** Wrapper for bus operation. */
+usb_transfer_batch_t *usb_transfer_batch_create(endpoint_t *);
 
-usb_transfer_batch_t * usb_transfer_batch_create(
-    endpoint_t *ep,
-    char *buffer,
-    size_t buffer_size,
-    uint64_t setup_buffer,
-    usbhc_iface_transfer_in_callback_t func_in,
-    usbhc_iface_transfer_out_callback_t func_out,
-    void *arg
-);
-void usb_transfer_batch_destroy(const usb_transfer_batch_t *instance);
+/** Batch initializer. */
+void usb_transfer_batch_init(usb_transfer_batch_t *, endpoint_t *);
 
-void usb_transfer_batch_finish_error(const usb_transfer_batch_t *instance,
-    const void* data, size_t size, int error);
+/** Call after status is known, but before releasing endpoint */
+int usb_transfer_batch_reset_toggle(usb_transfer_batch_t *);
 
-/** Finish batch using stored error value and transferred size.
- *
- * @param[in] instance Batch structure to use.
- * @param[in] data Data to copy to the output buffer.
+/** Batch finalization. */
+void usb_transfer_batch_abort(usb_transfer_batch_t *);
+void usb_transfer_batch_finish(usb_transfer_batch_t *);
+
+/** To be called from outside only when the transfer is not going to be finished
+ * (i.o.w. until successfuly scheduling)
  */
-static inline void usb_transfer_batch_finish(
-    const usb_transfer_batch_t *instance, const void* data)
-{
-	assert(instance);
-	usb_transfer_batch_finish_error(
-	    instance, data, instance->transfered_size, instance->error);
-}
-
-/** Determine batch direction based on the callbacks present
- * @param[in] instance Batch structure to use, non-null.
- * @return USB_DIRECTION_IN, or USB_DIRECTION_OUT.
- */
-static inline usb_direction_t usb_transfer_batch_direction(
-    const usb_transfer_batch_t *instance)
-{
-	assert(instance);
-	if (instance->callback_in) {
-		assert(instance->callback_out == NULL);
-		assert(instance->ep == NULL
-		    || instance->ep->transfer_type == USB_TRANSFER_CONTROL
-		    || instance->ep->direction == USB_DIRECTION_IN);
-		return USB_DIRECTION_IN;
-	}
-	if (instance->callback_out) {
-		assert(instance->callback_in == NULL);
-		assert(instance->ep == NULL
-		    || instance->ep->transfer_type == USB_TRANSFER_CONTROL
-		    || instance->ep->direction == USB_DIRECTION_OUT);
-		return USB_DIRECTION_OUT;
-	}
-	assert(false);
-}
+void usb_transfer_batch_destroy(usb_transfer_batch_t *);
 
 #endif
Index: uspace/lib/usbhost/src/bandwidth.c
===================================================================
--- uspace/lib/usbhost/src/bandwidth.c	(revision 6cad7765736ec29f90dd2a80f7df7d0dd4857b9d)
+++ uspace/lib/usbhost/src/bandwidth.c	(revision 6cad7765736ec29f90dd2a80f7df7d0dd4857b9d)
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/**  @addtogroup libusbhost
+ * @{
+ */
+/** @file
+ *
+ * Bandwidth calculation functions. Shared among uhci, ohci and ehci drivers.
+ */
+
+#include <usb/host/bandwidth.h>
+#include <usb/host/endpoint.h>
+
+#include <assert.h>
+#include <stdlib.h>
+
+/** Calculate bandwidth that needs to be reserved for communication with EP.
+ * Calculation follows USB 1.1 specification.
+ * @param speed Device's speed.
+ * @param type Type of the transfer.
+ * @param size Number of byte to transfer.
+ * @param max_packet_size Maximum bytes in one packet.
+ */
+size_t bandwidth_count_usb11(endpoint_t *ep, size_t size)
+{
+	assert(ep);
+
+	const usb_transfer_type_t type = ep->transfer_type;
+
+	/* We care about bandwidth only for interrupt and isochronous. */
+	if ((type != USB_TRANSFER_INTERRUPT)
+	    && (type != USB_TRANSFER_ISOCHRONOUS)) {
+		return 0;
+	}
+
+	const size_t max_packet_size = ep->max_packet_size;
+
+	const unsigned packet_count =
+	    (size + max_packet_size - 1) / max_packet_size;
+	/* TODO: It may be that ISO and INT transfers use only one packet per
+	 * transaction, but I did not find text in USB spec to confirm this */
+	/* NOTE: All data packets will be considered to be max_packet_size */
+	switch (ep->speed)
+	{
+	case USB_SPEED_LOW:
+		assert(type == USB_TRANSFER_INTERRUPT);
+		/* Protocol overhead 13B
+		 * (3 SYNC bytes, 3 PID bytes, 2 Endpoint + CRC bytes, 2
+		 * CRC bytes, and a 3-byte interpacket delay)
+		 * see USB spec page 45-46. */
+		/* Speed penalty 8: low speed is 8-times slower*/
+		return packet_count * (13 + max_packet_size) * 8;
+	case USB_SPEED_FULL:
+		/* Interrupt transfer overhead see above
+		 * or page 45 of USB spec */
+		if (type == USB_TRANSFER_INTERRUPT)
+			return packet_count * (13 + max_packet_size);
+
+		assert(type == USB_TRANSFER_ISOCHRONOUS);
+		/* Protocol overhead 9B
+		 * (2 SYNC bytes, 2 PID bytes, 2 Endpoint + CRC bytes, 2 CRC
+		 * bytes, and a 1-byte interpacket delay)
+		 * see USB spec page 42 */
+		return packet_count * (9 + max_packet_size);
+	default:
+		return 0;
+	}
+}
+
+/** Calculate bandwidth that needs to be reserved for communication with EP.
+ * Calculation follows USB 2.0 specification.
+ * @param speed Device's speed.
+ * @param type Type of the transfer.
+ * @param size Number of byte to transfer.
+ * @param max_packet_size Maximum bytes in one packet.
+ */
+size_t bandwidth_count_usb20(endpoint_t *ep, size_t size)
+{
+	assert(ep);
+
+	const usb_transfer_type_t type = ep->transfer_type;
+
+	/* We care about bandwidth only for interrupt and isochronous. */
+	if ((type != USB_TRANSFER_INTERRUPT)
+	    && (type != USB_TRANSFER_ISOCHRONOUS)) {
+		return 0;
+	}
+	//TODO Implement
+	return 0;
+}
Index: uspace/lib/usbhost/src/bus.c
===================================================================
--- uspace/lib/usbhost/src/bus.c	(revision 6cad7765736ec29f90dd2a80f7df7d0dd4857b9d)
+++ uspace/lib/usbhost/src/bus.c	(revision 6cad7765736ec29f90dd2a80f7df7d0dd4857b9d)
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2017 Ondrej Hlavaty <aearsis@eideo.cz>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libusbhost
+ * @{
+ */
+/** @file
+ *
+ */
+
+#include <usb/host/bus.h>
+#include <usb/host/endpoint.h>
+#include <usb/debug.h>
+#include <ddf/driver.h>
+
+#include <mem.h>
+#include <errno.h>
+#include <stdio.h>
+
+/**
+ * Initializes the bus structure.
+ */
+void bus_init(bus_t *bus, size_t device_size)
+{
+	assert(bus);
+	assert(device_size >= sizeof(device_t));
+	memset(bus, 0, sizeof(bus_t));
+
+	fibril_mutex_initialize(&bus->guard);
+	bus->device_size = device_size;
+}
+
+int device_init(device_t *dev)
+{
+	memset(dev, 0, sizeof(*dev));
+
+	link_initialize(&dev->link);
+	list_initialize(&dev->devices);
+	fibril_mutex_initialize(&dev->guard);
+
+	return EOK;
+}
+
+int device_set_default_name(device_t *dev)
+{
+	assert(dev);
+	assert(dev->fun);
+
+	char buf[10] = { 0 }; /* usbxyz-ss */
+	snprintf(buf, sizeof(buf) - 1, "usb%u-%cs",
+	    dev->address, usb_str_speed(dev->speed)[0]);
+
+	return ddf_fun_set_name(dev->fun, buf);
+}
+
+int bus_enumerate_device(bus_t *bus, hcd_t *hcd, device_t *dev)
+{
+	assert(bus);
+	assert(hcd);
+	assert(dev);
+
+	if (!bus->ops.enumerate_device)
+		return ENOTSUP;
+
+	return bus->ops.enumerate_device(bus, hcd, dev);
+}
+
+int bus_remove_device(bus_t *bus, hcd_t *hcd, device_t *dev)
+{
+	assert(bus);
+	assert(dev);
+
+	if (!bus->ops.remove_device)
+		return ENOTSUP;
+
+	return bus->ops.remove_device(bus, hcd, dev);
+}
+
+int bus_online_device(bus_t *bus, hcd_t *hcd, device_t *dev)
+{
+	assert(bus);
+	assert(hcd);
+	assert(dev);
+
+	if (!bus->ops.online_device)
+		return ENOTSUP;
+
+	return bus->ops.online_device(bus, hcd, dev);
+}
+
+int bus_offline_device(bus_t *bus, hcd_t *hcd, device_t *dev)
+{
+	assert(bus);
+	assert(hcd);
+	assert(dev);
+
+	if (!bus->ops.offline_device)
+		return ENOTSUP;
+
+	return bus->ops.offline_device(bus, hcd, dev);
+}
+
+int bus_add_endpoint(bus_t *bus, device_t *device, const usb_endpoint_desc_t *desc, endpoint_t **out_ep)
+{
+	assert(bus);
+	assert(device);
+
+	fibril_mutex_lock(&bus->guard);
+
+	if (desc->max_packet_size == 0 || desc->packets == 0) {
+		usb_log_warning("Invalid endpoint description (mps %zu, %u packets)", desc->max_packet_size, desc->packets);
+		return EINVAL;
+	}
+
+	int err = ENOMEM;
+	endpoint_t *ep = bus->ops.create_endpoint(bus);
+	if (!ep)
+		goto err;
+
+	/* Bus reference */
+	endpoint_add_ref(ep);
+
+	if ((err = bus->ops.register_endpoint(bus, device, ep, desc)))
+		goto err_ep;
+
+	if (out_ep) {
+		endpoint_add_ref(ep);
+		*out_ep = ep;
+	}
+
+	fibril_mutex_unlock(&bus->guard);
+	return EOK;
+
+err_ep:
+	endpoint_del_ref(ep);
+err:
+	fibril_mutex_unlock(&bus->guard);
+	return err;
+}
+
+/** Searches for an endpoint. Returns a reference.
+ */
+endpoint_t *bus_find_endpoint(bus_t *bus, device_t *device, usb_target_t endpoint, usb_direction_t dir)
+{
+	assert(bus);
+
+	fibril_mutex_lock(&bus->guard);
+	endpoint_t *ep = bus->ops.find_endpoint(bus, device, endpoint, dir);
+	if (ep) {
+		/* Exporting reference */
+		endpoint_add_ref(ep);
+	}
+
+	fibril_mutex_unlock(&bus->guard);
+	return ep;
+}
+
+int bus_remove_endpoint(bus_t *bus, endpoint_t *ep)
+{
+	assert(bus);
+	assert(ep);
+
+	fibril_mutex_lock(&bus->guard);
+	const int r = bus->ops.unregister_endpoint(bus, ep);
+	fibril_mutex_unlock(&bus->guard);
+
+	if (r)
+		return r;
+
+	/* Bus reference */
+	endpoint_del_ref(ep);
+
+	return EOK;
+}
+
+int bus_request_address(bus_t *bus, usb_address_t *hint, bool strict, usb_speed_t speed)
+{
+	assert(bus);
+
+	if (!bus->ops.request_address)
+		return ENOTSUP;
+
+	fibril_mutex_lock(&bus->guard);
+	const int r = bus->ops.request_address(bus, hint, strict, speed);
+	fibril_mutex_unlock(&bus->guard);
+	return r;
+}
+
+int bus_release_address(bus_t *bus, usb_address_t address)
+{
+	assert(bus);
+
+	if (!bus->ops.release_address)
+		return ENOTSUP;
+
+	fibril_mutex_lock(&bus->guard);
+	const int r = bus->ops.release_address(bus, address);
+	fibril_mutex_unlock(&bus->guard);
+	return r;
+}
+
+int bus_reset_toggle(bus_t *bus, usb_target_t target, bool all)
+{
+	assert(bus);
+
+	if (!bus->ops.reset_toggle)
+		return ENOTSUP;
+
+	fibril_mutex_lock(&bus->guard);
+	const int r = bus->ops.reset_toggle(bus, target, all);
+	fibril_mutex_unlock(&bus->guard);
+	return r;
+}
+
+size_t bus_count_bw(endpoint_t *ep, size_t size)
+{
+	assert(ep);
+
+	fibril_mutex_lock(&ep->guard);
+	const size_t bw = ep->bus->ops.count_bw(ep, size);
+	fibril_mutex_unlock(&ep->guard);
+	return bw;
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usbhost/src/ddf_helpers.c
===================================================================
--- uspace/lib/usbhost/src/ddf_helpers.c	(revision cecba66ea48d60cfa59865e98aeda663808e42c7)
+++ uspace/lib/usbhost/src/ddf_helpers.c	(revision 6cad7765736ec29f90dd2a80f7df7d0dd4857b9d)
@@ -35,4 +35,5 @@
 
 #include <usb/classes/classes.h>
+#include <usb/host/bus.h>
 #include <usb/debug.h>
 #include <usb/descriptor.h>
@@ -49,28 +50,14 @@
 #include <fibril_synch.h>
 #include <macros.h>
-#include <stdio.h>
 #include <stdlib.h>
 #include <str_error.h>
 #include <usb_iface.h>
+#include <usbhc_iface.h>
 
 #include "ddf_helpers.h"
-
-#define CTRL_PIPE_MIN_PACKET_SIZE 8
-
-typedef struct usb_dev {
-	link_t link;
-	list_t devices;
-	fibril_mutex_t guard;
-	ddf_fun_t *fun;
-	usb_address_t address;
-	usb_speed_t speed;
-	usb_address_t tt_address;
-	unsigned port;
-} usb_dev_t;
 
 typedef struct hc_dev {
 	ddf_fun_t *ctl_fun;
 	hcd_t hcd;
-	usb_dev_t *root_hub;
 } hc_dev_t;
 
@@ -91,6 +78,6 @@
 
 
-static int hcd_ddf_new_device(ddf_dev_t *device, usb_dev_t *hub, unsigned port);
-static int hcd_ddf_remove_device(ddf_dev_t *device, usb_dev_t *hub, unsigned port);
+static int hcd_ddf_new_device(hcd_t *hcd, ddf_dev_t *hc, device_t *hub_dev, unsigned port);
+static int hcd_ddf_remove_device(ddf_dev_t *device, device_t *hub, unsigned port);
 
 
@@ -99,54 +86,55 @@
 /** Register endpoint interface function.
  * @param fun DDF function.
- * @param address USB address of the device.
- * @param endpoint USB endpoint number to be registered.
- * @param transfer_type Endpoint's transfer type.
- * @param direction USB communication direction the endpoint is capable of.
- * @param max_packet_size Maximu size of packets the endpoint accepts.
- * @param interval Preferred timeout between communication.
+ * @param endpoint_desc Endpoint description.
  * @return Error code.
  */
 static int register_endpoint(
-    ddf_fun_t *fun, usb_endpoint_t endpoint,
-    usb_transfer_type_t transfer_type, usb_direction_t direction,
-    size_t max_packet_size, unsigned packets, unsigned interval)
+	ddf_fun_t *fun, usb_endpoint_desc_t *endpoint_desc)
 {
 	assert(fun);
 	hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
-	usb_dev_t *dev = ddf_fun_data_get(fun);
+	device_t *dev = ddf_fun_data_get(fun);
 	assert(hcd);
-	assert(dev);
-	const size_t size = max_packet_size;
-	const usb_target_t target =
-	    {{.address = dev->address, .endpoint = endpoint}};
+	assert(hcd->bus);
+	assert(dev);
 
 	usb_log_debug("Register endpoint %d:%d %s-%s %zuB %ums.\n",
-	    dev->address, endpoint, usb_str_transfer_type(transfer_type),
-	    usb_str_direction(direction), max_packet_size, interval);
-
-	return hcd_add_ep(hcd, target, direction, transfer_type,
-	    max_packet_size, packets, size, dev->tt_address, dev->port);
-}
-
-/** Unregister endpoint interface function.
- * @param fun DDF function.
- * @param address USB address of the endpoint.
- * @param endpoint USB endpoint number.
- * @param direction Communication direction of the enpdoint to unregister.
- * @return Error code.
- */
+		dev->address, endpoint_desc->endpoint_no,
+		usb_str_transfer_type(endpoint_desc->transfer_type),
+		usb_str_direction(endpoint_desc->direction),
+		endpoint_desc->max_packet_size, endpoint_desc->usb2.polling_interval);
+
+	return bus_add_endpoint(hcd->bus, dev, endpoint_desc, NULL);
+}
+
+ /** Unregister endpoint interface function.
+  * @param fun DDF function.
+  * @param endpoint_desc Endpoint description.
+  * @return Error code.
+  */
 static int unregister_endpoint(
-    ddf_fun_t *fun, usb_endpoint_t endpoint, usb_direction_t direction)
+	ddf_fun_t *fun, usb_endpoint_desc_t *endpoint_desc)
 {
 	assert(fun);
 	hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
-	usb_dev_t *dev = ddf_fun_data_get(fun);
+	device_t *dev = ddf_fun_data_get(fun);
 	assert(hcd);
-	assert(dev);
-	const usb_target_t target =
-	    {{.address = dev->address, .endpoint = endpoint}};
+	assert(hcd->bus);
+	assert(dev);
+
+	const usb_target_t target = {{
+		.address = dev->address,
+		.endpoint = endpoint_desc->endpoint_no
+	}};
+
 	usb_log_debug("Unregister endpoint %d:%d %s.\n",
-	    dev->address, endpoint, usb_str_direction(direction));
-	return hcd_remove_ep(hcd, target, direction);
+		dev->address, endpoint_desc->endpoint_no,
+		usb_str_direction(endpoint_desc->direction));
+
+	endpoint_t *ep = bus_find_endpoint(hcd->bus, dev, target, endpoint_desc->direction);
+	if (!ep)
+		return ENOENT;
+
+	return bus_remove_endpoint(hcd->bus, ep);
 }
 
@@ -155,11 +143,12 @@
 	assert(fun);
 	hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
-	usb_dev_t *dev = ddf_fun_data_get(fun);
+	device_t *dev = ddf_fun_data_get(fun);
 	assert(hcd);
+	assert(hcd->bus);
 	assert(dev);
 
 	usb_log_debug("Device %d requested default address at %s speed\n",
 	    dev->address, usb_str_speed(speed));
-	return hcd_reserve_default_address(hcd, speed);
+	return bus_reserve_default_address(hcd->bus, speed);
 }
 
@@ -168,10 +157,11 @@
 	assert(fun);
 	hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
-	usb_dev_t *dev = ddf_fun_data_get(fun);
+	device_t *dev = ddf_fun_data_get(fun);
 	assert(hcd);
+	assert(hcd->bus);
 	assert(dev);
 
 	usb_log_debug("Device %d released default address\n", dev->address);
-	return hcd_release_default_address(hcd);
+	return bus_release_default_address(hcd->bus);
 }
 
@@ -179,18 +169,21 @@
 {
 	assert(fun);
+	ddf_dev_t *hc = ddf_fun_get_dev(fun);
+	assert(hc);
+	hcd_t *hcd = dev_to_hcd(hc);
+	assert(hcd);
+	device_t *hub = ddf_fun_data_get(fun);
+	assert(hub);
+
+	usb_log_debug("Hub %d reported a new USB device on port: %u\n",
+	    hub->address, port);
+	return hcd_ddf_new_device(hcd, hc, hub, port);
+}
+
+static int device_remove(ddf_fun_t *fun, unsigned port)
+{
+	assert(fun);
 	ddf_dev_t *ddf_dev = ddf_fun_get_dev(fun);
-	usb_dev_t *dev = ddf_fun_data_get(fun);
-	assert(ddf_dev);
-	assert(dev);
-	usb_log_debug("Hub %d reported a new USB device on port: %u\n",
-	    dev->address, port);
-	return hcd_ddf_new_device(ddf_dev, dev, port);
-}
-
-static int device_remove(ddf_fun_t *fun, unsigned port)
-{
-	assert(fun);
-	ddf_dev_t *ddf_dev = ddf_fun_get_dev(fun);
-	usb_dev_t *dev = ddf_fun_data_get(fun);
+	device_t *dev = ddf_fun_data_get(fun);
 	assert(ddf_dev);
 	assert(dev);
@@ -224,18 +217,18 @@
  * @return Error code.
  */
-static int dev_read(ddf_fun_t *fun, usb_endpoint_t endpoint,
-    uint64_t setup_data, uint8_t *data, size_t size,
-    usbhc_iface_transfer_in_callback_t callback, void *arg)
-{
-	assert(fun);
-	usb_dev_t *usb_dev = ddf_fun_data_get(fun);
-	assert(usb_dev);
-	const usb_target_t target = {{
-	    .address =  usb_dev->address,
-	    .endpoint = endpoint,
-	}};
-	return hcd_send_batch(dev_to_hcd(ddf_fun_get_dev(fun)), target,
-	    USB_DIRECTION_IN, data, size, setup_data, callback, NULL, arg,
-	    "READ");
+static int dev_read(ddf_fun_t *fun, usb_target_t target,
+    uint64_t setup_data, char *data, size_t size,
+    usbhc_iface_transfer_callback_t callback, void *arg)
+{
+	assert(fun);
+	hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
+	device_t *dev = ddf_fun_data_get(fun);
+	assert(dev);
+
+	target.address = dev->address;
+
+	return hcd_send_batch(hcd, dev, target, USB_DIRECTION_IN,
+	    data, size, setup_data,
+	    callback, arg, "READ");
 }
 
@@ -250,17 +243,17 @@
  * @return Error code.
  */
-static int dev_write(ddf_fun_t *fun, usb_endpoint_t endpoint,
-    uint64_t setup_data, const uint8_t *data, size_t size,
-    usbhc_iface_transfer_out_callback_t callback, void *arg)
-{
-	assert(fun);
-	usb_dev_t *usb_dev = ddf_fun_data_get(fun);
-	assert(usb_dev);
-	const usb_target_t target = {{
-	    .address =  usb_dev->address,
-	    .endpoint = endpoint,
-	}};
-	return hcd_send_batch(dev_to_hcd(ddf_fun_get_dev(fun)),
-	    target, USB_DIRECTION_OUT, (uint8_t*)data, size, setup_data, NULL,
+static int dev_write(ddf_fun_t *fun, usb_target_t target,
+    uint64_t setup_data, const char *data, size_t size,
+    usbhc_iface_transfer_callback_t callback, void *arg)
+{
+	assert(fun);
+	hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
+	device_t *dev = ddf_fun_data_get(fun);
+	assert(dev);
+
+	target.address = dev->address;
+
+	return hcd_send_batch(hcd, dev, target, USB_DIRECTION_OUT,
+	    (char *) data, size, setup_data,
 	    callback, arg, "WRITE");
 }
@@ -269,5 +262,8 @@
 static usb_iface_t usb_iface = {
 	.get_my_device_handle = get_my_device_handle,
-
+};
+
+/** USB host controller interface */
+static usbhc_iface_t usbhc_iface = {
 	.reserve_default_address = reserve_default_address,
 	.release_default_address = release_default_address,
@@ -286,86 +282,9 @@
 static ddf_dev_ops_t usb_ops = {
 	.interfaces[USB_DEV_IFACE] = &usb_iface,
+	.interfaces[USBHC_DEV_IFACE] = &usbhc_iface,
 };
 
 
 /* DDF HELPERS */
-
-#define GET_DEVICE_DESC(size) \
-{ \
-	.request_type = SETUP_REQUEST_TYPE_DEVICE_TO_HOST \
-	    | (USB_REQUEST_TYPE_STANDARD << 5) \
-	    | USB_REQUEST_RECIPIENT_DEVICE, \
-	.request = USB_DEVREQ_GET_DESCRIPTOR, \
-	.value = uint16_host2usb(USB_DESCTYPE_DEVICE << 8), \
-	.index = uint16_host2usb(0), \
-	.length = uint16_host2usb(size), \
-};
-
-#define SET_ADDRESS(address) \
-{ \
-	.request_type = SETUP_REQUEST_TYPE_HOST_TO_DEVICE \
-	    | (USB_REQUEST_TYPE_STANDARD << 5) \
-	    | USB_REQUEST_RECIPIENT_DEVICE, \
-	.request = USB_DEVREQ_SET_ADDRESS, \
-	.value = uint16_host2usb(address), \
-	.index = uint16_host2usb(0), \
-	.length = uint16_host2usb(0), \
-};
-
-static int hcd_ddf_add_device(ddf_dev_t *parent, usb_dev_t *hub_dev,
-    unsigned port, usb_address_t address, usb_speed_t speed, const char *name,
-    const match_id_list_t *mids)
-{
-	assert(parent);
-
-	char default_name[10] = { 0 }; /* usbxyz-ss */
-	if (!name) {
-		snprintf(default_name, sizeof(default_name) - 1,
-		    "usb%u-%cs", address, usb_str_speed(speed)[0]);
-		name = default_name;
-	}
-
-	ddf_fun_t *fun = ddf_fun_create(parent, fun_inner, name);
-	if (!fun)
-		return ENOMEM;
-	usb_dev_t *info = ddf_fun_data_alloc(fun, sizeof(usb_dev_t));
-	if (!info) {
-		ddf_fun_destroy(fun);
-		return ENOMEM;
-	}
-	info->address = address;
-	info->speed = speed;
-	info->fun = fun;
-	info->port = port;
-	info->tt_address = hub_dev ? hub_dev->tt_address : -1;
-	link_initialize(&info->link);
-	list_initialize(&info->devices);
-	fibril_mutex_initialize(&info->guard);
-
-	if (hub_dev && hub_dev->speed == USB_SPEED_HIGH && usb_speed_is_11(speed))
-		info->tt_address = hub_dev->address;
-
-	ddf_fun_set_ops(fun, &usb_ops);
-	list_foreach(mids->ids, link, const match_id_t, mid) {
-		ddf_fun_add_match_id(fun, mid->id, mid->score);
-	}
-
-	int ret = ddf_fun_bind(fun);
-	if (ret != EOK) {
-		ddf_fun_destroy(fun);
-		return ret;
-	}
-
-	if (hub_dev) {
-		fibril_mutex_lock(&hub_dev->guard);
-		list_append(&info->link, &hub_dev->devices);
-		fibril_mutex_unlock(&hub_dev->guard);
-	} else {
-		hc_dev_t *hc_dev = dev_to_hc_dev(parent);
-		assert(hc_dev->root_hub == NULL);
-		hc_dev->root_hub = info;
-	}
-	return EOK;
-}
 
 #define ADD_MATCHID_OR_RETURN(list, sc, str, ...) \
@@ -394,5 +313,5 @@
 	assert(l);
 	assert(d);
-	
+
 	if (d->vendor_id != 0) {
 		/* First, with release number. */
@@ -401,5 +320,5 @@
 		    d->vendor_id, d->product_id, (d->device_version >> 8),
 		    (d->device_version & 0xff));
-	
+
 		/* Next, without release number. */
 		ADD_MATCHID_OR_RETURN(l, 90, "usb&vendor=%#04x&product=%#04x",
@@ -415,8 +334,7 @@
 
 	return EOK;
-
-}
-
-static int hcd_ddf_remove_device(ddf_dev_t *device, usb_dev_t *hub,
+}
+
+static int hcd_ddf_remove_device(ddf_dev_t *device, device_t *hub,
     unsigned port)
 {
@@ -425,4 +343,5 @@
 	hcd_t *hcd = dev_to_hcd(device);
 	assert(hcd);
+	assert(hcd->bus);
 
 	hc_dev_t *hc_dev = dev_to_hc_dev(device);
@@ -431,7 +350,7 @@
 	fibril_mutex_lock(&hub->guard);
 
-	usb_dev_t *victim = NULL;
-
-	list_foreach(hub->devices, link, usb_dev_t, it) {
+	device_t *victim = NULL;
+
+	list_foreach(hub->devices, link, device_t, it) {
 		if (it->port == port) {
 			victim = it;
@@ -440,5 +359,7 @@
 	}
 	if (victim) {
+		assert(victim->fun);
 		assert(victim->port == port);
+		assert(victim->hub == hub);
 		list_remove(&victim->link);
 		fibril_mutex_unlock(&hub->guard);
@@ -446,6 +367,7 @@
 		if (ret == EOK) {
 			usb_address_t address = victim->address;
+			bus_remove_device(hcd->bus, hcd, victim);
 			ddf_fun_destroy(victim->fun);
-			hcd_release_address(hcd, address);
+			bus_release_address(hcd->bus, address);
 		} else {
 			usb_log_warning("Failed to unbind device `%s': %s\n",
@@ -458,111 +380,44 @@
 }
 
-static int hcd_ddf_new_device(ddf_dev_t *device, usb_dev_t *hub, unsigned port)
-{
-	assert(device);
-
-	hcd_t *hcd = dev_to_hcd(device);
-	assert(hcd);
-
-	usb_speed_t speed = USB_SPEED_MAX;
-
-	/* This checks whether the default address is reserved and gets speed */
-	int ret = usb_bus_get_speed(&hcd->bus, USB_ADDRESS_DEFAULT, &speed);
-	if (ret != EOK) {
-		usb_log_error("Failed to verify speed: %s.", str_error(ret));
-		return ret;
-	}
-
-	usb_log_debug("Found new %s speed USB device.", usb_str_speed(speed));
-
-	static const usb_target_t default_target = {{
-		.address = USB_ADDRESS_DEFAULT,
+device_t *hcd_ddf_device_create(ddf_dev_t *hc, size_t device_size)
+{
+	/* Create DDF function for the new device */
+	ddf_fun_t *fun = ddf_fun_create(hc, fun_inner, NULL);
+	if (!fun)
+		return NULL;
+
+	ddf_fun_set_ops(fun, &usb_ops);
+
+	/* Create USB device node for the new device */
+	device_t *dev = ddf_fun_data_alloc(fun, device_size);
+	if (!dev) {
+		ddf_fun_destroy(fun);
+		return NULL;
+	}
+
+	device_init(dev);
+	dev->fun = fun;
+	return dev;
+}
+
+void hcd_ddf_device_destroy(device_t *dev)
+{
+	assert(dev);
+	assert(dev->fun);
+	ddf_fun_destroy(dev->fun);
+}
+
+int hcd_ddf_device_explore(hcd_t *hcd, device_t *device)
+{
+	int err;
+	match_id_list_t mids;
+	usb_standard_device_descriptor_t desc = { 0 };
+
+	init_match_ids(&mids);
+
+	const usb_target_t control_ep = {{
+		.address = device->address,
 		.endpoint = 0,
 	}};
-
-	const usb_address_t address = hcd_request_address(hcd, speed);
-	if (address < 0) {
-		usb_log_error("Failed to reserve new address: %s.",
-		    str_error(address));
-		return address;
-	}
-
-	usb_log_debug("Reserved new address: %d\n", address);
-
-	const usb_target_t target = {{
-		.address = address,
-		.endpoint = 0,
-	}};
-
-	const usb_address_t tt_address = hub ? hub->tt_address : -1;
-
-	/* Add default pipe on default address */
-	usb_log_debug("Device(%d): Adding default target(0:0)\n", address);
-	ret = hcd_add_ep(hcd,
-	    default_target, USB_DIRECTION_BOTH, USB_TRANSFER_CONTROL,
-	    CTRL_PIPE_MIN_PACKET_SIZE, CTRL_PIPE_MIN_PACKET_SIZE, 1,
-	    tt_address, port);
-	if (ret != EOK) {
-		usb_log_error("Device(%d): Failed to add default target: %s.",
-		    address, str_error(ret));
-		hcd_release_address(hcd, address);
-		return ret;
-	}
-
-	/* Get max packet size for default pipe */
-	usb_standard_device_descriptor_t desc = { 0 };
-	const usb_device_request_setup_packet_t get_device_desc_8 =
-	    GET_DEVICE_DESC(CTRL_PIPE_MIN_PACKET_SIZE);
-
-	// TODO CALLBACKS
-	usb_log_debug("Device(%d): Requesting first 8B of device descriptor.",
-	    address);
-	ssize_t got = hcd_send_batch_sync(hcd, default_target, USB_DIRECTION_IN,
-	    &desc, CTRL_PIPE_MIN_PACKET_SIZE, *(uint64_t *)&get_device_desc_8,
-	    "read first 8 bytes of dev descriptor");
-
-	if (got != CTRL_PIPE_MIN_PACKET_SIZE) {
-		ret = got < 0 ? got : EOVERFLOW;
-		usb_log_error("Device(%d): Failed to get 8B of dev descr: %s.",
-		    address, str_error(ret));
-		hcd_remove_ep(hcd, default_target, USB_DIRECTION_BOTH);
-		hcd_release_address(hcd, address);
-		return ret;
-	}
-
-	/* Register EP on the new address */
-	usb_log_debug("Device(%d): Registering control EP.", address);
-	ret = hcd_add_ep(hcd, target, USB_DIRECTION_BOTH, USB_TRANSFER_CONTROL,
-	    ED_MPS_PACKET_SIZE_GET(uint16_usb2host(desc.max_packet_size)),
-	    ED_MPS_TRANS_OPPORTUNITIES_GET(uint16_usb2host(desc.max_packet_size)),
-	    ED_MPS_PACKET_SIZE_GET(uint16_usb2host(desc.max_packet_size)),
-	    tt_address, port);
-	if (ret != EOK) {
-		usb_log_error("Device(%d): Failed to register EP0: %s",
-		    address, str_error(ret));
-		hcd_remove_ep(hcd, default_target, USB_DIRECTION_BOTH);
-		hcd_remove_ep(hcd, target, USB_DIRECTION_BOTH);
-		hcd_release_address(hcd, address);
-		return ret;
-	}
-
-	/* Set new address */
-	const usb_device_request_setup_packet_t set_address =
-	    SET_ADDRESS(target.address);
-
-	usb_log_debug("Device(%d): Setting USB address.", address);
-	got = hcd_send_batch_sync(hcd, default_target, USB_DIRECTION_OUT,
-	    NULL, 0, *(uint64_t *)&set_address, "set address");
-
-	usb_log_debug("Device(%d): Removing default (0:0) EP.", address);
-	hcd_remove_ep(hcd, default_target, USB_DIRECTION_BOTH);
-
-	if (got != 0) {
-		usb_log_error("Device(%d): Failed to set new address: %s.",
-		    address, str_error(got));
-		hcd_remove_ep(hcd, target, USB_DIRECTION_BOTH);
-		hcd_release_address(hcd, address);
-		return got;
-	}
 
 	/* Get std device descriptor */
@@ -571,42 +426,102 @@
 
 	usb_log_debug("Device(%d): Requesting full device descriptor.",
-	    address);
-	got = hcd_send_batch_sync(hcd, target, USB_DIRECTION_IN,
-	    &desc, sizeof(desc), *(uint64_t *)&get_device_desc,
+	    device->address);
+	ssize_t got = hcd_send_batch_sync(hcd, device, control_ep, USB_DIRECTION_IN,
+	    (char *) &desc, sizeof(desc), *(uint64_t *)&get_device_desc,
 	    "read device descriptor");
-	if (ret != EOK) {
+	if (got < 0) {
+		err = got < 0 ? got : EOVERFLOW;
 		usb_log_error("Device(%d): Failed to set get dev descriptor: %s",
-		    address, str_error(ret));
-		hcd_remove_ep(hcd, target, USB_DIRECTION_BOTH);
-		hcd_release_address(hcd, target.address);
-		return ret;
+		    device->address, str_error(err));
+		goto out;
 	}
 
 	/* Create match ids from the device descriptor */
-	match_id_list_t mids;
-	init_match_ids(&mids);
-
-	usb_log_debug("Device(%d): Creating match IDs.", address);
-	ret = create_match_ids(&mids, &desc);
-	if (ret != EOK) {
-		usb_log_error("Device(%d): Failed to create match ids: %s",
-		    address, str_error(ret));
-		hcd_remove_ep(hcd, target, USB_DIRECTION_BOTH);
-		hcd_release_address(hcd, target.address);
-		return ret;
-	}
-
-	/* Register device */
-	usb_log_debug("Device(%d): Registering DDF device.", address);
-	ret = hcd_ddf_add_device(device, hub, port, address, speed, NULL, &mids);
+	usb_log_debug("Device(%d): Creating match IDs.", device->address);
+	if ((err = create_match_ids(&mids, &desc))) {
+		usb_log_error("Device(%d): Failed to create match ids: %s", device->address, str_error(err));
+		goto out;
+	}
+
+	list_foreach(mids.ids, link, const match_id_t, mid) {
+		ddf_fun_add_match_id(device->fun, mid->id, mid->score);
+	}
+
+out:
 	clean_match_ids(&mids);
-	if (ret != EOK) {
-		usb_log_error("Device(%d): Failed to register: %s.",
-		    address, str_error(ret));
-		hcd_remove_ep(hcd, target, USB_DIRECTION_BOTH);
-		hcd_release_address(hcd, target.address);
-	}
-
-	return ret;
+	return err;
+}
+
+int hcd_ddf_device_online(ddf_fun_t *fun)
+{
+	assert(fun);
+
+	hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
+	device_t *dev = ddf_fun_data_get(fun);
+	assert(dev);
+	assert(hcd->bus);
+
+	usb_log_info("Device(%d): Requested to be brought online.", dev->address);
+
+	return bus_online_device(hcd->bus, hcd, dev);
+}
+
+int hcd_ddf_device_offline(ddf_fun_t *fun)
+{
+	assert(fun);
+
+	hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
+	device_t *dev = ddf_fun_data_get(fun);
+	assert(dev);
+	assert(hcd->bus);
+
+	usb_log_info("Device(%d): Requested to be taken offline.", dev->address);
+
+	return bus_offline_device(hcd->bus, hcd, dev);
+}
+
+static int hcd_ddf_new_device(hcd_t *hcd, ddf_dev_t *hc, device_t *hub, unsigned port)
+{
+	int err;
+	assert(hcd);
+	assert(hcd->bus);
+	assert(hub);
+	assert(hc);
+
+	device_t *dev = hcd_ddf_device_create(hc, hcd->bus->device_size);
+	if (!dev) {
+		usb_log_error("Failed to create USB device function.");
+		return ENOMEM;
+	}
+
+	dev->hub = hub;
+	dev->port = port;
+
+	if ((err = bus_enumerate_device(hcd->bus, hcd, dev))) {
+		usb_log_error("Failed to initialize USB dev memory structures.");
+		return err;
+	}
+
+	/* If the driver didn't name the dev when enumerating,
+	 * do it in some generic way.
+	 */
+	if (!ddf_fun_get_name(dev->fun)) {
+		device_set_default_name(dev);
+	}
+
+	if ((err = ddf_fun_bind(dev->fun))) {
+		usb_log_error("Device(%d): Failed to register: %s.", dev->address, str_error(err));
+		goto err_usb_dev;
+	}
+
+	fibril_mutex_lock(&hub->guard);
+	list_append(&dev->link, &hub->devices);
+	fibril_mutex_unlock(&hub->guard);
+
+	return EOK;
+
+err_usb_dev:
+	hcd_ddf_device_destroy(dev);
+	return err;
 }
 
@@ -616,14 +531,44 @@
  * @return Error code
  */
-int hcd_ddf_setup_root_hub(ddf_dev_t *device)
-{
-	assert(device);
-	hcd_t *hcd = dev_to_hcd(device);
+int hcd_setup_virtual_root_hub(hcd_t *hcd, ddf_dev_t *hc)
+{
+	int err;
+
+	assert(hc);
 	assert(hcd);
-
-	hcd_reserve_default_address(hcd, hcd->bus.max_speed);
-	const int ret = hcd_ddf_new_device(device, NULL, 0);
-	hcd_release_default_address(hcd);
-	return ret;
+	assert(hcd->bus);
+
+	if ((err = bus_reserve_default_address(hcd->bus, USB_SPEED_MAX))) {
+		usb_log_error("Failed to reserve default address for roothub setup: %s", str_error(err));
+		return err;
+	}
+
+	device_t *dev = hcd_ddf_device_create(hc, hcd->bus->device_size);
+	if (!dev) {
+		usb_log_error("Failed to create function for the root hub.");
+		goto err_default_address;
+	}
+
+	ddf_fun_set_name(dev->fun, "roothub");
+
+	/* Assign an address to the device */
+	if ((err = bus_enumerate_device(hcd->bus, hcd, dev))) {
+		usb_log_error("Failed to enumerate roothub device: %s", str_error(err));
+		goto err_usb_dev;
+	}
+
+	if ((err = ddf_fun_bind(dev->fun))) {
+		usb_log_error("Failed to register roothub: %s.", str_error(err));
+		goto err_usb_dev;
+	}
+
+	bus_release_default_address(hcd->bus);
+	return EOK;
+
+err_usb_dev:
+	hcd_ddf_device_destroy(dev);
+err_default_address:
+	bus_release_default_address(hcd->bus);
+	return err;
 }
 
@@ -638,6 +583,5 @@
  * This function does all the ddf work for hc driver.
  */
-int hcd_ddf_setup_hc(ddf_dev_t *device, usb_speed_t max_speed,
-    size_t bw, bw_count_func_t bw_count)
+int hcd_ddf_setup_hc(ddf_dev_t *device)
 {
 	assert(device);
@@ -648,6 +592,5 @@
 		return ENOMEM;
 	}
-	instance->root_hub = NULL;
-	hcd_init(&instance->hcd, max_speed, bw, bw_count);
+	hcd_init(&instance->hcd);
 
 	int ret = ENOMEM;
@@ -748,8 +691,10 @@
     const hw_res_list_parsed_t *hw_res,
     interrupt_handler_t handler,
-    int (*gen_irq_code)(irq_code_t *, const hw_res_list_parsed_t *hw_res))
-{
-
+    irq_code_gen_t gen_irq_code)
+{
 	assert(device);
+
+	hcd_t *hcd = dev_to_hcd(device);
+
 	if (!handler || !gen_irq_code)
 		return ENOTSUP;
@@ -757,5 +702,5 @@
 	irq_code_t irq_code = {0};
 
-	const int irq = gen_irq_code(&irq_code, hw_res);
+	const int irq = gen_irq_code(&irq_code, hcd, hw_res);
 	if (irq < 0) {
 		usb_log_error("Failed to generate IRQ code: %s.\n",
@@ -777,5 +722,5 @@
 	int ret = hcd_ddf_enable_interrupt(device, irq);
 	if (ret != EOK) {
-		usb_log_error("Failed to register interrupt handler: %s.\n",
+		usb_log_error("Failed to enable interrupts: %s.\n",
 		    str_error(ret));
 		unregister_interrupt_handler(device, irq_cap);
@@ -844,18 +789,6 @@
 {
 	assert(driver);
-	static const struct { size_t bw; bw_count_func_t bw_count; }bw[] = {
-	    [USB_SPEED_FULL] = { .bw = BANDWIDTH_AVAILABLE_USB11,
-	                         .bw_count = bandwidth_count_usb11 },
-	    [USB_SPEED_HIGH] = { .bw = BANDWIDTH_AVAILABLE_USB11,
-	                         .bw_count = bandwidth_count_usb11 },
-	};
 
 	int ret = EOK;
-	const usb_speed_t speed = driver->hc_speed;
-	if (speed >= ARRAY_SIZE(bw) || bw[speed].bw == 0) {
-		usb_log_error("Driver `%s' reported unsupported speed: %s",
-		    driver->name, usb_str_speed(speed));
-		return ENOTSUP;
-	}
 
 	hw_res_list_parsed_t hw_res;
@@ -868,11 +801,20 @@
 	}
 
-	ret = hcd_ddf_setup_hc(device, speed, bw[speed].bw, bw[speed].bw_count);
+	ret = hcd_ddf_setup_hc(device);
 	if (ret != EOK) {
 		usb_log_error("Failed to setup generic HCD.\n");
-		hw_res_list_parsed_clean(&hw_res);
-		return ret;
-	}
-
+		goto err_hw_res;
+	}
+
+	hcd_t *hcd = dev_to_hcd(device);
+
+	if (driver->init)
+		ret = driver->init(hcd, &hw_res, device);
+	if (ret != EOK) {
+		usb_log_error("Failed to init HCD.\n");
+		goto err_hcd;
+	}
+
+	/* Setup interrupts  */
 	interrupt_handler_t *irq_handler =
 	    driver->irq_handler ? driver->irq_handler : ddf_hcd_gen_irq_handler;
@@ -884,20 +826,19 @@
 	}
 
+	/* Claim the device from BIOS */
 	if (driver->claim)
-		ret = driver->claim(device);
+		ret = driver->claim(hcd, device);
 	if (ret != EOK) {
-		usb_log_error("Failed to claim `%s' for driver `%s'",
-		    ddf_dev_get_name(device), driver->name);
-		return ret;
-	}
-
-
-	/* Init hw driver */
-	hcd_t *hcd = dev_to_hcd(device);
-	ret = driver->init(hcd, &hw_res, irqs_enabled);
-	hw_res_list_parsed_clean(&hw_res);
+		usb_log_error("Failed to claim `%s' for driver `%s': %s",
+		    ddf_dev_get_name(device), driver->name, str_error(ret));
+		goto err_irq;
+	}
+
+	/* Start hw driver */
+	if (driver->start)
+		ret = driver->start(hcd, irqs_enabled);
 	if (ret != EOK) {
-		usb_log_error("Failed to init HCD: %s.\n", str_error(ret));
-		goto irq_unregister;
+		usb_log_error("Failed to start HCD: %s.\n", str_error(ret));
+		goto err_irq;
 	}
 
@@ -908,5 +849,5 @@
 			usb_log_error("Failed to create polling fibril\n");
 			ret = ENOMEM;
-			goto irq_unregister;
+			goto err_started;
 		}
 		fibril_add_ready(hcd->polling_fibril);
@@ -919,14 +860,10 @@
 	 * needs to be ready at this time.
 	 */
-	ret = hcd_ddf_setup_root_hub(device);
+	if (driver->setup_root_hub)
+		ret = driver->setup_root_hub(hcd, device);
 	if (ret != EOK) {
 		usb_log_error("Failed to setup HC root hub: %s.\n",
 		    str_error(ret));
-		driver->fini(dev_to_hcd(device));
-irq_unregister:
-		/* Unregistering non-existent should be ok */
-		unregister_interrupt_handler(device, irq_cap);
-		hcd_ddf_clean_hc(device);
-		return ret;
+		goto err_polling;
 	}
 
@@ -934,5 +871,22 @@
 	    driver->name, ddf_dev_get_name(device));
 	return EOK;
-}
+
+err_polling:
+	// TODO: Stop the polling fibril (refactor the interrupt_polling func)
+	//
+err_started:
+	if (driver->stop)
+		driver->stop(hcd);
+err_irq:
+	unregister_interrupt_handler(device, irq_cap);
+	if (driver->fini)
+		driver->fini(hcd);
+err_hcd:
+	hcd_ddf_clean_hc(device);
+err_hw_res:
+	hw_res_list_parsed_clean(&hw_res);
+	return ret;
+}
+
 /**
  * @}
Index: uspace/lib/usbhost/src/endpoint.c
===================================================================
--- uspace/lib/usbhost/src/endpoint.c	(revision cecba66ea48d60cfa59865e98aeda663808e42c7)
+++ uspace/lib/usbhost/src/endpoint.c	(revision 6cad7765736ec29f90dd2a80f7df7d0dd4857b9d)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2011 Jan Vesely
+ * Copyright (c) 2017 Ondrej Hlavaty <aearsis@eideo.cz>
  * All rights reserved.
  *
@@ -35,157 +36,121 @@
 
 #include <usb/host/endpoint.h>
+#include <usb/host/usb_transfer_batch.h>
+#include <usb/host/bus.h>
 
 #include <assert.h>
+#include <atomic.h>
+#include <mem.h>
 #include <stdlib.h>
-#include <atomic.h>
 
-/** Allocate ad initialize endpoint_t structure.
- * @param address USB address.
- * @param endpoint USB endpoint number.
- * @param direction Communication direction.
- * @param type USB transfer type.
- * @param speed Communication speed.
- * @param max_packet_size Maximum size of data packets.
- * @param bw Required bandwidth.
- * @return Pointer to initialized endpoint_t structure, NULL on failure.
+/** Initialize provided endpoint structure.
  */
-endpoint_t * endpoint_create(usb_address_t address, usb_endpoint_t endpoint,
-    usb_direction_t direction, usb_transfer_type_t type, usb_speed_t speed,
-    size_t max_packet_size, unsigned packets, size_t bw,
-    usb_address_t tt_address, unsigned tt_p)
+void endpoint_init(endpoint_t *ep, bus_t *bus)
 {
-	endpoint_t *instance = malloc(sizeof(endpoint_t));
-	if (instance) {
-		atomic_set(&instance->refcnt, 0);
-		instance->address = address;
-		instance->endpoint = endpoint;
-		instance->direction = direction;
-		instance->transfer_type = type;
-		instance->speed = speed;
-		instance->max_packet_size = max_packet_size;
-		instance->packets = packets;
-		instance->bandwidth = bw;
-		instance->toggle = 0;
-		instance->active = false;
-		instance->tt.address = tt_address;
-		instance->tt.port = tt_p;
-		instance->hc_data.data = NULL;
-		instance->hc_data.toggle_get = NULL;
-		instance->hc_data.toggle_set = NULL;
-		link_initialize(&instance->link);
-		fibril_mutex_initialize(&instance->guard);
-		fibril_condvar_initialize(&instance->avail);
-	}
-	return instance;
+	memset(ep, 0, sizeof(endpoint_t));
+
+	ep->bus = bus;
+	atomic_set(&ep->refcnt, 0);
+	link_initialize(&ep->link);
+	fibril_mutex_initialize(&ep->guard);
+	fibril_condvar_initialize(&ep->avail);
 }
 
-/** Properly dispose of endpoint_t structure.
- * @param instance endpoint_t structure.
- */
-void endpoint_destroy(endpoint_t *instance)
+void endpoint_add_ref(endpoint_t *ep)
 {
-	assert(instance);
-	assert(!instance->active);
-	assert(instance->hc_data.data == NULL);
-	free(instance);
+	atomic_inc(&ep->refcnt);
 }
 
-void endpoint_add_ref(endpoint_t *instance)
+void endpoint_del_ref(endpoint_t *ep)
 {
-	atomic_inc(&instance->refcnt);
-}
+	if (atomic_predec(&ep->refcnt) == 0) {
+		if (ep->bus->ops.destroy_endpoint) {
+			ep->bus->ops.destroy_endpoint(ep);
+		}
+		else {
+			assert(ep->active_batch == NULL);
 
-void endpoint_del_ref(endpoint_t *instance)
-{
-	if (atomic_predec(&instance->refcnt) == 0)
-		endpoint_destroy(instance);
-}
-
-/** Set device specific data and hooks.
- * @param instance endpoint_t structure.
- * @param data device specific data.
- * @param toggle_get Hook to call when retrieving value of toggle bit.
- * @param toggle_set Hook to call when setting the value of toggle bit.
- */
-void endpoint_set_hc_data(endpoint_t *instance,
-    void *data, int (*toggle_get)(void *), void (*toggle_set)(void *, int))
-{
-	assert(instance);
-	fibril_mutex_lock(&instance->guard);
-	instance->hc_data.data = data;
-	instance->hc_data.toggle_get = toggle_get;
-	instance->hc_data.toggle_set = toggle_set;
-	fibril_mutex_unlock(&instance->guard);
-}
-
-/** Clear device specific data and hooks.
- * @param instance endpoint_t structure.
- * @note This function does not free memory pointed to by data pointer.
- */
-void endpoint_clear_hc_data(endpoint_t *instance)
-{
-	assert(instance);
-	endpoint_set_hc_data(instance, NULL, NULL, NULL);
+			/* Assume mostly the eps will be allocated by malloc. */
+			free(ep);
+		}
+	}
 }
 
 /** Mark the endpoint as active and block access for further fibrils.
- * @param instance endpoint_t structure.
+ * @param ep endpoint_t structure.
  */
-void endpoint_use(endpoint_t *instance)
+void endpoint_activate_locked(endpoint_t *ep, usb_transfer_batch_t *batch)
 {
-	assert(instance);
-	/* Add reference for active endpoint. */
-	endpoint_add_ref(instance);
-	fibril_mutex_lock(&instance->guard);
-	while (instance->active)
-		fibril_condvar_wait(&instance->avail, &instance->guard);
-	instance->active = true;
-	fibril_mutex_unlock(&instance->guard);
+	assert(ep);
+	assert(batch);
+	assert(batch->ep == ep);
+	assert(fibril_mutex_is_locked(&ep->guard));
+
+	while (ep->active_batch != NULL)
+		fibril_condvar_wait(&ep->avail, &ep->guard);
+	ep->active_batch = batch;
 }
 
 /** Mark the endpoint as inactive and allow access for further fibrils.
- * @param instance endpoint_t structure.
+ * @param ep endpoint_t structure.
  */
-void endpoint_release(endpoint_t *instance)
+void endpoint_deactivate_locked(endpoint_t *ep)
 {
-	assert(instance);
-	fibril_mutex_lock(&instance->guard);
-	instance->active = false;
-	fibril_mutex_unlock(&instance->guard);
-	fibril_condvar_signal(&instance->avail);
-	/* Drop reference for active endpoint. */
-	endpoint_del_ref(instance);
+	assert(ep);
+	assert(fibril_mutex_is_locked(&ep->guard));
+
+	if (ep->active_batch && ep->active_batch->error == EOK)
+		usb_transfer_batch_reset_toggle(ep->active_batch);
+
+	ep->active_batch = NULL;
+	fibril_condvar_signal(&ep->avail);
 }
 
-/** Get the value of toggle bit.
- * @param instance endpoint_t structure.
- * @note Will use provided hook.
+/** Abort an active batch on endpoint, if any.
+ *
+ * @param[in] ep endpoint_t structure.
  */
-int endpoint_toggle_get(endpoint_t *instance)
+void endpoint_abort(endpoint_t *ep)
 {
-	assert(instance);
-	fibril_mutex_lock(&instance->guard);
-	if (instance->hc_data.toggle_get)
-		instance->toggle =
-		    instance->hc_data.toggle_get(instance->hc_data.data);
-	const int ret = instance->toggle;
-	fibril_mutex_unlock(&instance->guard);
-	return ret;
+	assert(ep);
+
+	fibril_mutex_lock(&ep->guard);
+	usb_transfer_batch_t *batch = ep->active_batch;
+	endpoint_deactivate_locked(ep);
+	fibril_mutex_unlock(&ep->guard);
+
+	if (batch)
+		usb_transfer_batch_abort(batch);
 }
 
-/** Set the value of toggle bit.
- * @param instance endpoint_t structure.
- * @note Will use provided hook.
+/** Get the value of toggle bit. Either uses the toggle_get op, or just returns
+ * the value of the toggle.
+ * @param ep endpoint_t structure.
  */
-void endpoint_toggle_set(endpoint_t *instance, int toggle)
+int endpoint_toggle_get(endpoint_t *ep)
 {
-	assert(instance);
-	assert(toggle == 0 || toggle == 1);
-	fibril_mutex_lock(&instance->guard);
-	instance->toggle = toggle;
-	if (instance->hc_data.toggle_set)
-		instance->hc_data.toggle_set(instance->hc_data.data, toggle);
-	fibril_mutex_unlock(&instance->guard);
+	assert(ep);
+
+	return ep->bus->ops.endpoint_get_toggle
+	    ? ep->bus->ops.endpoint_get_toggle(ep)
+	    : ep->toggle;
 }
+
+/** Set the value of toggle bit. Either uses the toggle_set op, or just sets
+ * the toggle inside.
+ * @param ep endpoint_t structure.
+ */
+void endpoint_toggle_set(endpoint_t *ep, bool toggle)
+{
+	assert(ep);
+
+	if (ep->bus->ops.endpoint_set_toggle) {
+		ep->bus->ops.endpoint_set_toggle(ep, toggle);
+	}
+	else {
+		ep->toggle = toggle;
+	}
+}
+
 
 /**
Index: uspace/lib/usbhost/src/hcd.c
===================================================================
--- uspace/lib/usbhost/src/hcd.c	(revision cecba66ea48d60cfa59865e98aeda663808e42c7)
+++ uspace/lib/usbhost/src/hcd.c	(revision 6cad7765736ec29f90dd2a80f7df7d0dd4857b9d)
@@ -41,46 +41,7 @@
 #include <errno.h>
 #include <usb_iface.h>
+#include <str_error.h>
 
 #include "hcd.h"
-
-/** Calls ep_add_hook upon endpoint registration.
- * @param ep Endpoint to be registered.
- * @param arg hcd_t in disguise.
- * @return Error code.
- */
-static int register_helper(endpoint_t *ep, void *arg)
-{
-	hcd_t *hcd = arg;
-	assert(ep);
-	assert(hcd);
-	if (hcd->ops.ep_add_hook)
-		return hcd->ops.ep_add_hook(hcd, ep);
-	return EOK;
-}
-
-/** Calls ep_remove_hook upon endpoint removal.
- * @param ep Endpoint to be unregistered.
- * @param arg hcd_t in disguise.
- */
-static void unregister_helper(endpoint_t *ep, void *arg)
-{
-	hcd_t *hcd = arg;
-	assert(ep);
-	assert(hcd);
-	if (hcd->ops.ep_remove_hook)
-		hcd->ops.ep_remove_hook(hcd, ep);
-}
-
-/** Calls ep_remove_hook upon endpoint removal. Prints warning.
- *  * @param ep Endpoint to be unregistered.
- *   * @param arg hcd_t in disguise.
- *    */
-static void unregister_helper_warn(endpoint_t *ep, void *arg)
-{
-        assert(ep);
-        usb_log_warning("Endpoint %d:%d %s was left behind, removing.\n",
-            ep->address, ep->endpoint, usb_str_direction(ep->direction));
-	unregister_helper(ep, arg);
-}
 
 
@@ -93,11 +54,8 @@
  * @param bw_count Bandwidth compute function, passed to endpoint manager.
  */
-void hcd_init(hcd_t *hcd, usb_speed_t max_speed, size_t bandwidth,
-    bw_count_func_t bw_count)
-{
+void hcd_init(hcd_t *hcd) {
 	assert(hcd);
-	usb_bus_init(&hcd->bus, bandwidth, bw_count, max_speed);
 
-	hcd_set_implementation(hcd, NULL, NULL);
+	hcd_set_implementation(hcd, NULL, NULL, NULL);
 }
 
@@ -106,6 +64,5 @@
 	assert(hcd);
 	usb_address_t address = 0;
-	const int ret = usb_bus_request_address(
-	    &hcd->bus, &address, false, speed);
+	const int ret = bus_request_address(hcd->bus, &address, false, speed);
 	if (ret != EOK)
 		return ret;
@@ -113,60 +70,6 @@
 }
 
-int hcd_release_address(hcd_t *hcd, usb_address_t address)
-{
-	assert(hcd);
-	return usb_bus_remove_address(&hcd->bus, address,
-	    unregister_helper_warn, hcd);
-}
-
-int hcd_reserve_default_address(hcd_t *hcd, usb_speed_t speed)
-{
-	assert(hcd);
-	usb_address_t address = 0;
-	return usb_bus_request_address(&hcd->bus, &address, true, speed);
-}
-
-int hcd_add_ep(hcd_t *hcd, usb_target_t target, usb_direction_t dir,
-    usb_transfer_type_t type, size_t max_packet_size, unsigned packets,
-    size_t size, usb_address_t tt_address, unsigned tt_port)
-{
-	assert(hcd);
-	return usb_bus_add_ep(&hcd->bus, target.address,
-	    target.endpoint, dir, type, max_packet_size, packets, size,
-	    register_helper, hcd, tt_address, tt_port);
-}
-
-int hcd_remove_ep(hcd_t *hcd, usb_target_t target, usb_direction_t dir)
-{
-	assert(hcd);
-	return usb_bus_remove_ep(&hcd->bus, target.address,
-	    target.endpoint, dir, unregister_helper, hcd);
-}
-
-
-typedef struct {
-	void *original_data;
-	usbhc_iface_transfer_out_callback_t original_callback;
-	usb_target_t target;
-	hcd_t *hcd;
-} toggle_t;
-
-static void toggle_reset_callback(int retval, void *arg)
-{
-	assert(arg);
-	toggle_t *toggle = arg;
-	if (retval == EOK) {
-		usb_log_debug2("Reseting toggle on %d:%d.\n",
-		    toggle->target.address, toggle->target.endpoint);
-		usb_bus_reset_toggle(&toggle->hcd->bus,
-		    toggle->target, toggle->target.endpoint == 0);
-	}
-
-	toggle->original_callback(retval, toggle->original_data);
-}
-
 /** Prepare generic usb_transfer_batch and schedule it.
  * @param hcd Host controller driver.
- * @param fun DDF fun
  * @param target address and endpoint number.
  * @param setup_data Data to use in setup stage (Control communication type)
@@ -177,32 +80,11 @@
  * @return Error code.
  */
-int hcd_send_batch(
-    hcd_t *hcd, usb_target_t target, usb_direction_t direction,
-    void *data, size_t size, uint64_t setup_data,
-    usbhc_iface_transfer_in_callback_t in,
-    usbhc_iface_transfer_out_callback_t out, void *arg, const char* name)
+int hcd_send_batch(hcd_t *hcd, device_t *device, usb_target_t target,
+    usb_direction_t direction, char *data, size_t size, uint64_t setup_data,
+    usbhc_iface_transfer_callback_t on_complete, void *arg, const char *name)
 {
 	assert(hcd);
+	assert(device->address == target.address);
 
-	endpoint_t *ep = usb_bus_find_ep(&hcd->bus,
-	    target.address, target.endpoint, direction);
-	if (ep == NULL) {
-		usb_log_error("Endpoint(%d:%d) not registered for %s.\n",
-		    target.address, target.endpoint, name);
-		return ENOENT;
-	}
-
-	usb_log_debug2("%s %d:%d %zu(%zu).\n",
-	    name, target.address, target.endpoint, size, ep->max_packet_size);
-
-	const size_t bw = bandwidth_count_usb11(
-	    ep->speed, ep->transfer_type, size, ep->max_packet_size);
-	/* Check if we have enough bandwidth reserved */
-	if (ep->bandwidth < bw) {
-		usb_log_error("Endpoint(%d:%d) %s needs %zu bw "
-		    "but only %zu is reserved.\n",
-		    ep->address, ep->endpoint, name, bw, ep->bandwidth);
-		return ENOSPC;
-	}
 	if (!hcd->ops.schedule) {
 		usb_log_error("HCD does not implement scheduler.\n");
@@ -210,26 +92,26 @@
 	}
 
-	/* Check for commands that reset toggle bit */
-	if (ep->transfer_type == USB_TRANSFER_CONTROL) {
-		const int reset_toggle = usb_request_needs_toggle_reset(
-		    (usb_device_request_setup_packet_t *) &setup_data);
-		if (reset_toggle >= 0) {
-			assert(out);
-			toggle_t *toggle = malloc(sizeof(toggle_t));
-			if (!toggle)
-				return ENOMEM;
-			toggle->target.address = target.address;
-			toggle->target.endpoint = reset_toggle;
-			toggle->original_callback = out;
-			toggle->original_data = arg;
-			toggle->hcd = hcd;
-
-			arg = toggle;
-			out = toggle_reset_callback;
-		}
+	endpoint_t *ep = bus_find_endpoint(hcd->bus, device, target, direction);
+	if (ep == NULL) {
+		usb_log_error("Endpoint(%d:%d) not registered for %s.\n",
+		    device->address, target.endpoint, name);
+		return ENOENT;
 	}
 
-	usb_transfer_batch_t *batch = usb_transfer_batch_create(
-	    ep, data, size, setup_data, in, out, arg);
+	// TODO cut here aka provide helper to call with instance of endpoint_t in hand
+
+	usb_log_debug2("%s %d:%d %zu(%zu).\n",
+	    name, target.address, target.endpoint, size, ep->max_packet_size);
+
+	const size_t bw = bus_count_bw(ep, size);
+	/* Check if we have enough bandwidth reserved */
+	if (ep->bandwidth < bw) {
+		usb_log_error("Endpoint(%d:%d) %s needs %zu bw "
+		    "but only %zu is reserved.\n",
+		    device->address, ep->endpoint, name, bw, ep->bandwidth);
+		return ENOSPC;
+	}
+
+	usb_transfer_batch_t *batch = usb_transfer_batch_create(ep);
 	if (!batch) {
 		usb_log_error("Failed to create transfer batch.\n");
@@ -237,7 +119,22 @@
 	}
 
+	batch->target = target;
+	batch->buffer = data;
+	batch->buffer_size = size;
+	batch->setup.packed = setup_data;
+	batch->dir = direction;
+	batch->on_complete = on_complete;
+	batch->on_complete_data = arg;
+
+	/* Check for commands that reset toggle bit */
+	if (ep->transfer_type == USB_TRANSFER_CONTROL)
+		batch->toggle_reset_mode
+			= usb_request_get_toggle_reset_mode(&batch->setup.packet);
+
 	const int ret = hcd->ops.schedule(hcd, batch);
-	if (ret != EOK)
+	if (ret != EOK) {
+		usb_log_warning("Batch %p failed to schedule: %s", batch, str_error(ret));
 		usb_transfer_batch_destroy(batch);
+	}
 
 	/* Drop our own reference to ep. */
@@ -248,47 +145,48 @@
 
 typedef struct {
-	volatile unsigned done;
-	int ret;
-	size_t size;
+	fibril_mutex_t done_mtx;
+	fibril_condvar_t done_cv;
+	unsigned done;
+
+	size_t transfered_size;
+	int error;
 } sync_data_t;
 
-static void transfer_in_cb(int ret, size_t size, void* data)
+static int sync_transfer_complete(void *arg, int error, size_t transfered_size)
 {
-	sync_data_t *d = data;
+	sync_data_t *d = arg;
 	assert(d);
-	d->ret = ret;
+	d->transfered_size = transfered_size;
+	d->error = error;
+	fibril_mutex_lock(&d->done_mtx);
 	d->done = 1;
-	d->size = size;
+	fibril_condvar_broadcast(&d->done_cv);
+	fibril_mutex_unlock(&d->done_mtx);
+	return EOK;
 }
 
-static void transfer_out_cb(int ret, void* data)
-{
-	sync_data_t *d = data;
-	assert(data);
-	d->ret = ret;
-	d->done = 1;
-}
-
-/** this is really ugly version of sync usb communication */
-ssize_t hcd_send_batch_sync(
-    hcd_t *hcd, usb_target_t target, usb_direction_t dir,
-    void *data, size_t size, uint64_t setup_data, const char* name)
+ssize_t hcd_send_batch_sync(hcd_t *hcd, device_t *device, usb_target_t target,
+    usb_direction_t direction, char *data, size_t size, uint64_t setup_data,
+    const char *name)
 {
 	assert(hcd);
-	sync_data_t sd = { .done = 0, .ret = EBUSY, .size = size };
+	sync_data_t sd = { .done = 0 };
+	fibril_mutex_initialize(&sd.done_mtx);
+	fibril_condvar_initialize(&sd.done_cv);
 
-	const int ret = hcd_send_batch(hcd, target, dir, data, size, setup_data,
-	    dir == USB_DIRECTION_IN ? transfer_in_cb : NULL,
-	    dir == USB_DIRECTION_OUT ? transfer_out_cb : NULL, &sd, name);
+	const int ret = hcd_send_batch(hcd, device, target, direction,
+	    data, size, setup_data,
+	    sync_transfer_complete, &sd, name);
 	if (ret != EOK)
 		return ret;
 
-	while (!sd.done) {
-		async_usleep(1000);
-	}
+	fibril_mutex_lock(&sd.done_mtx);
+	while (!sd.done)
+		fibril_condvar_wait(&sd.done_cv, &sd.done_mtx);
+	fibril_mutex_unlock(&sd.done_mtx);
 
-	if (sd.ret == EOK)
-		return sd.size;
-	return sd.ret;
+	return (sd.error == EOK)
+		? (ssize_t) sd.transfered_size
+		: (ssize_t) sd.error;
 }
 
Index: uspace/lib/usbhost/src/usb2_bus.c
===================================================================
--- uspace/lib/usbhost/src/usb2_bus.c	(revision 6cad7765736ec29f90dd2a80f7df7d0dd4857b9d)
+++ uspace/lib/usbhost/src/usb2_bus.c	(revision 6cad7765736ec29f90dd2a80f7df7d0dd4857b9d)
@@ -0,0 +1,505 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * Copyright (c) 2017 Ondrej Hlavaty <aearsis@eideo.cz>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/**  @addtogroup libusbhost
+ * @{
+ */
+/** @file
+ * HC Endpoint management.
+ */
+
+#include <usb/host/usb2_bus.h>
+#include <usb/host/endpoint.h>
+#include <usb/host/ddf_helpers.h>
+#include <usb/debug.h>
+#include <usb/request.h>
+#include <usb/descriptor.h>
+#include <usb/usb.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <macros.h>
+#include <str_error.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+/** Ops receive generic bus_t pointer. */
+static inline usb2_bus_t *bus_to_usb2_bus(bus_t *bus_base)
+{
+	assert(bus_base);
+	return (usb2_bus_t *) bus_base;
+}
+
+/** Get list that holds endpoints for given address.
+ * @param bus usb2_bus structure, non-null.
+ * @param addr USB address, must be >= 0.
+ * @return Pointer to the appropriate list.
+ */
+static list_t * get_list(usb2_bus_t *bus, usb_address_t addr)
+{
+	assert(bus);
+	assert(addr >= 0);
+	return &bus->devices[addr % ARRAY_SIZE(bus->devices)].endpoint_list;
+}
+
+/** Get speed assigned to USB address.
+ *
+ * @param[in] bus Device manager structure to use.
+ * @param[in] address Address the caller wants to find.
+ * @param[out] speed Assigned speed.
+ * @return Error code.
+ */
+static int usb2_bus_get_speed(bus_t *bus_base, usb_address_t address, usb_speed_t *speed)
+{
+	usb2_bus_t *bus = bus_to_usb2_bus(bus_base);
+
+	if (!usb_address_is_valid(address)) {
+		return EINVAL;
+	}
+
+	const int ret = bus->devices[address].occupied ? EOK : ENOENT;
+	if (speed && bus->devices[address].occupied) {
+		*speed = bus->devices[address].speed;
+	}
+
+	return ret;
+}
+
+static const usb_endpoint_desc_t usb2_default_control_ep = {
+	.endpoint_no = 0,
+	.transfer_type = USB_TRANSFER_CONTROL,
+	.direction = USB_DIRECTION_BOTH,
+	.max_packet_size = CTRL_PIPE_MIN_PACKET_SIZE,
+	.packets = 1,
+};
+
+
+static const usb_target_t usb2_default_target = {{
+	.address = USB_ADDRESS_DEFAULT,
+	.endpoint = 0,
+}};
+
+static int usb2_bus_address_device(bus_t *bus, hcd_t *hcd, device_t *dev)
+{
+	int err;
+
+	/* The default address is currently reserved for this device */
+	dev->address = USB_ADDRESS_DEFAULT;
+
+	/** Reserve address early, we want pretty log messages */
+	usb_address_t address;
+	if ((err = bus_request_address(bus, &address, false, dev->speed))) {
+		usb_log_error("Failed to reserve new address: %s.",
+		    str_error(err));
+		return err;
+	}
+	usb_log_debug("Device(%d): Reserved new address.", address);
+
+	/* Add default pipe on default address */
+	usb_log_debug("Device(%d): Adding default target (0:0)", address);
+
+	endpoint_t *default_ep;
+	err = bus_add_endpoint(bus, dev, &usb2_default_control_ep, &default_ep);
+	if (err != EOK) {
+		usb_log_error("Device(%d): Failed to add default target: %s.",
+		    address, str_error(err));
+		goto err_address;
+	}
+
+	/* Get max packet size for default pipe */
+	usb_standard_device_descriptor_t desc = { 0 };
+	const usb_device_request_setup_packet_t get_device_desc_8 =
+	    GET_DEVICE_DESC(CTRL_PIPE_MIN_PACKET_SIZE);
+
+	usb_log_debug("Device(%d): Requesting first 8B of device descriptor.",
+	    address);
+	ssize_t got = hcd_send_batch_sync(hcd, dev, usb2_default_target, USB_DIRECTION_IN,
+	    (char *) &desc, CTRL_PIPE_MIN_PACKET_SIZE, *(uint64_t *)&get_device_desc_8,
+	    "read first 8 bytes of dev descriptor");
+
+	if (got != CTRL_PIPE_MIN_PACKET_SIZE) {
+		err = got < 0 ? got : EOVERFLOW;
+		usb_log_error("Device(%d): Failed to get 8B of dev descr: %s.",
+		    address, str_error(err));
+		goto err_default_control_ep;
+	}
+
+	/* Set new address */
+	const usb_device_request_setup_packet_t set_address = SET_ADDRESS(address);
+
+	usb_log_debug("Device(%d): Setting USB address.", address);
+	err = hcd_send_batch_sync(hcd, dev, usb2_default_target, USB_DIRECTION_OUT,
+	    NULL, 0, *(uint64_t *)&set_address, "set address");
+	if (err != 0) {
+		usb_log_error("Device(%d): Failed to set new address: %s.",
+		    address, str_error(got));
+		goto err_default_control_ep;
+	}
+
+	/* We need to remove ep before we change the address */
+	if ((err = bus_remove_endpoint(bus, default_ep))) {
+		usb_log_error("Device(%d): Failed to unregister default target: %s", address, str_error(err));
+		goto err_address;
+	}
+	endpoint_del_ref(default_ep);
+
+	dev->address = address;
+
+	const usb_endpoint_desc_t control_ep = {
+		.endpoint_no = 0,
+		.transfer_type = USB_TRANSFER_CONTROL,
+		.direction = USB_DIRECTION_BOTH,
+		.max_packet_size = ED_MPS_PACKET_SIZE_GET(uint16_usb2host(desc.max_packet_size)),
+		.packets = ED_MPS_TRANS_OPPORTUNITIES_GET(uint16_usb2host(desc.max_packet_size)),
+	};
+
+	/* Register EP on the new address */
+	usb_log_debug("Device(%d): Registering control EP.", address);
+	err = bus_add_endpoint(bus, dev, &control_ep, NULL);
+	if (err != EOK) {
+		usb_log_error("Device(%d): Failed to register EP0: %s",
+		    address, str_error(err));
+		goto err_address;
+	}
+
+	return EOK;
+
+err_default_control_ep:
+	bus_remove_endpoint(bus, default_ep);
+	endpoint_del_ref(default_ep);
+err_address:
+	bus_release_address(bus, address);
+	return err;
+}
+
+/** Enumerate a new USB device
+ */
+static int usb2_bus_enumerate_device(bus_t *bus, hcd_t *hcd, device_t *dev)
+{
+	int err;
+
+	/* The speed of the new device was reported by the hub when reserving
+	 * default address.
+	 */
+	if ((err = usb2_bus_get_speed(bus, USB_ADDRESS_DEFAULT, &dev->speed))) {
+		usb_log_error("Failed to verify speed: %s.", str_error(err));
+		return err;
+	}
+	usb_log_debug("Found new %s speed USB device.", usb_str_speed(dev->speed));
+
+	if (dev->hub) {
+		/* Manage TT */
+		if (dev->hub->speed == USB_SPEED_HIGH && usb_speed_is_11(dev->speed)) {
+			/* For LS devices under HS hub */
+			/* TODO: How about SS hubs? */
+			dev->tt.address = dev->hub->address;
+			dev->tt.port = dev->port;
+		}
+		else {
+			/* Inherit hub's TT */
+			dev->tt = dev->hub->tt;
+		}
+	}
+	else {
+		dev->tt = (usb_tt_address_t) {
+			.address = -1,
+			.port = 0,
+		};
+	}
+
+	/* Assign an address to the device */
+	if ((err = usb2_bus_address_device(bus, hcd, dev))) {
+		usb_log_error("Failed to setup address of the new device: %s", str_error(err));
+		return err;
+	}
+
+	/* Read the device descriptor, derive the match ids */
+	if ((err = hcd_ddf_device_explore(hcd, dev))) {
+		usb_log_error("Device(%d): Failed to explore device: %s", dev->address, str_error(err));
+		bus_release_address(bus, dev->address);
+		return err;
+	}
+
+	return EOK;
+}
+
+/** Get a free USB address
+ *
+ * @param[in] bus Device manager structure to use.
+ * @return Free address, or error code.
+ */
+static int usb_bus_get_free_address(usb2_bus_t *bus, usb_address_t *addr)
+{
+	usb_address_t new_address = bus->last_address;
+	do {
+		new_address = (new_address + 1) % USB_ADDRESS_COUNT;
+		if (new_address == USB_ADDRESS_DEFAULT)
+			new_address = 1;
+		if (new_address == bus->last_address)
+			return ENOSPC;
+	} while (bus->devices[new_address].occupied);
+
+	assert(new_address != USB_ADDRESS_DEFAULT);
+	bus->last_address = new_address;
+
+	*addr = new_address;
+	return EOK;
+}
+
+/** Find endpoint.
+ * @param bus usb_bus structure, non-null.
+ * @param target Endpoint address.
+ * @param direction Communication direction.
+ * @return Pointer to endpoint_t structure representing given communication
+ * target, NULL if there is no such endpoint registered.
+ * @note Assumes that the internal mutex is locked.
+ */
+static endpoint_t *usb2_bus_find_ep(bus_t *bus_base, device_t *device, usb_target_t target, usb_direction_t direction)
+{
+	usb2_bus_t *bus = bus_to_usb2_bus(bus_base);
+
+	assert(device->address == target.address);
+
+	list_foreach(*get_list(bus, target.address), link, endpoint_t, ep) {
+		if (((direction == ep->direction)
+		       || (ep->direction == USB_DIRECTION_BOTH)
+		       || (direction == USB_DIRECTION_BOTH))
+		    && (target.endpoint == ep->endpoint))
+			return ep;
+	}
+	return NULL;
+}
+
+static endpoint_t *usb2_bus_create_ep(bus_t *bus)
+{
+	endpoint_t *ep = malloc(sizeof(endpoint_t));
+	if (!ep)
+		return NULL;
+
+	endpoint_init(ep, bus);
+	return ep;
+}
+
+static usb_target_t usb2_ep_to_target(endpoint_t *ep)
+{
+	assert(ep);
+	assert(ep->device);
+
+	return (usb_target_t) {{
+		.address = ep->device->address,
+		.endpoint = ep->endpoint,
+	}};
+}
+
+/** Register an endpoint to the bus. Reserves bandwidth.
+ * @param bus usb_bus structure, non-null.
+ * @param endpoint USB endpoint number.
+ */
+static int usb2_bus_register_ep(bus_t *bus_base, device_t *device, endpoint_t *ep, const usb_endpoint_desc_t *desc)
+{
+	usb2_bus_t *bus = bus_to_usb2_bus(bus_base);
+	assert(ep);
+
+	ep->device = device;
+
+	/* Extract USB2-related information from endpoint_desc */
+	ep->endpoint = desc->endpoint_no;
+	ep->direction = desc->direction;
+	ep->transfer_type = desc->transfer_type;
+	ep->max_packet_size = desc->max_packet_size;
+	ep->packets = desc->packets;
+
+	ep->bandwidth = bus_base->ops.count_bw(ep, desc->max_packet_size);
+
+	/* Check for existence */
+	if (usb2_bus_find_ep(bus_base, ep->device, usb2_ep_to_target(ep), ep->direction))
+		return EEXIST;
+
+	/* Check for available bandwidth */
+	if (ep->bandwidth > bus->free_bw)
+		return ENOSPC;
+
+	list_append(&ep->link, get_list(bus, ep->device->address));
+	bus->free_bw -= ep->bandwidth;
+
+	return EOK;
+}
+
+
+/** Release bandwidth reserved by the given endpoint.
+ */
+static int usb2_bus_unregister_ep(bus_t *bus_base, endpoint_t *ep)
+{
+	usb2_bus_t *bus = bus_to_usb2_bus(bus_base);
+	assert(ep);
+
+	list_remove(&ep->link);
+	ep->device = NULL;
+
+	bus->free_bw += ep->bandwidth;
+
+	return EOK;
+}
+
+static int usb2_bus_reset_toggle(bus_t *bus_base, usb_target_t target, toggle_reset_mode_t mode)
+{
+	usb2_bus_t *bus = bus_to_usb2_bus(bus_base);
+
+	if (!usb_target_is_valid(target))
+		return EINVAL;
+
+	if (mode == RESET_NONE)
+		return EOK;
+
+	int ret = ENOENT;
+
+	list_foreach(*get_list(bus, target.address), link, endpoint_t, ep) {
+		assert(ep->device->address == target.address);
+
+		if (mode == RESET_ALL || ep->endpoint == target.endpoint) {
+			endpoint_toggle_set(ep, 0);
+			ret = EOK;
+		}
+	}
+	return ret;
+}
+
+/** Unregister and destroy all endpoints using given address.
+ * @param bus usb_bus structure, non-null.
+ * @param address USB address.
+ * @param endpoint USB endpoint number.
+ * @param direction Communication direction.
+ * @return Error code.
+ */
+static int usb2_bus_release_address(bus_t *bus_base, usb_address_t address)
+{
+	usb2_bus_t *bus = bus_to_usb2_bus(bus_base);
+
+	if (!usb_address_is_valid(address))
+		return EINVAL;
+
+	const int ret = bus->devices[address].occupied ? EOK : ENOENT;
+	bus->devices[address].occupied = false;
+
+	list_t *list = get_list(bus, address);
+	for (link_t *link = list_first(list); link != NULL; ) {
+		endpoint_t *ep = list_get_instance(link, endpoint_t, link);
+		link = list_next(link, list);
+
+		assert(ep->device->address == address);
+		list_remove(&ep->link);
+
+		usb_log_warning("Endpoint %d:%d %s was left behind, removing.\n",
+		    address, ep->endpoint, usb_str_direction(ep->direction));
+
+		/* Drop bus reference */
+		endpoint_del_ref(ep);
+	}
+
+	return ret;
+}
+
+/** Request USB address.
+ * @param bus usb_device_manager
+ * @param addr Pointer to requested address value, place to store new address
+ * @parma strict Fail if the requested address is not available.
+ * @return Error code.
+ * @note Default address is only available in strict mode.
+ */
+static int usb2_bus_request_address(bus_t *bus_base, usb_address_t *addr, bool strict, usb_speed_t speed)
+{
+	int err;
+
+	usb2_bus_t *bus = bus_to_usb2_bus(bus_base);
+	assert(addr);
+
+	if (!usb_address_is_valid(*addr))
+		return EINVAL;
+
+	/* Only grant default address to strict requests */
+	if ((*addr == USB_ADDRESS_DEFAULT) && !strict) {
+		if ((err = usb_bus_get_free_address(bus, addr)))
+			return err;
+	}
+	else if (bus->devices[*addr].occupied) {
+		if (strict) {
+			return ENOENT;
+		}
+		if ((err = usb_bus_get_free_address(bus, addr)))
+			return err;
+	}
+
+	assert(usb_address_is_valid(*addr));
+	assert(bus->devices[*addr].occupied == false);
+	assert(*addr != USB_ADDRESS_DEFAULT || strict);
+
+	bus->devices[*addr].occupied = true;
+	bus->devices[*addr].speed = speed;
+
+	return EOK;
+}
+
+static const bus_ops_t usb2_bus_ops = {
+	.enumerate_device = usb2_bus_enumerate_device,
+	.create_endpoint = usb2_bus_create_ep,
+	.find_endpoint = usb2_bus_find_ep,
+	.unregister_endpoint = usb2_bus_unregister_ep,
+	.register_endpoint = usb2_bus_register_ep,
+	.request_address = usb2_bus_request_address,
+	.release_address = usb2_bus_release_address,
+	.reset_toggle = usb2_bus_reset_toggle,
+};
+
+/** Initialize to default state.
+ *
+ * @param bus usb_bus structure, non-null.
+ * @param available_bandwidth Size of the bandwidth pool.
+ * @param bw_count function to use to calculate endpoint bw requirements.
+ * @return Error code.
+ */
+int usb2_bus_init(usb2_bus_t *bus, size_t available_bandwidth, count_bw_func_t count_bw)
+{
+	assert(bus);
+
+	bus_init(&bus->base, sizeof(device_t));
+
+	bus->base.ops = usb2_bus_ops;
+	bus->base.ops.count_bw = count_bw;
+
+	bus->free_bw = available_bandwidth;
+	bus->last_address = 0;
+	for (unsigned i = 0; i < ARRAY_SIZE(bus->devices); ++i) {
+		list_initialize(&bus->devices[i].endpoint_list);
+		bus->devices[i].speed = USB_SPEED_MAX;
+		bus->devices[i].occupied = false;
+	}
+	return EOK;
+}
+/**
+ * @}
+ */
Index: uspace/lib/usbhost/src/usb_bus.c
===================================================================
--- uspace/lib/usbhost/src/usb_bus.c	(revision cecba66ea48d60cfa59865e98aeda663808e42c7)
+++ 	(revision )
@@ -1,548 +1,0 @@
-/*
- * Copyright (c) 2011 Jan Vesely
- * All rights eps.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-/**  @addtogroup libusbhost
- * @{
- */
-/** @file
- * HC Endpoint management.
- */
-
-#include <usb/host/usb_bus.h>
-#include <usb/debug.h>
-
-#include <assert.h>
-#include <errno.h>
-#include <macros.h>
-#include <stdbool.h>
-
-
-/** Endpoint compare helper function.
- *
- * USB_DIRECTION_BOTH matches both IN and OUT.
- * @param ep Endpoint to compare, non-null.
- * @param address Tested address.
- * @param endpoint Tested endpoint number.
- * @param direction Tested direction.
- * @return True if ep can be used to communicate with given device,
- * false otherwise.
- */
-static inline bool ep_match(const endpoint_t *ep,
-    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction)
-{
-	assert(ep);
-	return
-	    ((direction == ep->direction)
-	        || (ep->direction == USB_DIRECTION_BOTH)
-	        || (direction == USB_DIRECTION_BOTH))
-	    && (endpoint == ep->endpoint)
-	    && (address == ep->address);
-}
-
-/** Get list that holds endpoints for given address.
- * @param instance usb_bus structure, non-null.
- * @param addr USB address, must be >= 0.
- * @return Pointer to the appropriate list.
- */
-static list_t * get_list(usb_bus_t *instance, usb_address_t addr)
-{
-	assert(instance);
-	assert(addr >= 0);
-	return &instance->devices[addr % ARRAY_SIZE(instance->devices)].endpoint_list;
-}
-
-/** Internal search function, works on locked structure.
- * @param instance usb_bus structure, non-null.
- * @param address USB address, must be valid.
- * @param endpoint USB endpoint number.
- * @param direction Communication direction.
- * @return Pointer to endpoint_t structure representing given communication
- * target, NULL if there is no such endpoint registered.
- * @note Assumes that the internal mutex is locked.
- */
-static endpoint_t * find_locked(usb_bus_t *instance,
-    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction)
-{
-	assert(instance);
-	assert(fibril_mutex_is_locked(&instance->guard));
-	if (address < 0)
-		return NULL;
-	list_foreach(*get_list(instance, address), link, endpoint_t, ep) {
-		if (ep_match(ep, address, endpoint, direction))
-			return ep;
-	}
-	return NULL;
-}
-
-/** Get a free USB address
- *
- * @param[in] instance Device manager structure to use.
- * @return Free address, or error code.
- */
-static usb_address_t usb_bus_get_free_address(usb_bus_t *instance)
-{
-
-	usb_address_t new_address = instance->last_address;
-	do {
-		new_address = (new_address + 1) % USB_ADDRESS_COUNT;
-		if (new_address == USB_ADDRESS_DEFAULT)
-			new_address = 1;
-		if (new_address == instance->last_address)
-			return ENOSPC;
-	} while (instance->devices[new_address].occupied);
-
-	assert(new_address != USB_ADDRESS_DEFAULT);
-	instance->last_address = new_address;
-
-	return new_address;
-}
-
-/** Calculate bandwidth that needs to be reserved for communication with EP.
- * Calculation follows USB 1.1 specification.
- * @param speed Device's speed.
- * @param type Type of the transfer.
- * @param size Number of byte to transfer.
- * @param max_packet_size Maximum bytes in one packet.
- */
-size_t bandwidth_count_usb11(usb_speed_t speed, usb_transfer_type_t type,
-    size_t size, size_t max_packet_size)
-{
-	/* We care about bandwidth only for interrupt and isochronous. */
-	if ((type != USB_TRANSFER_INTERRUPT)
-	    && (type != USB_TRANSFER_ISOCHRONOUS)) {
-		return 0;
-	}
-
-	const unsigned packet_count =
-	    (size + max_packet_size - 1) / max_packet_size;
-	/* TODO: It may be that ISO and INT transfers use only one packet per
-	 * transaction, but I did not find text in USB spec to confirm this */
-	/* NOTE: All data packets will be considered to be max_packet_size */
-	switch (speed)
-	{
-	case USB_SPEED_LOW:
-		assert(type == USB_TRANSFER_INTERRUPT);
-		/* Protocol overhead 13B
-		 * (3 SYNC bytes, 3 PID bytes, 2 Endpoint + CRC bytes, 2
-		 * CRC bytes, and a 3-byte interpacket delay)
-		 * see USB spec page 45-46. */
-		/* Speed penalty 8: low speed is 8-times slower*/
-		return packet_count * (13 + max_packet_size) * 8;
-	case USB_SPEED_FULL:
-		/* Interrupt transfer overhead see above
-		 * or page 45 of USB spec */
-		if (type == USB_TRANSFER_INTERRUPT)
-			return packet_count * (13 + max_packet_size);
-
-		assert(type == USB_TRANSFER_ISOCHRONOUS);
-		/* Protocol overhead 9B
-		 * (2 SYNC bytes, 2 PID bytes, 2 Endpoint + CRC bytes, 2 CRC
-		 * bytes, and a 1-byte interpacket delay)
-		 * see USB spec page 42 */
-		return packet_count * (9 + max_packet_size);
-	default:
-		return 0;
-	}
-}
-
-/** Calculate bandwidth that needs to be reserved for communication with EP.
- * Calculation follows USB 2.0 specification.
- * @param speed Device's speed.
- * @param type Type of the transfer.
- * @param size Number of byte to transfer.
- * @param max_packet_size Maximum bytes in one packet.
- */
-size_t bandwidth_count_usb20(usb_speed_t speed, usb_transfer_type_t type,
-    size_t size, size_t max_packet_size)
-{
-	/* We care about bandwidth only for interrupt and isochronous. */
-	if ((type != USB_TRANSFER_INTERRUPT)
-	    && (type != USB_TRANSFER_ISOCHRONOUS)) {
-		return 0;
-	}
-	//TODO Implement
-	return 0;
-}
-
-/** Initialize to default state.
- * You need to provide valid bw_count function if you plan to use
- * add_endpoint/remove_endpoint pair.
- *
- * @param instance usb_bus structure, non-null.
- * @param available_bandwidth Size of the bandwidth pool.
- * @param bw_count function to use to calculate endpoint bw requirements.
- * @return Error code.
- */
-int usb_bus_init(usb_bus_t *instance,
-    size_t available_bandwidth, bw_count_func_t bw_count, usb_speed_t max_speed)
-{
-	assert(instance);
-	fibril_mutex_initialize(&instance->guard);
-	instance->free_bw = available_bandwidth;
-	instance->bw_count = bw_count;
-	instance->last_address = 0;
-	instance->max_speed = max_speed;
-	for (unsigned i = 0; i < ARRAY_SIZE(instance->devices); ++i) {
-		list_initialize(&instance->devices[i].endpoint_list);
-		instance->devices[i].speed = USB_SPEED_MAX;
-		instance->devices[i].occupied = false;
-	}
-	return EOK;
-}
-
-/** Register endpoint structure.
- * Checks for duplicates.
- * @param instance usb_bus, non-null.
- * @param ep endpoint_t to register.
- * @param data_size Size of data to transfer.
- * @return Error code.
- */
-int usb_bus_register_ep(usb_bus_t *instance, endpoint_t *ep, size_t data_size)
-{
-	assert(instance);
-	if (ep == NULL || ep->address < 0)
-		return EINVAL;
-
-	fibril_mutex_lock(&instance->guard);
-	/* Check for available bandwidth */
-	if (ep->bandwidth > instance->free_bw) {
-		fibril_mutex_unlock(&instance->guard);
-		return ENOSPC;
-	}
-
-	/* Check for existence */
-	const endpoint_t *endpoint =
-	    find_locked(instance, ep->address, ep->endpoint, ep->direction);
-	if (endpoint != NULL) {
-		fibril_mutex_unlock(&instance->guard);
-		return EEXIST;
-	}
-	/* Add endpoint list's reference to ep. */
-	endpoint_add_ref(ep);
-	list_append(&ep->link, get_list(instance, ep->address));
-
-	instance->free_bw -= ep->bandwidth;
-	usb_log_debug("Registered EP(%d:%d:%s:%s)\n", ep->address, ep->endpoint,
-	    usb_str_transfer_type_short(ep->transfer_type),
-	    usb_str_direction(ep->direction));
-	fibril_mutex_unlock(&instance->guard);
-	return EOK;
-}
-
-/** Unregister endpoint structure.
- * Checks for duplicates.
- * @param instance usb_bus, non-null.
- * @param ep endpoint_t to unregister.
- * @return Error code.
- */
-int usb_bus_unregister_ep(usb_bus_t *instance, endpoint_t *ep)
-{
-	assert(instance);
-	if (ep == NULL || ep->address < 0)
-		return EINVAL;
-
-	fibril_mutex_lock(&instance->guard);
-	if (!list_member(&ep->link, get_list(instance, ep->address))) {
-		fibril_mutex_unlock(&instance->guard);
-		return ENOENT;
-	}
-	list_remove(&ep->link);
-	instance->free_bw += ep->bandwidth;
-	usb_log_debug("Unregistered EP(%d:%d:%s:%s)\n", ep->address,
-	    ep->endpoint, usb_str_transfer_type_short(ep->transfer_type),
-	    usb_str_direction(ep->direction));
-	/* Drop endpoint list's reference to ep. */
-	endpoint_del_ref(ep);
-	fibril_mutex_unlock(&instance->guard);
-	return EOK;
-}
-
-/** Find endpoint_t representing the given communication route.
- * @param instance usb_bus, non-null.
- * @param address
- */
-endpoint_t * usb_bus_find_ep(usb_bus_t *instance,
-    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction)
-{
-	assert(instance);
-
-	fibril_mutex_lock(&instance->guard);
-	endpoint_t *ep = find_locked(instance, address, endpoint, direction);
-	if (ep) {
-		/* We are exporting ep to the outside world, add reference. */
-		endpoint_add_ref(ep);
-	}
-	fibril_mutex_unlock(&instance->guard);
-	return ep;
-}
-
-/** Create and register new endpoint_t structure.
- * @param instance usb_bus structure, non-null.
- * @param address USB address.
- * @param endpoint USB endpoint number.
- * @param direction Communication direction.
- * @param type USB transfer type.
- * @param speed USB Communication speed.
- * @param max_packet_size Maximum size of data packets.
- * @param data_size Expected communication size.
- * @param callback function to call just after registering.
- * @param arg Argument to pass to the callback function.
- * @return Error code.
- */
-int usb_bus_add_ep(usb_bus_t *instance,
-    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction,
-    usb_transfer_type_t type, size_t max_packet_size, unsigned packets,
-    size_t data_size, ep_add_callback_t callback, void *arg,
-    usb_address_t tt_address, unsigned tt_port)
-{
-	assert(instance);
-	if (instance->bw_count == NULL)
-		return ENOTSUP;
-	if (!usb_address_is_valid(address))
-		return EINVAL;
-
-
-	fibril_mutex_lock(&instance->guard);
-	/* Check for speed and address */
-	if (!instance->devices[address].occupied) {
-		fibril_mutex_unlock(&instance->guard);
-		return ENOENT;
-	}
-
-	/* Check for existence */
-	endpoint_t *ep = find_locked(instance, address, endpoint, direction);
-	if (ep != NULL) {
-		fibril_mutex_unlock(&instance->guard);
-		return EEXIST;
-	}
-
-	const usb_speed_t speed = instance->devices[address].speed;
-	const size_t bw =
-	    instance->bw_count(speed, type, data_size, max_packet_size);
-
-	/* Check for available bandwidth */
-	if (bw > instance->free_bw) {
-		fibril_mutex_unlock(&instance->guard);
-		return ENOSPC;
-	}
-
-	ep = endpoint_create(address, endpoint, direction, type, speed,
-	    max_packet_size, packets, bw, tt_address, tt_port);
-	if (!ep) {
-		fibril_mutex_unlock(&instance->guard);
-		return ENOMEM;
-	}
-
-	/* Add our reference to ep. */
-	endpoint_add_ref(ep);
-
-	if (callback) {
-		const int ret = callback(ep, arg);
-		if (ret != EOK) {
-			fibril_mutex_unlock(&instance->guard);
-			endpoint_del_ref(ep);
-			return ret;
-		}
-	}
-	
-	/* Add endpoint list's reference to ep. */
-	endpoint_add_ref(ep);
-	list_append(&ep->link, get_list(instance, ep->address));
-
-	instance->free_bw -= ep->bandwidth;
-	fibril_mutex_unlock(&instance->guard);
-
-	/* Drop our reference to ep. */
-	endpoint_del_ref(ep);
-
-	return EOK;
-}
-
-/** Unregister and destroy endpoint_t structure representing given route.
- * @param instance usb_bus structure, non-null.
- * @param address USB address.
- * @param endpoint USB endpoint number.
- * @param direction Communication direction.
- * @param callback Function to call after unregister, before destruction.
- * @arg Argument to pass to the callback function.
- * @return Error code.
- */
-int usb_bus_remove_ep(usb_bus_t *instance,
-    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction,
-    ep_remove_callback_t callback, void *arg)
-{
-	assert(instance);
-	fibril_mutex_lock(&instance->guard);
-	endpoint_t *ep = find_locked(instance, address, endpoint, direction);
-	if (ep != NULL) {
-		list_remove(&ep->link);
-		instance->free_bw += ep->bandwidth;
-	}
-	fibril_mutex_unlock(&instance->guard);
-	if (ep == NULL)
-		return ENOENT;
-
-	if (callback) {
-		callback(ep, arg);
-	}
-	/* Drop endpoint list's reference to ep. */
-	endpoint_del_ref(ep);
-	return EOK;
-}
-
-int usb_bus_reset_toggle(usb_bus_t *instance, usb_target_t target, bool all)
-{
-	assert(instance);
-	if (!usb_target_is_valid(target))
-		return EINVAL;
-
-	int ret = ENOENT;
-
-	fibril_mutex_lock(&instance->guard);
-	list_foreach(*get_list(instance, target.address), link, endpoint_t, ep) {
-		if ((ep->address == target.address)
-		    && (all || ep->endpoint == target.endpoint)) {
-			endpoint_toggle_set(ep, 0);
-			ret = EOK;
-		}
-	}
-	fibril_mutex_unlock(&instance->guard);
-	return ret;
-}
-
-/** Unregister and destroy all endpoints using given address.
- * @param instance usb_bus structure, non-null.
- * @param address USB address.
- * @param endpoint USB endpoint number.
- * @param direction Communication direction.
- * @param callback Function to call after unregister, before destruction.
- * @arg Argument to pass to the callback function.
- * @return Error code.
- */
-int usb_bus_remove_address(usb_bus_t *instance,
-    usb_address_t address, ep_remove_callback_t callback, void *arg)
-{
-	assert(instance);
-	if (!usb_address_is_valid(address))
-		return EINVAL;
-
-	fibril_mutex_lock(&instance->guard);
-
-	const int ret = instance->devices[address].occupied ? EOK : ENOENT;
-	instance->devices[address].occupied = false;
-
-	list_t *list = get_list(instance, address);
-	for (link_t *link = list_first(list); link != NULL; ) {
-		endpoint_t *ep = list_get_instance(link, endpoint_t, link);
-		link = list_next(link, list);
-		if (ep->address == address) {
-			list_remove(&ep->link);
-			if (callback)
-				callback(ep, arg);
-			/* Drop endpoint list's reference to ep. */
-			endpoint_del_ref(ep);
-		}
-	}
-	fibril_mutex_unlock(&instance->guard);
-	return ret;
-}
-
-/** Request USB address.
- * @param instance usb_device_manager
- * @param address Pointer to requested address value, place to store new address
- * @parma strict Fail if the requested address is not available.
- * @return Error code.
- * @note Default address is only available in strict mode.
- */
-int usb_bus_request_address(usb_bus_t *instance,
-    usb_address_t *address, bool strict, usb_speed_t speed)
-{
-	assert(instance);
-	assert(address);
-	if (speed > instance->max_speed)
-		return ENOTSUP;
-
-	if (!usb_address_is_valid(*address))
-		return EINVAL;
-
-	usb_address_t addr = *address;
-
-	fibril_mutex_lock(&instance->guard);
-	/* Only grant default address to strict requests */
-	if ((addr == USB_ADDRESS_DEFAULT) && !strict) {
-		addr = usb_bus_get_free_address(instance);
-	}
-
-	if (instance->devices[addr].occupied) {
-		if (strict) {
-			fibril_mutex_unlock(&instance->guard);
-			return ENOENT;
-		}
-		addr = usb_bus_get_free_address(instance);
-	}
-	if (usb_address_is_valid(addr)) {
-		assert(instance->devices[addr].occupied == false);
-		assert(addr != USB_ADDRESS_DEFAULT || strict);
-
-		instance->devices[addr].occupied = true;
-		instance->devices[addr].speed = speed;
-		*address = addr;
-		addr = 0;
-	}
-
-	fibril_mutex_unlock(&instance->guard);
-	return addr;
-}
-
-/** Get speed assigned to USB address.
- *
- * @param[in] instance Device manager structure to use.
- * @param[in] address Address the caller wants to find.
- * @param[out] speed Assigned speed.
- * @return Error code.
- */
-int usb_bus_get_speed(usb_bus_t *instance, usb_address_t address,
-    usb_speed_t *speed)
-{
-	assert(instance);
-	if (!usb_address_is_valid(address)) {
-		return EINVAL;
-	}
-
-	fibril_mutex_lock(&instance->guard);
-
-	const int ret = instance->devices[address].occupied ? EOK : ENOENT;
-	if (speed && instance->devices[address].occupied) {
-		*speed = instance->devices[address].speed;
-	}
-
-	fibril_mutex_unlock(&instance->guard);
-	return ret;
-}
-/**
- * @}
- */
Index: uspace/lib/usbhost/src/usb_transfer_batch.c
===================================================================
--- uspace/lib/usbhost/src/usb_transfer_batch.c	(revision cecba66ea48d60cfa59865e98aeda663808e42c7)
+++ uspace/lib/usbhost/src/usb_transfer_batch.c	(revision 6cad7765736ec29f90dd2a80f7df7d0dd4857b9d)
@@ -34,104 +34,116 @@
 
 #include <usb/host/usb_transfer_batch.h>
+#include <usb/host/endpoint.h>
+#include <usb/host/bus.h>
 #include <usb/debug.h>
 
 #include <assert.h>
+#include <stdlib.h>
 #include <errno.h>
-#include <macros.h>
-#include <mem.h>
-#include <stdlib.h>
-#include <usbhc_iface.h>
+#include <str_error.h>
 
-/** Allocate and initialize usb_transfer_batch structure.
- * @param ep endpoint used by the transfer batch.
- * @param buffer data to send/recieve.
- * @param buffer_size Size of data buffer.
- * @param setup_buffer Data to send in SETUP stage of control transfer.
- * @param func_in callback on IN transfer completion.
- * @param func_out callback on OUT transfer completion.
- * @param fun DDF function (passed to callback function).
- * @param arg Argument to pass to the callback function.
- * @param private_data driver specific per batch data.
- * @param private_data_dtor Function to properly destroy private_data.
- * @return Pointer to valid usb_transfer_batch_t structure, NULL on failure.
+
+/** Create a batch on given endpoint.
  */
-usb_transfer_batch_t *usb_transfer_batch_create(endpoint_t *ep, char *buffer,
-    size_t buffer_size,
-    uint64_t setup_buffer,
-    usbhc_iface_transfer_in_callback_t func_in,
-    usbhc_iface_transfer_out_callback_t func_out,
-    void *arg)
+usb_transfer_batch_t *usb_transfer_batch_create(endpoint_t *ep)
 {
-	if (func_in == NULL && func_out == NULL)
-		return NULL;
-	if (func_in != NULL && func_out != NULL)
-		return NULL;
+	assert(ep);
+	assert(ep->bus);
 
-	usb_transfer_batch_t *instance = malloc(sizeof(usb_transfer_batch_t));
-	if (instance) {
-		instance->ep = ep;
-		instance->callback_in = func_in;
-		instance->callback_out = func_out;
-		instance->arg = arg;
-		instance->buffer = buffer;
-		instance->buffer_size = buffer_size;
-		instance->setup_size = 0;
-		instance->transfered_size = 0;
-		instance->error = EOK;
-		if (ep && ep->transfer_type == USB_TRANSFER_CONTROL) {
-			memcpy(instance->setup_buffer, &setup_buffer,
-			    USB_SETUP_PACKET_SIZE);
-			instance->setup_size = USB_SETUP_PACKET_SIZE;
-		}
-		if (instance->ep)
-			endpoint_use(instance->ep);
-	}
-	return instance;
+	usb_transfer_batch_t *batch;
+	if (ep->bus->ops.create_batch)
+		batch = ep->bus->ops.create_batch(ep->bus, ep);
+	else
+		batch = malloc(sizeof(usb_transfer_batch_t));
+
+	return batch;
 }
 
-/** Correctly dispose all used data structures.
- *
- * @param[in] instance Batch structure to use.
+/** Initialize given batch structure.
  */
-void usb_transfer_batch_destroy(const usb_transfer_batch_t *instance)
+void usb_transfer_batch_init(usb_transfer_batch_t *batch, endpoint_t *ep)
 {
-	if (!instance)
-		return;
-	usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " disposing.\n",
-	    instance, USB_TRANSFER_BATCH_ARGS(*instance));
-	if (instance->ep) {
-		endpoint_release(instance->ep);
-	}
-	free(instance);
+	memset(batch, 0, sizeof(*batch));
+	batch->ep = ep;
 }
 
-/** Prepare data and call the right callback.
+/** Resolve resetting toggle.
  *
- * @param[in] instance Batch structure to use.
- * @param[in] data Data to copy to the output buffer.
- * @param[in] size Size of @p data.
- * @param[in] error Error value to use.
+ * @param[in] batch Batch structure to use.
  */
-void usb_transfer_batch_finish_error(const usb_transfer_batch_t *instance,
-    const void *data, size_t size, int error)
+int usb_transfer_batch_reset_toggle(usb_transfer_batch_t *batch)
 {
-	assert(instance);
+	assert(batch);
+
+	if (batch->error != EOK || batch->toggle_reset_mode == RESET_NONE)
+		return EOK;
+
+	usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " resets %s",
+	    batch, USB_TRANSFER_BATCH_ARGS(*batch),
+	    batch->toggle_reset_mode == RESET_ALL ? "all EPs toggle" : "EP toggle");
+
+	return bus_reset_toggle(batch->ep->bus, batch->target, batch->toggle_reset_mode);
+}
+
+/** Destroy the batch.
+ *
+ * @param[in] batch Batch structure to use.
+ */
+void usb_transfer_batch_destroy(usb_transfer_batch_t *batch)
+{
+	assert(batch);
+	assert(batch->ep);
+	assert(batch->ep->bus);
+
+	bus_t *bus = batch->ep->bus;
+	if (bus->ops.destroy_batch) {
+		usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " destroying.\n",
+		    batch, USB_TRANSFER_BATCH_ARGS(*batch));
+		bus->ops.destroy_batch(batch);
+	}
+	else {
+		usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " disposing.\n",
+		    batch, USB_TRANSFER_BATCH_ARGS(*batch));
+		free(batch);
+	}
+}
+
+/** Finish a transfer batch: call handler, destroy batch, release endpoint.
+ *
+ * Call only after the batch have been scheduled && completed!
+ *
+ * @param[in] batch Batch structure to use.
+ */
+void usb_transfer_batch_finish(usb_transfer_batch_t *batch)
+{
+	assert(batch);
+	assert(batch->ep);
+
 	usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " finishing.\n",
-	    instance, USB_TRANSFER_BATCH_ARGS(*instance));
+	    batch, USB_TRANSFER_BATCH_ARGS(*batch));
 
-	/* NOTE: Only one of these pointers should be set. */
-        if (instance->callback_out) {
-		instance->callback_out(error, instance->arg);
+	if (batch->on_complete) {
+		const int err = batch->on_complete(batch->on_complete_data, batch->error, batch->transfered_size);
+		if (err)
+			usb_log_warning("batch %p failed to complete: %s",
+			    batch, str_error(err));
 	}
 
-        if (instance->callback_in) {
-		/* We care about the data and there are some to copy */
-		const size_t safe_size = min(size, instance->buffer_size);
-		if (data) {
-	                memcpy(instance->buffer, data, safe_size);
-		}
-		instance->callback_in(error, safe_size, instance->arg);
-	}
+	usb_transfer_batch_destroy(batch);
 }
+
+/** Finish a transfer batch as an aborted one.
+ *
+ * @param[in] batch Batch structure to use.
+ */
+void usb_transfer_batch_abort(usb_transfer_batch_t *batch)
+{
+	assert(batch);
+	assert(batch->ep);
+
+	batch->error = EAGAIN;
+	usb_transfer_batch_finish(batch);
+}
+
 /**
  * @}
