Index: uspace/drv/bus/usb/ehci/main.c
===================================================================
--- uspace/drv/bus/usb/ehci/main.c	(revision 861b5d6f1de4d4c071b00ff016eeb5fdba73d042)
+++ uspace/drv/bus/usb/ehci/main.c	(revision 944f8fdd006b2359954cee16ede3ed01c2d88b24)
@@ -37,5 +37,5 @@
 #include <io/logctl.h>
 #include <usb/host/hcd.h>
-#include <usb/host/ddf_helpers.h>
+#include <usb/host/utility.h>
 
 #include "res.h"
@@ -52,5 +52,5 @@
 	.claim = disable_legacy,
 	.start = hc_start,
-	.setup_root_hub = hcd_setup_virtual_root_hub,
+	.setup_root_hub = hc_setup_virtual_root_hub,
 	.hc_gone = hc_gone,
 };
Index: uspace/drv/bus/usb/ohci/main.c
===================================================================
--- uspace/drv/bus/usb/ohci/main.c	(revision 861b5d6f1de4d4c071b00ff016eeb5fdba73d042)
+++ uspace/drv/bus/usb/ohci/main.c	(revision 944f8fdd006b2359954cee16ede3ed01c2d88b24)
@@ -43,5 +43,5 @@
 
 #include <usb/debug.h>
-#include <usb/host/ddf_helpers.h>
+#include <usb/host/utility.h>
 
 #include "hc.h"
@@ -58,5 +58,5 @@
 	.claim = hc_gain_control,
 	.start = hc_start,
-	.setup_root_hub = hcd_setup_virtual_root_hub,
+	.setup_root_hub = hc_setup_virtual_root_hub,
 	.hc_gone = hc_gone,
 };
Index: uspace/drv/bus/usb/uhci/main.c
===================================================================
--- uspace/drv/bus/usb/uhci/main.c	(revision 861b5d6f1de4d4c071b00ff016eeb5fdba73d042)
+++ uspace/drv/bus/usb/uhci/main.c	(revision 944f8fdd006b2359954cee16ede3ed01c2d88b24)
@@ -43,5 +43,5 @@
 #include <str_error.h>
 #include <usb/debug.h>
-#include <usb/host/ddf_helpers.h>
+#include <usb/host/utility.h>
 
 #include "hc.h"
@@ -58,5 +58,5 @@
 	.hc_add = hc_add,
 	.start = hc_start,
-	.setup_root_hub = hcd_setup_virtual_root_hub,
+	.setup_root_hub = hc_setup_virtual_root_hub,
 	.hc_gone = hc_gone,
 };
Index: uspace/drv/bus/usb/vhc/main.c
===================================================================
--- uspace/drv/bus/usb/vhc/main.c	(revision 861b5d6f1de4d4c071b00ff016eeb5fdba73d042)
+++ uspace/drv/bus/usb/vhc/main.c	(revision 944f8fdd006b2359954cee16ede3ed01c2d88b24)
@@ -40,4 +40,5 @@
 
 #include <usb/host/ddf_helpers.h>
+#include <usb/host/utility.h>
 
 #include <usb/debug.h>
@@ -106,5 +107,5 @@
 	 * needs to be ready at this time.
 	 */
-	ret = hcd_setup_virtual_root_hub(&vhc->base);
+	ret = hc_setup_virtual_root_hub(&vhc->base);
 	if (ret != EOK) {
 		usb_log_error("Failed to init VHC root hub: %s",
Index: uspace/drv/bus/usb/xhci/bus.c
===================================================================
--- uspace/drv/bus/usb/xhci/bus.c	(revision 861b5d6f1de4d4c071b00ff016eeb5fdba73d042)
+++ uspace/drv/bus/usb/xhci/bus.c	(revision 944f8fdd006b2359954cee16ede3ed01c2d88b24)
@@ -36,4 +36,5 @@
 #include <usb/host/endpoint.h>
 #include <usb/host/hcd.h>
+#include <usb/host/utility.h>
 #include <usb/descriptor.h>
 #include <usb/debug.h>
@@ -113,5 +114,5 @@
 
 	uint16_t max_packet_size;
-	if ((err = hcd_get_ep0_max_packet_size(&max_packet_size, (bus_t *) &hc->bus, &dev->base)))
+	if ((err = hc_get_ep0_max_packet_size(&max_packet_size, (bus_t *) &hc->bus, &dev->base)))
 		return err;
 
@@ -184,5 +185,5 @@
 
 	/* Read the device descriptor, derive the match ids */
-	if ((err = hcd_device_explore(dev))) {
+	if ((err = hc_device_explore(dev))) {
 		usb_log_error("Device(%d): Failed to explore device: %s", dev->address, str_error(err));
 		goto err_address;
Index: uspace/lib/usbhost/Makefile
===================================================================
--- uspace/lib/usbhost/Makefile	(revision 861b5d6f1de4d4c071b00ff016eeb5fdba73d042)
+++ uspace/lib/usbhost/Makefile	(revision 944f8fdd006b2359954cee16ede3ed01c2d88b24)
@@ -41,4 +41,5 @@
 	src/bandwidth.c \
 	src/dma_buffer.c \
+	src/utility.c \
 	src/usb_transfer_batch.c
 
Index: uspace/lib/usbhost/include/usb/host/ddf_helpers.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/ddf_helpers.h	(revision 861b5d6f1de4d4c071b00ff016eeb5fdba73d042)
+++ uspace/lib/usbhost/include/usb/host/ddf_helpers.h	(revision 944f8fdd006b2359954cee16ede3ed01c2d88b24)
@@ -48,12 +48,9 @@
 void hcd_ddf_clean_hc(hc_device_t *);
 
-int hcd_setup_virtual_root_hub(hc_device_t *);
 
 device_t *hcd_ddf_fun_create(hc_device_t *, usb_speed_t);
 void hcd_ddf_fun_destroy(device_t *);
 
-int hcd_get_device_desc(device_t *, usb_standard_device_descriptor_t *);
-int hcd_setup_match_ids(device_t *, usb_standard_device_descriptor_t *);
-int hcd_device_explore(device_t *);
+int hcd_ddf_setup_match_ids(device_t *, usb_standard_device_descriptor_t *);
 
 int hcd_ddf_enable_interrupt(hc_device_t *hcd, int);
Index: uspace/lib/usbhost/include/usb/host/hcd.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/hcd.h	(revision 861b5d6f1de4d4c071b00ff016eeb5fdba73d042)
+++ uspace/lib/usbhost/include/usb/host/hcd.h	(revision 944f8fdd006b2359954cee16ede3ed01c2d88b24)
@@ -110,19 +110,4 @@
 int hc_driver_main(const hc_driver_t *);
 
-/* TODO: These are a kind of utility functions, they should probably go
- * somewhere else.
- */
-extern int hcd_get_ep0_max_packet_size(uint16_t *, bus_t *, device_t *);
-
-/** How many toggles need to be reset */
-typedef enum {
-	RESET_NONE,
-	RESET_EP,
-	RESET_ALL
-} toggle_reset_mode_t;
-
-extern toggle_reset_mode_t hcd_get_request_toggle_reset_mode(
-    const usb_device_request_setup_packet_t *request);
-
 #endif
 
Index: uspace/lib/usbhost/include/usb/host/usb_transfer_batch.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/usb_transfer_batch.h	(revision 861b5d6f1de4d4c071b00ff016eeb5fdba73d042)
+++ uspace/lib/usbhost/include/usb/host/usb_transfer_batch.h	(revision 944f8fdd006b2359954cee16ede3ed01c2d88b24)
@@ -51,4 +51,11 @@
 typedef struct endpoint endpoint_t;
 typedef struct bus bus_t;
+
+/** How many toggles need to be reset */
+typedef enum {
+	RESET_NONE,
+	RESET_EP,
+	RESET_ALL
+} toggle_reset_mode_t;
 
 /** Structure stores additional data needed for communication with EP */
Index: uspace/lib/usbhost/include/usb/host/utility.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/utility.h	(revision 944f8fdd006b2359954cee16ede3ed01c2d88b24)
+++ uspace/lib/usbhost/include/usb/host/utility.h	(revision 944f8fdd006b2359954cee16ede3ed01c2d88b24)
@@ -0,0 +1,54 @@
+/*
+ * 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 drvusbehci
+ * @{
+ */
+/** @file
+ * @brief USB host controller library: Utility functions.
+ *
+ * A mix of various functions that makes life of USB HC driver developers
+ * easier.
+ */
+#ifndef LIB_USBHOST_UTILITY
+#define LIB_USBHOST_UTILITY
+
+#include <usb/host/bus.h>
+#include <usb/host/usb_transfer_batch.h>
+#include <usb/descriptor.h>
+#include <usb/request.h>
+
+int hc_get_ep0_max_packet_size(uint16_t *, bus_t *, device_t *);
+toggle_reset_mode_t hc_get_request_toggle_reset_mode(const usb_device_request_setup_packet_t *request);
+int hc_setup_virtual_root_hub(hc_device_t *);
+int hc_get_device_desc(device_t *, usb_standard_device_descriptor_t *);
+int hc_device_explore(device_t *);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbhost/src/ddf_helpers.c
===================================================================
--- uspace/lib/usbhost/src/ddf_helpers.c	(revision 861b5d6f1de4d4c071b00ff016eeb5fdba73d042)
+++ uspace/lib/usbhost/src/ddf_helpers.c	(revision 944f8fdd006b2359954cee16ede3ed01c2d88b24)
@@ -393,28 +393,5 @@
 }
 
-int hcd_get_device_desc(device_t *device, usb_standard_device_descriptor_t *desc)
-{
-	const usb_target_t control_ep = {{
-		.address = device->address,
-		.endpoint = 0,
-	}};
-
-	/* Get std device descriptor */
-	const usb_device_request_setup_packet_t get_device_desc =
-	    GET_DEVICE_DESC(sizeof(*desc));
-
-	usb_log_debug("Device(%d): Requesting full device descriptor.",
-	    device->address);
-	ssize_t got = bus_device_send_batch_sync(device, control_ep, USB_DIRECTION_IN,
-	    (char *) desc, sizeof(*desc), *(uint64_t *)&get_device_desc,
-	    "read device descriptor");
-
-	if (got < 0)
-		return got;
-
-	return got == sizeof(*desc) ? EOK : EOVERFLOW;
-}
-
-int hcd_setup_match_ids(device_t *device, usb_standard_device_descriptor_t *desc)
+int hcd_ddf_setup_match_ids(device_t *device, usb_standard_device_descriptor_t *desc)
 {
 	int err;
@@ -434,63 +411,4 @@
 
 	return EOK;
-}
-
-
-int hcd_device_explore(device_t *device)
-{
-	int err;
-	usb_standard_device_descriptor_t desc = { 0 };
-
-	if ((err = hcd_get_device_desc(device, &desc))) {
-		usb_log_error("Device(%d): Failed to get dev descriptor: %s",
-		    device->address, str_error(err));
-		return err;
-	}
-
-	if ((err = hcd_setup_match_ids(device, &desc))) {
-		usb_log_error("Device(%d): Failed to setup match ids: %s", device->address, str_error(err));
-		return err;
-	}
-
-	return EOK;
-}
-
-/** Announce root hub to the DDF
- *
- * @param[in] device Host controller ddf device
- * @return Error code
- */
-int hcd_setup_virtual_root_hub(hc_device_t *hcd)
-{
-	int err;
-
-	assert(hcd);
-
-	device_t *dev = hcd_ddf_fun_create(hcd, USB_SPEED_MAX);
-	if (!dev) {
-		usb_log_error("Failed to create function for the root hub.");
-		return ENOMEM;
-	}
-
-	ddf_fun_set_name(dev->fun, "roothub");
-
-	/* Assign an address to the device */
-	if ((err = bus_device_enumerate(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_enumerated;
-	}
-
-	return EOK;
-
-err_enumerated:
-	bus_device_gone(dev);
-err_usb_dev:
-	hcd_ddf_fun_destroy(dev);
-	return err;
 }
 
Index: uspace/lib/usbhost/src/endpoint.c
===================================================================
--- uspace/lib/usbhost/src/endpoint.c	(revision 861b5d6f1de4d4c071b00ff016eeb5fdba73d042)
+++ uspace/lib/usbhost/src/endpoint.c	(revision 944f8fdd006b2359954cee16ede3ed01c2d88b24)
@@ -43,4 +43,5 @@
 #include <usb/descriptor.h>
 #include <usb/host/hcd.h>
+#include <usb/host/utility.h>
 
 #include "usb_transfer_batch.h"
@@ -284,5 +285,5 @@
 	if (ep->transfer_type == USB_TRANSFER_CONTROL)
 		batch->toggle_reset_mode
-			= hcd_get_request_toggle_reset_mode(&batch->setup.packet);
+			= hc_get_request_toggle_reset_mode(&batch->setup.packet);
 
 	const int ret = ops->batch_schedule(batch);
Index: uspace/lib/usbhost/src/hcd.c
===================================================================
--- uspace/lib/usbhost/src/hcd.c	(revision 861b5d6f1de4d4c071b00ff016eeb5fdba73d042)
+++ uspace/lib/usbhost/src/hcd.c	(revision 944f8fdd006b2359954cee16ede3ed01c2d88b24)
@@ -370,101 +370,4 @@
 }
 
-/** Get max packet size for the control endpoint 0.
- *
- * For LS, HS, and SS devices this value is fixed. For FS devices we must fetch
- * the first 8B of the device descriptor to determine it.
- *
- * @return Max packet size for EP 0
- */
-int hcd_get_ep0_max_packet_size(uint16_t *mps, bus_t *bus, device_t *dev)
-{
-	assert(mps);
-
-	static const uint16_t mps_fixed [] = {
-		[USB_SPEED_LOW] = 8,
-		[USB_SPEED_HIGH] = 64,
-		[USB_SPEED_SUPER] = 512,
-	};
-
-	if (dev->speed < ARRAY_SIZE(mps_fixed) && mps_fixed[dev->speed] != 0) {
-		*mps = mps_fixed[dev->speed];
-		return EOK;
-	}
-
-	const usb_target_t control_ep = {{
-		.address = dev->address,
-		.endpoint = 0,
-	}};
-
-	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("Requesting first 8B of device descriptor to determine MPS.");
-	ssize_t got = bus_device_send_batch_sync(dev, control_ep, USB_DIRECTION_IN,
-	    (char *) &desc, CTRL_PIPE_MIN_PACKET_SIZE, *(uint64_t *)&get_device_desc_8,
-	    "read first 8 bytes of dev descriptor");
-
-	if (got != CTRL_PIPE_MIN_PACKET_SIZE) {
-		const int err = got < 0 ? got : EOVERFLOW;
-		usb_log_error("Failed to get 8B of dev descr: %s.", str_error(err));
-		return err;
-	}
-
-	if (desc.descriptor_type != USB_DESCTYPE_DEVICE) {
-		usb_log_error("The device responded with wrong device descriptor.");
-		return EIO;
-	}
-
-	uint16_t version = uint16_usb2host(desc.usb_spec_version);
-	if (version < 0x0300) {
-		/* USB 2 and below have MPS raw in the field */
-		*mps = desc.max_packet_size;
-	} else {
-		/* USB 3 have MPS as an 2-based exponent */
-		*mps = (1 << desc.max_packet_size);
-	}
-	return EOK;
-}
-
-/** Check setup packet data for signs of toggle reset.
- *
- * @param[in] requst Setup requst data.
- *
- * @retval -1 No endpoints need reset.
- * @retval 0 All endpoints need reset.
- * @retval >0 Specified endpoint needs reset.
- *
- */
-toggle_reset_mode_t hcd_get_request_toggle_reset_mode(
-    const usb_device_request_setup_packet_t *request)
-{
-	assert(request);
-	switch (request->request)
-	{
-	/* Clear Feature ENPOINT_STALL */
-	case USB_DEVREQ_CLEAR_FEATURE: /*resets only cleared ep */
-		/* 0x2 ( HOST to device | STANDART | TO ENPOINT) */
-		if ((request->request_type == 0x2) &&
-		    (request->value == USB_FEATURE_ENDPOINT_HALT))
-			return RESET_EP;
-		break;
-	case USB_DEVREQ_SET_CONFIGURATION:
-	case USB_DEVREQ_SET_INTERFACE:
-		/* Recipient must be device, this resets all endpoints,
-		 * In fact there should be no endpoints but EP 0 registered
-		 * as different interfaces use different endpoints,
-		 * unless you're changing configuration or alternative
-		 * interface of an already setup device. */
-		if (!(request->request_type & SETUP_REQUEST_TYPE_DEVICE_TO_HOST))
-			return RESET_ALL;
-		break;
-	default:
-		break;
-	}
-
-	return RESET_NONE;
-}
-
 
 /**
Index: uspace/lib/usbhost/src/usb2_bus.c
===================================================================
--- uspace/lib/usbhost/src/usb2_bus.c	(revision 861b5d6f1de4d4c071b00ff016eeb5fdba73d042)
+++ uspace/lib/usbhost/src/usb2_bus.c	(revision 944f8fdd006b2359954cee16ede3ed01c2d88b24)
@@ -45,4 +45,5 @@
 #include <usb/descriptor.h>
 #include <usb/request.h>
+#include <usb/host/utility.h>
 #include <usb/usb.h>
 
@@ -140,5 +141,5 @@
 	}
 
-	if ((err = hcd_get_ep0_max_packet_size(&ep0_desc.endpoint.max_packet_size, &bus->base, dev)))
+	if ((err = hc_get_ep0_max_packet_size(&ep0_desc.endpoint.max_packet_size, &bus->base, dev)))
 		goto err_address;
 
@@ -199,5 +200,5 @@
 
 	/* Read the device descriptor, derive the match ids */
-	if ((err = hcd_device_explore(dev))) {
+	if ((err = hc_device_explore(dev))) {
 		usb_log_error("Device(%d): Failed to explore device: %s", dev->address, str_error(err));
 		release_address(bus, dev->address);
Index: uspace/lib/usbhost/src/utility.c
===================================================================
--- uspace/lib/usbhost/src/utility.c	(revision 944f8fdd006b2359954cee16ede3ed01c2d88b24)
+++ uspace/lib/usbhost/src/utility.c	(revision 944f8fdd006b2359954cee16ede3ed01c2d88b24)
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2013 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
+ */
+
+#include <macros.h>
+#include <str_error.h>
+#include <usb/debug.h>
+#include <usb/descriptor.h>
+
+#include "ddf_helpers.h"
+#include "utility.h"
+
+
+/**
+ * Get max packet size for the control endpoint 0.
+ *
+ * For LS, HS, and SS devices this value is fixed. For FS devices we must fetch
+ * the first 8B of the device descriptor to determine it.
+ *
+ * @return Max packet size for EP 0
+ */
+int hc_get_ep0_max_packet_size(uint16_t *mps, bus_t *bus, device_t *dev)
+{
+	assert(mps);
+
+	static const uint16_t mps_fixed [] = {
+		[USB_SPEED_LOW] = 8,
+		[USB_SPEED_HIGH] = 64,
+		[USB_SPEED_SUPER] = 512,
+	};
+
+	if (dev->speed < ARRAY_SIZE(mps_fixed) && mps_fixed[dev->speed] != 0) {
+		*mps = mps_fixed[dev->speed];
+		return EOK;
+	}
+
+	const usb_target_t control_ep = {{
+		.address = dev->address,
+		.endpoint = 0,
+	}};
+
+	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("Requesting first 8B of device descriptor to determine MPS.");
+	ssize_t got = bus_device_send_batch_sync(dev, control_ep, USB_DIRECTION_IN,
+	    (char *) &desc, CTRL_PIPE_MIN_PACKET_SIZE, *(uint64_t *)&get_device_desc_8,
+	    "read first 8 bytes of dev descriptor");
+
+	if (got != CTRL_PIPE_MIN_PACKET_SIZE) {
+		const int err = got < 0 ? got : EOVERFLOW;
+		usb_log_error("Failed to get 8B of dev descr: %s.", str_error(err));
+		return err;
+	}
+
+	if (desc.descriptor_type != USB_DESCTYPE_DEVICE) {
+		usb_log_error("The device responded with wrong device descriptor.");
+		return EIO;
+	}
+
+	uint16_t version = uint16_usb2host(desc.usb_spec_version);
+	if (version < 0x0300) {
+		/* USB 2 and below have MPS raw in the field */
+		*mps = desc.max_packet_size;
+	} else {
+		/* USB 3 have MPS as an 2-based exponent */
+		*mps = (1 << desc.max_packet_size);
+	}
+	return EOK;
+}
+
+/** Check setup packet data for signs of toggle reset.
+ *
+ * @param[in] requst Setup requst data.
+ *
+ * @retval -1 No endpoints need reset.
+ * @retval 0 All endpoints need reset.
+ * @retval >0 Specified endpoint needs reset.
+ *
+ */
+toggle_reset_mode_t hc_get_request_toggle_reset_mode(const usb_device_request_setup_packet_t *request)
+{
+	assert(request);
+	switch (request->request)
+	{
+	/* Clear Feature ENPOINT_STALL */
+	case USB_DEVREQ_CLEAR_FEATURE: /*resets only cleared ep */
+		/* 0x2 ( HOST to device | STANDART | TO ENPOINT) */
+		if ((request->request_type == 0x2) &&
+		    (request->value == USB_FEATURE_ENDPOINT_HALT))
+			return RESET_EP;
+		break;
+	case USB_DEVREQ_SET_CONFIGURATION:
+	case USB_DEVREQ_SET_INTERFACE:
+		/* Recipient must be device, this resets all endpoints,
+		 * In fact there should be no endpoints but EP 0 registered
+		 * as different interfaces use different endpoints,
+		 * unless you're changing configuration or alternative
+		 * interface of an already setup device. */
+		if (!(request->request_type & SETUP_REQUEST_TYPE_DEVICE_TO_HOST))
+			return RESET_ALL;
+		break;
+	default:
+		break;
+	}
+
+	return RESET_NONE;
+}
+
+int hc_get_device_desc(device_t *device, usb_standard_device_descriptor_t *desc)
+{
+	const usb_target_t control_ep = {{
+		.address = device->address,
+		.endpoint = 0,
+	}};
+
+	/* Get std device descriptor */
+	const usb_device_request_setup_packet_t get_device_desc =
+	    GET_DEVICE_DESC(sizeof(*desc));
+
+	usb_log_debug("Device(%d): Requesting full device descriptor.",
+	    device->address);
+	ssize_t got = bus_device_send_batch_sync(device, control_ep, USB_DIRECTION_IN,
+	    (char *) desc, sizeof(*desc), *(uint64_t *)&get_device_desc,
+	    "read device descriptor");
+
+	if (got < 0)
+		return got;
+
+	return got == sizeof(*desc) ? EOK : EOVERFLOW;
+}
+
+int hc_device_explore(device_t *device)
+{
+	int err;
+	usb_standard_device_descriptor_t desc = { 0 };
+
+	if ((err = hc_get_device_desc(device, &desc))) {
+		usb_log_error("Device(%d): Failed to get dev descriptor: %s",
+		    device->address, str_error(err));
+		return err;
+	}
+
+	if ((err = hcd_ddf_setup_match_ids(device, &desc))) {
+		usb_log_error("Device(%d): Failed to setup match ids: %s", device->address, str_error(err));
+		return err;
+	}
+
+	return EOK;
+}
+
+/** Announce root hub to the DDF
+ *
+ * @param[in] device Host controller ddf device
+ * @return Error code
+ */
+int hc_setup_virtual_root_hub(hc_device_t *hcd)
+{
+	int err;
+
+	assert(hcd);
+
+	device_t *dev = hcd_ddf_fun_create(hcd, USB_SPEED_MAX);
+	if (!dev) {
+		usb_log_error("Failed to create function for the root hub.");
+		return ENOMEM;
+	}
+
+	ddf_fun_set_name(dev->fun, "roothub");
+
+	/* Assign an address to the device */
+	if ((err = bus_device_enumerate(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_enumerated;
+	}
+
+	return EOK;
+
+err_enumerated:
+	bus_device_gone(dev);
+err_usb_dev:
+	hcd_ddf_fun_destroy(dev);
+	return err;
+}
+
+/**
+ * @}
+ */
