Index: uspace/drv/bus/usb/usbhub/port.c
===================================================================
--- uspace/drv/bus/usb/usbhub/port.c	(revision 479e32d1f14d8a612f29cd0c2feff2501360407b)
+++ uspace/drv/bus/usb/usbhub/port.c	(revision 41df71f99dd4001594df602dcc612186bdf02430)
@@ -40,4 +40,5 @@
 #include <inttypes.h>
 #include <fibril_synch.h>
+#include <usbhc_iface.h>
 
 #include <usb/debug.h>
@@ -267,5 +268,5 @@
 	if (!exch)
 		return ENOMEM;
-	const int rc = usb_device_remove(exch, port->port_number);
+	const int rc = usbhc_device_remove(exch, port->port_number);
 	usb_device_bus_exchange_end(exch);
 	if (rc == EOK)
@@ -405,5 +406,5 @@
 
 	/* Reserve default address */
-	while ((ret = usb_reserve_default_address(exch, speed)) == ENOENT) {
+	while ((ret = usbhc_reserve_default_address(exch, speed)) == ENOENT) {
 		async_usleep(1000000);
 	}
@@ -421,5 +422,5 @@
 		usb_log_error("(%p-%u): Failed to reset port.", hub,
 		    port->port_number);
-		if (usb_release_default_address(exch) != EOK)
+		if (usbhc_release_default_address(exch) != EOK)
 			usb_log_warning("(%p-%u): Failed to release default "
 			    "address.", hub, port->port_number);
@@ -430,5 +431,5 @@
 	    port->port_number);
 
-	ret = usb_device_enumerate(exch, port->port_number);
+	ret = usbhc_device_enumerate(exch, port->port_number);
 	if (ret != EOK) {
 		usb_log_error("(%p-%u): Failed to enumerate device: %s", hub,
@@ -440,5 +441,5 @@
 			    port->port_number, str_error(ret));
 		} else {
-			const int ret = usb_release_default_address(exch);
+			const int ret = usbhc_release_default_address(exch);
 			if (ret != EOK)
 				usb_log_warning("(%p-%u): Failed to release "
@@ -450,5 +451,5 @@
 		    port->port_number);
 		port->device_attached = true;
-		if (usb_release_default_address(exch) != EOK)
+		if (usbhc_release_default_address(exch) != EOK)
 			usb_log_warning("(%p-%u): Failed to release default "
 			    "address", hub, port->port_number);
Index: uspace/drv/bus/usb/usbhub/port.h
===================================================================
--- uspace/drv/bus/usb/usbhub/port.h	(revision 479e32d1f14d8a612f29cd0c2feff2501360407b)
+++ uspace/drv/bus/usb/usbhub/port.h	(revision 41df71f99dd4001594df602dcc612186bdf02430)
@@ -40,5 +40,4 @@
 #include <usb/dev/driver.h>
 #include <usb/classes/hub.h>
-#include <usb_iface.h>
 
 typedef struct usb_hub_dev usb_hub_dev_t;
Index: uspace/lib/c/include/ipc/dev_iface.h
===================================================================
--- uspace/lib/c/include/ipc/dev_iface.h	(revision 479e32d1f14d8a612f29cd0c2feff2501360407b)
+++ uspace/lib/c/include/ipc/dev_iface.h	(revision 41df71f99dd4001594df602dcc612186bdf02430)
@@ -56,4 +56,6 @@
 	/** Interface provided by any USB device. */
 	USB_DEV_IFACE,
+	/** Interface provided by USB host controller to USB device. */
+	USBHC_DEV_IFACE,
 	/** Interface provided by USB HID devices. */
 	USBHID_DEV_IFACE,
Index: uspace/lib/drv/Makefile
===================================================================
--- uspace/lib/drv/Makefile	(revision 479e32d1f14d8a612f29cd0c2feff2501360407b)
+++ uspace/lib/drv/Makefile	(revision 41df71f99dd4001594df602dcc612186bdf02430)
@@ -52,4 +52,5 @@
 	generic/remote_usb.c \
 	generic/remote_pci.c \
+	generic/remote_usbhc.c \
 	generic/remote_usbhid.c \
 	generic/remote_clock_dev.c \
Index: uspace/lib/drv/generic/dev_iface.c
===================================================================
--- uspace/lib/drv/generic/dev_iface.c	(revision 479e32d1f14d8a612f29cd0c2feff2501360407b)
+++ uspace/lib/drv/generic/dev_iface.c	(revision 41df71f99dd4001594df602dcc612186bdf02430)
@@ -49,4 +49,5 @@
 #include "remote_ieee80211.h"
 #include "remote_usb.h"
+#include "remote_usbhc.h"
 #include "remote_usbhid.h"
 #include "remote_pci.h"
@@ -66,4 +67,5 @@
 		[PCI_DEV_IFACE] = &remote_pci_iface,
 		[USB_DEV_IFACE] = &remote_usb_iface,
+		[USBHC_DEV_IFACE] = &remote_usbhc_iface,
 		[USBHID_DEV_IFACE] = &remote_usbhid_iface,
 		[CLOCK_DEV_IFACE] = &remote_clock_dev_iface,
Index: uspace/lib/drv/generic/private/remote_usbhc.h
===================================================================
--- uspace/lib/drv/generic/private/remote_usbhc.h	(revision 41df71f99dd4001594df602dcc612186bdf02430)
+++ uspace/lib/drv/generic/private/remote_usbhc.h	(revision 41df71f99dd4001594df602dcc612186bdf02430)
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * Copyright (c) 2017 Ondrej Hlavaty
+ * 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 libdrv
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBDRV_REMOTE_USBHC_H_
+#define LIBDRV_REMOTE_USBHC_H_
+
+extern remote_iface_t remote_usbhc_iface;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/lib/drv/generic/remote_usb.c
===================================================================
--- uspace/lib/drv/generic/remote_usb.c	(revision 479e32d1f14d8a612f29cd0c2feff2501360407b)
+++ uspace/lib/drv/generic/remote_usb.c	(revision 41df71f99dd4001594df602dcc612186bdf02430)
@@ -63,12 +63,4 @@
 	IPC_M_USB_GET_MY_INTERFACE,
 	IPC_M_USB_GET_MY_DEVICE_HANDLE,
-	IPC_M_USB_RESERVE_DEFAULT_ADDRESS,
-	IPC_M_USB_RELEASE_DEFAULT_ADDRESS,
-	IPC_M_USB_DEVICE_ENUMERATE,
-	IPC_M_USB_DEVICE_REMOVE,
-	IPC_M_USB_REGISTER_ENDPOINT,
-	IPC_M_USB_UNREGISTER_ENDPOINT,
-	IPC_M_USB_READ,
-	IPC_M_USB_WRITE,
 } usb_iface_funcs_t;
 
@@ -109,220 +101,6 @@
 }
 
-/** Reserve default USB address.
- * @param[in] exch IPC communication exchange
- * @param[in] speed Communication speed of the newly attached device
- * @return Error code.
- */
-int usb_reserve_default_address(async_exch_t *exch, usb_speed_t speed)
-{
-	if (!exch)
-		return EBADMEM;
-	return async_req_2_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
-	    IPC_M_USB_RESERVE_DEFAULT_ADDRESS, speed);
-}
-
-/** Release default USB address.
- *
- * @param[in] exch IPC communication exchange
- *
- * @return Error code.
- *
- */
-int usb_release_default_address(async_exch_t *exch)
-{
-	if (!exch)
-		return EBADMEM;
-	return async_req_1_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
-	    IPC_M_USB_RELEASE_DEFAULT_ADDRESS);
-}
-
-/** Trigger USB device enumeration
- *
- * @param[in]  exch   IPC communication exchange
- * @param[out] handle Identifier of the newly added device (if successful)
- *
- * @return Error code.
- *
- */
-int usb_device_enumerate(async_exch_t *exch, unsigned port)
-{
-	if (!exch)
-		return EBADMEM;
-	const int ret = async_req_2_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
-	    IPC_M_USB_DEVICE_ENUMERATE, port);
-	return ret;
-}
-
-/** Trigger USB device enumeration
- *
- * @param[in] exch   IPC communication exchange
- * @param[in] handle Identifier of the device
- *
- * @return Error code.
- *
- */
-int usb_device_remove(async_exch_t *exch, unsigned port)
-{
-	if (!exch)
-		return EBADMEM;
-	return async_req_2_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
-	    IPC_M_USB_DEVICE_REMOVE, port);
-}
-
-int static_assert[sizeof(sysarg_t) >= 4 ? 1 : -1];
-typedef union {
-	uint8_t arr[sizeof(sysarg_t)];
-	sysarg_t arg;
-} pack8_t;
-
-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;
-}
-
-int usb_read(async_exch_t *exch, usb_endpoint_t endpoint, uint64_t setup,
-    void *data, size_t size, size_t *rec_size)
-{
-	if (!exch)
-		return EBADMEM;
-
-	if (size == 0 && setup == 0)
-		return EOK;
-
-	/* Make call identifying target USB device and type of transfer. */
-	aid_t opening_request = async_send_4(exch,
-	    DEV_IFACE_ID(USB_DEV_IFACE), IPC_M_USB_READ, endpoint,
-	    (setup & UINT32_MAX), (setup >> 32), NULL);
-
-	if (opening_request == 0) {
-		return ENOMEM;
-	}
-
-	/* Retrieve the data. */
-	ipc_call_t data_request_call;
-	aid_t data_request =
-	    async_data_read(exch, data, size, &data_request_call);
-
-	if (data_request == 0) {
-		// FIXME: How to let the other side know that we want to abort?
-		async_forget(opening_request);
-		return ENOMEM;
-	}
-
-	/* Wait for the answer. */
-	sysarg_t data_request_rc;
-	sysarg_t opening_request_rc;
-	async_wait_for(data_request, &data_request_rc);
-	async_wait_for(opening_request, &opening_request_rc);
-
-	if (data_request_rc != EOK) {
-		/* Prefer the return code of the opening request. */
-		if (opening_request_rc != EOK) {
-			return (int) opening_request_rc;
-		} else {
-			return (int) data_request_rc;
-		}
-	}
-	if (opening_request_rc != EOK) {
-		return (int) opening_request_rc;
-	}
-
-	*rec_size = IPC_GET_ARG2(data_request_call);
-	return EOK;
-}
-
-int usb_write(async_exch_t *exch, usb_endpoint_t endpoint, uint64_t setup,
-    const void *data, size_t size)
-{
-	if (!exch)
-		return EBADMEM;
-
-	if (size == 0 && setup == 0)
-		return EOK;
-
-	aid_t opening_request = async_send_5(exch,
-	    DEV_IFACE_ID(USB_DEV_IFACE), IPC_M_USB_WRITE, endpoint, size,
-	    (setup & UINT32_MAX), (setup >> 32), NULL);
-
-	if (opening_request == 0) {
-		return ENOMEM;
-	}
-
-	/* Send the data if any. */
-	if (size > 0) {
-		const int ret = async_data_write_start(exch, data, size);
-		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;
-}
-
 static void remote_usb_get_my_interface(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
 static void remote_usb_get_my_device_handle(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
-static void remote_usb_reserve_default_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
-static void remote_usb_release_default_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
-static void remote_usb_device_enumerate(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
-static void remote_usb_device_remove(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
-static void remote_usb_register_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
-static void remote_usb_unregister_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
-static void remote_usb_read(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call);
-static void remote_usb_write(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call);
 
 /** Remote USB interface operations. */
@@ -330,12 +108,4 @@
 	[IPC_M_USB_GET_MY_INTERFACE] = remote_usb_get_my_interface,
 	[IPC_M_USB_GET_MY_DEVICE_HANDLE] = remote_usb_get_my_device_handle,
-	[IPC_M_USB_RESERVE_DEFAULT_ADDRESS] = remote_usb_reserve_default_address,
-	[IPC_M_USB_RELEASE_DEFAULT_ADDRESS] = remote_usb_release_default_address,
-	[IPC_M_USB_DEVICE_ENUMERATE] = remote_usb_device_enumerate,
-	[IPC_M_USB_DEVICE_REMOVE] = remote_usb_device_remove,
-	[IPC_M_USB_REGISTER_ENDPOINT] = remote_usb_register_endpoint,
-	[IPC_M_USB_UNREGISTER_ENDPOINT] = remote_usb_unregister_endpoint,
-	[IPC_M_USB_READ] = remote_usb_read,
-	[IPC_M_USB_WRITE] = remote_usb_write,
 };
 
@@ -346,10 +116,4 @@
 	.methods = remote_usb_iface_ops,
 };
-
-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,
@@ -391,288 +155,4 @@
 }
 
-void remote_usb_reserve_default_address(ddf_fun_t *fun, void *iface,
-    ipc_callid_t callid, ipc_call_t *call)
-{
-	const usb_iface_t *usb_iface = (usb_iface_t *) iface;
-
-	if (usb_iface->reserve_default_address == NULL) {
-		async_answer_0(callid, ENOTSUP);
-		return;
-	}
-
-	usb_speed_t speed = DEV_IPC_GET_ARG1(*call);
-	const int ret = usb_iface->reserve_default_address(fun, speed);
-	async_answer_0(callid, ret);
-}
-
-void remote_usb_release_default_address(ddf_fun_t *fun, void *iface,
-    ipc_callid_t callid, ipc_call_t *call)
-{
-	const usb_iface_t *usb_iface = (usb_iface_t *) iface;
-
-	if (usb_iface->release_default_address == NULL) {
-		async_answer_0(callid, ENOTSUP);
-		return;
-	}
-
-	const int ret = usb_iface->release_default_address(fun);
-	async_answer_0(callid, ret);
-}
-
-static void remote_usb_device_enumerate(ddf_fun_t *fun, void *iface,
-    ipc_callid_t callid, ipc_call_t *call)
-{
-	const usb_iface_t *usb_iface = (usb_iface_t *) iface;
-
-	if (usb_iface->device_enumerate == NULL) {
-		async_answer_0(callid, ENOTSUP);
-		return;
-	}
-
-	const unsigned port = DEV_IPC_GET_ARG1(*call);
-	const int ret = usb_iface->device_enumerate(fun, port);
-	async_answer_0(callid, ret);
-}
-
-static void remote_usb_device_remove(ddf_fun_t *fun, void *iface,
-    ipc_callid_t callid, ipc_call_t *call)
-{
-	const usb_iface_t *usb_iface = (usb_iface_t *) iface;
-
-	if (usb_iface->device_remove == NULL) {
-		async_answer_0(callid, ENOTSUP);
-		return;
-	}
-
-	const unsigned port = DEV_IPC_GET_ARG1(*call);
-	const int ret = usb_iface->device_remove(fun, port);
-	async_answer_0(callid, ret);
-}
-
-static void remote_usb_register_endpoint(ddf_fun_t *fun, void *iface,
-    ipc_callid_t callid, ipc_call_t *call)
-{
-	assert(fun);
-	assert(iface);
-	assert(call);
-
-	const usb_iface_t *usb_iface = iface;
-
-	if (!usb_iface->register_endpoint) {
-		async_answer_0(callid, ENOTSUP);
-		return;
-	}
-
-	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);
-}
-
-static void remote_usb_unregister_endpoint(ddf_fun_t *fun, void *iface,
-    ipc_callid_t callid, ipc_call_t *call)
-{
-	assert(fun);
-	assert(iface);
-	assert(call);
-
-	const usb_iface_t *usb_iface = iface;
-
-	if (!usb_iface->unregister_endpoint) {
-		async_answer_0(callid, ENOTSUP);
-		return;
-	}
-
-	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);
-	async_answer_0(callid, rc);
-}
-
-static void async_transaction_destroy(async_transaction_t *trans)
-{
-	if (trans == NULL) {
-		return;
-	}
-	if (trans->buffer != NULL) {
-		free(trans->buffer);
-	}
-
-	free(trans);
-}
-
-static async_transaction_t *async_transaction_create(ipc_callid_t caller)
-{
-	async_transaction_t *trans = malloc(sizeof(async_transaction_t));
-	if (trans == NULL) {
-		return NULL;
-	}
-
-	trans->caller = caller;
-	trans->data_caller = 0;
-	trans->buffer = NULL;
-
-	return trans;
-}
-
-static int callback_out(usb_transfer_batch_t *batch)
-{
-	async_transaction_t *trans = batch->on_complete_data;
-
-	const int err = async_answer_0(trans->caller, batch->error);
-
-	async_transaction_destroy(trans);
-
-	return err;
-}
-
-static int callback_in(usb_transfer_batch_t *batch)
-{
-	async_transaction_t *trans = batch->on_complete_data;
-
-	if (trans->data_caller) {
-		if (batch->error == EOK) {
-			batch->error = async_data_read_finalize(trans->data_caller,
-			    trans->buffer, batch->transfered_size);
-		} else {
-			async_answer_0(trans->data_caller, EINTR);
-		}
-	}
-
-	const int err = async_answer_0(trans->caller, batch->error);
-	async_transaction_destroy(trans);
-	return err;
-}
-
-void remote_usb_read(
-    ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
-{
-	assert(fun);
-	assert(iface);
-	assert(call);
-
-	const usb_iface_t *usb_iface = iface;
-
-	if (!usb_iface->read) {
-		async_answer_0(callid, ENOTSUP);
-		return;
-	}
-
-	const usb_endpoint_t ep = DEV_IPC_GET_ARG1(*call);
-	const uint64_t setup =
-	    ((uint64_t)DEV_IPC_GET_ARG2(*call)) |
-	    (((uint64_t)DEV_IPC_GET_ARG3(*call)) << 32);
-
-	async_transaction_t *trans = async_transaction_create(callid);
-	if (trans == NULL) {
-		async_answer_0(callid, ENOMEM);
-		return;
-	}
-
-	size_t size = 0;
-	if (!async_data_read_receive(&trans->data_caller, &size)) {
-		async_answer_0(callid, EPARTY);
-		async_transaction_destroy(trans);
-		return;
-	}
-
-	trans->buffer = malloc(size);
-	if (trans->buffer == NULL) {
-		async_answer_0(trans->data_caller, ENOMEM);
-		async_answer_0(callid, ENOMEM);
-		async_transaction_destroy(trans);
-		return;
-	}
-
-	const usb_target_t target = {{
-		/* .address is initialized by read itself */
-		.endpoint = ep,
-	}};
-
-	const int rc = usb_iface->read(
-	    fun, target, setup, trans->buffer, size, callback_in, trans);
-
-	if (rc != EOK) {
-		async_answer_0(trans->data_caller, rc);
-		async_answer_0(callid, rc);
-		async_transaction_destroy(trans);
-	}
-}
-
-void remote_usb_write(
-    ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
-{
-	assert(fun);
-	assert(iface);
-	assert(call);
-
-	const usb_iface_t *usb_iface = iface;
-
-	if (!usb_iface->write) {
-		async_answer_0(callid, ENOTSUP);
-		return;
-	}
-
-	const usb_endpoint_t ep = DEV_IPC_GET_ARG1(*call);
-	const size_t data_buffer_len = DEV_IPC_GET_ARG2(*call);
-	const uint64_t setup =
-	    ((uint64_t)DEV_IPC_GET_ARG3(*call)) |
-	    (((uint64_t)DEV_IPC_GET_ARG4(*call)) << 32);
-
-	async_transaction_t *trans = async_transaction_create(callid);
-	if (trans == NULL) {
-		async_answer_0(callid, ENOMEM);
-		return;
-	}
-
-	size_t size = 0;
-	if (data_buffer_len > 0) {
-		const int rc = async_data_write_accept(&trans->buffer, false,
-		    1, data_buffer_len, 0, &size);
-
-		if (rc != EOK) {
-			async_answer_0(callid, rc);
-			async_transaction_destroy(trans);
-			return;
-		}
-	}
-
-	const usb_target_t target = {{
-		/* .address is initialized by write itself */
-		.endpoint = ep,
-	}};
-
-	const int rc = usb_iface->write(
-	    fun, target, setup, trans->buffer, size, callback_out, trans);
-
-	if (rc != EOK) {
-		async_answer_0(callid, rc);
-		async_transaction_destroy(trans);
-	}
-}
 /**
  * @}
Index: uspace/lib/drv/generic/remote_usbhc.c
===================================================================
--- uspace/lib/drv/generic/remote_usbhc.c	(revision 41df71f99dd4001594df602dcc612186bdf02430)
+++ uspace/lib/drv/generic/remote_usbhc.c	(revision 41df71f99dd4001594df602dcc612186bdf02430)
@@ -0,0 +1,584 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * Copyright (c) 2011 Jan Vesely
+ * Copyright (c) 2017 Ondrej Hlavaty
+ * 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 libdrv
+ * @{
+ */
+/** @file
+ */
+
+#include <async.h>
+#include <macros.h>
+#include <errno.h>
+#include <devman.h>
+#include <usb/host/usb_transfer_batch.h>
+
+#include "usbhc_iface.h"
+#include "ddf/driver.h"
+
+
+typedef enum {
+	IPC_M_USB_RESERVE_DEFAULT_ADDRESS,
+	IPC_M_USB_RELEASE_DEFAULT_ADDRESS,
+	IPC_M_USB_DEVICE_ENUMERATE,
+	IPC_M_USB_DEVICE_REMOVE,
+	IPC_M_USB_REGISTER_ENDPOINT,
+	IPC_M_USB_UNREGISTER_ENDPOINT,
+	IPC_M_USB_READ,
+	IPC_M_USB_WRITE,
+} usbhc_iface_funcs_t;
+
+/** Reserve default USB address.
+ * @param[in] exch IPC communication exchange
+ * @param[in] speed Communication speed of the newly attached device
+ * @return Error code.
+ */
+int usbhc_reserve_default_address(async_exch_t *exch, usb_speed_t speed)
+{
+	if (!exch)
+		return EBADMEM;
+	return async_req_2_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USB_RESERVE_DEFAULT_ADDRESS, speed);
+}
+
+/** Release default USB address.
+ *
+ * @param[in] exch IPC communication exchange
+ *
+ * @return Error code.
+ *
+ */
+int usbhc_release_default_address(async_exch_t *exch)
+{
+	if (!exch)
+		return EBADMEM;
+	return async_req_1_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USB_RELEASE_DEFAULT_ADDRESS);
+}
+
+/** Trigger USB device enumeration
+ *
+ * @param[in]  exch   IPC communication exchange
+ * @param[out] handle Identifier of the newly added device (if successful)
+ *
+ * @return Error code.
+ *
+ */
+int usbhc_device_enumerate(async_exch_t *exch, unsigned port)
+{
+	if (!exch)
+		return EBADMEM;
+	const int ret = async_req_2_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USB_DEVICE_ENUMERATE, port);
+	return ret;
+}
+
+/** Trigger USB device enumeration
+ *
+ * @param[in] exch   IPC communication exchange
+ * @param[in] handle Identifier of the device
+ *
+ * @return Error code.
+ *
+ */
+int usbhc_device_remove(async_exch_t *exch, unsigned port)
+{
+	if (!exch)
+		return EBADMEM;
+	return async_req_2_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USB_DEVICE_REMOVE, port);
+}
+
+int static_assert[sizeof(sysarg_t) >= 4 ? 1 : -1];
+typedef union {
+	uint8_t arr[sizeof(sysarg_t)];
+	sysarg_t arg;
+} pack8_t;
+
+int usbhc_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(USBHC_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 usbhc_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(USBHC_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;
+}
+
+int usbhc_read(async_exch_t *exch, usb_endpoint_t endpoint, uint64_t setup,
+    void *data, size_t size, size_t *rec_size)
+{
+	if (!exch)
+		return EBADMEM;
+
+	if (size == 0 && setup == 0)
+		return EOK;
+
+	/* Make call identifying target USB device and type of transfer. */
+	aid_t opening_request = async_send_4(exch,
+	    DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_READ, endpoint,
+	    (setup & UINT32_MAX), (setup >> 32), NULL);
+
+	if (opening_request == 0) {
+		return ENOMEM;
+	}
+
+	/* Retrieve the data. */
+	ipc_call_t data_request_call;
+	aid_t data_request =
+	    async_data_read(exch, data, size, &data_request_call);
+
+	if (data_request == 0) {
+		// FIXME: How to let the other side know that we want to abort?
+		async_forget(opening_request);
+		return ENOMEM;
+	}
+
+	/* Wait for the answer. */
+	sysarg_t data_request_rc;
+	sysarg_t opening_request_rc;
+	async_wait_for(data_request, &data_request_rc);
+	async_wait_for(opening_request, &opening_request_rc);
+
+	if (data_request_rc != EOK) {
+		/* Prefer the return code of the opening request. */
+		if (opening_request_rc != EOK) {
+			return (int) opening_request_rc;
+		} else {
+			return (int) data_request_rc;
+		}
+	}
+	if (opening_request_rc != EOK) {
+		return (int) opening_request_rc;
+	}
+
+	*rec_size = IPC_GET_ARG2(data_request_call);
+	return EOK;
+}
+
+int usbhc_write(async_exch_t *exch, usb_endpoint_t endpoint, uint64_t setup,
+    const void *data, size_t size)
+{
+	if (!exch)
+		return EBADMEM;
+
+	if (size == 0 && setup == 0)
+		return EOK;
+
+	aid_t opening_request = async_send_5(exch,
+	    DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_WRITE, endpoint, size,
+	    (setup & UINT32_MAX), (setup >> 32), NULL);
+
+	if (opening_request == 0) {
+		return ENOMEM;
+	}
+
+	/* Send the data if any. */
+	if (size > 0) {
+		const int ret = async_data_write_start(exch, data, size);
+		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;
+}
+
+static void remote_usbhc_reserve_default_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_release_default_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_device_enumerate(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_device_remove(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_register_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_unregister_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_read(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call);
+static void remote_usbhc_write(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call);
+
+/** Remote USB interface operations. */
+static const remote_iface_func_ptr_t remote_usbhc_iface_ops [] = {
+	[IPC_M_USB_RESERVE_DEFAULT_ADDRESS] = remote_usbhc_reserve_default_address,
+	[IPC_M_USB_RELEASE_DEFAULT_ADDRESS] = remote_usbhc_release_default_address,
+	[IPC_M_USB_DEVICE_ENUMERATE] = remote_usbhc_device_enumerate,
+	[IPC_M_USB_DEVICE_REMOVE] = remote_usbhc_device_remove,
+	[IPC_M_USB_REGISTER_ENDPOINT] = remote_usbhc_register_endpoint,
+	[IPC_M_USB_UNREGISTER_ENDPOINT] = remote_usbhc_unregister_endpoint,
+	[IPC_M_USB_READ] = remote_usbhc_read,
+	[IPC_M_USB_WRITE] = remote_usbhc_write,
+};
+
+/** Remote USB interface structure.
+ */
+const remote_iface_t remote_usbhc_iface = {
+	.method_count = ARRAY_SIZE(remote_usbhc_iface_ops),
+	.methods = remote_usbhc_iface_ops,
+};
+
+typedef struct {
+	ipc_callid_t caller;
+	ipc_callid_t data_caller;
+	void *buffer;
+} async_transaction_t;
+
+void remote_usbhc_reserve_default_address(ddf_fun_t *fun, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	const usbhc_iface_t *usbhc_iface = (usbhc_iface_t *) iface;
+
+	if (usbhc_iface->reserve_default_address == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	usb_speed_t speed = DEV_IPC_GET_ARG1(*call);
+	const int ret = usbhc_iface->reserve_default_address(fun, speed);
+	async_answer_0(callid, ret);
+}
+
+void remote_usbhc_release_default_address(ddf_fun_t *fun, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	const usbhc_iface_t *usbhc_iface = (usbhc_iface_t *) iface;
+
+	if (usbhc_iface->release_default_address == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	const int ret = usbhc_iface->release_default_address(fun);
+	async_answer_0(callid, ret);
+}
+
+static void remote_usbhc_device_enumerate(ddf_fun_t *fun, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	const usbhc_iface_t *usbhc_iface = (usbhc_iface_t *) iface;
+
+	if (usbhc_iface->device_enumerate == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	const unsigned port = DEV_IPC_GET_ARG1(*call);
+	const int ret = usbhc_iface->device_enumerate(fun, port);
+	async_answer_0(callid, ret);
+}
+
+static void remote_usbhc_device_remove(ddf_fun_t *fun, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	const usbhc_iface_t *usbhc_iface = (usbhc_iface_t *) iface;
+
+	if (usbhc_iface->device_remove == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	const unsigned port = DEV_IPC_GET_ARG1(*call);
+	const int ret = usbhc_iface->device_remove(fun, port);
+	async_answer_0(callid, ret);
+}
+
+static void remote_usbhc_register_endpoint(ddf_fun_t *fun, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	assert(fun);
+	assert(iface);
+	assert(call);
+
+	const usbhc_iface_t *usbhc_iface = iface;
+
+	if (!usbhc_iface->register_endpoint) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	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 = usbhc_iface->register_endpoint(fun, endpoint_desc);
+
+	free(buffer);
+	async_answer_0(callid, rc);
+}
+
+static void remote_usbhc_unregister_endpoint(ddf_fun_t *fun, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	assert(fun);
+	assert(iface);
+	assert(call);
+
+	const usbhc_iface_t *usbhc_iface = iface;
+
+	if (!usbhc_iface->unregister_endpoint) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	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;
+	usbhc_iface->unregister_endpoint(fun, endpoint_desc);
+
+	free(buffer);
+	async_answer_0(callid, rc);
+}
+
+static void async_transaction_destroy(async_transaction_t *trans)
+{
+	if (trans == NULL) {
+		return;
+	}
+	if (trans->buffer != NULL) {
+		free(trans->buffer);
+	}
+
+	free(trans);
+}
+
+static async_transaction_t *async_transaction_create(ipc_callid_t caller)
+{
+	async_transaction_t *trans = malloc(sizeof(async_transaction_t));
+	if (trans == NULL) {
+		return NULL;
+	}
+
+	trans->caller = caller;
+	trans->data_caller = 0;
+	trans->buffer = NULL;
+
+	return trans;
+}
+
+static int callback_out(usb_transfer_batch_t *batch)
+{
+	async_transaction_t *trans = batch->on_complete_data;
+
+	const int err = async_answer_0(trans->caller, batch->error);
+
+	async_transaction_destroy(trans);
+
+	return err;
+}
+
+static int callback_in(usb_transfer_batch_t *batch)
+{
+	async_transaction_t *trans = batch->on_complete_data;
+
+	if (trans->data_caller) {
+		if (batch->error == EOK) {
+			batch->error = async_data_read_finalize(trans->data_caller,
+			    trans->buffer, batch->transfered_size);
+		} else {
+			async_answer_0(trans->data_caller, EINTR);
+		}
+	}
+
+	const int err = async_answer_0(trans->caller, batch->error);
+	async_transaction_destroy(trans);
+	return err;
+}
+
+void remote_usbhc_read(
+    ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
+{
+	assert(fun);
+	assert(iface);
+	assert(call);
+
+	const usbhc_iface_t *usbhc_iface = iface;
+
+	if (!usbhc_iface->read) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	const usb_endpoint_t ep = DEV_IPC_GET_ARG1(*call);
+	const uint64_t setup =
+	    ((uint64_t)DEV_IPC_GET_ARG2(*call)) |
+	    (((uint64_t)DEV_IPC_GET_ARG3(*call)) << 32);
+
+	async_transaction_t *trans = async_transaction_create(callid);
+	if (trans == NULL) {
+		async_answer_0(callid, ENOMEM);
+		return;
+	}
+
+	size_t size = 0;
+	if (!async_data_read_receive(&trans->data_caller, &size)) {
+		async_answer_0(callid, EPARTY);
+		async_transaction_destroy(trans);
+		return;
+	}
+
+	trans->buffer = malloc(size);
+	if (trans->buffer == NULL) {
+		async_answer_0(trans->data_caller, ENOMEM);
+		async_answer_0(callid, ENOMEM);
+		async_transaction_destroy(trans);
+		return;
+	}
+
+	const usb_target_t target = {{
+		/* .address is initialized by read itself */
+		.endpoint = ep,
+	}};
+
+	const int rc = usbhc_iface->read(
+	    fun, target, setup, trans->buffer, size, callback_in, trans);
+
+	if (rc != EOK) {
+		async_answer_0(trans->data_caller, rc);
+		async_answer_0(callid, rc);
+		async_transaction_destroy(trans);
+	}
+}
+
+void remote_usbhc_write(
+    ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
+{
+	assert(fun);
+	assert(iface);
+	assert(call);
+
+	const usbhc_iface_t *usbhc_iface = iface;
+
+	if (!usbhc_iface->write) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	const usb_endpoint_t ep = DEV_IPC_GET_ARG1(*call);
+	const size_t data_buffer_len = DEV_IPC_GET_ARG2(*call);
+	const uint64_t setup =
+	    ((uint64_t)DEV_IPC_GET_ARG3(*call)) |
+	    (((uint64_t)DEV_IPC_GET_ARG4(*call)) << 32);
+
+	async_transaction_t *trans = async_transaction_create(callid);
+	if (trans == NULL) {
+		async_answer_0(callid, ENOMEM);
+		return;
+	}
+
+	size_t size = 0;
+	if (data_buffer_len > 0) {
+		const int rc = async_data_write_accept(&trans->buffer, false,
+		    1, data_buffer_len, 0, &size);
+
+		if (rc != EOK) {
+			async_answer_0(callid, rc);
+			async_transaction_destroy(trans);
+			return;
+		}
+	}
+
+	const usb_target_t target = {{
+		/* .address is initialized by write itself */
+		.endpoint = ep,
+	}};
+
+	const int rc = usbhc_iface->write(
+	    fun, target, setup, trans->buffer, size, callback_out, trans);
+
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		async_transaction_destroy(trans);
+	}
+}
+/**
+ * @}
+ */
Index: uspace/lib/drv/include/usb_iface.h
===================================================================
--- uspace/lib/drv/include/usb_iface.h	(revision 479e32d1f14d8a612f29cd0c2feff2501360407b)
+++ uspace/lib/drv/include/usb_iface.h	(revision 41df71f99dd4001594df602dcc612186bdf02430)
@@ -32,5 +32,5 @@
  */
 /** @file
- * @brief USB interface definition.
+ * @brief USB device interface definition.
  */
 
@@ -51,43 +51,8 @@
 extern int usb_get_my_device_handle(async_exch_t *, devman_handle_t *);
 
-extern int usb_reserve_default_address(async_exch_t *, usb_speed_t);
-extern int usb_release_default_address(async_exch_t *);
-
-extern int usb_device_enumerate(async_exch_t *, unsigned port);
-extern int usb_device_remove(async_exch_t *, unsigned port);
-
-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 *);
-extern int usb_write(async_exch_t *, usb_endpoint_t, uint64_t, const void *,
-    size_t);
-
-/** Defined in usb/host/usb_transfer_batch.h */
-typedef struct usb_transfer_batch usb_transfer_batch_t;
-
-/** Callback for outgoing transfer - clone of usb_transfer_batch_callback_t */
-typedef int (*usb_iface_transfer_callback_t)(usb_transfer_batch_t *);
-
 /** USB device communication interface. */
 typedef struct {
 	int (*get_my_interface)(ddf_fun_t *, int *);
 	int (*get_my_device_handle)(ddf_fun_t *, devman_handle_t *);
-
-	int (*reserve_default_address)(ddf_fun_t *, usb_speed_t);
-	int (*release_default_address)(ddf_fun_t *);
-
-	int (*device_enumerate)(ddf_fun_t *, unsigned);
-	int (*device_remove)(ddf_fun_t *, unsigned);
-
-	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_target_t,
-		uint64_t, char *, size_t,
-		usb_iface_transfer_callback_t, void *);
-	int (*write)(ddf_fun_t *, usb_target_t,
-		uint64_t, const char *, size_t,
-		usb_iface_transfer_callback_t, void *);
 } usb_iface_t;
 
Index: uspace/lib/drv/include/usbhc_iface.h
===================================================================
--- uspace/lib/drv/include/usbhc_iface.h	(revision 41df71f99dd4001594df602dcc612186bdf02430)
+++ uspace/lib/drv/include/usbhc_iface.h	(revision 41df71f99dd4001594df602dcc612186bdf02430)
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * Copyright (c) 2017 Ondrej Hlavaty
+ * 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 libdrv
+ * @addtogroup usb
+ * @{
+ */
+/** @file
+ * @brief USB host controler interface definition. This is the interface of
+ * USB host controller function, which can be used by usb device drivers.
+ */
+
+#ifndef LIBDRV_USBHC_IFACE_H_
+#define LIBDRV_USBHC_IFACE_H_
+
+#include "ddf/driver.h"
+#include <async.h>
+#include <usb/usb.h>
+
+extern int usbhc_reserve_default_address(async_exch_t *, usb_speed_t);
+extern int usbhc_release_default_address(async_exch_t *);
+
+extern int usbhc_device_enumerate(async_exch_t *, unsigned port);
+extern int usbhc_device_remove(async_exch_t *, unsigned port);
+
+extern int usbhc_register_endpoint(async_exch_t *, usb_endpoint_desc_t *);
+extern int usbhc_unregister_endpoint(async_exch_t *, usb_endpoint_desc_t *);
+extern int usbhc_read(async_exch_t *, usb_endpoint_t, uint64_t, void *, size_t,
+    size_t *);
+extern int usbhc_write(async_exch_t *, usb_endpoint_t, uint64_t, const void *,
+    size_t);
+
+/** Defined in usb/host/usb_transfer_batch.h */
+typedef struct usb_transfer_batch usb_transfer_batch_t;
+
+/** Callback for outgoing transfer - clone of usb_transfer_batch_callback_t */
+typedef int (*usbhc_iface_transfer_callback_t)(usb_transfer_batch_t *);
+
+/** USB device communication interface. */
+typedef struct {
+	int (*reserve_default_address)(ddf_fun_t *, usb_speed_t);
+	int (*release_default_address)(ddf_fun_t *);
+
+	int (*device_enumerate)(ddf_fun_t *, unsigned);
+	int (*device_remove)(ddf_fun_t *, unsigned);
+
+	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_target_t,
+		uint64_t, char *, size_t,
+		usbhc_iface_transfer_callback_t, void *);
+	int (*write)(ddf_fun_t *, usb_target_t,
+		uint64_t, const char *, size_t,
+		usbhc_iface_transfer_callback_t, void *);
+} usbhc_iface_t;
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbdev/src/pipes.c
===================================================================
--- uspace/lib/usbdev/src/pipes.c	(revision 479e32d1f14d8a612f29cd0c2feff2501360407b)
+++ uspace/lib/usbdev/src/pipes.c	(revision 41df71f99dd4001594df602dcc612186bdf02430)
@@ -36,5 +36,5 @@
 #include <usb/dev/request.h>
 #include <usb/usb.h>
-#include <usb_iface.h>
+#include <usbhc_iface.h>
 
 #include <assert.h>
@@ -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->desc.endpoint_no, setup_packet, buffer,
+	const int rc = usbhc_read(exch, pipe->desc.endpoint_no, setup_packet, buffer,
 	    buffer_size, &act_size);
 	async_exchange_end(exch);
@@ -151,5 +151,5 @@
 
 	async_exch_t *exch = async_exchange_begin(pipe->bus_session);
-	const int rc = usb_write(exch,
+	const int rc = usbhc_write(exch,
 	    pipe->desc.endpoint_no, setup_packet, buffer, buffer_size);
 	async_exchange_end(exch);
@@ -199,5 +199,5 @@
 	size_t act_size = 0;
 	const int rc =
-	    usb_read(exch, pipe->desc.endpoint_no, 0, buffer, size, &act_size);
+	    usbhc_read(exch, pipe->desc.endpoint_no, 0, buffer, size, &act_size);
 	async_exchange_end(exch);
 
@@ -238,5 +238,5 @@
 
 	async_exch_t *exch = async_exchange_begin(pipe->bus_session);
-	const int rc = usb_write(exch, pipe->desc.endpoint_no, 0, buffer, size);
+	const int rc = usbhc_write(exch, pipe->desc.endpoint_no, 0, buffer, size);
 	async_exchange_end(exch);
 	return rc;
@@ -307,5 +307,5 @@
 		return ENOMEM;
 
-	const int ret = usb_register_endpoint(exch, &pipe->desc);
+	const int ret = usbhc_register_endpoint(exch, &pipe->desc);
 
 	async_exchange_end(exch);
@@ -326,5 +326,5 @@
 		return ENOMEM;
 
-	const int ret = usb_unregister_endpoint(exch, &pipe->desc);
+	const int ret = usbhc_unregister_endpoint(exch, &pipe->desc);
 
 	async_exchange_end(exch);
Index: uspace/lib/usbhost/src/ddf_helpers.c
===================================================================
--- uspace/lib/usbhost/src/ddf_helpers.c	(revision 479e32d1f14d8a612f29cd0c2feff2501360407b)
+++ uspace/lib/usbhost/src/ddf_helpers.c	(revision 41df71f99dd4001594df602dcc612186bdf02430)
@@ -53,4 +53,5 @@
 #include <str_error.h>
 #include <usb_iface.h>
+#include <usbhc_iface.h>
 
 #include "ddf_helpers.h"
@@ -218,5 +219,5 @@
 static int dev_read(ddf_fun_t *fun, usb_target_t target,
     uint64_t setup_data, char *data, size_t size,
-    usb_iface_transfer_callback_t callback, void *arg)
+    usbhc_iface_transfer_callback_t callback, void *arg)
 {
 	assert(fun);
@@ -244,5 +245,5 @@
 static int dev_write(ddf_fun_t *fun, usb_target_t target,
     uint64_t setup_data, const char *data, size_t size,
-    usb_iface_transfer_callback_t callback, void *arg)
+    usbhc_iface_transfer_callback_t callback, void *arg)
 {
 	assert(fun);
@@ -261,5 +262,8 @@
 static usb_iface_t usb_iface = {
 	.get_my_device_handle = get_my_device_handle,
-
+};
+
+/** USB host controller interface */
+static usbhc_iface_t usbhc_iface = {
 	.reserve_default_address = reserve_default_address,
 	.release_default_address = release_default_address,
@@ -278,4 +282,5 @@
 static ddf_dev_ops_t usb_ops = {
 	.interfaces[USB_DEV_IFACE] = &usb_iface,
+	.interfaces[USBHC_DEV_IFACE] = &usbhc_iface,
 };
 
