Index: uspace/lib/drv/generic/remote_usb.c
===================================================================
--- uspace/lib/drv/generic/remote_usb.c	(revision 2449396b19fb28746d546abfb95ce0c13e29f1da)
+++ uspace/lib/drv/generic/remote_usb.c	(revision b8b1e6316d7aaa2e058c2099df2fd5541df4abaa)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2010 Vojtech Horky
+ * Copyright (c) 2011 Jan Vesely
  * All rights reserved.
  *
@@ -39,14 +40,74 @@
 #include "ddf/driver.h"
 
+typedef enum {
+	IPC_M_USB_GET_MY_ADDRESS,
+	IPC_M_USB_GET_MY_INTERFACE,
+	IPC_M_USB_GET_HOST_CONTROLLER_HANDLE,
+} usb_iface_funcs_t;
+
+/** Tell USB address assigned to device.
+ * @param exch Vaid IPC exchange
+ * @param address Pointer to address storage place.
+ * @return Error code.
+ *
+ * Exch param is an open communication to device implementing usb_iface.
+ */
+int usb_get_my_address(async_exch_t *exch, usb_address_t *address)
+{
+	if (!exch)
+		return EINVAL;
+	sysarg_t addr;
+	const int ret = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
+	    IPC_M_USB_GET_MY_ADDRESS, &addr);
+
+	if (ret == EOK && address != NULL)
+		*address = (usb_address_t) addr;
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+/** Tell interface number given device can use.
+ * @param[in] exch IPC communication exchange
+ * @param[in] handle Id of the device
+ * @param[out] usb_iface Assigned USB interface
+ * @return Error code.
+ */
+int usb_get_my_interface(async_exch_t *exch, int *usb_iface)
+{
+	if (!exch)
+		return EINVAL;
+	sysarg_t iface_no;
+	const int ret = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
+	    IPC_M_USB_GET_MY_INTERFACE, &iface_no);
+	if (ret == EOK && usb_iface)
+		*usb_iface = (int)iface_no;
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+/** Tell devman handle of device host controller.
+ * @param[in] exch IPC communication exchange
+ * @param[out] hc_handle devman handle of the HC used by the target device.
+ * @return Error code.
+ */
+int usb_get_hc_handle(async_exch_t *exch, devman_handle_t *hc_handle)
+{
+	if (!exch)
+		return EINVAL;
+	devman_handle_t h;
+	const int ret = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
+	    IPC_M_USB_GET_HOST_CONTROLLER_HANDLE, &h);
+	if (ret == EOK && hc_handle)
+		*hc_handle = (devman_handle_t)h;
+	return ret;
+}
+
 
 static void remote_usb_get_my_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
-static void remote_usb_get_interface(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usb_get_my_interface(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
 static void remote_usb_get_hc_handle(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
-//static void remote_usb(device_t *, void *, ipc_callid_t, ipc_call_t *);
 
 /** Remote USB interface operations. */
 static remote_iface_func_ptr_t remote_usb_iface_ops [] = {
 	[IPC_M_USB_GET_MY_ADDRESS] = remote_usb_get_my_address,
-	[IPC_M_USB_GET_INTERFACE] = remote_usb_get_interface,
+	[IPC_M_USB_GET_MY_INTERFACE] = remote_usb_get_my_interface,
 	[IPC_M_USB_GET_HOST_CONTROLLER_HANDLE] = remote_usb_get_hc_handle,
 };
@@ -60,9 +121,9 @@
 };
 
-
+/*----------------------------------------------------------------------------*/
 void remote_usb_get_my_address(ddf_fun_t *fun, void *iface,
     ipc_callid_t callid, ipc_call_t *call)
 {
-	usb_iface_t *usb_iface = (usb_iface_t *) iface;
+	const usb_iface_t *usb_iface = (usb_iface_t *) iface;
 
 	if (usb_iface->get_my_address == NULL) {
@@ -72,37 +133,35 @@
 
 	usb_address_t address;
-	int rc = usb_iface->get_my_address(fun, &address);
-	if (rc != EOK) {
-		async_answer_0(callid, rc);
+	const int ret = usb_iface->get_my_address(fun, &address);
+	if (ret != EOK) {
+		async_answer_0(callid, ret);
 	} else {
 		async_answer_1(callid, EOK, address);
 	}
 }
-
-void remote_usb_get_interface(ddf_fun_t *fun, void *iface,
+/*----------------------------------------------------------------------------*/
+void remote_usb_get_my_interface(ddf_fun_t *fun, void *iface,
     ipc_callid_t callid, ipc_call_t *call)
 {
-	usb_iface_t *usb_iface = (usb_iface_t *) iface;
+	const usb_iface_t *usb_iface = (usb_iface_t *) iface;
 
-	if (usb_iface->get_interface == NULL) {
+	if (usb_iface->get_my_interface == NULL) {
 		async_answer_0(callid, ENOTSUP);
 		return;
 	}
 
-	devman_handle_t handle = DEV_IPC_GET_ARG1(*call);
-
 	int iface_no;
-	int rc = usb_iface->get_interface(fun, handle, &iface_no);
-	if (rc != EOK) {
-		async_answer_0(callid, rc);
+	const int ret = usb_iface->get_my_interface(fun, &iface_no);
+	if (ret != EOK) {
+		async_answer_0(callid, ret);
 	} else {
 		async_answer_1(callid, EOK, iface_no);
 	}
 }
-
+/*----------------------------------------------------------------------------*/
 void remote_usb_get_hc_handle(ddf_fun_t *fun, void *iface,
     ipc_callid_t callid, ipc_call_t *call)
 {
-	usb_iface_t *usb_iface = (usb_iface_t *) iface;
+	const usb_iface_t *usb_iface = (usb_iface_t *) iface;
 
 	if (usb_iface->get_hc_handle == NULL) {
@@ -112,14 +171,11 @@
 
 	devman_handle_t handle;
-	int rc = usb_iface->get_hc_handle(fun, &handle);
-	if (rc != EOK) {
-		async_answer_0(callid, rc);
+	const int ret = usb_iface->get_hc_handle(fun, &handle);
+	if (ret != EOK) {
+		async_answer_0(callid, ret);
 	}
 
 	async_answer_1(callid, EOK, (sysarg_t) handle);
 }
-
-
-
 /**
  * @}
Index: uspace/lib/drv/generic/remote_usbhc.c
===================================================================
--- uspace/lib/drv/generic/remote_usbhc.c	(revision 2449396b19fb28746d546abfb95ce0c13e29f1da)
+++ uspace/lib/drv/generic/remote_usbhc.c	(revision b8b1e6316d7aaa2e058c2099df2fd5541df4abaa)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2010-2011 Vojtech Horky
+ * Copyright (c) 2011 Jan Vesely
  * All rights reserved.
  *
@@ -42,7 +43,285 @@
 #define USB_MAX_PAYLOAD_SIZE 1020
 
+/** IPC methods for communication with HC through DDF interface.
+ *
+ * Notes for async methods:
+ *
+ * Methods for sending data to device (OUT transactions)
+ * - e.g. IPC_M_USBHC_INTERRUPT_OUT -
+ * always use the same semantics:
+ * - first, IPC call with given method is made
+ *   - argument #1 is target address
+ *   - argument #2 is target endpoint
+ *   - argument #3 is max packet size of the endpoint
+ * - this call is immediately followed by IPC data write (from caller)
+ * - the initial call (and the whole transaction) is answer after the
+ *   transaction is scheduled by the HC and acknowledged by the device
+ *   or immediately after error is detected
+ * - the answer carries only the error code
+ *
+ * Methods for retrieving data from device (IN transactions)
+ * - e.g. IPC_M_USBHC_INTERRUPT_IN -
+ * also use the same semantics:
+ * - first, IPC call with given method is made
+ *   - argument #1 is target address
+ *   - argument #2 is target endpoint
+ * - this call is immediately followed by IPC data read (async version)
+ * - the call is not answered until the device returns some data (or until
+ *   error occurs)
+ *
+ * Some special methods (NO-DATA transactions) do not send any data. These
+ * might behave as both OUT or IN transactions because communication parts
+ * where actual buffers are exchanged are omitted.
+ **
+ * For all these methods, wrap functions exists. Important rule: functions
+ * for IN transactions have (as parameters) buffers where retrieved data
+ * will be stored. These buffers must be already allocated and shall not be
+ * touch until the transaction is completed
+ * (e.g. not before calling usb_wait_for() with appropriate handle).
+ * OUT transactions buffers can be freed immediately after call is dispatched
+ * (i.e. after return from wrapping function).
+ *
+ */
+typedef enum {
+	/** Asks for address assignment by host controller.
+	 * Answer:
+	 * - ELIMIT - host controller run out of address
+	 * - EOK - address assigned
+	 * Answer arguments:
+	 * - assigned address
+	 *
+	 * The address must be released by via IPC_M_USBHC_RELEASE_ADDRESS.
+	 */
+	IPC_M_USBHC_REQUEST_ADDRESS,
+
+	/** Bind USB address with devman handle.
+	 * Parameters:
+	 * - USB address
+	 * - devman handle
+	 * Answer:
+	 * - EOK - address binded
+	 * - ENOENT - address is not in use
+	 */
+	IPC_M_USBHC_BIND_ADDRESS,
+
+	/** Get handle binded with given USB address.
+	 * Parameters
+	 * - USB address
+	 * Answer:
+	 * - EOK - address binded, first parameter is the devman handle
+	 * - ENOENT - address is not in use at the moment
+	 */
+	IPC_M_USBHC_GET_HANDLE_BY_ADDRESS,
+
+	/** Release address in use.
+	 * Arguments:
+	 * - address to be released
+	 * Answer:
+	 * - ENOENT - address not in use
+	 * - EPERM - trying to release default USB address
+	 */
+	IPC_M_USBHC_RELEASE_ADDRESS,
+
+	/** Register endpoint attributes at host controller.
+	 * This is used to reserve portion of USB bandwidth.
+	 * When speed is invalid, speed of the device is used.
+	 * Parameters:
+	 * - USB address + endpoint number
+	 *   - packed as ADDR << 16 + EP
+	 * - speed + transfer type + direction
+	 *   - packed as ( SPEED << 8 + TYPE ) << 8 + DIR
+	 * - maximum packet size + interval (in milliseconds)
+	 *   - packed as MPS << 16 + INT
+	 * Answer:
+	 * - EOK - reservation successful
+	 * - ELIMIT - not enough bandwidth to satisfy the request
+	 */
+	IPC_M_USBHC_REGISTER_ENDPOINT,
+
+	/** Revert endpoint registration.
+	 * Parameters:
+	 * - USB address
+	 * - endpoint number
+	 * - data direction
+	 * Answer:
+	 * - EOK - endpoint unregistered
+	 * - ENOENT - unknown endpoint
+	 */
+	IPC_M_USBHC_UNREGISTER_ENDPOINT,
+
+	/** Get data from device.
+	 * See explanation at usb_iface_funcs_t (IN transaction).
+	 */
+	IPC_M_USBHC_READ,
+
+	/** Send data to device.
+	 * See explanation at usb_iface_funcs_t (OUT transaction).
+	 */
+	IPC_M_USBHC_WRITE,
+} usbhc_iface_funcs_t;
+
+int usbhc_request_address(async_exch_t *exch, usb_address_t *address,
+    bool strict, usb_speed_t speed)
+{
+	if (!exch || !address)
+		return EINVAL;
+	sysarg_t new_address;
+	const int ret = async_req_4_1(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_REQUEST_ADDRESS, *address, strict, speed, &new_address);
+	if (ret == EOK)
+		*address = (usb_address_t)new_address;
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+int usbhc_bind_address(async_exch_t *exch, usb_address_t address,
+    devman_handle_t handle)
+{
+	if (!exch)
+		return EINVAL;
+	return async_req_3_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_BIND_ADDRESS, address, handle);
+}
+/*----------------------------------------------------------------------------*/
+int usbhc_get_handle(async_exch_t *exch, usb_address_t address,
+    devman_handle_t *handle)
+{
+	if (!exch)
+		return EINVAL;
+	sysarg_t h;
+	const int ret = async_req_2_1(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_GET_HANDLE_BY_ADDRESS, address, &h);
+	if (ret == EOK && handle)
+		*handle = (devman_handle_t)h;
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+int usbhc_release_address(async_exch_t *exch, usb_address_t address)
+{
+	if (!exch)
+		return EINVAL;
+	return async_req_2_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_RELEASE_ADDRESS, address);
+}
+/*----------------------------------------------------------------------------*/
+int usbhc_register_endpoint(async_exch_t *exch, usb_address_t address,
+    usb_endpoint_t endpoint, usb_transfer_type_t type,
+    usb_direction_t direction, size_t mps, unsigned interval)
+{
+	if (!exch)
+		return EINVAL;
+	const usb_target_t target =
+	    {{ .address = address, .endpoint = endpoint }};
+#define _PACK2(high, low) (((high & 0xffff) << 16) | (low & 0xffff))
+
+	return async_req_4_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_REGISTER_ENDPOINT, target.packed,
+	    _PACK2(type, direction), _PACK2(mps, interval));
+
+#undef _PACK2
+}
+/*----------------------------------------------------------------------------*/
+int usbhc_unregister_endpoint(async_exch_t *exch, usb_address_t address,
+    usb_endpoint_t endpoint, usb_direction_t direction)
+{
+	if (!exch)
+		return EINVAL;
+	return async_req_4_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_UNREGISTER_ENDPOINT, address, endpoint, direction);
+}
+/*----------------------------------------------------------------------------*/
+int usbhc_read(async_exch_t *exch, usb_address_t address,
+    usb_endpoint_t endpoint, uint64_t setup, void *data, size_t size,
+    size_t *rec_size)
+{
+	if (size == 0 && setup == 0)
+		return EOK;
+
+	if (!exch)
+		return EINVAL;
+	const usb_target_t target =
+	    {{ .address = address, .endpoint = endpoint }};
+
+	/* 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_USBHC_READ, target.packed,
+	    (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_wait_for(opening_request, NULL);
+		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_address_t address,
+    usb_endpoint_t endpoint, uint64_t setup, const void *data, size_t size)
+{
+	if (size == 0 && setup == 0)
+		return EOK;
+
+	if (!exch)
+		return EINVAL;
+	const usb_target_t target =
+	    {{ .address = address, .endpoint = endpoint }};
+
+	aid_t opening_request = async_send_5(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_WRITE, target.packed, 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_wait_for(opening_request, NULL);
+			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_request_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
 static void remote_usbhc_bind_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
-static void remote_usbhc_find_by_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_get_handle(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
 static void remote_usbhc_release_address(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 *);
@@ -57,5 +336,5 @@
 	[IPC_M_USBHC_RELEASE_ADDRESS] = remote_usbhc_release_address,
 	[IPC_M_USBHC_BIND_ADDRESS] = remote_usbhc_bind_address,
-	[IPC_M_USBHC_GET_HANDLE_BY_ADDRESS] = remote_usbhc_find_by_address,
+	[IPC_M_USBHC_GET_HANDLE_BY_ADDRESS] = remote_usbhc_get_handle,
 
 	[IPC_M_USBHC_REGISTER_ENDPOINT] = remote_usbhc_register_endpoint,
@@ -78,5 +357,4 @@
 	ipc_callid_t data_caller;
 	void *buffer;
-	size_t size;
 } async_transaction_t;
 
@@ -103,13 +381,12 @@
 	trans->data_caller = 0;
 	trans->buffer = NULL;
-	trans->size = 0;
 
 	return trans;
 }
-
+/*----------------------------------------------------------------------------*/
 void remote_usbhc_request_address(ddf_fun_t *fun, void *iface,
     ipc_callid_t callid, ipc_call_t *call)
 {
-	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+	const usbhc_iface_t *usb_iface = iface;
 
 	if (!usb_iface->request_address) {
@@ -129,9 +406,9 @@
 	}
 }
-
+/*----------------------------------------------------------------------------*/
 void remote_usbhc_bind_address(ddf_fun_t *fun, void *iface,
     ipc_callid_t callid, ipc_call_t *call)
 {
-	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+	const usbhc_iface_t *usb_iface = iface;
 
 	if (!usb_iface->bind_address) {
@@ -140,37 +417,36 @@
 	}
 
-	usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
-	devman_handle_t handle = (devman_handle_t) DEV_IPC_GET_ARG2(*call);
-
-	int rc = usb_iface->bind_address(fun, address, handle);
-
-	async_answer_0(callid, rc);
-}
-
-void remote_usbhc_find_by_address(ddf_fun_t *fun, void *iface,
+	const usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
+	const devman_handle_t handle = (devman_handle_t) DEV_IPC_GET_ARG2(*call);
+
+	const int ret = usb_iface->bind_address(fun, address, handle);
+	async_answer_0(callid, ret);
+}
+/*----------------------------------------------------------------------------*/
+void remote_usbhc_get_handle(ddf_fun_t *fun, void *iface,
     ipc_callid_t callid, ipc_call_t *call)
 {
-	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
-
-	if (!usb_iface->find_by_address) {
-		async_answer_0(callid, ENOTSUP);
-		return;
-	}
-
-	usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
+	const usbhc_iface_t *usb_iface = iface;
+
+	if (!usb_iface->get_handle) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	const usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
 	devman_handle_t handle;
-	int rc = usb_iface->find_by_address(fun, address, &handle);
-
-	if (rc == EOK) {
-		async_answer_1(callid, EOK, handle);
+	const int ret = usb_iface->get_handle(fun, address, &handle);
+
+	if (ret == EOK) {
+		async_answer_1(callid, ret, handle);
 	} else {
-		async_answer_0(callid, rc);
-	}
-}
-
+		async_answer_0(callid, ret);
+	}
+}
+/*----------------------------------------------------------------------------*/
 void remote_usbhc_release_address(ddf_fun_t *fun, void *iface,
     ipc_callid_t callid, ipc_call_t *call)
 {
-	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+	const usbhc_iface_t *usb_iface = iface;
 
 	if (!usb_iface->release_address) {
@@ -179,16 +455,14 @@
 	}
 
-	usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
-
-	int rc = usb_iface->release_address(fun, address);
-
-	async_answer_0(callid, rc);
-}
-
-
+	const usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
+
+	const int ret = usb_iface->release_address(fun, address);
+	async_answer_0(callid, ret);
+}
+/*----------------------------------------------------------------------------*/
 static void callback_out(ddf_fun_t *fun,
     int outcome, void *arg)
 {
-	async_transaction_t *trans = (async_transaction_t *)arg;
+	async_transaction_t *trans = arg;
 
 	async_answer_0(trans->caller, outcome);
@@ -196,5 +470,5 @@
 	async_transaction_destroy(trans);
 }
-
+/*----------------------------------------------------------------------------*/
 static void callback_in(ddf_fun_t *fun,
     int outcome, size_t actual_size, void *arg)
@@ -211,6 +485,4 @@
 	}
 
-	trans->size = actual_size;
-
 	if (trans->data_caller) {
 		async_data_read_finalize(trans->data_caller,
@@ -222,5 +494,5 @@
 	async_transaction_destroy(trans);
 }
-
+/*----------------------------------------------------------------------------*/
 void remote_usbhc_register_endpoint(ddf_fun_t *fun, void *iface,
     ipc_callid_t callid, ipc_call_t *call)
@@ -300,10 +572,11 @@
 	}
 
-	if (!async_data_read_receive(&trans->data_caller, &trans->size)) {
+	size_t size = 0;
+	if (!async_data_read_receive(&trans->data_caller, &size)) {
 		async_answer_0(callid, EPARTY);
 		return;
 	}
 
-	trans->buffer = malloc(trans->size);
+	trans->buffer = malloc(size);
 	if (trans->buffer == NULL) {
 		async_answer_0(trans->data_caller, ENOMEM);
@@ -313,5 +586,5 @@
 
 	const int rc = hc_iface->read(
-	    fun, target, setup, trans->buffer, trans->size, callback_in, trans);
+	    fun, target, setup, trans->buffer, size, callback_in, trans);
 
 	if (rc != EOK) {
@@ -321,5 +594,5 @@
 	}
 }
-
+/*----------------------------------------------------------------------------*/
 void remote_usbhc_write(
     ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
@@ -348,8 +621,9 @@
 	}
 
+	size_t size = 0;
 	if (data_buffer_len > 0) {
-		int rc = async_data_write_accept(&trans->buffer, false,
+		const int rc = async_data_write_accept(&trans->buffer, false,
 		    1, USB_MAX_PAYLOAD_SIZE,
-		    0, &trans->size);
+		    0, &size);
 
 		if (rc != EOK) {
@@ -360,6 +634,6 @@
 	}
 
-	int rc = hc_iface->write(
-	    fun, target, setup, trans->buffer, trans->size, callback_out, trans);
+	const int rc = hc_iface->write(
+	    fun, target, setup, trans->buffer, size, callback_out, trans);
 
 	if (rc != EOK) {
@@ -368,6 +642,4 @@
 	}
 }
-
-
 /**
  * @}
Index: uspace/lib/drv/include/usb_iface.h
===================================================================
--- uspace/lib/drv/include/usb_iface.h	(revision 2449396b19fb28746d546abfb95ce0c13e29f1da)
+++ uspace/lib/drv/include/usb_iface.h	(revision b8b1e6316d7aaa2e058c2099df2fd5541df4abaa)
@@ -39,60 +39,17 @@
 
 #include "ddf/driver.h"
+#include <async.h>
 #include <usb/usb.h>
-typedef enum {
-	/** Tell USB address assigned to device.
-	 * Parameters:
-	 * - devman handle id
-	 * Answer:
-	 * - EINVAL - unknown handle or handle not managed by this driver
-	 * - ENOTSUP - operation not supported (shall not happen)
-	 * - arbitrary error code if returned by remote implementation
-	 * - EOK - handle found, first parameter contains the USB address
-	 *
-	 * The handle must be the one used for binding USB address with
-	 * it (IPC_M_USBHC_BIND_ADDRESS), otherwise the host controller
-	 * (that this request would eventually reach) would not be able
-	 * to find it.
-	 * The problem is that this handle is actually assigned to the
-	 * function inside driver of the parent device (usually hub driver).
-	 * To bypass this problem, the initial caller specify handle as
-	 * zero and the first parent assigns the actual value.
-	 * See usb_iface_get_address_hub_child_impl() implementation
-	 * that could be assigned to device ops of a child device of in a
-	 * hub driver.
-	 * For example, the USB multi interface device driver (MID)
-	 * passes this initial zero without any modification because the
-	 * handle must be resolved by its parent.
-	 */
-	IPC_M_USB_GET_MY_ADDRESS,
 
-	/** Tell interface number given device can use.
-	 * Parameters
-	 * - devman handle id of the device
-	 * Answer:
-	 * - ENOTSUP - operation not supported (can also mean any interface)
-	 * - EOK - operation okay, first parameter contains interface number
-	 */
-	IPC_M_USB_GET_INTERFACE,
-
-	/** Tell devman handle of device host controller.
-	 * Parameters:
-	 * - none
-	 * Answer:
-	 * - EOK - request processed without errors
-	 * - ENOTSUP - this indicates invalid USB driver
-	 * Parameters of the answer:
-	 * - devman handle of HC caller is physically connected to
-	 */
-	IPC_M_USB_GET_HOST_CONTROLLER_HANDLE
-} usb_iface_funcs_t;
+int usb_get_my_address(async_exch_t *, usb_address_t *);
+int usb_get_my_interface(async_exch_t *, int *);
+int usb_get_hc_handle(async_exch_t *, devman_handle_t *);
 
 /** USB device communication interface. */
 typedef struct {
 	int (*get_my_address)(ddf_fun_t *, usb_address_t *);
-	int (*get_interface)(ddf_fun_t *, devman_handle_t, int *);
+	int (*get_my_interface)(ddf_fun_t *, int *);
 	int (*get_hc_handle)(ddf_fun_t *, devman_handle_t *);
 } usb_iface_t;
-
 
 #endif
Index: uspace/lib/drv/include/usbhc_iface.h
===================================================================
--- uspace/lib/drv/include/usbhc_iface.h	(revision 2449396b19fb28746d546abfb95ce0c13e29f1da)
+++ uspace/lib/drv/include/usbhc_iface.h	(revision b8b1e6316d7aaa2e058c2099df2fd5541df4abaa)
@@ -42,122 +42,16 @@
 #include <bool.h>
 
-
-/** IPC methods for communication with HC through DDF interface.
- *
- * Notes for async methods:
- *
- * Methods for sending data to device (OUT transactions)
- * - e.g. IPC_M_USBHC_INTERRUPT_OUT -
- * always use the same semantics:
- * - first, IPC call with given method is made
- *   - argument #1 is target address
- *   - argument #2 is target endpoint
- *   - argument #3 is max packet size of the endpoint
- * - this call is immediately followed by IPC data write (from caller)
- * - the initial call (and the whole transaction) is answer after the
- *   transaction is scheduled by the HC and acknowledged by the device
- *   or immediately after error is detected
- * - the answer carries only the error code
- *
- * Methods for retrieving data from device (IN transactions)
- * - e.g. IPC_M_USBHC_INTERRUPT_IN -
- * also use the same semantics:
- * - first, IPC call with given method is made
- *   - argument #1 is target address
- *   - argument #2 is target endpoint
- * - this call is immediately followed by IPC data read (async version)
- * - the call is not answered until the device returns some data (or until
- *   error occurs)
- *
- * Some special methods (NO-DATA transactions) do not send any data. These
- * might behave as both OUT or IN transactions because communication parts
- * where actual buffers are exchanged are omitted.
- **
- * For all these methods, wrap functions exists. Important rule: functions
- * for IN transactions have (as parameters) buffers where retrieved data
- * will be stored. These buffers must be already allocated and shall not be
- * touch until the transaction is completed
- * (e.g. not before calling usb_wait_for() with appropriate handle).
- * OUT transactions buffers can be freed immediately after call is dispatched
- * (i.e. after return from wrapping function).
- *
- */
-typedef enum {
-	/** Asks for address assignment by host controller.
-	 * Answer:
-	 * - ELIMIT - host controller run out of address
-	 * - EOK - address assigned
-	 * Answer arguments:
-	 * - assigned address
-	 *
-	 * The address must be released by via IPC_M_USBHC_RELEASE_ADDRESS.
-	 */
-	IPC_M_USBHC_REQUEST_ADDRESS,
-
-	/** Bind USB address with devman handle.
-	 * Parameters:
-	 * - USB address
-	 * - devman handle
-	 * Answer:
-	 * - EOK - address binded
-	 * - ENOENT - address is not in use
-	 */
-	IPC_M_USBHC_BIND_ADDRESS,
-
-	/** Get handle binded with given USB address.
-	 * Parameters
-	 * - USB address
-	 * Answer:
-	 * - EOK - address binded, first parameter is the devman handle
-	 * - ENOENT - address is not in use at the moment
-	 */
-	IPC_M_USBHC_GET_HANDLE_BY_ADDRESS,
-
-	/** Release address in use.
-	 * Arguments:
-	 * - address to be released
-	 * Answer:
-	 * - ENOENT - address not in use
-	 * - EPERM - trying to release default USB address
-	 */
-	IPC_M_USBHC_RELEASE_ADDRESS,
-
-	/** Register endpoint attributes at host controller.
-	 * This is used to reserve portion of USB bandwidth.
-	 * When speed is invalid, speed of the device is used.
-	 * Parameters:
-	 * - USB address + endpoint number
-	 *   - packed as ADDR << 16 + EP
-	 * - speed + transfer type + direction
-	 *   - packed as ( SPEED << 8 + TYPE ) << 8 + DIR
-	 * - maximum packet size + interval (in milliseconds)
-	 *   - packed as MPS << 16 + INT
-	 * Answer:
-	 * - EOK - reservation successful
-	 * - ELIMIT - not enough bandwidth to satisfy the request
-	 */
-	IPC_M_USBHC_REGISTER_ENDPOINT,
-
-	/** Revert endpoint registration.
-	 * Parameters:
-	 * - USB address
-	 * - endpoint number
-	 * - data direction
-	 * Answer:
-	 * - EOK - endpoint unregistered
-	 * - ENOENT - unknown endpoint
-	 */
-	IPC_M_USBHC_UNREGISTER_ENDPOINT,
-
-	/** Get data from device.
-	 * See explanation at usb_iface_funcs_t (IN transaction).
-	 */
-	IPC_M_USBHC_READ,
-
-	/** Send data to device.
-	 * See explanation at usb_iface_funcs_t (OUT transaction).
-	 */
-	IPC_M_USBHC_WRITE,
-} usbhc_iface_funcs_t;
+int usbhc_request_address(async_exch_t *, usb_address_t *, bool, usb_speed_t);
+int usbhc_bind_address(async_exch_t *, usb_address_t, devman_handle_t);
+int usbhc_get_handle(async_exch_t *, usb_address_t, devman_handle_t *);
+int usbhc_release_address(async_exch_t *, usb_address_t);
+int usbhc_register_endpoint(async_exch_t *, usb_address_t,  usb_endpoint_t,
+    usb_transfer_type_t, usb_direction_t, size_t, unsigned int);
+int usbhc_unregister_endpoint(async_exch_t *, usb_address_t, usb_endpoint_t,
+    usb_direction_t);
+int usbhc_read(async_exch_t *, usb_address_t, usb_endpoint_t,
+    uint64_t, void *, size_t, size_t *);
+int usbhc_write(async_exch_t *, usb_address_t, usb_endpoint_t,
+    uint64_t, const void *, size_t);
 
 /** Callback for outgoing transfer. */
@@ -172,5 +66,6 @@
 	int (*request_address)(ddf_fun_t *, usb_address_t *, bool, usb_speed_t);
 	int (*bind_address)(ddf_fun_t *, usb_address_t, devman_handle_t);
-	int (*find_by_address)(ddf_fun_t *, usb_address_t, devman_handle_t *);
+	int (*get_handle)(ddf_fun_t *, usb_address_t,
+	    devman_handle_t *);
 	int (*release_address)(ddf_fun_t *, usb_address_t);
 
Index: uspace/lib/usb/src/ddfiface.c
===================================================================
--- uspace/lib/usb/src/ddfiface.c	(revision 2449396b19fb28746d546abfb95ce0c13e29f1da)
+++ uspace/lib/usb/src/ddfiface.c	(revision b8b1e6316d7aaa2e058c2099df2fd5541df4abaa)
@@ -36,4 +36,5 @@
 #include <devman.h>
 #include <async.h>
+#include <usb_iface.h>
 #include <usb/ddfiface.h>
 #include <usb/hc.h>
@@ -104,19 +105,15 @@
 
 	async_exch_t *exch = async_exchange_begin(parent_sess);
+	if (!exch) {
+		async_hangup(parent_sess);
+		return ENOMEM;
+	}
 
-	sysarg_t addr;
-	int rc = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
-	    IPC_M_USB_GET_MY_ADDRESS, &addr);
+	const int ret = usb_get_my_address(exch, address);
 
 	async_exchange_end(exch);
 	async_hangup(parent_sess);
 
-	if (rc != EOK)
-		return rc;
-
-	if (address != NULL)
-		*address = (usb_address_t) addr;
-
-	return EOK;
+	return ret;
 }
 
Index: uspace/lib/usb/src/hc.c
===================================================================
--- uspace/lib/usb/src/hc.c	(revision 2449396b19fb28746d546abfb95ce0c13e29f1da)
+++ uspace/lib/usb/src/hc.c	(revision b8b1e6316d7aaa2e058c2099df2fd5541df4abaa)
@@ -153,18 +153,11 @@
 	if (!usb_hc_connection_is_opened(connection))
 		return ENOENT;
-	
+
 	async_exch_t *exch = async_exchange_begin(connection->hc_sess);
-	
-	sysarg_t tmp;
-	int rc = async_req_2_1(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
-	    IPC_M_USBHC_GET_HANDLE_BY_ADDRESS,
-	    address, &tmp);
-	
+	if (!exch)
+		return ENOMEM;
+	const int ret = usbhc_get_handle(exch, address, handle);
 	async_exchange_end(exch);
-	
-	if ((rc == EOK) && (handle != NULL))
-		*handle = tmp;
-	
-	return rc;
+	return ret;
 }
 
@@ -181,18 +174,20 @@
 	if (!parent_sess)
 		return ENOMEM;
-	
+
 	async_exch_t *exch = async_exchange_begin(parent_sess);
-	
-	sysarg_t address;
-	int rc = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
-	    IPC_M_USB_GET_MY_ADDRESS, &address);
-	
+	if (!exch) {
+		async_hangup(parent_sess);
+		return ENOMEM;
+	}
+	usb_address_t address;
+	const int ret = usb_get_my_address(exch, &address);
+
 	async_exchange_end(exch);
 	async_hangup(parent_sess);
-	
-	if (rc != EOK)
-		return rc;
-	
-	return (usb_address_t) address;
+
+	if (ret != EOK)
+		return ret;
+
+	return address;
 }
 
@@ -231,21 +226,16 @@
 	if (!parent_sess)
 		return ENOMEM;
-	
+
 	async_exch_t *exch = async_exchange_begin(parent_sess);
-	
-	devman_handle_t h;
-	int rc = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
-	    IPC_M_USB_GET_HOST_CONTROLLER_HANDLE, &h);
-	
+	if (!exch) {
+		async_hangup(parent_sess);
+		return ENOMEM;
+	}
+	const int ret = usb_get_hc_handle(exch, hc_handle);
+
 	async_exchange_end(exch);
 	async_hangup(parent_sess);
-	
-	if (rc != EOK)
-		return rc;
-	
-	if (hc_handle != NULL)
-		*hc_handle = h;
-	
-	return EOK;
+
+	return ret;
 }
 
Index: uspace/lib/usbdev/include/usb/dev/pipes.h
===================================================================
--- uspace/lib/usbdev/include/usb/dev/pipes.h	(revision 2449396b19fb28746d546abfb95ce0c13e29f1da)
+++ uspace/lib/usbdev/include/usb/dev/pipes.h	(revision b8b1e6316d7aaa2e058c2099df2fd5541df4abaa)
@@ -179,5 +179,5 @@
 
 int usb_pipe_read(usb_pipe_t *, void *, size_t, size_t *);
-int usb_pipe_write(usb_pipe_t *, void *, size_t);
+int usb_pipe_write(usb_pipe_t *, const void *, size_t);
 
 int usb_pipe_control_read(usb_pipe_t *, const void *, size_t,
Index: uspace/lib/usbdev/include/usb/dev/request.h
===================================================================
--- uspace/lib/usbdev/include/usb/dev/request.h	(revision 2449396b19fb28746d546abfb95ce0c13e29f1da)
+++ uspace/lib/usbdev/include/usb/dev/request.h	(revision b8b1e6316d7aaa2e058c2099df2fd5541df4abaa)
@@ -82,4 +82,6 @@
 	 */
 	uint8_t request_type;
+#define SETUP_REQUEST_TYPE_DEVICE_TO_HOST (1 << 7)
+
 	/** Request identification. */
 	uint8_t request;
Index: uspace/lib/usbdev/src/altiface.c
===================================================================
--- uspace/lib/usbdev/src/altiface.c	(revision 2449396b19fb28746d546abfb95ce0c13e29f1da)
+++ uspace/lib/usbdev/src/altiface.c	(revision b8b1e6316d7aaa2e058c2099df2fd5541df4abaa)
@@ -65,13 +65,11 @@
 	size_t alternate_count = 0;
 
-	const uint8_t *iface_ptr = usb_dp_get_nested_descriptor(&dp_parser,
-	    &dp_data, config_descr);
+	const void *iface_ptr =
+	    usb_dp_get_nested_descriptor(&dp_parser, &dp_data, config_descr);
 	while (iface_ptr != NULL) {
-		usb_standard_interface_descriptor_t *iface
-		    = (usb_standard_interface_descriptor_t *) iface_ptr;
-		if (iface->descriptor_type == USB_DESCTYPE_INTERFACE) {
-			if (iface->interface_number == interface_no) {
-				alternate_count++;
-			}
+		const usb_standard_interface_descriptor_t *iface = iface_ptr;
+		if (iface->descriptor_type == USB_DESCTYPE_INTERFACE
+		    && iface->interface_number == interface_no) {
+			++alternate_count;
 		}
 		iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser, &dp_data,
@@ -82,10 +80,10 @@
 }
 
-/** Create alternate interface representation structure.
+/** Initialize alternate interface representation structure.
  *
+ * @param[in] alternates Pointer to allocated structure.
  * @param[in] config_descr Configuration descriptor.
  * @param[in] config_descr_size Size of configuration descriptor.
  * @param[in] interface_number Interface number.
- * @param[out] alternates_ptr Where to store pointer to allocated structure.
  * @return Error code.
  */
@@ -101,4 +99,5 @@
 	alternates->current = 0;
 
+	/* No interfaces. */
 	if (interface_number < 0) {
 		return EOK;
@@ -107,5 +106,5 @@
 	alternates->alternative_count
 	    = usb_interface_count_alternates(config_descr, config_descr_size,
-	    interface_number);
+	        interface_number);
 
 	if (alternates->alternative_count == 0) {
@@ -128,14 +127,20 @@
 	};
 
-	usb_alternate_interface_descriptors_t *cur_alt_iface
+	usb_alternate_interface_descriptors_t *iterator
 	    = &alternates->alternatives[0];
 
-	const uint8_t *iface_ptr = usb_dp_get_nested_descriptor(&dp_parser,
-	    &dp_data, dp_data.data);
-	while (iface_ptr != NULL) {
-		usb_standard_interface_descriptor_t *iface
-		    = (usb_standard_interface_descriptor_t *) iface_ptr;
+	const usb_alternate_interface_descriptors_t *end
+	    = &alternates->alternatives[alternates->alternative_count];
+
+	const void *iface_ptr =
+	    usb_dp_get_nested_descriptor(&dp_parser, &dp_data, dp_data.data);
+
+	while (iface_ptr != NULL && iterator < end) {
+		const usb_standard_interface_descriptor_t *iface = iface_ptr;
+
 		if ((iface->descriptor_type != USB_DESCTYPE_INTERFACE)
 		    || (iface->interface_number != interface_number)) {
+			/* This is not a valid alternate interface descriptor
+			 * for interface with number == interface_number. */
 			iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser,
 			    &dp_data, dp_data.data, iface_ptr);
@@ -143,20 +148,18 @@
 		}
 
-		cur_alt_iface->interface = iface;
-		cur_alt_iface->nested_descriptors = iface_ptr + sizeof(*iface);
+		iterator->interface = iface;
+		iterator->nested_descriptors = iface_ptr + sizeof(*iface);
 
 		/* Find next interface to count size of nested descriptors. */
 		iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser, &dp_data,
 		    dp_data.data, iface_ptr);
-		if (iface_ptr == NULL) {
-			const uint8_t *next = dp_data.data + dp_data.size;
-			cur_alt_iface->nested_descriptors_size
-			    = next - cur_alt_iface->nested_descriptors;
-		} else {
-			cur_alt_iface->nested_descriptors_size
-			    = iface_ptr - cur_alt_iface->nested_descriptors;
-		}
 
-		cur_alt_iface++;
+		const uint8_t *next = (iface_ptr == NULL) ?
+		    dp_data.data + dp_data.size : iface_ptr;
+
+		iterator->nested_descriptors_size
+		    = next - iterator->nested_descriptors;
+
+		++iterator;
 	}
 
Index: uspace/lib/usbdev/src/devpoll.c
===================================================================
--- uspace/lib/usbdev/src/devpoll.c	(revision 2449396b19fb28746d546abfb95ce0c13e29f1da)
+++ uspace/lib/usbdev/src/devpoll.c	(revision b8b1e6316d7aaa2e058c2099df2fd5541df4abaa)
@@ -46,11 +46,5 @@
 /** Data needed for polling. */
 typedef struct {
-	int debug;
-	size_t max_failures;
-	useconds_t delay;
-	bool auto_clear_halt;
-	bool (*on_data)(usb_device_t *, uint8_t *, size_t, void *);
-	void (*on_polling_end)(usb_device_t *, bool, void *);
-	bool (*on_error)(usb_device_t *, int, void *);
+	usb_device_auto_polling_t auto_polling;
 
 	usb_device_t *dev;
@@ -69,38 +63,38 @@
 static int polling_fibril(void *arg)
 {
-	polling_data_t *polling_data = (polling_data_t *) arg;
-	assert(polling_data);
+	assert(arg);
+	const polling_data_t *data = arg;
+	/* Helper to reduce typing. */
+	const usb_device_auto_polling_t *params = &data->auto_polling;
 
 	usb_pipe_t *pipe
-	    = &polling_data->dev->pipes[polling_data->pipe_index].pipe;
-	
-	if (polling_data->debug > 0) {
-		usb_endpoint_mapping_t *mapping
-		    = &polling_data->dev->pipes[polling_data->pipe_index];
+	    = &data->dev->pipes[data->pipe_index].pipe;
+
+	if (params->debug > 0) {
+		const usb_endpoint_mapping_t *mapping
+		    = &data->dev->pipes[data->pipe_index];
 		usb_log_debug("Poll%p: started polling of `%s' - " \
 		    "interface %d (%s,%d,%d), %zuB/%zu.\n",
-		    polling_data,
-		    polling_data->dev->ddf_dev->name,
+		    data, data->dev->ddf_dev->name,
 		    (int) mapping->interface->interface_number,
 		    usb_str_class(mapping->interface->interface_class),
 		    (int) mapping->interface->interface_subclass,
 		    (int) mapping->interface->interface_protocol,
-		    polling_data->request_size, pipe->max_packet_size);
-	}
-
+		    data->request_size, pipe->max_packet_size);
+	}
+
+	usb_pipe_start_long_transfer(pipe);
 	size_t failed_attempts = 0;
-	while (failed_attempts <= polling_data->max_failures) {
-		int rc;
-
+	while (failed_attempts <= params->max_failures) {
 		size_t actual_size;
-		rc = usb_pipe_read(pipe, polling_data->buffer,
-		    polling_data->request_size, &actual_size);
-
-		if (polling_data->debug > 1) {
+		const int rc = usb_pipe_read(pipe, data->buffer,
+		    data->request_size, &actual_size);
+
+		if (params->debug > 1) {
 			if (rc == EOK) {
 				usb_log_debug(
 				    "Poll%p: received: '%s' (%zuB).\n",
-				    polling_data,
-				    usb_debug_str_buffer(polling_data->buffer,
+				    data,
+				    usb_debug_str_buffer(data->buffer,
 				        actual_size, 16),
 				    actual_size);
@@ -108,10 +102,10 @@
 				usb_log_debug(
 				    "Poll%p: polling failed: %s.\n",
-				    polling_data, str_error(rc));
+				    data, str_error(rc));
 			}
 		}
 
 		/* If the pipe stalled, we can try to reset the stall. */
-		if ((rc == ESTALL) && (polling_data->auto_clear_halt)) {
+		if ((rc == ESTALL) && (params->auto_clear_halt)) {
 			/*
 			 * We ignore error here as this is usually a futile
@@ -119,28 +113,24 @@
 			 */
 			usb_request_clear_endpoint_halt(
-			    &polling_data->dev->ctrl_pipe,
-			    pipe->endpoint_no);
+			    &data->dev->ctrl_pipe, pipe->endpoint_no);
 		}
 
 		if (rc != EOK) {
-			if (polling_data->on_error != NULL) {
-				bool cont = polling_data->on_error(
-				    polling_data->dev, rc,
-				    polling_data->custom_arg);
-				if (!cont) {
-					failed_attempts
-					    = polling_data->max_failures;
-				}
+			++failed_attempts;
+			const bool cont = (params->on_error == NULL) ? true :
+			    params->on_error(data->dev, rc, data->custom_arg);
+			if (!cont) {
+				failed_attempts = params->max_failures;
 			}
-			failed_attempts++;
 			continue;
 		}
 
 		/* We have the data, execute the callback now. */
-		bool carry_on = polling_data->on_data(polling_data->dev,
-		    polling_data->buffer, actual_size,
-		    polling_data->custom_arg);
+		assert(params->on_data);
+		const bool carry_on = params->on_data(
+		    data->dev, data->buffer, actual_size, data->custom_arg);
 
 		if (!carry_on) {
+			/* This is user requested abort, erases failures. */
 			failed_attempts = 0;
 			break;
@@ -151,29 +141,28 @@
 
 		/* Take a rest before next request. */
-		async_usleep(polling_data->delay);
-	}
-
-	if (polling_data->on_polling_end != NULL) {
-		polling_data->on_polling_end(polling_data->dev,
-		    failed_attempts > 0, polling_data->custom_arg);
-	}
-
-	if (polling_data->debug > 0) {
-		if (failed_attempts > 0) {
-			usb_log_error(
-			    "Polling of device `%s' terminated: %s.\n",
-			    polling_data->dev->ddf_dev->name,
-			    "recurring failures");
+		async_usleep(params->delay);
+	}
+
+	usb_pipe_end_long_transfer(pipe);
+
+	const bool failed = failed_attempts > 0;
+
+	if (params->on_polling_end != NULL) {
+		params->on_polling_end(data->dev, failed, data->custom_arg);
+	}
+
+	if (params->debug > 0) {
+		if (failed) {
+			usb_log_error("Polling of device `%s' terminated: "
+			    "recurring failures.\n", data->dev->ddf_dev->name);
 		} else {
-			usb_log_debug(
-			    "Polling of device `%s' terminated by user.\n",
-			    polling_data->dev->ddf_dev->name
-			);
+			usb_log_debug("Polling of device `%s' terminated: "
+			    "driver request.\n", data->dev->ddf_dev->name);
 		}
 	}
 
 	/* Free the allocated memory. */
-	free(polling_data->buffer);
-	free(polling_data);
+	free(data->buffer);
+	free(data);
 
 	return EOK;
@@ -202,15 +191,4 @@
     usb_polling_terminted_callback_t terminated_callback, void *arg)
 {
-	if ((dev == NULL) || (callback == NULL)) {
-		return EBADMEM;
-	}
-	if (request_size == 0) {
-		return EINVAL;
-	}
-	if ((dev->pipes[pipe_index].pipe.transfer_type != USB_TRANSFER_INTERRUPT)
-	    || (dev->pipes[pipe_index].pipe.direction != USB_DIRECTION_IN)) {
-		return EINVAL;
-	}
-
 	const usb_device_auto_polling_t auto_polling = {
 		.debug = 1,
@@ -248,8 +226,9 @@
     size_t request_size, void *arg)
 {
-	if (dev == NULL) {
+	if ((dev == NULL) || (polling == NULL) || (polling->on_data == NULL)) {
 		return EBADMEM;
 	}
-	if (pipe_index >= dev->pipes_count) {
+
+	if (pipe_index >= dev->pipes_count || request_size == 0) {
 		return EINVAL;
 	}
@@ -257,7 +236,4 @@
 	    || (dev->pipes[pipe_index].pipe.direction != USB_DIRECTION_IN)) {
 		return EINVAL;
-	}
-	if ((polling == NULL) || (polling->on_data == NULL)) {
-		return EBADMEM;
 	}
 
@@ -278,17 +254,12 @@
 	polling_data->custom_arg = arg;
 
-	polling_data->debug = polling->debug;
-	polling_data->max_failures = polling->max_failures;
-	if (polling->delay >= 0) {
-		polling_data->delay = (useconds_t) polling->delay;
-	} else {
-		polling_data->delay = (useconds_t) dev->pipes[pipe_index]
-		    .descriptor->poll_interval;
-	}
-	polling_data->auto_clear_halt = polling->auto_clear_halt;
-
-	polling_data->on_data = polling->on_data;
-	polling_data->on_polling_end = polling->on_polling_end;
-	polling_data->on_error = polling->on_error;
+	/* Copy provided settings. */
+	polling_data->auto_polling = *polling;
+
+	/* Negative value means use descriptor provided value. */
+	if (polling->delay < 0) {
+		polling_data->auto_polling.delay =
+		    (int) dev->pipes[pipe_index].descriptor->poll_interval;
+	}
 
 	fid_t fibril = fibril_create(polling_fibril, polling_data);
Index: uspace/lib/usbdev/src/hub.c
===================================================================
--- uspace/lib/usbdev/src/hub.c	(revision 2449396b19fb28746d546abfb95ce0c13e29f1da)
+++ uspace/lib/usbdev/src/hub.c	(revision b8b1e6316d7aaa2e058c2099df2fd5541df4abaa)
@@ -76,17 +76,14 @@
 {
 	CHECK_CONNECTION(connection);
-	
+
 	async_exch_t *exch = async_exchange_begin(connection->hc_sess);
-	
-	sysarg_t address;
-	int rc = async_req_4_1(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
-	    IPC_M_USBHC_REQUEST_ADDRESS, preferred, strict, speed, &address);
-	
+	if (!exch)
+		return (usb_address_t)ENOMEM;
+
+	usb_address_t address = preferred;
+	const int ret = usbhc_request_address(exch, &address, strict, speed);
+
 	async_exchange_end(exch);
-	
-	if (rc != EOK)
-		return (usb_address_t) rc;
-	
-	return (usb_address_t) address;
+	return ret == EOK ? address : ret;
 }
 
@@ -97,19 +94,19 @@
  * @return Error code.
  */
-int usb_hc_register_device(usb_hc_connection_t * connection,
+int usb_hc_register_device(usb_hc_connection_t *connection,
     const usb_hub_attached_device_t *attached_device)
 {
 	CHECK_CONNECTION(connection);
-	
-	if (attached_device == NULL)
-		return EBADMEM;
-	
+	if (attached_device == NULL || attached_device->fun == NULL)
+		return EINVAL;
+
 	async_exch_t *exch = async_exchange_begin(connection->hc_sess);
-	int rc = async_req_3_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
-	    IPC_M_USBHC_BIND_ADDRESS,
+	if (!exch)
+		return ENOMEM;
+	const int ret = usbhc_bind_address(exch,
 	    attached_device->address, attached_device->fun->handle);
 	async_exchange_end(exch);
-	
-	return rc;
+
+	return ret;
 }
 
@@ -124,11 +121,12 @@
 {
 	CHECK_CONNECTION(connection);
-	
+
 	async_exch_t *exch = async_exchange_begin(connection->hc_sess);
-	int rc = async_req_2_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
-	    IPC_M_USBHC_RELEASE_ADDRESS, address);
+	if (!exch)
+		return ENOMEM;
+	const int ret = usbhc_release_address(exch, address);
 	async_exchange_end(exch);
-	
-	return rc;
+
+	return ret;
 }
 
@@ -221,6 +219,6 @@
  *	request or requests for descriptors when creating match ids).
  */
-int usb_hc_new_device_wrapper(ddf_dev_t *parent, usb_hc_connection_t *connection,
-    usb_speed_t dev_speed,
+int usb_hc_new_device_wrapper(ddf_dev_t *parent,
+    usb_hc_connection_t *connection, usb_speed_t dev_speed,
     int (*enable_port)(void *arg), void *arg, usb_address_t *assigned_address,
     ddf_dev_ops_t *dev_ops, void *new_dev_data, ddf_fun_t **new_fun)
@@ -229,10 +227,7 @@
 		return EINVAL;
 
-	// FIXME: this is awful, we are accessing directly the structure.
 	// TODO: Why not use provided connection?
-	usb_hc_connection_t hc_conn = {
-		.hc_handle = connection->hc_handle,
-		.hc_sess = NULL
-	};
+	usb_hc_connection_t hc_conn;
+	usb_hc_connection_initialize(&hc_conn, connection->hc_handle);
 
 	int rc;
Index: uspace/lib/usbdev/src/pipepriv.c
===================================================================
--- uspace/lib/usbdev/src/pipepriv.c	(revision 2449396b19fb28746d546abfb95ce0c13e29f1da)
+++ uspace/lib/usbdev/src/pipepriv.c	(revision b8b1e6316d7aaa2e058c2099df2fd5541df4abaa)
@@ -87,4 +87,5 @@
 	
 	if (pipe->refcount == 0) {
+		assert(pipe->hc_sess == NULL);
 		/* Need to open the phone by ourselves. */
 		async_sess_t *sess =
Index: uspace/lib/usbdev/src/pipes.c
===================================================================
--- uspace/lib/usbdev/src/pipes.c	(revision 2449396b19fb28746d546abfb95ce0c13e29f1da)
+++ uspace/lib/usbdev/src/pipes.c	(revision b8b1e6316d7aaa2e058c2099df2fd5541df4abaa)
@@ -54,16 +54,15 @@
 static usb_address_t get_my_address(async_sess_t *sess, const ddf_dev_t *dev)
 {
+	assert(sess);
 	async_exch_t *exch = async_exchange_begin(sess);
-	
-	sysarg_t address;
-	int rc = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
-	    IPC_M_USB_GET_MY_ADDRESS, &address);
-	
+	if (!exch)
+		return ENOMEM;
+
+	usb_address_t address;
+	const int ret = usb_get_my_address(exch, &address);
+
 	async_exchange_end(exch);
-	
-	if (rc != EOK)
-		return rc;
-	
-	return (usb_address_t) address;
+
+	return (ret == EOK) ? address : ret;
 }
 
@@ -71,5 +70,5 @@
  *
  * @param device Device in question.
- * @return Interface number (negative code means any).
+ * @return Error code (ENOTSUP means any).
  */
 int usb_device_get_assigned_interface(const ddf_dev_t *device)
@@ -80,19 +79,16 @@
 	    IPC_FLAG_BLOCKING);
 	if (!parent_sess)
-		return -1;
-	
+		return ENOMEM;
+
 	async_exch_t *exch = async_exchange_begin(parent_sess);
-	
-	sysarg_t iface_no;
-	int rc = async_req_2_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
-	    IPC_M_USB_GET_INTERFACE, device->handle, &iface_no);
-	
-	async_exchange_end(exch);
-	async_hangup(parent_sess);
-	
-	if (rc != EOK)
-		return -1;
-	
-	return (int) iface_no;
+	if (!exch) {
+		async_hangup(parent_sess);
+		return ENOMEM;
+	}
+
+	int iface_no;
+	const int ret = usb_get_my_interface(exch, &iface_no);
+
+	return ret == EOK ? iface_no : ret;
 }
 
Index: uspace/lib/usbdev/src/pipesinit.c
===================================================================
--- uspace/lib/usbdev/src/pipesinit.c	(revision 2449396b19fb28746d546abfb95ce0c13e29f1da)
+++ uspace/lib/usbdev/src/pipesinit.c	(revision b8b1e6316d7aaa2e058c2099df2fd5541df4abaa)
@@ -54,5 +54,5 @@
 
 /** Nesting pairs of standard descriptors. */
-static usb_dp_descriptor_nesting_t descriptor_nesting[] = {
+static const usb_dp_descriptor_nesting_t descriptor_nesting[] = {
 	NESTING(CONFIGURATION, INTERFACE),
 	NESTING(INTERFACE, ENDPOINT),
@@ -405,9 +405,4 @@
 	}
 
-#define TRY_LOOP(attempt_var) \
-	for (attempt_var = 0; attempt_var < 3; attempt_var++)
-
-	size_t failed_attempts;
-	int rc;
 
 	usb_pipe_start_long_transfer(pipe);
@@ -415,5 +410,6 @@
 	uint8_t dev_descr_start[CTRL_PIPE_MIN_PACKET_SIZE];
 	size_t transferred_size;
-	TRY_LOOP(failed_attempts) {
+	int rc;
+	for (size_t attempt_var = 0; attempt_var < 3; ++attempt_var) {
 		rc = usb_request_get_descriptor(pipe, USB_REQUEST_TYPE_STANDARD,
 		    USB_REQUEST_RECIPIENT_DEVICE, USB_DESCTYPE_DEVICE,
@@ -450,22 +446,18 @@
 {
 	assert(pipe);
+	assert(pipe->wire);
 	assert(hc_connection);
 
 	if (!usb_hc_connection_is_opened(hc_connection))
 		return EBADF;
-
-	const usb_target_t target =
-	    {{ .address = pipe->wire->address, .endpoint = pipe->endpoint_no }};
-#define _PACK2(high, low) (((high & 0xffff) << 16) | (low & 0xffff))
-
 	async_exch_t *exch = async_exchange_begin(hc_connection->hc_sess);
-	int rc = async_req_4_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
-	    IPC_M_USBHC_REGISTER_ENDPOINT, target.packed,
-	    _PACK2(pipe->transfer_type, pipe->direction),
-	    _PACK2(pipe->max_packet_size, interval));
+	if (!exch)
+		return ENOMEM;
+	const int ret = usbhc_register_endpoint(exch,
+	    pipe->wire->address, pipe->endpoint_no, pipe->transfer_type,
+	    pipe->direction, pipe->max_packet_size, interval);
+
 	async_exchange_end(exch);
-
-#undef _PACK2
-	return rc;
+	return ret;
 }
 
@@ -482,15 +474,16 @@
 	assert(pipe->wire);
 	assert(hc_connection);
-	
+
 	if (!usb_hc_connection_is_opened(hc_connection))
 		return EBADF;
-	
+
 	async_exch_t *exch = async_exchange_begin(hc_connection->hc_sess);
-	int rc = async_req_4_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
-	    IPC_M_USBHC_UNREGISTER_ENDPOINT,
+	if (!exch)
+		return ENOMEM;
+	const int ret = usbhc_unregister_endpoint(exch,
 	    pipe->wire->address, pipe->endpoint_no, pipe->direction);
 	async_exchange_end(exch);
-	
-	return rc;
+
+	return ret;
 }
 
Index: uspace/lib/usbdev/src/pipesio.c
===================================================================
--- uspace/lib/usbdev/src/pipesio.c	(revision 2449396b19fb28746d546abfb95ce0c13e29f1da)
+++ uspace/lib/usbdev/src/pipesio.c	(revision b8b1e6316d7aaa2e058c2099df2fd5541df4abaa)
@@ -62,135 +62,34 @@
  * @return Error code.
  */
-static int usb_pipe_read_no_checks(usb_pipe_t *pipe,
+static int usb_pipe_read_no_check(usb_pipe_t *pipe, uint64_t setup,
     void *buffer, size_t size, size_t *size_transfered)
 {
-	/* Only interrupt and bulk transfers are supported */
+	/* Isochronous transfer are not supported (yet) */
 	if (pipe->transfer_type != USB_TRANSFER_INTERRUPT &&
-	    pipe->transfer_type != USB_TRANSFER_BULK)
+	    pipe->transfer_type != USB_TRANSFER_BULK &&
+	    pipe->transfer_type != USB_TRANSFER_CONTROL)
 	    return ENOTSUP;
 
-	const usb_target_t target =
-	    {{ .address = pipe->wire->address, .endpoint = pipe->endpoint_no }};
-	
+	int ret = pipe_add_ref(pipe, false);
+	if (ret != EOK) {
+		return ret;
+	}
+
 	/* Ensure serialization over the phone. */
 	pipe_start_transaction(pipe);
 	async_exch_t *exch = async_exchange_begin(pipe->hc_sess);
-	
-	/*
-	 * Make call identifying target USB device and type of transfer.
-	 */
-	aid_t opening_request = async_send_2(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
-	    IPC_M_USBHC_READ, target.packed, NULL);
-	
-	if (opening_request == 0) {
-		async_exchange_end(exch);
+	if (!exch) {
 		pipe_end_transaction(pipe);
+		pipe_drop_ref(pipe);
 		return ENOMEM;
 	}
-	
-	/*
-	 * Retrieve the data.
-	 */
-	ipc_call_t data_request_call;
-	aid_t data_request = async_data_read(exch, buffer, size,
-	    &data_request_call);
-	
-	/*
-	 * Since now on, someone else might access the backing phone
-	 * without breaking the transfer IPC protocol.
-	 */
+
+	ret = usbhc_read(exch, pipe->wire->address, pipe->endpoint_no,
+	    setup, buffer, size, size_transfered);
 	async_exchange_end(exch);
 	pipe_end_transaction(pipe);
-	
-	if (data_request == 0) {
-		/*
-		 * FIXME:
-		 * How to let the other side know that we want to abort?
-		 */
-		async_wait_for(opening_request, NULL);
-		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;
-	}
-	
-	*size_transfered = IPC_GET_ARG2(data_request_call);
-	
-	return EOK;
-}
-
-
-/** Request a read (in) transfer on an endpoint pipe.
- *
- * @param[in] pipe Pipe used for the transfer.
- * @param[out] buffer Buffer where to store the data.
- * @param[in] size Size of the buffer (in bytes).
- * @param[out] size_transfered Number of bytes that were actually transfered.
- * @return Error code.
- */
-int usb_pipe_read(usb_pipe_t *pipe,
-    void *buffer, size_t size, size_t *size_transfered)
-{
-	assert(pipe);
-
-	if (buffer == NULL) {
-		return EINVAL;
-	}
-
-	if (size == 0) {
-		return EINVAL;
-	}
-
-	if (pipe->direction != USB_DIRECTION_IN) {
-		return EBADF;
-	}
-
-	if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
-		return EBADF;
-	}
-
-	int rc;
-	rc = pipe_add_ref(pipe, false);
-	if (rc != EOK) {
-		return rc;
-	}
-
-
-	size_t act_size = 0;
-
-	rc = usb_pipe_read_no_checks(pipe, buffer, size, &act_size);
-
 	pipe_drop_ref(pipe);
-
-	if (rc != EOK) {
-		return rc;
-	}
-
-	if (size_transfered != NULL) {
-		*size_transfered = act_size;
-	}
-
-	return EOK;
-}
-
-
-
+	return ret;
+}
 
 /** Request an out transfer, no checking of input parameters.
@@ -201,97 +100,32 @@
  * @return Error code.
  */
-static int usb_pipe_write_no_check(usb_pipe_t *pipe,
-    void *buffer, size_t size)
+static int usb_pipe_write_no_check(usb_pipe_t *pipe, uint64_t setup,
+    const void *buffer, size_t size)
 {
 	/* Only interrupt and bulk transfers are supported */
 	if (pipe->transfer_type != USB_TRANSFER_INTERRUPT &&
-	    pipe->transfer_type != USB_TRANSFER_BULK)
+	    pipe->transfer_type != USB_TRANSFER_BULK &&
+	    pipe->transfer_type != USB_TRANSFER_CONTROL)
 	    return ENOTSUP;
 
-	const usb_target_t target =
-	    {{ .address = pipe->wire->address, .endpoint = pipe->endpoint_no }};
+	int ret = pipe_add_ref(pipe, false);
+	if (ret != EOK) {
+		return ret;
+	}
 
 	/* Ensure serialization over the phone. */
 	pipe_start_transaction(pipe);
 	async_exch_t *exch = async_exchange_begin(pipe->hc_sess);
-	
-	/*
-	 * Make call identifying target USB device and type of transfer.
-	 */
-	aid_t opening_request = async_send_3(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
-	    IPC_M_USBHC_WRITE, target.packed, size, NULL);
-	
-	if (opening_request == 0) {
-		async_exchange_end(exch);
+	if (!exch) {
 		pipe_end_transaction(pipe);
+		pipe_drop_ref(pipe);
 		return ENOMEM;
 	}
-	
-	/*
-	 * Send the data.
-	 */
-	int rc = async_data_write_start(exch, buffer, size);
-	
-	/*
-	 * Since now on, someone else might access the backing phone
-	 * without breaking the transfer IPC protocol.
-	 */
+	ret = usbhc_write(exch, pipe->wire->address, pipe->endpoint_no,
+	    setup, buffer, size);
 	async_exchange_end(exch);
 	pipe_end_transaction(pipe);
-	
-	if (rc != EOK) {
-		async_wait_for(opening_request, NULL);
-		return rc;
-	}
-	
-	/*
-	 * Wait for the answer.
-	 */
-	sysarg_t opening_request_rc;
-	async_wait_for(opening_request, &opening_request_rc);
-	
-	return (int) opening_request_rc;
-}
-
-/** Request a write (out) transfer on an endpoint pipe.
- *
- * @param[in] pipe Pipe used for the transfer.
- * @param[in] buffer Buffer with data to transfer.
- * @param[in] size Size of the buffer (in bytes).
- * @return Error code.
- */
-int usb_pipe_write(usb_pipe_t *pipe,
-    void *buffer, size_t size)
-{
-	assert(pipe);
-
-	if (buffer == NULL) {
-		return EINVAL;
-	}
-
-	if (size == 0) {
-		return EINVAL;
-	}
-
-	if (pipe->direction != USB_DIRECTION_OUT) {
-		return EBADF;
-	}
-
-	if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
-		return EBADF;
-	}
-
-	int rc;
-
-	rc = pipe_add_ref(pipe, false);
-	if (rc != EOK) {
-		return rc;
-	}
-
-	rc = usb_pipe_write_no_check(pipe, buffer, size);
-
 	pipe_drop_ref(pipe);
-
-	return rc;
+	return ret;
 }
 
@@ -309,5 +143,5 @@
 
 
-	/* Prevent indefinite recursion. */
+	/* Prevent infinite recursion. */
 	pipe->auto_reset_halt = false;
 	usb_request_clear_endpoint_halt(pipe, 0);
@@ -315,6 +149,7 @@
 }
 
-
-/** Request a control read transfer, no checking of input parameters.
+/** Request a control read transfer on an endpoint pipe.
+ *
+ * This function encapsulates all three stages of a control transfer.
  *
  * @param[in] pipe Pipe used for the transfer.
@@ -327,87 +162,4 @@
  * @return Error code.
  */
-static int usb_pipe_control_read_no_check(usb_pipe_t *pipe,
-    const void *setup_buffer, size_t setup_buffer_size,
-    void *data_buffer, size_t data_buffer_size, size_t *data_transfered_size)
-{
-	/* Ensure serialization over the phone. */
-	pipe_start_transaction(pipe);
-
-	const usb_target_t target =
-	    {{ .address = pipe->wire->address, .endpoint = pipe->endpoint_no }};
-
-	assert(setup_buffer_size == 8);
-	uint64_t setup_packet;
-	memcpy(&setup_packet, setup_buffer, 8);
-	/*
-	 * Make call identifying target USB device and control transfer type.
-	 */
-	async_exch_t *exch = async_exchange_begin(pipe->hc_sess);
-	aid_t opening_request = async_send_4(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
-	    IPC_M_USBHC_READ, target.packed,
-	    (setup_packet & UINT32_MAX), (setup_packet >> 32), NULL);
-
-	if (opening_request == 0) {
-		async_exchange_end(exch);
-		return ENOMEM;
-	}
-
-	/*
-	 * Retrieve the data.
-	 */
-	ipc_call_t data_request_call;
-	aid_t data_request = async_data_read(exch, data_buffer,
-	    data_buffer_size, &data_request_call);
-	
-	/*
-	 * Since now on, someone else might access the backing phone
-	 * without breaking the transfer IPC protocol.
-	 */
-	async_exchange_end(exch);
-	pipe_end_transaction(pipe);
-	
-	if (data_request == 0) {
-		async_wait_for(opening_request, NULL);
-		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;
-	}
-
-	*data_transfered_size = IPC_GET_ARG2(data_request_call);
-
-	return EOK;
-}
-
-/** Request a control read transfer on an endpoint pipe.
- *
- * This function encapsulates all three stages of a control transfer.
- *
- * @param[in] pipe Pipe used for the transfer.
- * @param[in] setup_buffer Buffer with the setup packet.
- * @param[in] setup_buffer_size Size of the setup packet (in bytes).
- * @param[out] data_buffer Buffer for incoming data.
- * @param[in] data_buffer_size Size of the buffer for incoming data (in bytes).
- * @param[out] data_transfered_size Number of bytes that were actually
- *                                  transfered during the DATA stage.
- * @return Error code.
- */
 int usb_pipe_control_read(usb_pipe_t *pipe,
     const void *setup_buffer, size_t setup_buffer_size,
@@ -416,5 +168,5 @@
 	assert(pipe);
 
-	if ((setup_buffer == NULL) || (setup_buffer_size == 0)) {
+	if ((setup_buffer == NULL) || (setup_buffer_size != 8)) {
 		return EINVAL;
 	}
@@ -429,14 +181,9 @@
 	}
 
-	int rc;
-
-	rc = pipe_add_ref(pipe, false);
-	if (rc != EOK) {
-		return rc;
-	}
+	uint64_t setup_packet;
+	memcpy(&setup_packet, setup_buffer, 8);
 
 	size_t act_size = 0;
-	rc = usb_pipe_control_read_no_check(pipe,
-	    setup_buffer, setup_buffer_size,
+	const int rc = usb_pipe_read_no_check(pipe, setup_packet,
 	    data_buffer, data_buffer_size, &act_size);
 
@@ -445,19 +192,14 @@
 	}
 
-	pipe_drop_ref(pipe);
-
-	if (rc != EOK) {
-		return rc;
-	}
-
-	if (data_transfered_size != NULL) {
+	if (rc == EOK && data_transfered_size != NULL) {
 		*data_transfered_size = act_size;
 	}
 
-	return EOK;
-}
-
-
-/** Request a control write transfer, no checking of input parameters.
+	return rc;
+}
+
+/** Request a control write transfer on an endpoint pipe.
+ *
+ * This function encapsulates all three stages of a control transfer.
  *
  * @param[in] pipe Pipe used for the transfer.
@@ -468,71 +210,4 @@
  * @return Error code.
  */
-static int usb_pipe_control_write_no_check(usb_pipe_t *pipe,
-    const void *setup_buffer, size_t setup_buffer_size,
-    const void *data_buffer, size_t data_buffer_size)
-{
-	/* Ensure serialization over the phone. */
-	pipe_start_transaction(pipe);
-
-	const usb_target_t target =
-	    {{ .address = pipe->wire->address, .endpoint = pipe->endpoint_no }};
-	assert(setup_buffer_size == 8);
-	uint64_t setup_packet;
-	memcpy(&setup_packet, setup_buffer, 8);
-
-	/*
-	 * Make call identifying target USB device and control transfer type.
-	 */
-	async_exch_t *exch = async_exchange_begin(pipe->hc_sess);
-	aid_t opening_request = async_send_5(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
-	    IPC_M_USBHC_WRITE, target.packed, data_buffer_size,
-	    (setup_packet & UINT32_MAX), (setup_packet >> 32), NULL);
-	
-	if (opening_request == 0) {
-		async_exchange_end(exch);
-		pipe_end_transaction(pipe);
-		return ENOMEM;
-	}
-
-	/*
-	 * Send the data (if any).
-	 */
-	if (data_buffer_size > 0) {
-		int rc = async_data_write_start(exch, data_buffer, data_buffer_size);
-		
-		/* All data sent, pipe can be released. */
-		async_exchange_end(exch);
-		pipe_end_transaction(pipe);
-	
-		if (rc != EOK) {
-			async_wait_for(opening_request, NULL);
-			return rc;
-		}
-	} else {
-		/* No data to send, we can release the pipe for others. */
-		async_exchange_end(exch);
-		pipe_end_transaction(pipe);
-	}
-	
-	/*
-	 * Wait for the answer.
-	 */
-	sysarg_t opening_request_rc;
-	async_wait_for(opening_request, &opening_request_rc);
-
-	return (int) opening_request_rc;
-}
-
-/** Request a control write transfer on an endpoint pipe.
- *
- * This function encapsulates all three stages of a control transfer.
- *
- * @param[in] pipe Pipe used for the transfer.
- * @param[in] setup_buffer Buffer with the setup packet.
- * @param[in] setup_buffer_size Size of the setup packet (in bytes).
- * @param[in] data_buffer Buffer with data to be sent.
- * @param[in] data_buffer_size Size of the buffer with outgoing data (in bytes).
- * @return Error code.
- */
 int usb_pipe_control_write(usb_pipe_t *pipe,
     const void *setup_buffer, size_t setup_buffer_size,
@@ -541,5 +216,5 @@
 	assert(pipe);
 
-	if ((setup_buffer == NULL) || (setup_buffer_size == 0)) {
+	if ((setup_buffer == NULL) || (setup_buffer_size != 8)) {
 		return EINVAL;
 	}
@@ -558,13 +233,9 @@
 	}
 
-	int rc;
-
-	rc = pipe_add_ref(pipe, false);
-	if (rc != EOK) {
-		return rc;
-	}
-
-	rc = usb_pipe_control_write_no_check(pipe,
-	    setup_buffer, setup_buffer_size, data_buffer, data_buffer_size);
+	uint64_t setup_packet;
+	memcpy(&setup_packet, setup_buffer, 8);
+
+	const int rc = usb_pipe_write_no_check(pipe, setup_packet,
+	    data_buffer, data_buffer_size);
 
 	if (rc == ESTALL) {
@@ -572,9 +243,72 @@
 	}
 
-	pipe_drop_ref(pipe);
-
 	return rc;
 }
 
+/** Request a read (in) transfer on an endpoint pipe.
+ *
+ * @param[in] pipe Pipe used for the transfer.
+ * @param[out] buffer Buffer where to store the data.
+ * @param[in] size Size of the buffer (in bytes).
+ * @param[out] size_transfered Number of bytes that were actually transfered.
+ * @return Error code.
+ */
+int usb_pipe_read(usb_pipe_t *pipe,
+    void *buffer, size_t size, size_t *size_transfered)
+{
+	assert(pipe);
+
+	if (buffer == NULL) {
+		return EINVAL;
+	}
+
+	if (size == 0) {
+		return EINVAL;
+	}
+
+	if (pipe->direction != USB_DIRECTION_IN) {
+		return EBADF;
+	}
+
+	if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
+		return EBADF;
+	}
+
+	size_t act_size = 0;
+	const int rc = usb_pipe_read_no_check(pipe, 0, buffer, size, &act_size);
+
+
+	if (rc == EOK && size_transfered != NULL) {
+		*size_transfered = act_size;
+	}
+
+	return rc;
+}
+
+/** Request a write (out) transfer on an endpoint pipe.
+ *
+ * @param[in] pipe Pipe used for the transfer.
+ * @param[in] buffer Buffer with data to transfer.
+ * @param[in] size Size of the buffer (in bytes).
+ * @return Error code.
+ */
+int usb_pipe_write(usb_pipe_t *pipe, const void *buffer, size_t size)
+{
+	assert(pipe);
+
+	if (buffer == NULL || size == 0) {
+		return EINVAL;
+	}
+
+	if (pipe->direction != USB_DIRECTION_OUT) {
+		return EBADF;
+	}
+
+	if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
+		return EBADF;
+	}
+
+	return usb_pipe_write_no_check(pipe, 0, buffer, size);
+}
 
 /**
Index: uspace/lib/usbdev/src/request.c
===================================================================
--- uspace/lib/usbdev/src/request.c	(revision 2449396b19fb28746d546abfb95ce0c13e29f1da)
+++ uspace/lib/usbdev/src/request.c	(revision b8b1e6316d7aaa2e058c2099df2fd5541df4abaa)
@@ -143,16 +143,15 @@
 	 */
 
-	usb_device_request_setup_packet_t setup_packet;
-	setup_packet.request_type = 128 | (request_type << 5) | recipient;
-	setup_packet.request = request;
-	setup_packet.value = value;
-	setup_packet.index = index;
-	setup_packet.length = (uint16_t) data_size;
-
-	int rc = usb_pipe_control_read(pipe,
-	    &setup_packet, sizeof(setup_packet),
+	const usb_device_request_setup_packet_t setup_packet = {
+		.request_type = SETUP_REQUEST_TYPE_DEVICE_TO_HOST
+		    | (request_type << 5) | recipient,
+		.request = request,
+		.value = value,
+		.index = index,
+		.length = (uint16_t) data_size,
+	};
+
+	return usb_pipe_control_read(pipe, &setup_packet, sizeof(setup_packet),
 	    data, data_size, actual_data_size);
-
-	return rc;
 }
 
@@ -276,5 +275,5 @@
 	}
 
-	uint16_t wValue = descriptor_index | (descriptor_type << 8);
+	const uint16_t wValue = descriptor_index | (descriptor_type << 8);
 
 	return usb_control_request_get(pipe,
Index: uspace/lib/usbhost/include/usb/host/hcd.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/hcd.h	(revision 2449396b19fb28746d546abfb95ce0c13e29f1da)
+++ uspace/lib/usbhost/include/usb/host/hcd.h	(revision b8b1e6316d7aaa2e058c2099df2fd5541df4abaa)
@@ -63,5 +63,5 @@
 /*----------------------------------------------------------------------------*/
 /** Initialize hcd_t structure.
- * Initializes device and endpoint managers. Sets data nd hook pointer to NULL.
+ * Initializes device and endpoint managers. Sets data and hook pointer to NULL.
  * @param hcd hcd_t structure to initialize, non-null.
  * @param bandwidth Available bandwidth, passed to endpoint manager.
Index: uspace/lib/usbhost/src/iface.c
===================================================================
--- uspace/lib/usbhost/src/iface.c	(revision 2449396b19fb28746d546abfb95ce0c13e29f1da)
+++ uspace/lib/usbhost/src/iface.c	(revision b8b1e6316d7aaa2e058c2099df2fd5541df4abaa)
@@ -252,5 +252,5 @@
 	.request_address = request_address,
 	.bind_address = bind_address,
-	.find_by_address = find_by_address,
+	.get_handle = find_by_address,
 	.release_address = release_address,
 
