Index: uspace/lib/c/include/bitops.h
===================================================================
--- uspace/lib/c/include/bitops.h	(revision 04649677bb4fbe5c0b699c27add4f8664d9a15fc)
+++ uspace/lib/c/include/bitops.h	(revision f45c78f205c41f1c67dfb0cfec097c87e866c376)
@@ -54,4 +54,8 @@
 #define BIT_RANGE_EXTRACT(type, hi, lo, value) \
     (((value) >> (lo)) & BIT_RRANGE(type, (hi) - (lo) + 1))
+
+/** Insert @a value between bits @a hi .. @a lo. */
+#define BIT_RANGE_INSERT(type, hi, lo, value) \
+    (((value) & BIT_RRANGE(type, (hi) - (lo) + 1)) << (lo))
 
 /** Return position of first non-zero bit from left (i.e. [log_2(arg)]).
Index: uspace/lib/c/include/byteorder.h
===================================================================
--- uspace/lib/c/include/byteorder.h	(revision 04649677bb4fbe5c0b699c27add4f8664d9a15fc)
+++ uspace/lib/c/include/byteorder.h	(revision f45c78f205c41f1c67dfb0cfec097c87e866c376)
@@ -85,4 +85,9 @@
 #define ntohl(n)  uint32_t_be2host((n))
 
+#define uint8_t_be2host(n)  (n)
+#define uint8_t_le2host(n)  (n)
+#define host2uint8_t_be(n)  (n)
+#define host2uint8_t_le(n)  (n)
+
 static inline uint64_t uint64_t_byteorder_swap(uint64_t n)
 {
Index: uspace/lib/drv/generic/remote_usb.c
===================================================================
--- uspace/lib/drv/generic/remote_usb.c	(revision 04649677bb4fbe5c0b699c27add4f8664d9a15fc)
+++ uspace/lib/drv/generic/remote_usb.c	(revision f45c78f205c41f1c67dfb0cfec097c87e866c376)
@@ -175,28 +175,57 @@
 } pack8_t;
 
-int usb_register_endpoint(async_exch_t *exch, usb_endpoint_t endpoint,
-    usb_transfer_type_t type, usb_direction_t direction,
-    size_t mps, unsigned packets, unsigned interval)
-{
-	if (!exch)
-		return EBADMEM;
-	pack8_t pack;
-	pack.arr[0] = type;
-	pack.arr[1] = direction;
-	pack.arr[2] = interval;
-	pack.arr[3] = packets;
-
-	return async_req_4_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
-	    IPC_M_USB_REGISTER_ENDPOINT, endpoint, pack.arg, mps);
-
-}
-
-int usb_unregister_endpoint(async_exch_t *exch, usb_endpoint_t endpoint,
-    usb_direction_t direction)
-{
-	if (!exch)
-		return EBADMEM;
-	return async_req_3_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
-	    IPC_M_USB_UNREGISTER_ENDPOINT, endpoint, direction);
+int usb_register_endpoint(async_exch_t *exch,
+	usb_endpoint_desc_t *endpoint_desc)
+{
+	if (!exch)
+		return EBADMEM;
+
+	aid_t opening_request = async_send_1(exch,
+	    DEV_IFACE_ID(USB_DEV_IFACE), IPC_M_USB_REGISTER_ENDPOINT, NULL);
+
+	if (opening_request == 0) {
+		return ENOMEM;
+	}
+
+	const int ret = async_data_write_start(exch, (void *) endpoint_desc,
+		sizeof(usb_endpoint_desc_t));
+
+	if (ret != EOK) {
+		async_forget(opening_request);
+		return ret;
+	}
+
+	/* Wait for the answer. */
+	sysarg_t opening_request_rc;
+	async_wait_for(opening_request, &opening_request_rc);
+
+	return (int) opening_request_rc;
+}
+
+int usb_unregister_endpoint(async_exch_t *exch,
+	usb_endpoint_desc_t *endpoint_desc)
+{
+	if (!exch)
+		return EBADMEM;
+
+	aid_t opening_request = async_send_1(exch,
+		DEV_IFACE_ID(USB_DEV_IFACE), IPC_M_USB_UNREGISTER_ENDPOINT, NULL);
+
+	if (opening_request == 0) {
+		return ENOMEM;
+	}
+
+	const int ret = async_data_write_start(exch, endpoint_desc,
+		sizeof(usb_endpoint_desc_t));
+	if (ret != EOK) {
+		async_forget(opening_request);
+		return ret;
+	}
+
+	/* Wait for the answer. */
+	sysarg_t opening_request_rc;
+	async_wait_for(opening_request, &opening_request_rc);
+
+	return (int) opening_request_rc;
 }
 
@@ -317,4 +346,10 @@
 };
 
+typedef struct {
+	ipc_callid_t caller;
+	ipc_callid_t data_caller;
+	void *buffer;
+} async_transaction_t;
+
 void remote_usb_get_my_interface(ddf_fun_t *fun, void *iface,
     ipc_callid_t callid, ipc_call_t *call)
@@ -417,5 +452,9 @@
     ipc_callid_t callid, ipc_call_t *call)
 {
-	usb_iface_t *usb_iface = (usb_iface_t *) iface;
+	assert(fun);
+	assert(iface);
+	assert(call);
+
+	const usb_iface_t *usb_iface = iface;
 
 	if (!usb_iface->register_endpoint) {
@@ -424,17 +463,20 @@
 	}
 
-	const usb_endpoint_t endpoint = DEV_IPC_GET_ARG1(*call);
-	const pack8_t pack = { .arg = DEV_IPC_GET_ARG2(*call)};
-	const size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
-
-	const usb_transfer_type_t transfer_type = pack.arr[0];
-	const usb_direction_t direction = pack.arr[1];
-	unsigned packets = pack.arr[2];
-	unsigned interval = pack.arr[3];
-
-	const int ret = usb_iface->register_endpoint(fun, endpoint,
-	    transfer_type, direction, max_packet_size, packets, interval);
-
-	async_answer_0(callid, ret);
+	void *buffer = NULL;
+	size_t size = 0;
+	int rc = async_data_write_accept(&buffer, false,
+		sizeof(usb_endpoint_desc_t), sizeof(usb_endpoint_desc_t), 0, &size);
+
+	if (rc != EOK) {
+		free(buffer);
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	usb_endpoint_desc_t *endpoint_desc = (usb_endpoint_desc_t *) buffer;
+	rc = usb_iface->register_endpoint(fun, endpoint_desc);
+
+	free(buffer);
+	async_answer_0(callid, rc);
 }
 
@@ -442,5 +484,9 @@
     ipc_callid_t callid, ipc_call_t *call)
 {
-	usb_iface_t *usb_iface = (usb_iface_t *) iface;
+	assert(fun);
+	assert(iface);
+	assert(call);
+
+	const usb_iface_t *usb_iface = iface;
 
 	if (!usb_iface->unregister_endpoint) {
@@ -449,17 +495,23 @@
 	}
 
-	usb_endpoint_t endpoint = (usb_endpoint_t) DEV_IPC_GET_ARG1(*call);
-	usb_direction_t direction = (usb_direction_t) DEV_IPC_GET_ARG2(*call);
-
-	int rc = usb_iface->unregister_endpoint(fun, endpoint, direction);
-
-	async_answer_0(callid, rc);
-}
-
-typedef struct {
-	ipc_callid_t caller;
-	ipc_callid_t data_caller;
-	void *buffer;
-} async_transaction_t;
+	void *buffer = NULL;
+	size_t size = 0;
+	int rc = async_data_write_accept(&buffer, false,
+		sizeof(usb_endpoint_desc_t), sizeof(usb_endpoint_desc_t), 0, &size);
+
+	if (rc != EOK) {
+		free(buffer);
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	usb_endpoint_desc_t *endpoint_desc = (usb_endpoint_desc_t *) buffer;
+	usb_iface->unregister_endpoint(fun, endpoint_desc);
+
+	free(buffer);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+	}
+}
 
 static void async_transaction_destroy(async_transaction_t *trans)
Index: uspace/lib/drv/include/usb_iface.h
===================================================================
--- uspace/lib/drv/include/usb_iface.h	(revision 04649677bb4fbe5c0b699c27add4f8664d9a15fc)
+++ uspace/lib/drv/include/usb_iface.h	(revision f45c78f205c41f1c67dfb0cfec097c87e866c376)
@@ -57,8 +57,6 @@
 extern int usb_device_remove(async_exch_t *, unsigned port);
 
-extern int usb_register_endpoint(async_exch_t *, usb_endpoint_t,
-    usb_transfer_type_t, usb_direction_t, size_t, unsigned, unsigned);
-extern int usb_unregister_endpoint(async_exch_t *, usb_endpoint_t,
-    usb_direction_t);
+extern int usb_register_endpoint(async_exch_t *, usb_endpoint_desc_t *);
+extern int usb_unregister_endpoint(async_exch_t *, usb_endpoint_desc_t *);
 extern int usb_read(async_exch_t *, usb_endpoint_t, uint64_t, void *, size_t,
     size_t *);
@@ -83,8 +81,6 @@
 	int (*device_remove)(ddf_fun_t *, unsigned);
 
-	int (*register_endpoint)(ddf_fun_t *, usb_endpoint_t,
-	    usb_transfer_type_t, usb_direction_t, size_t, unsigned, unsigned);
-	int (*unregister_endpoint)(ddf_fun_t *, usb_endpoint_t,
-	    usb_direction_t);
+	int (*register_endpoint)(ddf_fun_t *, usb_endpoint_desc_t *);
+	int (*unregister_endpoint)(ddf_fun_t *, usb_endpoint_desc_t *);
 
 	int (*read)(ddf_fun_t *, usb_endpoint_t, uint64_t, uint8_t *, size_t,
Index: uspace/lib/pcm/src/format.c
===================================================================
--- uspace/lib/pcm/src/format.c	(revision 04649677bb4fbe5c0b699c27add4f8664d9a15fc)
+++ uspace/lib/pcm/src/format.c	(revision f45c78f205c41f1c67dfb0cfec097c87e866c376)
@@ -41,9 +41,4 @@
 
 #include "format.h"
-
-#define uint8_t_le2host(x) (x)
-#define host2uint8_t_le(x) (x)
-#define uint8_t_be2host(x) (x)
-#define host2uint8_t_be(x) (x)
 
 #define int8_t_le2host(x) (x)
Index: uspace/lib/usb/include/usb/descriptor.h
===================================================================
--- uspace/lib/usb/include/usb/descriptor.h	(revision 04649677bb4fbe5c0b699c27add4f8664d9a15fc)
+++ uspace/lib/usb/include/usb/descriptor.h	(revision f45c78f205c41f1c67dfb0cfec097c87e866c376)
@@ -49,4 +49,10 @@
 	USB_DESCTYPE_OTHER_SPEED_CONFIGURATION = 7,
 	USB_DESCTYPE_INTERFACE_POWER = 8,
+	/* USB 3.0 types */
+	USB_DESCTYPE_OTG = 9,
+	USB_DESCTYPE_DEBUG = 0xa,
+	USB_DESCTYPE_IFACE_ASSOC = 0xb,
+	USB_DESCTYPE_BOS = 0xf,
+	USB_DESCTYPE_DEVICE_CAP = 0x10,
 	/* Class specific */
 	USB_DESCTYPE_HID = 0x21,
@@ -54,4 +60,5 @@
 	USB_DESCTYPE_HID_PHYSICAL = 0x23,
 	USB_DESCTYPE_HUB = 0x29,
+	USB_DESCTYPE_SSPEED_EP_COMPANION = 0x30
 	/* USB_DESCTYPE_ = */
 } usb_descriptor_type_t;
@@ -217,4 +224,32 @@
 } __attribute__ ((packed)) usb_standard_endpoint_descriptor_t;
 
+/** Superspeed USB endpoint companion descriptor.
+ * See USB 3 specification, section 9.6.7.
+ */
+typedef struct {
+	/** Size of this descriptor in bytes */
+	uint8_t length;
+	/** Descriptor type (USB_DESCTYPE_SSPEED_EP_COMPANION). */
+	uint8_t descriptor_type;
+	/** The maximum number of packets the endpoint can send
+	 * or receive as part of a burst. Valid values are from 0 to 15.
+	 * The endpoint can only burst max_burst + 1 packets at a time.
+	 */
+	uint8_t max_burst;
+	/** Valid only for bulk and isochronous endpoints.
+	 * For bulk endpoints, this field contains the amount of streams
+	 * supported by the endpoint.
+	 * For isochronous endpoints, this field contains either maximum
+	 * number of packets supported within a service interval, or
+	 * whether an isochronous endpoint companion descriptor follows.
+	 */
+	uint8_t attributes;
+	/** The total number of bytes this endpoint will transfer
+	 * every service interval (SI).
+	 * This field is only valid for periodic endpoints.
+	 */
+	uint16_t bytes_per_interval;
+} __attribute__ ((packed)) usb_superspeed_endpoint_companion_descriptor_t;
+
 /** Part of standard USB HID descriptor specifying one class descriptor.
  *
Index: uspace/lib/usb/include/usb/request.h
===================================================================
--- uspace/lib/usb/include/usb/request.h	(revision 04649677bb4fbe5c0b699c27add4f8664d9a15fc)
+++ uspace/lib/usb/include/usb/request.h	(revision f45c78f205c41f1c67dfb0cfec097c87e866c376)
@@ -112,4 +112,28 @@
     const usb_device_request_setup_packet_t *request);
 
+#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), \
+};
+
+#define CTRL_PIPE_MIN_PACKET_SIZE 8
+
 #endif
 /**
Index: uspace/lib/usb/include/usb/usb.h
===================================================================
--- uspace/lib/usb/include/usb/usb.h	(revision 04649677bb4fbe5c0b699c27add4f8664d9a15fc)
+++ uspace/lib/usb/include/usb/usb.h	(revision f45c78f205c41f1c67dfb0cfec097c87e866c376)
@@ -81,4 +81,6 @@
 	/** USB 2.0 high speed (480Mbits/s). */
 	USB_SPEED_HIGH,
+	/** USB 3.0 super speed (5Gbits/s). */
+	USB_SPEED_SUPER,
 	/** Psuedo-speed serving as a boundary. */
 	USB_SPEED_MAX
@@ -113,4 +115,9 @@
 typedef int16_t usb_address_t;
 
+typedef struct {
+	usb_address_t address;
+	unsigned port;
+} usb_tt_address_t;
+
 /** Default USB address. */
 #define USB_ADDRESS_DEFAULT 0
@@ -157,5 +164,5 @@
 
 
-/** USB complete address type. 
+/** USB complete address type.
  * Pair address + endpoint is identification of transaction recipient.
  */
@@ -167,4 +174,28 @@
 	uint32_t packed;
 } usb_target_t;
+
+/** Description of usb endpoint.
+ */
+typedef struct {
+	/** Endpoint number. */
+	usb_endpoint_t endpoint_no;
+
+	/** Endpoint transfer type. */
+	usb_transfer_type_t transfer_type;
+
+	/** Endpoint direction. */
+	usb_direction_t direction;
+
+	/** Maximum packet size for the endpoint. */
+	size_t max_packet_size;
+
+	/** Number of packets per frame/uframe.
+	 * Only valid for HS INT and ISO transfers. All others should set to 1*/
+	unsigned packets;
+
+	struct {
+		unsigned polling_interval;
+	} usb2;
+} usb_endpoint_desc_t;
 
 /** Check USB target for allowed values (address and endpoint).
Index: uspace/lib/usb/src/usb.c
===================================================================
--- uspace/lib/usb/src/usb.c	(revision 04649677bb4fbe5c0b699c27add4f8664d9a15fc)
+++ uspace/lib/usb/src/usb.c	(revision f45c78f205c41f1c67dfb0cfec097c87e866c376)
@@ -44,4 +44,5 @@
 	[USB_SPEED_FULL] = "full",
 	[USB_SPEED_HIGH] = "high",
+	[USB_SPEED_SUPER] = "super",
 };
 
Index: uspace/lib/usbdev/include/usb/dev/pipes.h
===================================================================
--- uspace/lib/usbdev/include/usb/dev/pipes.h	(revision 04649677bb4fbe5c0b699c27add4f8664d9a15fc)
+++ uspace/lib/usbdev/include/usb/dev/pipes.h	(revision f45c78f205c41f1c67dfb0cfec097c87e866c376)
@@ -50,25 +50,10 @@
  */
 typedef struct {
-	/** Endpoint number. */
-	usb_endpoint_t endpoint_no;
-
-	/** Endpoint transfer type. */
-	usb_transfer_type_t transfer_type;
-
-	/** Endpoint direction. */
-	usb_direction_t direction;
-
-	/** Maximum packet size for the endpoint. */
-	size_t max_packet_size;
-
-	/** Number of packets per frame/uframe.
-	 * Only valid for HS INT and ISO transfers. All others should set to 1*/
-	unsigned packets;
-
+	/** Endpoint description */
+	usb_endpoint_desc_t desc;
 	/** Whether to automatically reset halt on the endpoint.
 	 * Valid only for control endpoint zero.
 	 */
 	bool auto_reset_halt;
-
 	/** The connection used for sending the data. */
 	usb_dev_session_t *bus_session;
Index: uspace/lib/usbdev/src/devdrv.c
===================================================================
--- uspace/lib/usbdev/src/devdrv.c	(revision 04649677bb4fbe5c0b699c27add4f8664d9a15fc)
+++ uspace/lib/usbdev/src/devdrv.c	(revision f45c78f205c41f1c67dfb0cfec097c87e866c376)
@@ -56,11 +56,11 @@
 	/** Connection to device on USB bus */
 	usb_dev_session_t *bus_session;
-	
+
 	/** devman handle */
 	devman_handle_t handle;
-	
+
 	/** The default control pipe. */
 	usb_pipe_t ctrl_pipe;
-	
+
 	/** Other endpoint pipes.
 	 *
@@ -69,8 +69,8 @@
 	 */
 	usb_endpoint_mapping_t *pipes;
-	
+
 	/** Number of other endpoint pipes. */
 	size_t pipes_count;
-	
+
 	/** Current interface.
 	 *
@@ -79,14 +79,14 @@
 	 */
 	int interface_no;
-	
+
 	/** Alternative interfaces. */
 	usb_alternate_interfaces_t alternate_interfaces;
-	
+
 	/** Some useful descriptors for USB device. */
 	usb_device_descriptors_t descriptors;
-	
+
 	/** Generic DDF device backing this one. DO NOT TOUCH! */
 	ddf_dev_t *ddf_dev;
-	
+
 	/** Custom driver data.
 	 *
@@ -146,5 +146,5 @@
 		return rc;
 	}
-	
+
 	/* Change current alternative */
 	usb_dev->alternate_interfaces.current = alternate_setting;
@@ -296,5 +296,5 @@
 	assert(usb_dev);
 	assert(usb_dev->pipes || usb_dev->pipes_count == 0);
-	
+
 	/* Destroy the pipes. */
 	for (size_t i = 0; i < usb_dev->pipes_count; ++i) {
@@ -304,5 +304,5 @@
 			usb_pipe_unregister(&usb_dev->pipes[i].pipe);
 	}
-	
+
 	free(usb_dev->pipes);
 	usb_dev->pipes = NULL;
@@ -332,5 +332,5 @@
 	assert(usb_dev);
 	for (unsigned i = 0; i < usb_dev->pipes_count; ++i) {
-		if (usb_dev->pipes[i].pipe.endpoint_no == ep)
+		if (usb_dev->pipes[i].pipe.desc.endpoint_no == ep)
 			return &usb_dev->pipes[i];
 	}
@@ -462,9 +462,9 @@
 	assert(handle);
 	assert(iface_no);
-	
+
 	async_exch_t *exch = async_exchange_begin(sess);
 	if (!exch)
 		return EPARTY;
-	
+
 	int ret = usb_get_my_device_handle(exch, handle);
 	if (ret == EOK) {
@@ -475,5 +475,5 @@
 		}
 	}
-	
+
 	async_exchange_end(exch);
 	return ret;
@@ -502,5 +502,5 @@
 		return ENOMEM;
 	}
-	
+
 	return usb_device_init(usb_dev, ddf_dev, desc, err, h, iface_no);
 }
Index: uspace/lib/usbdev/src/devpoll.c
===================================================================
--- uspace/lib/usbdev/src/devpoll.c	(revision 04649677bb4fbe5c0b699c27add4f8664d9a15fc)
+++ uspace/lib/usbdev/src/devpoll.c	(revision f45c78f205c41f1c67dfb0cfec097c87e866c376)
@@ -96,5 +96,5 @@
 		    (int) mapping->interface->interface_subclass,
 		    (int) mapping->interface->interface_protocol,
-		    data->request_size, pipe->max_packet_size);
+		    data->request_size, pipe->desc.max_packet_size);
 	}
 
@@ -128,5 +128,5 @@
 			usb_request_clear_endpoint_halt(
 			    usb_device_get_default_pipe(data->dev),
-			    pipe->endpoint_no);
+			    pipe->desc.endpoint_no);
 		}
 
@@ -156,5 +156,5 @@
 
 		/* Take a rest before next request. */
-		
+
 		// FIXME TODO: This is broken, the time is in ms not us.
 		// but first we need to fix drivers to actually stop using this,
@@ -216,9 +216,9 @@
 	if (request_size == 0)
 		return EINVAL;
-	
-	if (!epm || (epm->pipe.transfer_type != USB_TRANSFER_INTERRUPT) ||
-	    (epm->pipe.direction != USB_DIRECTION_IN))
+
+	if (!epm || (epm->pipe.desc.transfer_type != USB_TRANSFER_INTERRUPT) ||
+	    (epm->pipe.desc.direction != USB_DIRECTION_IN))
 		return EINVAL;
-	
+
 
 	polling_data_t *polling_data = malloc(sizeof(polling_data_t));
Index: uspace/lib/usbdev/src/pipes.c
===================================================================
--- uspace/lib/usbdev/src/pipes.c	(revision 04649677bb4fbe5c0b699c27add4f8664d9a15fc)
+++ uspace/lib/usbdev/src/pipes.c	(revision f45c78f205c41f1c67dfb0cfec097c87e866c376)
@@ -51,5 +51,5 @@
 	assert(pipe != NULL);
 
-	if (!pipe->auto_reset_halt || (pipe->endpoint_no != 0)) {
+	if (!pipe->auto_reset_halt || (pipe->desc.endpoint_no != 0)) {
 		return;
 	}
@@ -88,6 +88,6 @@
 	}
 
-	if ((pipe->direction != USB_DIRECTION_BOTH)
-	    || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
+	if ((pipe->desc.direction != USB_DIRECTION_BOTH)
+	    || (pipe->desc.transfer_type != USB_TRANSFER_CONTROL)) {
 		return EBADF;
 	}
@@ -98,5 +98,5 @@
 	async_exch_t *exch = async_exchange_begin(pipe->bus_session);
 	size_t act_size = 0;
-	const int rc = usb_read(exch, pipe->endpoint_no, setup_packet, buffer,
+	const int rc = usb_read(exch, pipe->desc.endpoint_no, setup_packet, buffer,
 	    buffer_size, &act_size);
 	async_exchange_end(exch);
@@ -142,6 +142,6 @@
 	}
 
-	if ((pipe->direction != USB_DIRECTION_BOTH)
-	    || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
+	if ((pipe->desc.direction != USB_DIRECTION_BOTH)
+	    || (pipe->desc.transfer_type != USB_TRANSFER_CONTROL)) {
 		return EBADF;
 	}
@@ -152,5 +152,5 @@
 	async_exch_t *exch = async_exchange_begin(pipe->bus_session);
 	const int rc = usb_write(exch,
-	    pipe->endpoint_no, setup_packet, buffer, buffer_size);
+	    pipe->desc.endpoint_no, setup_packet, buffer, buffer_size);
 	async_exchange_end(exch);
 
@@ -183,15 +183,15 @@
 	}
 
-	if (pipe->direction != USB_DIRECTION_IN) {
-		return EBADF;
-	}
-
-	if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
+	if (pipe->desc.direction != USB_DIRECTION_IN) {
+		return EBADF;
+	}
+
+	if (pipe->desc.transfer_type == USB_TRANSFER_CONTROL) {
 		return EBADF;
 	}
 
 	/* Isochronous transfer are not supported (yet) */
-	if (pipe->transfer_type != USB_TRANSFER_INTERRUPT &&
-	    pipe->transfer_type != USB_TRANSFER_BULK)
+	if (pipe->desc.transfer_type != USB_TRANSFER_INTERRUPT &&
+	    pipe->desc.transfer_type != USB_TRANSFER_BULK)
 	    return ENOTSUP;
 
@@ -199,5 +199,5 @@
 	size_t act_size = 0;
 	const int rc =
-	    usb_read(exch, pipe->endpoint_no, 0, buffer, size, &act_size);
+	    usb_read(exch, pipe->desc.endpoint_no, 0, buffer, size, &act_size);
 	async_exchange_end(exch);
 
@@ -224,19 +224,19 @@
 	}
 
-	if (pipe->direction != USB_DIRECTION_OUT) {
-		return EBADF;
-	}
-
-	if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
+	if (pipe->desc.direction != USB_DIRECTION_OUT) {
+		return EBADF;
+	}
+
+	if (pipe->desc.transfer_type == USB_TRANSFER_CONTROL) {
 		return EBADF;
 	}
 
 	/* Isochronous transfer are not supported (yet) */
-	if (pipe->transfer_type != USB_TRANSFER_INTERRUPT &&
-	    pipe->transfer_type != USB_TRANSFER_BULK)
+	if (pipe->desc.transfer_type != USB_TRANSFER_INTERRUPT &&
+	    pipe->desc.transfer_type != USB_TRANSFER_BULK)
 	    return ENOTSUP;
 
 	async_exch_t *exch = async_exchange_begin(pipe->bus_session);
-	const int rc = usb_write(exch, pipe->endpoint_no, 0, buffer, size);
+	const int rc = usb_write(exch, pipe->desc.endpoint_no, 0, buffer, size);
 	async_exchange_end(exch);
 	return rc;
@@ -258,9 +258,9 @@
 	assert(pipe);
 
-	pipe->endpoint_no = endpoint_no;
-	pipe->transfer_type = transfer_type;
-	pipe->packets = packets;
-	pipe->max_packet_size = max_packet_size;
-	pipe->direction = direction;
+	pipe->desc.endpoint_no = endpoint_no;
+	pipe->desc.transfer_type = transfer_type;
+	pipe->desc.packets = packets;
+	pipe->desc.max_packet_size = max_packet_size;
+	pipe->desc.direction = direction;
 	pipe->auto_reset_halt = false;
 	pipe->bus_session = bus_session;
@@ -297,10 +297,12 @@
 	assert(pipe);
 	assert(pipe->bus_session);
+
+	pipe->desc.usb2.polling_interval = interval;
 	async_exch_t *exch = async_exchange_begin(pipe->bus_session);
 	if (!exch)
 		return ENOMEM;
-	const int ret = usb_register_endpoint(exch, pipe->endpoint_no,
-	    pipe->transfer_type, pipe->direction, pipe->max_packet_size,
-	    pipe->packets, interval);
+
+	const int ret = usb_register_endpoint(exch, &pipe->desc);
+
 	async_exchange_end(exch);
 	return ret;
@@ -319,6 +321,7 @@
 	if (!exch)
 		return ENOMEM;
-	const int ret = usb_unregister_endpoint(exch, pipe->endpoint_no,
-	    pipe->direction);
+
+	const int ret = usb_unregister_endpoint(exch, &pipe->desc);
+
 	async_exchange_end(exch);
 	return ret;
Index: uspace/lib/usbdev/src/pipesinit.c
===================================================================
--- uspace/lib/usbdev/src/pipesinit.c	(revision 04649677bb4fbe5c0b699c27add4f8664d9a15fc)
+++ uspace/lib/usbdev/src/pipesinit.c	(revision f45c78f205c41f1c67dfb0cfec097c87e866c376)
@@ -288,5 +288,5 @@
 	if (config_descriptor == NULL)
 		return EBADMEM;
-	
+
 	if (config_descriptor_size <
 	    sizeof(usb_standard_configuration_descriptor_t)) {
@@ -343,7 +343,7 @@
 	static_assert(DEV_DESCR_MAX_PACKET_SIZE_OFFSET < CTRL_PIPE_MIN_PACKET_SIZE);
 
-	if ((pipe->direction != USB_DIRECTION_BOTH) ||
-	    (pipe->transfer_type != USB_TRANSFER_CONTROL) ||
-	    (pipe->endpoint_no != 0)) {
+	if ((pipe->desc.direction != USB_DIRECTION_BOTH) ||
+	    (pipe->desc.transfer_type != USB_TRANSFER_CONTROL) ||
+	    (pipe->desc.endpoint_no != 0)) {
 		return EINVAL;
 	}
@@ -369,5 +369,5 @@
 	}
 
-	pipe->max_packet_size
+	pipe->desc.max_packet_size
 	    = dev_descr_start[DEV_DESCR_MAX_PACKET_SIZE_OFFSET];
 
Index: uspace/lib/usbdev/src/request.c
===================================================================
--- uspace/lib/usbdev/src/request.c	(revision 04649677bb4fbe5c0b699c27add4f8664d9a15fc)
+++ uspace/lib/usbdev/src/request.c	(revision f45c78f205c41f1c67dfb0cfec097c87e866c376)
@@ -844,5 +844,5 @@
 	}
 	return usb_request_clear_endpoint_halt(ctrl_pipe,
-	    target_pipe->endpoint_no);
+	    target_pipe->desc.endpoint_no);
 }
 
@@ -858,5 +858,5 @@
 {
 	uint16_t status_tmp;
-	uint16_t pipe_index = (uint16_t) pipe->endpoint_no;
+	uint16_t pipe_index = (uint16_t) pipe->desc.endpoint_no;
 	int rc = usb_request_get_status(ctrl_pipe,
 	    USB_REQUEST_RECIPIENT_ENDPOINT, uint16_host2usb(pipe_index),
Index: uspace/lib/usbhost/Makefile
===================================================================
--- uspace/lib/usbhost/Makefile	(revision 04649677bb4fbe5c0b699c27add4f8664d9a15fc)
+++ uspace/lib/usbhost/Makefile	(revision f45c78f205c41f1c67dfb0cfec097c87e866c376)
@@ -39,5 +39,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 f45c78f205c41f1c67dfb0cfec097c87e866c376)
+++ uspace/lib/usbhost/include/usb/host/bandwidth.h	(revision f45c78f205c41f1c67dfb0cfec097c87e866c376)
@@ -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 f45c78f205c41f1c67dfb0cfec097c87e866c376)
+++ uspace/lib/usbhost/include/usb/host/bus.h	(revision f45c78f205c41f1c67dfb0cfec097c87e866c376)
@@ -0,0 +1,154 @@
+/*
+ * 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 enpoints, 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 <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 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 *);
+
+	endpoint_t *(*create_endpoint)(bus_t *);
+	int (*register_endpoint)(bus_t *, endpoint_t *);
+	int (*release_endpoint)(bus_t *, endpoint_t *);
+	endpoint_t *(*find_endpoint)(bus_t *, usb_target_t, usb_direction_t);
+
+	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, bool);
+
+	size_t (*count_bw) (endpoint_t *, size_t);
+
+	/* Endpoint ops, optional (have generic fallback) */
+	void (*destroy_endpoint)(endpoint_t *);
+	bool (*endpoint_get_toggle)(endpoint_t *);
+	void (*endpoint_set_toggle)(endpoint_t *, bool);
+} 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 *);
+
+extern int bus_add_ep(bus_t *bus, device_t *device, usb_endpoint_t endpoint,
+    usb_direction_t dir, usb_transfer_type_t type, size_t max_packet_size,
+    unsigned packets, size_t size);
+extern int bus_remove_ep(bus_t *bus, usb_target_t target, usb_direction_t dir);
+
+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 *);
+
+endpoint_t *bus_create_endpoint(bus_t *);
+int bus_register_endpoint(bus_t *, endpoint_t *);
+int bus_release_endpoint(bus_t *, endpoint_t *);
+endpoint_t *bus_find_endpoint(bus_t *, usb_target_t, usb_direction_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 04649677bb4fbe5c0b699c27add4f8664d9a15fc)
+++ uspace/lib/usbhost/include/usb/host/ddf_helpers.h	(revision f45c78f205c41f1c67dfb0cfec097c87e866c376)
@@ -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,44 @@
 #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 *);
 
 hcd_t *dev_to_hcd(ddf_dev_t *dev);
@@ -75,5 +93,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 04649677bb4fbe5c0b699c27add4f8664d9a15fc)
+++ uspace/lib/usbhost/include/usb/host/endpoint.h	(revision f45c78f205c41f1c67dfb0cfec097c87e866c376)
@@ -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,14 +46,19 @@
 #include <atomic.h>
 
+typedef struct bus bus_t;
+typedef struct device device_t;
+
 /** Host controller side endpoint structure. */
 typedef struct endpoint {
+	/** Managing bus */
+	bus_t *bus;
 	/** Reference count. */
-	atomic_t refcnt;	
+	atomic_t refcnt;
 	/** Part of linked list. */
 	link_t link;
+	/** USB device */
+	device_t *device;
 	/** USB address. */
-	usb_address_t address;
-	/** USB endpoint number. */
-	usb_endpoint_t endpoint;
+	usb_target_t target;
 	/** Communication direction. */
 	usb_direction_t direction;
@@ -62,41 +71,22 @@
 	/** 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;
+	bool active;
 	/** 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 *);
 
 extern void endpoint_use(endpoint_t *);
@@ -104,5 +94,5 @@
 
 extern int endpoint_toggle_get(endpoint_t *);
-extern void endpoint_toggle_set(endpoint_t *, int);
+extern void endpoint_toggle_set(endpoint_t *, unsigned);
 
 /** list_get_instance wrapper.
Index: uspace/lib/usbhost/include/usb/host/hcd.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/hcd.h	(revision 04649677bb4fbe5c0b699c27add4f8664d9a15fc)
+++ uspace/lib/usbhost/include/usb/host/hcd.h	(revision f45c78f205c41f1c67dfb0cfec097c87e866c376)
@@ -38,5 +38,5 @@
 
 #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>
@@ -50,20 +50,17 @@
 
 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 +68,5 @@
 struct hcd {
 	/** Endpoint manager. */
-	usb_bus_t bus;
+	bus_t *bus;
 
 	/** Interrupt replacement fibril */
@@ -78,12 +75,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 +89,5 @@
 		hcd->driver_data = data;
 		hcd->ops = *ops;
+		hcd->bus = bus;
 	} else {
 		memset(&hcd->ops, 0, sizeof(hcd->ops));
@@ -104,16 +103,6 @@
 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);
Index: uspace/lib/usbhost/include/usb/host/usb2_bus.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/usb2_bus.h	(revision f45c78f205c41f1c67dfb0cfec097c87e866c376)
+++ uspace/lib/usbhost/include/usb/host/usb2_bus.h	(revision f45c78f205c41f1c67dfb0cfec097c87e866c376)
@@ -0,0 +1,72 @@
+/*
+ * 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. */
+		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 04649677bb4fbe5c0b699c27add4f8664d9a15fc)
+++ 	(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 04649677bb4fbe5c0b699c27add4f8664d9a15fc)
+++ uspace/lib/usbhost/include/usb/host/usb_transfer_batch.h	(revision f45c78f205c41f1c67dfb0cfec097c87e866c376)
@@ -89,5 +89,5 @@
  */
 #define USB_TRANSFER_BATCH_ARGS(batch) \
-	(batch).ep->address, (batch).ep->endpoint, \
+	(batch).ep->target.address, (batch).ep->target.endpoint, \
 	usb_str_speed((batch).ep->speed), \
 	usb_str_transfer_type_short((batch).ep->transfer_type), \
Index: uspace/lib/usbhost/src/bandwidth.c
===================================================================
--- uspace/lib/usbhost/src/bandwidth.c	(revision f45c78f205c41f1c67dfb0cfec097c87e866c376)
+++ uspace/lib/usbhost/src/bandwidth.c	(revision f45c78f205c41f1c67dfb0cfec097c87e866c376)
@@ -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 f45c78f205c41f1c67dfb0cfec097c87e866c376)
+++ uspace/lib/usbhost/src/bus.c	(revision f45c78f205c41f1c67dfb0cfec097c87e866c376)
@@ -0,0 +1,268 @@
+/*
+ * 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 <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 bus_add_ep(bus_t *bus, device_t *device, usb_endpoint_t endpoint,
+    usb_direction_t dir, usb_transfer_type_t type, size_t max_packet_size,
+    unsigned packets, size_t size)
+{
+	assert(bus);
+	assert(device);
+
+	/* Temporary reference */
+	endpoint_t *ep = bus_create_endpoint(bus);
+	if (!ep)
+		return ENOMEM;
+
+	ep->target = (usb_target_t) {
+		.address = device->address,
+		.endpoint = endpoint,
+	};
+
+	ep->device = device;
+	ep->direction = dir;
+	ep->transfer_type = type;
+	ep->max_packet_size = max_packet_size;
+	ep->packets = packets;
+
+	ep->bandwidth = bus_count_bw(ep, size);
+
+	const int err = bus_register_endpoint(bus, ep);
+
+	/* drop Temporary reference */
+	endpoint_del_ref(ep);
+
+	return err;
+}
+
+int bus_remove_ep(bus_t *bus, usb_target_t target, usb_direction_t dir)
+{
+	assert(bus);
+	endpoint_t *ep = bus_find_endpoint(bus, target, dir);
+	if (!ep)
+		return ENOENT;
+
+	return bus_release_endpoint(bus, ep);
+}
+
+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;
+
+	fibril_mutex_lock(&bus->guard);
+	const int r = bus->ops.enumerate_device(bus, hcd, dev);
+	fibril_mutex_unlock(&bus->guard);
+	return r;
+}
+
+int bus_remove_device(bus_t *bus, hcd_t *hcd, device_t *dev)
+{
+	assert(bus);
+	assert(dev);
+
+	if (!bus->ops.remove_device)
+		return ENOTSUP;
+
+	fibril_mutex_lock(&bus->guard);
+	const int r = bus->ops.remove_device(bus, hcd, dev);
+	fibril_mutex_unlock(&bus->guard);
+	return r;
+}
+
+endpoint_t *bus_create_endpoint(bus_t *bus)
+{
+	assert(bus);
+
+	fibril_mutex_lock(&bus->guard);
+	endpoint_t *ep = bus->ops.create_endpoint(bus);
+	if (ep) {
+		/* Exporting reference */
+		endpoint_add_ref(ep);
+	}
+	fibril_mutex_unlock(&bus->guard);
+
+	return ep;
+}
+
+int bus_register_endpoint(bus_t *bus, endpoint_t *ep)
+{
+	assert(bus);
+	assert(ep);
+
+	/* Bus reference */
+	endpoint_add_ref(ep);
+
+	fibril_mutex_lock(&bus->guard);
+	const int r = bus->ops.register_endpoint(bus, ep);
+	fibril_mutex_unlock(&bus->guard);
+
+	return r;
+}
+
+int bus_release_endpoint(bus_t *bus, endpoint_t *ep)
+{
+	int err;
+
+	assert(bus);
+	assert(ep);
+
+	fibril_mutex_lock(&bus->guard);
+	if ((err = bus->ops.release_endpoint(bus, ep)))
+		return err;
+	fibril_mutex_unlock(&bus->guard);
+
+	/* Bus reference */
+	endpoint_del_ref(ep);
+
+	return EOK;
+}
+
+/** Searches for an endpoint. Returns a reference.
+ */
+endpoint_t *bus_find_endpoint(bus_t *bus, usb_target_t target, usb_direction_t dir)
+{
+	assert(bus);
+
+	fibril_mutex_lock(&bus->guard);
+	endpoint_t *ep = bus->ops.find_endpoint(bus, target, dir);
+	if (ep) {
+		/* Exporting reference */
+		endpoint_add_ref(ep);
+	}
+
+	fibril_mutex_unlock(&bus->guard);
+	return ep;
+}
+
+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 04649677bb4fbe5c0b699c27add4f8664d9a15fc)
+++ uspace/lib/usbhost/src/ddf_helpers.c	(revision f45c78f205c41f1c67dfb0cfec097c87e866c376)
@@ -35,4 +35,5 @@
 
 #include <usb/classes/classes.h>
+#include <usb/host/bus.h>
 #include <usb/debug.h>
 #include <usb/descriptor.h>
@@ -49,5 +50,4 @@
 #include <fibril_synch.h>
 #include <macros.h>
-#include <stdio.h>
 #include <stdlib.h>
 #include <str_error.h>
@@ -56,21 +56,7 @@
 #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 +77,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 +85,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(hcd->bus);
 	assert(dev);
-	const size_t size = max_packet_size;
-	const usb_target_t target =
-	    {{.address = dev->address, .endpoint = endpoint}};
+
+	const size_t size = endpoint_desc->max_packet_size;
 
 	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_ep(hcd->bus, dev, endpoint_desc->endpoint_no,
+		endpoint_desc->direction, endpoint_desc->transfer_type,
+		endpoint_desc->max_packet_size, endpoint_desc->packets,
+		size);
+}
+
+ /** 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(hcd->bus);
 	assert(dev);
-	const usb_target_t target =
-	    {{.address = dev->address, .endpoint = endpoint}};
+
+	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));
+	return bus_remove_ep(hcd->bus, target, endpoint_desc->direction);
 }
 
@@ -155,11 +142,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,29 +156,33 @@
 	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);
 }
 
 static int device_enumerate(ddf_fun_t *fun, unsigned port)
+{
+	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);
@@ -229,8 +221,8 @@
 {
 	assert(fun);
-	usb_dev_t *usb_dev = ddf_fun_data_get(fun);
-	assert(usb_dev);
+	device_t *dev = ddf_fun_data_get(fun);
+	assert(dev);
 	const usb_target_t target = {{
-	    .address =  usb_dev->address,
+	    .address  = dev->address,
 	    .endpoint = endpoint,
 	}};
@@ -255,8 +247,8 @@
 {
 	assert(fun);
-	usb_dev_t *usb_dev = ddf_fun_data_get(fun);
-	assert(usb_dev);
+	device_t *dev = ddf_fun_data_get(fun);
+	assert(dev);
 	const usb_target_t target = {{
-	    .address =  usb_dev->address,
+	    .address  = dev->address,
 	    .endpoint = endpoint,
 	}};
@@ -290,82 +282,4 @@
 
 /* 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 +308,5 @@
 	assert(l);
 	assert(d);
-	
+
 	if (d->vendor_id != 0) {
 		/* First, with release number. */
@@ -401,5 +315,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 +329,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 +338,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 +345,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 +354,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 +362,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 +375,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,
-		.endpoint = 0,
+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);
+
+	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 +421,74 @@
 
 	usb_log_debug("Device(%d): Requesting full device descriptor.",
-	    address);
-	got = hcd_send_batch_sync(hcd, target, USB_DIRECTION_IN,
+	    device->address);
+	ssize_t got = hcd_send_batch_sync(hcd, control_ep, USB_DIRECTION_IN,
 	    &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;
+}
+
+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 +498,49 @@
  * @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, USB_SPEED_MAX);
+	if (!dev) {
+		usb_log_error("Failed to create function for the root hub.");
+		goto err_default_address;
+	}
+
+	ddf_fun_set_name(dev->fun, "roothub");
+
+	dev->tt = (usb_tt_address_t) {
+		.address = -1,
+		.port = 0,
+	};
+
+	/* 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 +555,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 +564,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 +663,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 +674,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 +694,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 +761,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 +773,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 +798,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 +821,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 +832,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 +843,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 04649677bb4fbe5c0b699c27add4f8664d9a15fc)
+++ uspace/lib/usbhost/src/endpoint.c	(revision f45c78f205c41f1c67dfb0cfec097c87e866c376)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2011 Jan Vesely
+ * Copyright (c) 2017 Ondrej Hlavaty <aearsis@eideo.cz>
  * All rights reserved.
  *
@@ -35,157 +36,106 @@
 
 #include <usb/host/endpoint.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);
 
-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_use(endpoint_t *ep)
 {
-	assert(instance);
+	assert(ep);
 	/* 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);
+	endpoint_add_ref(ep);
+	fibril_mutex_lock(&ep->guard);
+	while (ep->active)
+		fibril_condvar_wait(&ep->avail, &ep->guard);
+	ep->active = true;
+	fibril_mutex_unlock(&ep->guard);
 }
 
 /** 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_release(endpoint_t *ep)
 {
-	assert(instance);
-	fibril_mutex_lock(&instance->guard);
-	instance->active = false;
-	fibril_mutex_unlock(&instance->guard);
-	fibril_condvar_signal(&instance->avail);
+	assert(ep);
+	fibril_mutex_lock(&ep->guard);
+	ep->active = false;
+	fibril_mutex_unlock(&ep->guard);
+	fibril_condvar_signal(&ep->avail);
 	/* Drop reference for active endpoint. */
-	endpoint_del_ref(instance);
+	endpoint_del_ref(ep);
 }
 
-/** Get 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.
  */
-int endpoint_toggle_get(endpoint_t *instance)
+int endpoint_toggle_get(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);
+	assert(ep);
+	fibril_mutex_lock(&ep->guard);
+	const int ret = ep->bus->ops.endpoint_get_toggle
+	    ? ep->bus->ops.endpoint_get_toggle(ep)
+	    : ep->toggle;
+	fibril_mutex_unlock(&ep->guard);
 	return ret;
 }
 
-/** Set the value of toggle bit.
- * @param instance endpoint_t structure.
- * @note Will use provided hook.
+/** 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 *instance, int toggle)
+void endpoint_toggle_set(endpoint_t *ep, unsigned toggle)
 {
-	assert(instance);
+	assert(ep);
 	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);
+	fibril_mutex_lock(&ep->guard);
+	if (ep->bus->ops.endpoint_set_toggle) {
+		ep->bus->ops.endpoint_set_toggle(ep, toggle);
+	}
+	else {
+		ep->toggle = toggle;
+	}
+	fibril_mutex_unlock(&ep->guard);
 }
+
 
 /**
Index: uspace/lib/usbhost/src/hcd.c
===================================================================
--- uspace/lib/usbhost/src/hcd.c	(revision 04649677bb4fbe5c0b699c27add4f8664d9a15fc)
+++ uspace/lib/usbhost/src/hcd.c	(revision f45c78f205c41f1c67dfb0cfec097c87e866c376)
@@ -44,44 +44,4 @@
 #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);
-}
-
 
 /** Initialize hcd_t structure.
@@ -93,11 +53,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)
-{
-	assert(hcd);
-	usb_bus_init(&hcd->bus, bandwidth, bw_count, max_speed);
-
-	hcd_set_implementation(hcd, NULL, NULL);
+void hcd_init(hcd_t *hcd) {
+	assert(hcd);
+
+	hcd_set_implementation(hcd, NULL, NULL, NULL);
 }
 
@@ -106,42 +63,9 @@
 	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;
 	return address;
 }
-
-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 {
@@ -159,5 +83,5 @@
 		usb_log_debug2("Reseting toggle on %d:%d.\n",
 		    toggle->target.address, toggle->target.endpoint);
-		usb_bus_reset_toggle(&toggle->hcd->bus,
+		bus_reset_toggle(toggle->hcd->bus,
 		    toggle->target, toggle->target.endpoint == 0);
 	}
@@ -185,6 +109,5 @@
 	assert(hcd);
 
-	endpoint_t *ep = usb_bus_find_ep(&hcd->bus,
-	    target.address, target.endpoint, direction);
+	endpoint_t *ep = bus_find_endpoint(hcd->bus, target, direction);
 	if (ep == NULL) {
 		usb_log_error("Endpoint(%d:%d) not registered for %s.\n",
@@ -196,11 +119,10 @@
 	    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);
+	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",
-		    ep->address, ep->endpoint, name, bw, ep->bandwidth);
+		    ep->target.address, ep->target.endpoint, name, bw, ep->bandwidth);
 		return ENOSPC;
 	}
@@ -248,5 +170,7 @@
 
 typedef struct {
-	volatile unsigned done;
+	fibril_mutex_t done_mtx;
+	fibril_condvar_t done_cv;
+	unsigned done;
 	int ret;
 	size_t size;
@@ -258,6 +182,9 @@
 	assert(d);
 	d->ret = ret;
+	d->size = size;
+	fibril_mutex_lock(&d->done_mtx);
 	d->done = 1;
-	d->size = size;
+	fibril_condvar_broadcast(&d->done_cv);
+	fibril_mutex_unlock(&d->done_mtx);
 }
 
@@ -267,5 +194,8 @@
 	assert(data);
 	d->ret = ret;
+	fibril_mutex_lock(&d->done_mtx);
 	d->done = 1;
+	fibril_condvar_broadcast(&d->done_cv);
+	fibril_mutex_unlock(&d->done_mtx);
 }
 
@@ -277,4 +207,6 @@
 	assert(hcd);
 	sync_data_t sd = { .done = 0, .ret = EBUSY, .size = size };
+	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,
@@ -284,7 +216,8 @@
 		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)
Index: uspace/lib/usbhost/src/usb2_bus.c
===================================================================
--- uspace/lib/usbhost/src/usb2_bus.c	(revision f45c78f205c41f1c67dfb0cfec097c87e866c376)
+++ uspace/lib/usbhost/src/usb2_bus.c	(revision f45c78f205c41f1c67dfb0cfec097c87e866c376)
@@ -0,0 +1,452 @@
+/*
+ * 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 int usb2_bus_address_device(bus_t *bus, hcd_t *hcd, device_t *dev)
+{
+	int err;
+
+	static const usb_target_t default_target = {{
+		.address = USB_ADDRESS_DEFAULT,
+		.endpoint = 0,
+	}};
+
+	/** Reserve address early, we want pretty log messages */
+	const usb_address_t address = bus_reserve_default_address(bus, dev->speed);
+	if (address < 0) {
+		usb_log_error("Failed to reserve new address: %s.",
+		    str_error(address));
+		return address;
+	}
+	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);
+	err = bus_add_ep(bus, dev, 0, USB_DIRECTION_BOTH, USB_TRANSFER_CONTROL,
+	    CTRL_PIPE_MIN_PACKET_SIZE, CTRL_PIPE_MIN_PACKET_SIZE, 1);
+	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, 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) {
+		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_target;
+	}
+
+	/* 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, 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_target;
+	}
+
+	dev->address = address;
+
+	/* Register EP on the new address */
+	usb_log_debug("Device(%d): Registering control EP.", address);
+	err = bus_add_ep(bus, dev, 0, 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)));
+	if (err != EOK) {
+		usb_log_error("Device(%d): Failed to register EP0: %s",
+		    address, str_error(err));
+		goto err_default_target;
+	}
+
+	bus_remove_ep(bus, default_target, USB_DIRECTION_BOTH);
+	return EOK;
+
+err_default_target:
+	bus_remove_ep(bus, default_target, USB_DIRECTION_BOTH);
+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));
+
+	/* 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;
+	}
+
+	/* 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, usb_target_t target, usb_direction_t direction)
+{
+	usb2_bus_t *bus = bus_to_usb2_bus(bus_base);
+
+	if (!usb_address_is_valid(target.address))
+		return NULL;
+
+	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.packed == ep->target.packed))
+			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;
+}
+
+/** 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, endpoint_t *ep)
+{
+	usb2_bus_t *bus = bus_to_usb2_bus(bus_base);
+	assert(ep);
+
+	usb_address_t address = ep->target.address;
+
+	if (!usb_address_is_valid(address))
+		return EINVAL;
+
+	/* Check for speed and address */
+	if (!bus->devices[address].occupied)
+		return ENOENT;
+
+	/* Check for existence */
+	if (usb2_bus_find_ep(bus_base, ep->target, ep->direction))
+		return EEXIST;
+
+	/* Check for available bandwidth */
+	if (ep->bandwidth > bus->free_bw)
+		return ENOSPC;
+
+	list_append(&ep->link, get_list(bus, ep->target.address));
+	bus->free_bw -= ep->bandwidth;
+
+	return EOK;
+}
+
+
+/** Release bandwidth reserved by the given endpoint.
+ */
+static int usb2_bus_release_ep(bus_t *bus_base, endpoint_t *ep)
+{
+	usb2_bus_t *bus = bus_to_usb2_bus(bus_base);
+	assert(ep);
+
+	bus->free_bw += ep->bandwidth;
+
+	return EOK;
+}
+
+static int usb2_bus_reset_toggle(bus_t *bus_base, usb_target_t target, bool all)
+{
+	usb2_bus_t *bus = bus_to_usb2_bus(bus_base);
+
+	if (!usb_target_is_valid(target))
+		return EINVAL;
+
+	int ret = ENOENT;
+
+	list_foreach(*get_list(bus, target.address), link, endpoint_t, ep) {
+		if ((ep->target.address == target.address)
+		    && (all || ep->target.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->target.address == address);
+		list_remove(&ep->link);
+
+		usb_log_warning("Endpoint %d:%d %s was left behind, removing.\n",
+		    ep->target.address, ep->target.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,
+	.release_endpoint = usb2_bus_release_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 04649677bb4fbe5c0b699c27add4f8664d9a15fc)
+++ 	(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;
-}
-/**
- * @}
- */
