Index: uspace/lib/usbvirt/Makefile
===================================================================
--- uspace/lib/usbvirt/Makefile	(revision f90c0d6c1710d4e0841deffb9389c9f882f27afd)
+++ uspace/lib/usbvirt/Makefile	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -33,6 +33,8 @@
 
 SOURCES = \
-	src/ipc.c \
 	src/ctrltransfer.c \
+	src/device.c \
+	src/ipc_dev.c \
+	src/ipc_hc.c \
 	src/stdreq.c \
 	src/transfer.c
Index: uspace/lib/usbvirt/include/usbvirt/device.h
===================================================================
--- uspace/lib/usbvirt/include/usbvirt/device.h	(revision f90c0d6c1710d4e0841deffb9389c9f882f27afd)
+++ uspace/lib/usbvirt/include/usbvirt/device.h	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -31,5 +31,5 @@
  */
 /** @file
- * @brief Virtual USB device.
+ * Virtual USB device.
  */
 #ifndef LIBUSBVIRT_DEVICE_H_
@@ -39,21 +39,68 @@
 #include <usb/request.h>
 
+/** Maximum number of endpoints supported by virtual USB. */
 #define USBVIRT_ENDPOINT_MAX 16
 
 typedef struct usbvirt_device usbvirt_device_t;
 
-typedef int (*usbvirt_on_data_to_device_t)(usbvirt_device_t *, usb_endpoint_t,
-    usb_transfer_type_t, void *, size_t);
-typedef int (*usbvirt_on_data_from_device_t)(usbvirt_device_t *, usb_endpoint_t,
-    usb_transfer_type_t, void *, size_t, size_t *);
-typedef int (*usbvirt_on_control_t)(usbvirt_device_t *,
-    const usb_device_request_setup_packet_t *, uint8_t *, size_t *);
-
-typedef struct {
+/** Callback for data to device (OUT transaction).
+ *
+ * @param dev Virtual device to which the transaction belongs.
+ * @param endpoint Target endpoint number.
+ * @param transfer_type Transfer type.
+ * @param buffer Data buffer.
+ * @param buffer_size Size of the buffer in bytes.
+ * @return Error code.
+ */
+typedef int (*usbvirt_on_data_to_device_t)(usbvirt_device_t *dev,
+    usb_endpoint_t endpoint, usb_transfer_type_t transfer_type,
+    void *buffer, size_t buffer_size);
+
+/** Callback for data from device (IN transaction).
+ *
+ * @param dev Virtual device to which the transaction belongs.
+ * @param endpoint Target endpoint number.
+ * @param transfer_type Transfer type.
+ * @param buffer Data buffer to write answer to.
+ * @param buffer_size Size of the buffer in bytes.
+ * @param act_buffer_size Write here how many bytes were actually written.
+ * @return Error code.
+ */
+typedef int (*usbvirt_on_data_from_device_t)(usbvirt_device_t *dev,
+    usb_endpoint_t endpoint, usb_transfer_type_t transfer_type,
+    void *buffer, size_t buffer_size, size_t *act_buffer_size);
+
+/** Callback for control transfer on endpoint zero.
+ *
+ * Notice that size of the data buffer is expected to be read from the
+ * setup packet.
+ *
+ * @param dev Virtual device to which the transaction belongs.
+ * @param setup_packet Standard setup packet.
+ * @param data Data (might be NULL).
+ * @param act_data_size Size of returned data in bytes.
+ * @return Error code.
+ */
+typedef int (*usbvirt_on_control_t)(usbvirt_device_t *dev,
+    const usb_device_request_setup_packet_t *setup_packet,
+    uint8_t *data, size_t *act_data_size);
+
+/** Callback for control request on a virtual USB device.
+ *
+ * See usbvirt_control_reply_helper() for simple way of answering
+ * control read requests.
+ */
+typedef struct {
+	/** Request direction (in or out). */
 	usb_direction_t req_direction;
+	/** Request recipient (device, interface or endpoint). */
 	usb_request_recipient_t req_recipient;
+	/** Request type (standard, class or vendor). */
 	usb_request_type_t req_type;
+	/** Actual request code. */
 	uint8_t request;
+	/** Request handler name for debugging purposes. */
 	const char *name;
+	/** Callback to be executed on matching request. */
 	usbvirt_on_control_t callback;
 } usbvirt_control_request_handler_t;
@@ -77,5 +124,5 @@
 } usbvirt_device_configuration_t;
 
-/** Standard USB descriptors. */
+/** Standard USB descriptors for virtual device. */
 typedef struct {
 	/** Standard device descriptor.
@@ -102,22 +149,57 @@
 } usbvirt_device_state_t;
 
-typedef struct {
+/** Ops structure for virtual USB device. */
+typedef struct {
+	/** Callbacks for data to device.
+	 * Index zero is ignored.
+	 */
 	usbvirt_on_data_to_device_t data_out[USBVIRT_ENDPOINT_MAX];
+	/** Callbacks for data from device.
+	 * Index zero is ignored.
+	 */
 	usbvirt_on_data_from_device_t data_in[USBVIRT_ENDPOINT_MAX];
+	/** Array of control handlers.
+	 * Last handler is expected to have the @c callback field set to NULL
+	 */
 	usbvirt_control_request_handler_t *control;
+	/** Callback when device changes state.
+	 *
+	 * The value of @c state attribute of @p dev device is not
+	 * defined during call of this function.
+	 *
+	 * @param dev The virtual USB device.
+	 * @param old_state Old device state.
+	 * @param new_state New device state.
+	 */
 	void (*state_changed)(usbvirt_device_t *dev,
 	    usbvirt_device_state_t old_state, usbvirt_device_state_t new_state);
 } usbvirt_device_ops_t;
 
+/** Virtual USB device. */
 struct usbvirt_device {
+	/** Name for debugging purposes. */
 	const char *name;
+	/** Custom device data. */
 	void *device_data;
+	/** Device ops. */
 	usbvirt_device_ops_t *ops;
+	/** Device descriptors. */
 	usbvirt_descriptors_t *descriptors;
+	/** Current device address.
+	 * You shall treat this field as read only in your code.
+	 */
 	usb_address_t address;
+	/** Current device state.
+	 * You shall treat this field as read only in your code.
+	 */
 	usbvirt_device_state_t state;
+	/** Phone to the host controller.
+	 * You shall treat this field as read only in your code.
+	 */
+	int vhc_phone;
 };
 
 int usbvirt_device_plug(usbvirt_device_t *, const char *);
+void usbvirt_device_unplug(usbvirt_device_t *);
 
 void usbvirt_control_reply_helper(const usb_device_request_setup_packet_t *,
Index: uspace/lib/usbvirt/include/usbvirt/ipc.h
===================================================================
--- uspace/lib/usbvirt/include/usbvirt/ipc.h	(revision f90c0d6c1710d4e0841deffb9389c9f882f27afd)
+++ uspace/lib/usbvirt/include/usbvirt/ipc.h	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Vojtech Horky
+ * Copyright (c) 2011 Vojtech Horky
  * All rights reserved.
  *
@@ -31,5 +31,5 @@
  */
 /** @file
- * @brief Virtual USB device.
+ * IPC wrappers for virtual USB.
  */
 #ifndef LIBUSBVIRT_IPC_H_
@@ -40,4 +40,5 @@
 #include <bool.h>
 
+/** IPC methods communication between host controller and virtual device. */
 typedef enum {
 	IPC_M_USBVIRT_GET_NAME = IPC_FIRST_USER_METHOD + 80,
@@ -45,10 +46,12 @@
 	IPC_M_USBVIRT_CONTROL_WRITE,
 	IPC_M_USBVIRT_INTERRUPT_IN,
-	IPC_M_USBVIRT_INTERRUPT_OUT
-} usbvirt_ipc_t;
+	IPC_M_USBVIRT_INTERRUPT_OUT,
+	IPC_M_USBVIRT_BULK_IN,
+	IPC_M_USBVIRT_BULK_OUT
+} usbvirt_hc_to_device_method_t;
 
-int usbvirt_ipc_send_control_read(int, usb_endpoint_t, void *, size_t,
+int usbvirt_ipc_send_control_read(int, void *, size_t,
     void *, size_t, size_t *);
-int usbvirt_ipc_send_control_write(int, usb_endpoint_t, void *, size_t,
+int usbvirt_ipc_send_control_write(int, void *, size_t,
     void *, size_t);
 int usbvirt_ipc_send_data_in(int, usb_endpoint_t, usb_transfer_type_t,
Index: uspace/lib/usbvirt/src/ctrltransfer.c
===================================================================
--- uspace/lib/usbvirt/src/ctrltransfer.c	(revision f90c0d6c1710d4e0841deffb9389c9f882f27afd)
+++ uspace/lib/usbvirt/src/ctrltransfer.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -1,2 +1,36 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * 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 libusbvirt
+ * @{
+ */
+/** @file
+ * Control transfer handling.
+ */
 #include "private.h"
 #include <usb/request.h>
@@ -5,4 +39,14 @@
 #include <errno.h>
 
+/** Find and execute control transfer handler for virtual USB device.
+ *
+ * @param dev Target virtual device.
+ * @param control_handlers Array of control request handlers.
+ * @param setup Setup packet.
+ * @param data Extra data.
+ * @param data_sent_size Size of extra data in bytes.
+ * @return Error code.
+ * @retval EFORWARD No suitable handler found.
+ */
 int process_control_transfer(usbvirt_device_t *dev,
     usbvirt_control_request_handler_t *control_handlers,
@@ -52,2 +96,7 @@
 	return EFORWARD;
 }
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/device.c
===================================================================
--- uspace/lib/usbvirt/src/device.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
+++ uspace/lib/usbvirt/src/device.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * 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 libusbvirt
+ * @{
+ */
+/** @file
+ * Virtual USB device main routines.
+ */
+#include <errno.h>
+#include <str.h>
+#include <stdio.h>
+#include <assert.h>
+#include <async.h>
+#include <devman.h>
+#include <usbvirt/device.h>
+#include <usbvirt/ipc.h>
+
+#include <usb/debug.h>
+
+/** Current device. */
+static usbvirt_device_t *DEV = NULL;
+
+/** Main IPC call handling from virtual host controller.
+ *
+ * @param iid Caller identification.
+ * @param icall Initial incoming call.
+ */
+static void callback_connection(ipc_callid_t iid, ipc_call_t *icall)
+{
+	assert(DEV != NULL);
+
+	async_answer_0(iid, EOK);
+
+	while (true) {
+		ipc_callid_t callid;
+		ipc_call_t call;
+
+		callid = async_get_call(&call);
+		bool processed = usbvirt_ipc_handle_call(DEV, callid, &call);
+		if (!processed) {
+			switch (IPC_GET_IMETHOD(call)) {
+				case IPC_M_PHONE_HUNGUP:
+					async_answer_0(callid, EOK);
+					return;
+				default:
+					async_answer_0(callid, EINVAL);
+					break;
+			}
+		}
+	}
+}
+
+/** Connect the device to the virtual host controller.
+ *
+ * @param dev The virtual device to be (virtually) plugged in.
+ * @param vhc_path Devman path to the virtual host controller.
+ * @return Error code.
+ */
+int usbvirt_device_plug(usbvirt_device_t *dev, const char *vhc_path)
+{
+	int rc;
+	devman_handle_t handle;
+
+	if (DEV != NULL) {
+		return ELIMIT;
+	}
+
+	rc = devman_device_get_handle(vhc_path, &handle, 0);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	int hcd_phone = devman_device_connect(handle, 0);
+
+	if (hcd_phone < 0) {
+		return hcd_phone;
+	}
+
+	DEV = dev;
+	dev->vhc_phone = hcd_phone;
+
+	rc = async_connect_to_me(hcd_phone, 0, 0, 0, callback_connection);
+	if (rc != EOK) {
+		DEV = NULL;
+	}
+
+	return rc;
+}
+
+/** Disconnect the device from virtual host controller.
+ *
+ * @param dev Device to be disconnected.
+ */
+void usbvirt_device_unplug(usbvirt_device_t *dev)
+{
+	async_hangup(dev->vhc_phone);
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/ipc.c
===================================================================
--- uspace/lib/usbvirt/src/ipc.c	(revision f90c0d6c1710d4e0841deffb9389c9f882f27afd)
+++ 	(revision )
@@ -1,455 +1,0 @@
-/*
- * Copyright (c) 2011 Vojtech Horky
- * 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 libusbvirt
- * @{
- */
-/** @file
- *
- */
-#include <errno.h>
-#include <str.h>
-#include <stdio.h>
-#include <assert.h>
-#include <async.h>
-#include <devman.h>
-#include <usbvirt/device.h>
-#include <usbvirt/ipc.h>
-
-#include <usb/debug.h>
-
-static usbvirt_device_t *DEV = NULL;
-
-static void ipc_get_name(usbvirt_device_t *dev,
-    ipc_callid_t iid, ipc_call_t *icall)
-{
-	if (dev->name == NULL) {
-		async_answer_0(iid, ENOENT);
-	}
-
-	size_t size = str_size(dev->name);
-
-	ipc_callid_t callid;
-	size_t accepted_size;
-	if (!async_data_read_receive(&callid, &accepted_size)) {
-		async_answer_0(iid, EINVAL);
-		return;
-	}
-
-	if (accepted_size > size) {
-		accepted_size = size;
-	}
-	async_data_read_finalize(callid, dev->name, accepted_size);
-
-	async_answer_1(iid, EOK, accepted_size);
-}
-
-static void ipc_control_read(usbvirt_device_t *dev,
-    ipc_callid_t iid, ipc_call_t *icall)
-{
-	//usb_endpoint_t endpoint = IPC_GET_ARG1(*icall);
-
-	int rc;
-
-	void *setup_packet = NULL;
-	size_t setup_packet_len = 0;
-	size_t data_len = 0;
-
-	rc = async_data_write_accept(&setup_packet, false,
-	    1, 1024, 0, &setup_packet_len);
-	if (rc != EOK) {
-		async_answer_0(iid, rc);
-		return;
-	}
-
-	ipc_callid_t data_callid;
-	if (!async_data_read_receive(&data_callid, &data_len)) {
-		async_answer_0(iid, EPARTY);
-		free(setup_packet);
-		return;
-	}
-
-	void *buffer = malloc(data_len);
-	if (buffer == NULL) {
-		async_answer_0(iid, ENOMEM);
-		free(setup_packet);
-		return;
-	}
-
-	size_t actual_len;
-	rc = usbvirt_control_read(dev, setup_packet, setup_packet_len,
-	    buffer, data_len, &actual_len);
-
-	if (rc != EOK) {
-		async_answer_0(data_callid, rc);
-		async_answer_0(iid, rc);
-		free(setup_packet);
-		free(buffer);
-		return;
-	}
-
-	async_data_read_finalize(data_callid, buffer, actual_len);
-	async_answer_0(iid, EOK);
-
-	free(setup_packet);
-	free(buffer);
-}
-
-static void ipc_control_write(usbvirt_device_t *dev,
-    ipc_callid_t iid, ipc_call_t *icall)
-{
-	size_t data_buffer_len = IPC_GET_ARG2(*icall);
-	int rc;
-
-	void *setup_packet = NULL;
-	void *data_buffer = NULL;
-	size_t setup_packet_len = 0;
-
-	rc = async_data_write_accept(&setup_packet, false,
-	    1, 1024, 0, &setup_packet_len);
-	if (rc != EOK) {
-		async_answer_0(iid, rc);
-		return;
-	}
-
-	if (data_buffer_len > 0) {
-		rc = async_data_write_accept(&data_buffer, false,
-		    1, 1024, 0, &data_buffer_len);
-		if (rc != EOK) {
-			async_answer_0(iid, rc);
-			free(setup_packet);
-			return;
-		}
-	}
-
-	rc = usbvirt_control_write(dev, setup_packet, setup_packet_len,
-	    data_buffer, data_buffer_len);
-
-	async_answer_0(iid, rc);
-}
-
-static void ipc_interrupt_in(usbvirt_device_t *dev,
-    ipc_callid_t iid, ipc_call_t *icall)
-{
-	usb_endpoint_t endpoint = IPC_GET_ARG1(*icall);
-	usb_transfer_type_t transfer_type = IPC_GET_ARG2(*icall);
-
-	int rc;
-
-	size_t data_len = 0;
-	ipc_callid_t data_callid;
-	if (!async_data_read_receive(&data_callid, &data_len)) {
-		async_answer_0(iid, EPARTY);
-		return;
-	}
-
-	void *buffer = malloc(data_len);
-	if (buffer == NULL) {
-		async_answer_0(iid, ENOMEM);
-		return;
-	}
-
-	size_t actual_len;
-	rc = usbvirt_data_in(dev, transfer_type, endpoint,
-	    buffer, data_len, &actual_len);
-
-	if (rc != EOK) {
-		async_answer_0(data_callid, rc);
-		async_answer_0(iid, rc);
-		free(buffer);
-		return;
-	}
-
-	async_data_read_finalize(data_callid, buffer, actual_len);
-	async_answer_0(iid, EOK);
-
-	free(buffer);
-}
-
-static void ipc_interrupt_out(usbvirt_device_t *dev,
-    ipc_callid_t iid, ipc_call_t *icall)
-{
-	usb_endpoint_t endpoint = IPC_GET_ARG1(*icall);
-	usb_transfer_type_t transfer_type = IPC_GET_ARG2(*icall);
-
-	void *data_buffer = NULL;
-	size_t data_buffer_size = 0;
-
-	int rc = async_data_write_accept(&data_buffer, false,
-	    1, 1024, 0, &data_buffer_size);
-	if (rc != EOK) {
-		async_answer_0(iid, rc);
-		return;
-	}
-
-	rc = usbvirt_data_out(dev, transfer_type, endpoint,
-	    data_buffer, data_buffer_size);
-
-	async_answer_0(iid, rc);
-
-	free(data_buffer);
-}
-
-
-bool usbvirt_ipc_handle_call(usbvirt_device_t *dev,
-    ipc_callid_t callid, ipc_call_t *call)
-{
-	switch (IPC_GET_IMETHOD(*call)) {
-		case IPC_M_USBVIRT_GET_NAME:
-			ipc_get_name(dev, callid, call);
-			break;
-
-		case IPC_M_USBVIRT_CONTROL_READ:
-			ipc_control_read(dev, callid, call);
-			break;
-
-		case IPC_M_USBVIRT_CONTROL_WRITE:
-			ipc_control_write(dev, callid, call);
-			break;
-
-		case IPC_M_USBVIRT_INTERRUPT_IN:
-			ipc_interrupt_in(dev, callid, call);
-			break;
-
-		case IPC_M_USBVIRT_INTERRUPT_OUT:
-			ipc_interrupt_out(dev, callid, call);
-			break;
-
-		default:
-			return false;
-	}
-
-	return true;
-}
-
-static void callback_connection(ipc_callid_t iid, ipc_call_t *icall)
-{
-	assert(DEV != NULL);
-
-	async_answer_0(iid, EOK);
-
-	while (true) {
-		ipc_callid_t callid;
-		ipc_call_t call;
-
-		callid = async_get_call(&call);
-		bool processed = usbvirt_ipc_handle_call(DEV, callid, &call);
-		if (!processed) {
-			switch (IPC_GET_IMETHOD(call)) {
-				case IPC_M_PHONE_HUNGUP:
-					async_answer_0(callid, EOK);
-					return;
-				default:
-					async_answer_0(callid, EINVAL);
-					break;
-			}
-		}
-	}
-}
-
-int usbvirt_device_plug(usbvirt_device_t *dev, const char *vhc_path)
-{
-	int rc;
-	devman_handle_t handle;
-
-	rc = devman_device_get_handle(vhc_path, &handle, 0);
-	if (rc != EOK) {
-		return rc;
-	}
-
-	int hcd_phone = devman_device_connect(handle, 0);
-
-	if (hcd_phone < 0) {
-		return hcd_phone;
-	}
-
-	DEV = dev;
-
-	rc = async_connect_to_me(hcd_phone, 0, 0, 0, callback_connection);
-	if (rc != EOK) {
-		DEV = NULL;
-		return rc;
-	}
-
-
-
-	return EOK;
-}
-
-
-
-int usbvirt_ipc_send_control_read(int phone, usb_endpoint_t ep,
-    void *setup_buffer, size_t setup_buffer_size,
-    void *data_buffer, size_t data_buffer_size, size_t *data_transfered_size)
-{
-	aid_t opening_request = async_send_1(phone,
-	    IPC_M_USBVIRT_CONTROL_READ, ep, NULL);
-	if (opening_request == 0) {
-		return ENOMEM;
-	}
-
-	int rc = async_data_write_start(phone,
-	    setup_buffer, setup_buffer_size);
-	if (rc != EOK) {
-		async_wait_for(opening_request, NULL);
-		return rc;
-	}
-
-	ipc_call_t data_request_call;
-	aid_t data_request = async_data_read(phone,
-	    data_buffer, data_buffer_size,
-	    &data_request_call);
-
-	if (data_request == 0) {
-		async_wait_for(opening_request, NULL);
-		return ENOMEM;
-	}
-
-	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;
-}
-
-int usbvirt_ipc_send_control_write(int phone, usb_endpoint_t ep,
-    void *setup_buffer, size_t setup_buffer_size,
-    void *data_buffer, size_t data_buffer_size)
-{
-	aid_t opening_request = async_send_2(phone,
-	    IPC_M_USBVIRT_CONTROL_WRITE, ep, data_buffer_size,  NULL);
-	if (opening_request == 0) {
-		return ENOMEM;
-	}
-
-	int rc = async_data_write_start(phone,
-	    setup_buffer, setup_buffer_size);
-	if (rc != EOK) {
-		async_wait_for(opening_request, NULL);
-		return rc;
-	}
-
-	if (data_buffer_size > 0) {
-		rc = async_data_write_start(phone,
-		    data_buffer, data_buffer_size);
-
-		if (rc != EOK) {
-			async_wait_for(opening_request, NULL);
-			return rc;
-		}
-	}
-
-	sysarg_t opening_request_rc;
-	async_wait_for(opening_request, &opening_request_rc);
-
-	return (int) opening_request_rc;
-}
-
-int usbvirt_ipc_send_data_in(int phone, usb_endpoint_t ep,
-    usb_transfer_type_t tr_type, void *data, size_t data_size, size_t *act_size)
-{
-	aid_t opening_request = async_send_2(phone,
-	    IPC_M_USBVIRT_INTERRUPT_IN, ep, tr_type, NULL);
-	if (opening_request == 0) {
-		return ENOMEM;
-	}
-
-	ipc_call_t data_request_call;
-	aid_t data_request = async_data_read(phone,
-	    data, data_size,  &data_request_call);
-
-	if (data_request == 0) {
-		async_wait_for(opening_request, NULL);
-		return ENOMEM;
-	}
-
-	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;
-	}
-
-	if (act_size != NULL) {
-		*act_size = IPC_GET_ARG2(data_request_call);
-	}
-
-	return EOK;
-}
-
-int usbvirt_ipc_send_data_out(int phone, usb_endpoint_t ep,
-    usb_transfer_type_t tr_type, void *data, size_t data_size)
-{
-	aid_t opening_request = async_send_2(phone,
-	    IPC_M_USBVIRT_INTERRUPT_OUT, ep, tr_type, NULL);
-	if (opening_request == 0) {
-		return ENOMEM;
-	}
-
-	int rc = async_data_write_start(phone,
-	    data, data_size);
-	if (rc != EOK) {
-		async_wait_for(opening_request, NULL);
-		return rc;
-	}
-
-	sysarg_t opening_request_rc;
-	async_wait_for(opening_request, &opening_request_rc);
-
-	return (int) opening_request_rc;
-}
-
-
-/**
- * @}
- */
Index: uspace/lib/usbvirt/src/ipc_dev.c
===================================================================
--- uspace/lib/usbvirt/src/ipc_dev.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
+++ uspace/lib/usbvirt/src/ipc_dev.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * 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 libusbvirt
+ * @{
+ */
+/** @file
+ * IPC wrappers, device side.
+ */
+#include <errno.h>
+#include <str.h>
+#include <stdio.h>
+#include <assert.h>
+#include <async.h>
+#include <devman.h>
+#include <usbvirt/device.h>
+#include <usbvirt/ipc.h>
+#include <usb/debug.h>
+
+/** Handle VHC request for device name.
+ *
+ * @param dev Target virtual device.
+ * @param iid Caller id.
+ * @param icall The call with the request.
+ */
+static void ipc_get_name(usbvirt_device_t *dev,
+    ipc_callid_t iid, ipc_call_t *icall)
+{
+	if (dev->name == NULL) {
+		async_answer_0(iid, ENOENT);
+	}
+
+	size_t size = str_size(dev->name);
+
+	ipc_callid_t callid;
+	size_t accepted_size;
+	if (!async_data_read_receive(&callid, &accepted_size)) {
+		async_answer_0(iid, EINVAL);
+		return;
+	}
+
+	if (accepted_size > size) {
+		accepted_size = size;
+	}
+	async_data_read_finalize(callid, dev->name, accepted_size);
+
+	async_answer_1(iid, EOK, accepted_size);
+}
+
+/** Handle VHC request for control read from the device.
+ *
+ * @param dev Target virtual device.
+ * @param iid Caller id.
+ * @param icall The call with the request.
+ */
+static void ipc_control_read(usbvirt_device_t *dev,
+    ipc_callid_t iid, ipc_call_t *icall)
+{
+	int rc;
+
+	void *setup_packet = NULL;
+	size_t setup_packet_len = 0;
+	size_t data_len = 0;
+
+	rc = async_data_write_accept(&setup_packet, false,
+	    1, 1024, 0, &setup_packet_len);
+	if (rc != EOK) {
+		async_answer_0(iid, rc);
+		return;
+	}
+
+	ipc_callid_t data_callid;
+	if (!async_data_read_receive(&data_callid, &data_len)) {
+		async_answer_0(iid, EPARTY);
+		free(setup_packet);
+		return;
+	}
+
+	void *buffer = malloc(data_len);
+	if (buffer == NULL) {
+		async_answer_0(iid, ENOMEM);
+		free(setup_packet);
+		return;
+	}
+
+	size_t actual_len;
+	rc = usbvirt_control_read(dev, setup_packet, setup_packet_len,
+	    buffer, data_len, &actual_len);
+
+	if (rc != EOK) {
+		async_answer_0(data_callid, rc);
+		async_answer_0(iid, rc);
+		free(setup_packet);
+		free(buffer);
+		return;
+	}
+
+	async_data_read_finalize(data_callid, buffer, actual_len);
+	async_answer_0(iid, EOK);
+
+	free(setup_packet);
+	free(buffer);
+}
+
+/** Handle VHC request for control write to the device.
+ *
+ * @param dev Target virtual device.
+ * @param iid Caller id.
+ * @param icall The call with the request.
+ */
+static void ipc_control_write(usbvirt_device_t *dev,
+    ipc_callid_t iid, ipc_call_t *icall)
+{
+	size_t data_buffer_len = IPC_GET_ARG1(*icall);
+	int rc;
+
+	void *setup_packet = NULL;
+	void *data_buffer = NULL;
+	size_t setup_packet_len = 0;
+
+	rc = async_data_write_accept(&setup_packet, false,
+	    1, 0, 0, &setup_packet_len);
+	if (rc != EOK) {
+		async_answer_0(iid, rc);
+		return;
+	}
+
+	if (data_buffer_len > 0) {
+		rc = async_data_write_accept(&data_buffer, false,
+		    1, 0, 0, &data_buffer_len);
+		if (rc != EOK) {
+			async_answer_0(iid, rc);
+			free(setup_packet);
+			return;
+		}
+	}
+
+	rc = usbvirt_control_write(dev, setup_packet, setup_packet_len,
+	    data_buffer, data_buffer_len);
+
+	async_answer_0(iid, rc);
+
+	free(setup_packet);
+	if (data_buffer != NULL) {
+		free(data_buffer);
+	}
+}
+
+/** Handle VHC request for data read from the device (in transfer).
+ *
+ * @param dev Target virtual device.
+ * @param iid Caller id.
+ * @param icall The call with the request.
+ */
+static void ipc_data_in(usbvirt_device_t *dev,
+    usb_transfer_type_t transfer_type,
+    ipc_callid_t iid, ipc_call_t *icall)
+{
+	usb_endpoint_t endpoint = IPC_GET_ARG1(*icall);
+
+	int rc;
+
+	size_t data_len = 0;
+	ipc_callid_t data_callid;
+	if (!async_data_read_receive(&data_callid, &data_len)) {
+		async_answer_0(iid, EPARTY);
+		return;
+	}
+
+	void *buffer = malloc(data_len);
+	if (buffer == NULL) {
+		async_answer_0(iid, ENOMEM);
+		return;
+	}
+
+	size_t actual_len;
+	rc = usbvirt_data_in(dev, transfer_type, endpoint,
+	    buffer, data_len, &actual_len);
+
+	if (rc != EOK) {
+		async_answer_0(data_callid, rc);
+		async_answer_0(iid, rc);
+		free(buffer);
+		return;
+	}
+
+	async_data_read_finalize(data_callid, buffer, actual_len);
+	async_answer_0(iid, EOK);
+
+	free(buffer);
+}
+
+/** Handle VHC request for data write to the device (out transfer).
+ *
+ * @param dev Target virtual device.
+ * @param iid Caller id.
+ * @param icall The call with the request.
+ */
+static void ipc_data_out(usbvirt_device_t *dev,
+    usb_transfer_type_t transfer_type,
+    ipc_callid_t iid, ipc_call_t *icall)
+{
+	usb_endpoint_t endpoint = IPC_GET_ARG1(*icall);
+
+	void *data_buffer = NULL;
+	size_t data_buffer_size = 0;
+
+	int rc = async_data_write_accept(&data_buffer, false,
+	    1, 0, 0, &data_buffer_size);
+	if (rc != EOK) {
+		async_answer_0(iid, rc);
+		return;
+	}
+
+	rc = usbvirt_data_out(dev, transfer_type, endpoint,
+	    data_buffer, data_buffer_size);
+
+	async_answer_0(iid, rc);
+
+	free(data_buffer);
+}
+
+/** Handle incoming IPC call for virtual USB device.
+ *
+ * @param dev Target USB device.
+ * @param callid Caller id.
+ * @param call Incoming call.
+ * @return Whether the call was handled.
+ */
+bool usbvirt_ipc_handle_call(usbvirt_device_t *dev,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	switch (IPC_GET_IMETHOD(*call)) {
+	case IPC_M_USBVIRT_GET_NAME:
+		ipc_get_name(dev, callid, call);
+		break;
+
+	case IPC_M_USBVIRT_CONTROL_READ:
+		ipc_control_read(dev, callid, call);
+		break;
+
+	case IPC_M_USBVIRT_CONTROL_WRITE:
+		ipc_control_write(dev, callid, call);
+		break;
+
+	case IPC_M_USBVIRT_INTERRUPT_IN:
+		ipc_data_in(dev, USB_TRANSFER_INTERRUPT, callid, call);
+		break;
+
+	case IPC_M_USBVIRT_BULK_IN:
+		ipc_data_in(dev, USB_TRANSFER_BULK, callid, call);
+		break;
+
+	case IPC_M_USBVIRT_INTERRUPT_OUT:
+		ipc_data_out(dev, USB_TRANSFER_INTERRUPT, callid, call);
+		break;
+
+	case IPC_M_USBVIRT_BULK_OUT:
+		ipc_data_out(dev, USB_TRANSFER_BULK, callid, call);
+		break;
+
+
+	default:
+		return false;
+	}
+
+	return true;
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/ipc_hc.c
===================================================================
--- uspace/lib/usbvirt/src/ipc_hc.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
+++ uspace/lib/usbvirt/src/ipc_hc.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * 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 libusbvirt
+ * @{
+ */
+/** @file
+ * IPC wrappers, host controller side.
+ */
+#include <errno.h>
+#include <str.h>
+#include <stdio.h>
+#include <assert.h>
+#include <async.h>
+#include <devman.h>
+#include <usbvirt/device.h>
+#include <usbvirt/ipc.h>
+#include <usb/debug.h>
+
+/** Send control read transfer to virtual USB device.
+ *
+ * @param phone IPC phone to the virtual device.
+ * @param ep Target endpoint number.
+ * @param setup_buffer Setup buffer.
+ * @param setup_buffer_size Setup buffer size in bytes.
+ * @param data_buffer Data buffer (DATA stage of control transfer).
+ * @param data_buffer_size Size of data buffer in bytes.
+ * @param data_transfered_size Number of actually transferred bytes.
+ * @return Error code.
+ */
+int usbvirt_ipc_send_control_read(int phone,
+    void *setup_buffer, size_t setup_buffer_size,
+    void *data_buffer, size_t data_buffer_size, size_t *data_transfered_size)
+{
+	if (phone < 0) {
+		return EINVAL;
+	}
+	if ((setup_buffer == NULL) || (setup_buffer_size == 0)) {
+		return EINVAL;
+	}
+	if ((data_buffer == NULL) || (data_buffer_size == 0)) {
+		return EINVAL;
+	}
+
+	aid_t opening_request = async_send_0(phone,
+	    IPC_M_USBVIRT_CONTROL_READ, NULL);
+	if (opening_request == 0) {
+		return ENOMEM;
+	}
+
+	int rc = async_data_write_start(phone,
+	    setup_buffer, setup_buffer_size);
+	if (rc != EOK) {
+		async_wait_for(opening_request, NULL);
+		return rc;
+	}
+
+	ipc_call_t data_request_call;
+	aid_t data_request = async_data_read(phone,
+	    data_buffer, data_buffer_size,
+	    &data_request_call);
+
+	if (data_request == 0) {
+		async_wait_for(opening_request, NULL);
+		return ENOMEM;
+	}
+
+	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;
+	}
+
+	if (data_transfered_size != NULL) {
+		*data_transfered_size = IPC_GET_ARG2(data_request_call);
+	}
+
+	return EOK;
+}
+
+/** Send control write transfer to virtual USB device.
+ *
+ * @param phone IPC phone to the virtual device.
+ * @param ep Target endpoint number.
+ * @param setup_buffer Setup buffer.
+ * @param setup_buffer_size Setup buffer size in bytes.
+ * @param data_buffer Data buffer (DATA stage of control transfer).
+ * @param data_buffer_size Size of data buffer in bytes.
+ * @return Error code.
+ */
+int usbvirt_ipc_send_control_write(int phone,
+    void *setup_buffer, size_t setup_buffer_size,
+    void *data_buffer, size_t data_buffer_size)
+{
+	if (phone < 0) {
+		return EINVAL;
+	}
+	if ((setup_buffer == NULL) || (setup_buffer_size == 0)) {
+		return EINVAL;
+	}
+	if ((data_buffer_size > 0) && (data_buffer == NULL)) {
+		return EINVAL;
+	}
+
+	aid_t opening_request = async_send_1(phone,
+	    IPC_M_USBVIRT_CONTROL_WRITE, data_buffer_size,  NULL);
+	if (opening_request == 0) {
+		return ENOMEM;
+	}
+
+	int rc = async_data_write_start(phone,
+	    setup_buffer, setup_buffer_size);
+	if (rc != EOK) {
+		async_wait_for(opening_request, NULL);
+		return rc;
+	}
+
+	if (data_buffer_size > 0) {
+		rc = async_data_write_start(phone,
+		    data_buffer, data_buffer_size);
+
+		if (rc != EOK) {
+			async_wait_for(opening_request, NULL);
+			return rc;
+		}
+	}
+
+	sysarg_t opening_request_rc;
+	async_wait_for(opening_request, &opening_request_rc);
+
+	return (int) opening_request_rc;
+}
+
+/** Request data transfer from virtual USB device.
+ *
+ * @param phone IPC phone to the virtual device.
+ * @param ep Target endpoint number.
+ * @param tr_type Transfer type (interrupt or bulk).
+ * @param data Data buffer.
+ * @param data_size Size of the data buffer in bytes.
+ * @param act_size Number of actually returned bytes.
+ * @return Error code.
+ */
+int usbvirt_ipc_send_data_in(int phone, usb_endpoint_t ep,
+    usb_transfer_type_t tr_type, void *data, size_t data_size, size_t *act_size)
+{
+	if (phone < 0) {
+		return EINVAL;
+	}
+	usbvirt_hc_to_device_method_t method;
+	switch (tr_type) {
+	case USB_TRANSFER_INTERRUPT:
+		method = IPC_M_USBVIRT_INTERRUPT_IN;
+		break;
+	case USB_TRANSFER_BULK:
+		method = IPC_M_USBVIRT_BULK_IN;
+		break;
+	default:
+		return EINVAL;
+	}
+	if ((ep <= 0) || (ep >= USBVIRT_ENDPOINT_MAX)) {
+		return EINVAL;
+	}
+	if ((data == NULL) || (data_size == 0)) {
+		return EINVAL;
+	}
+
+
+	aid_t opening_request = async_send_2(phone, method, ep, tr_type, NULL);
+	if (opening_request == 0) {
+		return ENOMEM;
+	}
+
+
+	ipc_call_t data_request_call;
+	aid_t data_request = async_data_read(phone,
+	    data, data_size,  &data_request_call);
+
+	if (data_request == 0) {
+		async_wait_for(opening_request, NULL);
+		return ENOMEM;
+	}
+
+	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;
+	}
+
+	if (act_size != NULL) {
+		*act_size = IPC_GET_ARG2(data_request_call);
+	}
+
+	return EOK;
+}
+
+/** Send data to virtual USB device.
+ *
+ * @param phone IPC phone to the virtual device.
+ * @param ep Target endpoint number.
+ * @param tr_type Transfer type (interrupt or bulk).
+ * @param data Data buffer.
+ * @param data_size Size of the data buffer in bytes.
+ * @return Error code.
+ */
+int usbvirt_ipc_send_data_out(int phone, usb_endpoint_t ep,
+    usb_transfer_type_t tr_type, void *data, size_t data_size)
+{
+	if (phone < 0) {
+		return EINVAL;
+	}
+	usbvirt_hc_to_device_method_t method;
+	switch (tr_type) {
+	case USB_TRANSFER_INTERRUPT:
+		method = IPC_M_USBVIRT_INTERRUPT_OUT;
+		break;
+	case USB_TRANSFER_BULK:
+		method = IPC_M_USBVIRT_BULK_OUT;
+		break;
+	default:
+		return EINVAL;
+	}
+	if ((ep <= 0) || (ep >= USBVIRT_ENDPOINT_MAX)) {
+		return EINVAL;
+	}
+	if ((data == NULL) || (data_size == 0)) {
+		return EINVAL;
+	}
+
+	aid_t opening_request = async_send_1(phone, method, ep, NULL);
+	if (opening_request == 0) {
+		return ENOMEM;
+	}
+
+	int rc = async_data_write_start(phone,
+	    data, data_size);
+	if (rc != EOK) {
+		async_wait_for(opening_request, NULL);
+		return rc;
+	}
+
+	sysarg_t opening_request_rc;
+	async_wait_for(opening_request, &opening_request_rc);
+
+	return (int) opening_request_rc;
+}
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/private.h
===================================================================
--- uspace/lib/usbvirt/src/private.h	(revision f90c0d6c1710d4e0841deffb9389c9f882f27afd)
+++ uspace/lib/usbvirt/src/private.h	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -1,2 +1,39 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * 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 libusbvirt
+ * @{
+ */
+/** @file
+ * Private definitions.
+ */
+#ifndef USBVIRT_PRIVATE_H_
+#define USBVIRT_PRIVATE_H_
+
 #include <usbvirt/device.h>
 
@@ -7,2 +44,7 @@
 
 extern usbvirt_control_request_handler_t library_handlers[];
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/stdreq.c
===================================================================
--- uspace/lib/usbvirt/src/stdreq.c	(revision f90c0d6c1710d4e0841deffb9389c9f882f27afd)
+++ uspace/lib/usbvirt/src/stdreq.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -1,2 +1,36 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * 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 libusbvirt
+ * @{
+ */
+/** @file
+ * Standard control request handlers.
+ */
 #include "private.h"
 #include <usb/request.h>
@@ -4,4 +38,15 @@
 #include <errno.h>
 
+/** Helper for replying to control read transfer from virtual USB device.
+ *
+ * This function takes care of copying data to answer buffer taking care
+ * of buffer sizes properly.
+ *
+ * @param setup_packet The setup packet.
+ * @param data Data buffer to write to.
+ * @param act_size Where to write actual size of returned data.
+ * @param actual_data Data to be returned.
+ * @param actual_data_size Size of answer data (@p actual_data) in bytes.
+ */
 void usbvirt_control_reply_helper(const usb_device_request_setup_packet_t *setup_packet,
     uint8_t *data, size_t *act_size,
@@ -144,4 +189,5 @@
 }
 
+/** Standard request handlers. */
 usbvirt_control_request_handler_t library_handlers[] = {
 	{
@@ -173,2 +219,5 @@
 };
 
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/transfer.c
===================================================================
--- uspace/lib/usbvirt/src/transfer.c	(revision f90c0d6c1710d4e0841deffb9389c9f882f27afd)
+++ uspace/lib/usbvirt/src/transfer.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -31,5 +31,5 @@
  */
 /** @file
- *
+ * Transfer handling.
  */
 #include <usbvirt/device.h>
@@ -39,4 +39,15 @@
 #include "private.h"
 
+/** Process a control transfer to the virtual USB device.
+ *
+ * @param dev Target device.
+ * @param setup Setup packet data.
+ * @param setup_size Size of setup packet.
+ * @param data Extra data (DATA stage).
+ * @param data_size Size of extra data in bytes.
+ * @param data_size_sent Number of actually send bytes during the transfer
+ *	(only used for READ transfers).
+ * @return Error code.
+ */
 static int usbvirt_control_transfer(usbvirt_device_t *dev,
     void *setup, size_t setup_size,
@@ -78,4 +89,15 @@
 }
 
+/** Issue a control write transfer to virtual USB device.
+ *
+ * @see usbvirt_control_transfer
+ *
+ * @param dev Target virtual device.
+ * @param setup Setup data.
+ * @param setup_size Size of setup packet.
+ * @param data Extra data (DATA stage).
+ * @param data_size Size of extra data buffer in bytes.
+ * @return Error code.
+ */
 int usbvirt_control_write(usbvirt_device_t *dev, void *setup, size_t setup_size,
     void *data, size_t data_size)
@@ -85,4 +107,16 @@
 }
 
+/** Issue a control read transfer to virtual USB device.
+ *
+ * @see usbvirt_control_transfer
+ *
+ * @param dev Target virtual device.
+ * @param setup Setup data.
+ * @param setup_size Size of setup packet.
+ * @param data Extra data (DATA stage).
+ * @param data_size Size of extra data buffer in bytes.
+ * @param data_size_sent Number of actually send bytes during the transfer.
+ * @return Error code.
+ */
 int usbvirt_control_read(usbvirt_device_t *dev, void *setup, size_t setup_size,
     void *data, size_t data_size, size_t *data_size_sent)
@@ -92,4 +126,13 @@
 }
 
+/** Send data to virtual USB device.
+ *
+ * @param dev Target virtual device.
+ * @param transf_type Transfer type (interrupt, bulk).
+ * @param endpoint Endpoint number.
+ * @param data Data sent from the driver to the device.
+ * @param data_size Size of the @p data buffer in bytes.
+ * @return Error code.
+ */
 int usbvirt_data_out(usbvirt_device_t *dev, usb_transfer_type_t transf_type,
     usb_endpoint_t endpoint, void *data, size_t data_size)
@@ -108,4 +151,14 @@
 }
 
+/** Request data from virtual USB device.
+ *
+ * @param dev Target virtual device.
+ * @param transf_type Transfer type (interrupt, bulk).
+ * @param endpoint Endpoint number.
+ * @param data Where to stored data the device returns to the driver.
+ * @param data_size Size of the @p data buffer in bytes.
+ * @param data_size_sent Number of actually written bytes.
+ * @return Error code.
+ */
 int usbvirt_data_in(usbvirt_device_t *dev, usb_transfer_type_t transf_type,
     usb_endpoint_t endpoint, void *data, size_t data_size, size_t *data_size_sent)
