Index: uspace/app/usb/example.c
===================================================================
--- uspace/app/usb/example.c	(revision af894a21f770d0fbb50043118dbc9445ae68f6c3)
+++ uspace/app/usb/example.c	(revision 1d1f8944ede1a0aa44224dfdbf374178bcb040a0)
@@ -82,62 +82,4 @@
 }
 
-static void client_connection(ipc_callid_t iid, ipc_call_t *icall)
-{
-	ipc_answer_0(iid, EOK);
-	//printf("%s: client connection()\n", NAME);
-	
-	while (true) {
-		ipc_callid_t callid; 
-		ipc_call_t call; 
-		int rc;
-		void * buffer;
-		size_t len;
-		
-		callid = async_get_call(&call);
-		
-		switch (IPC_GET_METHOD(call)) {
-			case IPC_M_USB_HCD_DATA_SENT:
-				printf("%s: >> Data sent over USB (handle %d, outcome %s).\n",
-				    NAME, IPC_GET_ARG1(call),
-				    usb_str_transaction_outcome(IPC_GET_ARG2(call)));
-				ipc_answer_0(callid, EOK);
-				break;
-				
-			case IPC_M_USB_HCD_DATA_RECEIVED:
-				printf("%s: << Data received over USB (handle %d, outcome %s).\n",
-				    NAME, IPC_GET_ARG1(call),
-				    usb_str_transaction_outcome(IPC_GET_ARG2(call)));
-				if (IPC_GET_ARG2(call) != USB_OUTCOME_OK) {
-					ipc_answer_0(callid, EOK);
-					break;
-				}
-				len = IPC_GET_ARG3(call);
-				if (len > 0) {
-					rc = async_data_write_accept(&buffer, false,
-					    1, MAX_SIZE_RECEIVE,
-					    0, &len);
-					if (rc != EOK) {
-						ipc_answer_0(callid, rc);
-						break;
-					}
-					free(buffer);
-				}
-				printf("%s: << Received %uB long buffer (handle %d).\n",
-				    NAME, len, IPC_GET_ARG1(call));
-				ipc_answer_0(callid, EOK);
-				break;
-				
-			case IPC_M_PHONE_HUNGUP:
-				//printf("%s: hang-up.\n", NAME);
-				return;
-				
-			default:
-				printf("%s: method %d called.\n", NAME, IPC_GET_METHOD(call));
-				ipc_answer_0(callid, EOK);
-				break;
-		}
-	}
-}
-
 static void data_dump(uint8_t *data, size_t len)
 {
@@ -154,5 +96,5 @@
 int main(int argc, char * argv[])
 {
-	int hcd_phone = usb_hcd_create_phones(DEV_HCD_NAME, client_connection);
+	int hcd_phone = usb_hcd_connect(DEV_HCD_NAME);
 	if (hcd_phone < 0) {
 		printf("%s: Unable to start comunication with HCD at usb://%s (%d: %s).\n",
@@ -233,26 +175,4 @@
 	
 	fibril_sleep(1);
-	
-#if 0
-	int rc;
-	
-	printf("%s: usb_hcd_transfer_control_write_setup(...)\n", NAME);
-	rc = usb_hcd_transfer_control_write_setup(hcd_phone, target,
-	    &setup_packet, sizeof(setup_packet), NULL);
-	if (rc != EOK) {
-		printf("%s: failed setting address (%d).\n", NAME, rc);
-		return rc;
-	}
-	
-	printf("%s: usb_hcd_transfer_control_write_status(...)\n", NAME);
-	rc = usb_hcd_transfer_control_write_status(hcd_phone, target, NULL);
-	if (rc != EOK) {
-		printf("%s: failed completing control transfer (%d).\n", NAME, rc);
-		return rc;
-	}
-	
-	printf("%s: sleeping for a while...\n", NAME);
-	fibril_sleep(5);
-#endif
 
 	printf("%s: exiting.\n", NAME);
Index: uspace/app/virtusbkbd/virtusbkbd.c
===================================================================
--- uspace/app/virtusbkbd/virtusbkbd.c	(revision af894a21f770d0fbb50043118dbc9445ae68f6c3)
+++ uspace/app/virtusbkbd/virtusbkbd.c	(revision 1d1f8944ede1a0aa44224dfdbf374178bcb040a0)
@@ -58,5 +58,5 @@
 #define NAME "virt-usb-kbd"
 
-#define DEV_HCD_NAME "hcd-virt"
+#define DEV_HCD_NAME "hcd-virt-dev"
 
 #define __QUOTEME(x) #x
Index: uspace/lib/usb/hcd.c
===================================================================
--- uspace/lib/usb/hcd.c	(revision af894a21f770d0fbb50043118dbc9445ae68f6c3)
+++ uspace/lib/usb/hcd.c	(revision 1d1f8944ede1a0aa44224dfdbf374178bcb040a0)
@@ -90,23 +90,19 @@
 }
 
-/** Create necessary phones for comunicating with HCD.
+/** Create necessary phones for communicating with HCD.
  * This function wraps following calls:
  * -# open <code>/dev/usb/<i>hcd_path</i></code> for reading
  * -# access phone of file opened in previous step
- * -# create callback through just opened phone
- * -# set handler for this callback
  * -# return the (outgoing) phone
  *
  * @warning This function is wrapper for several actions and therefore
  * it is not possible - in case of error - to determine at which point
- * error occured.
+ * error occurred.
  *
  * @param hcd_path HCD identification under devfs
  *     (without <code>/dev/usb/</code>).
- * @param callback_connection Handler for callbacks from HCD.
- * @return Phone for comunicating with HCD or error code from errno.h.
- */
-int usb_hcd_create_phones(const char * hcd_path,
-    async_client_conn_t callback_connection)
+ * @return Phone for communicating with HCD or error code from errno.h.
+ */
+int usb_hcd_connect(const char * hcd_path)
 {
 	char dev_path[DEVMAP_NAME_MAXLEN + 1];
@@ -124,242 +120,7 @@
 		return hcd_phone;
 	}
-	
-	ipcarg_t phonehash;
-	int rc = ipc_connect_to_me(hcd_phone, 0, 0, 0, &phonehash);
-	if (rc != EOK) {
-		return rc;
-	}
-	async_new_connection(phonehash, 0, NULL, callback_connection);
-	
+
 	return hcd_phone;
 }
-
-/** Send data from USB host to a function.
- *
- * @param hcd_phone Connected phone to HCD.
- * @param target USB function address.
- * @param transfer_type USB transfer type.
- * @param buffer Buffer with data to be sent.
- * @param len Buffer @p buffer size.
- * @param[out] transaction_handle Handle of created transaction (NULL to ignore).
- * @return Error status.
- * @retval EOK Everything OK, buffer transfered to HCD and queued there.
- * @retval EINVAL Invalid phone.
- * @retval EINVAL @p buffer is NULL.
- */
-int usb_hcd_send_data_to_function(int hcd_phone,
-    usb_target_t target, usb_transfer_type_t transfer_type,
-    void * buffer, size_t len,
-    usb_transaction_handle_t * transaction_handle)
-{
-	if (hcd_phone < 0) {
-		return EINVAL;
-	}
-	if (buffer == NULL) {
-		return EINVAL;
-	}
-
-	ipc_call_t answer_data;
-	ipcarg_t answer_rc;
-	aid_t req;
-	int rc;
-	
-	req = async_send_4(hcd_phone,
-	    IPC_M_USB_HCD_SEND_DATA,
-	    target.address, target.endpoint,
-	    transfer_type, 0,
-	    &answer_data);
-	
-	rc = async_data_write_start(hcd_phone, buffer, len);
-	if (rc != EOK) {
-		async_wait_for(req, NULL);
-		return rc;
-	}
-	
-	async_wait_for(req, &answer_rc);
-	rc = (int)answer_rc;
-	if (rc != EOK) {
-		return rc;
-	}
-	
-	if (transaction_handle != NULL) {
-		*transaction_handle = IPC_GET_ARG1(answer_data);
-	}
-	
-	return EOK;
-}
-
-
-/** Inform HCD about data reception.
- * The actual reception is handled in callback.
- *
- * @param hcd_phone Connected phone to HCD.
- * @param target USB function address.
- * @param transfer_type USB transfer type.
- * @param len Maximum accepted packet size.
- * @param[out] transaction_handle Handle of created transaction (NULL to ignore).
- * @return Error status.
- */
-int usb_hcd_prepare_data_reception(int hcd_phone,
-    usb_target_t target, usb_transfer_type_t transfer_type,
-    size_t len,
-    usb_transaction_handle_t * transaction_handle)
-{
-	if (hcd_phone < 0) {
-		return EINVAL;
-	}
-	
-	usb_transaction_handle_t handle;
-	
-	int rc = ipc_call_sync_5_1(hcd_phone, IPC_M_USB_HCD_RECEIVE_DATA,
-	    target.address, target.endpoint,
-	    transfer_type, len, 0, &handle);
-	
-	if (rc != EOK) {
-		return rc;
-	}
-	
-	if (transaction_handle != NULL) {
-		*transaction_handle = handle;
-	}
-	
-	return EOK;
-}
-
-
-static int send_buffer(int phone, ipcarg_t method, usb_target_t target,
-    void *buffer, size_t size, usb_transaction_handle_t * transaction_handle)
-{
-	if (phone < 0) {
-		return EINVAL;
-	}
-	
-	if ((buffer == NULL) && (size > 0)) {
-		return EINVAL;
-	}
-
-	ipc_call_t answer_data;
-	ipcarg_t answer_rc;
-	aid_t req;
-	int rc;
-	
-	req = async_send_3(phone,
-	    method,
-	    target.address, target.endpoint,
-	    size,
-	    &answer_data);
-	
-	if (size > 0) {
-		rc = async_data_write_start(phone, buffer, size);
-		if (rc != EOK) {
-			async_wait_for(req, NULL);
-			return rc;
-		}
-	}
-	
-	async_wait_for(req, &answer_rc);
-	rc = (int)answer_rc;
-	if (rc != EOK) {
-		return rc;
-	}
-	
-	if (transaction_handle != NULL) {
-		*transaction_handle = IPC_GET_ARG1(answer_data);
-	}
-	
-	return EOK;
-}
-
-
-static int prep_receive_data(int phone, ipcarg_t method, usb_target_t target,
-    size_t size, usb_transaction_handle_t * transaction_handle)
-{
-	if (phone < 0) {
-		return EINVAL;
-	}
-	
-	usb_transaction_handle_t handle;
-	
-	int rc = ipc_call_sync_3_1(phone,
-	    method,
-	    target.address, target.endpoint,
-	    size,
-	    &handle);
-	
-	if (rc != EOK) {
-		return rc;
-	}
-	
-	if (transaction_handle != NULL) {
-		*transaction_handle = handle;
-	}
-	
-	return EOK;
-}
-
-
-int usb_hcd_transfer_interrupt_out(int hcd_phone, usb_target_t target,
-    void *buffer, size_t size, usb_transaction_handle_t *handle)
-{
-	return send_buffer(hcd_phone, IPC_M_USB_HCD_INTERRUPT_OUT,
-	    target, buffer, size, handle);
-}
-
-int usb_hcd_transfer_interrupt_in(int hcd_phone, usb_target_t target,
-    size_t size, usb_transaction_handle_t *handle)
-{
-	return prep_receive_data(hcd_phone, IPC_M_USB_HCD_INTERRUPT_IN,
-	    target, size, handle);
-}
-
-int usb_hcd_transfer_control_write_setup(int hcd_phone, usb_target_t target,
-    void *buffer, size_t size, usb_transaction_handle_t *handle)
-{
-	return send_buffer(hcd_phone, IPC_M_USB_HCD_CONTROL_WRITE_SETUP,
-	    target, buffer, size, handle);
-}
-
-int usb_hcd_transfer_control_write_data(int hcd_phone, usb_target_t target,
-    void *buffer, size_t size, usb_transaction_handle_t *handle)
-{
-	return send_buffer(hcd_phone, IPC_M_USB_HCD_CONTROL_WRITE_DATA,
-	    target, buffer, size, handle);
-	
-}
-int usb_hcd_transfer_control_write_status(int hcd_phone, usb_target_t target,
-    usb_transaction_handle_t *handle)
-{
-	return prep_receive_data(hcd_phone, IPC_M_USB_HCD_CONTROL_WRITE_STATUS,
-	    target, 0, handle);
-}
-
-int usb_hcd_transfer_control_read_setup(int hcd_phone, usb_target_t target,
-    void *buffer, size_t size, usb_transaction_handle_t *handle)
-{
-	return send_buffer(hcd_phone, IPC_M_USB_HCD_CONTROL_READ_SETUP,
-	    target, buffer, size, handle);
-}
-int usb_hcd_transfer_control_read_data(int hcd_phone, usb_target_t target,
-    size_t size, usb_transaction_handle_t *handle)
-{
-	return prep_receive_data(hcd_phone, IPC_M_USB_HCD_CONTROL_READ_DATA,
-	   target, size, handle);
-}
-int usb_hcd_transfer_control_read_status(int hcd_phone, usb_target_t target,
-    usb_transaction_handle_t *handle)
-{
-	return send_buffer(hcd_phone, IPC_M_USB_HCD_CONTROL_READ_STATUS,
-	    target, NULL, 0, handle);
-}
-
-
-
-
-
-/*
- * =================
- * async versions of the above functions
- * =================
- */
 
 /** Send data to HCD.
Index: uspace/lib/usb/hcd.h
===================================================================
--- uspace/lib/usb/hcd.h	(revision af894a21f770d0fbb50043118dbc9445ae68f6c3)
+++ uspace/lib/usb/hcd.h	(revision 1d1f8944ede1a0aa44224dfdbf374178bcb040a0)
@@ -133,53 +133,7 @@
  * OUT transactions buffers can be freed immediatelly after call is dispatched
  * (i.e. after return from wrapping function).
- * 
- * Async methods for retrieving data from device:
- */
-typedef enum {
-	/** Send data over USB to a function.
-	 * This method initializes large data transfer that must follow
-	 * immediatelly.
-	 * The recipient of this method must issue immediately data reception
-	 * and answer this call after data buffer was transfered.
-	 * 
-	 * Arguments of the call:
-	 * - USB address of the function
-	 * - endpoint of the function
-	 * - transfer type
-	 * - flags (not used)
-	 * 
-	 * Answer:
-	 * - EOK - ready to accept the data buffer
-	 * - ELIMIT - too many transactions for current connection
-	 * - ENOENT - callback connection does not exist
-	 * - EINVAL - other kind of error
-	 * 
-	 * Arguments of the answer:
-	 * - opaque transaction handle (used in callbacks)
-	 */
-	IPC_M_USB_HCD_SEND_DATA = IPC_FIRST_USER_METHOD,
-	
-	/** Initiate data receive from a function.
-	 * This method announces the HCD that some data will come.
-	 * When this data arrives, the HCD will call back with
-	 * IPC_M_USB_HCD_DATA_RECEIVED.
-	 * 
-	 * Arguments of the call:
-	 * - USB address of the function
-	 * - endpoint of the function
-	 * - transfer type
-	 * - buffer size
-	 * - flags (not used)
-	 *
-	 * Answer:
-	 * - EOK - HCD accepted the request
-	 * - ELIMIT - too many transactions for current connection
-	 * - ENOENT - callback connection does not exist
-	 *
-	 * Arguments of the answer:
-	 * - opaque transaction handle (used in callbacks)
-	 */
-	IPC_M_USB_HCD_RECEIVE_DATA,
-	
+ *
+ */
+typedef enum {
 	/** Tell maximum size of the transaction buffer (payload).
 	 * 
@@ -193,19 +147,5 @@
 	 * - buffer size (in bytes):
 	 */
-	IPC_M_USB_HCD_TRANSACTION_SIZE,
-	
-	
-	IPC_M_USB_HCD_INTERRUPT_OUT,
-	IPC_M_USB_HCD_INTERRUPT_IN,
-	
-	IPC_M_USB_HCD_CONTROL_WRITE_SETUP,
-	IPC_M_USB_HCD_CONTROL_WRITE_DATA,
-	IPC_M_USB_HCD_CONTROL_WRITE_STATUS,
-	
-	IPC_M_USB_HCD_CONTROL_READ_SETUP,
-	IPC_M_USB_HCD_CONTROL_READ_DATA,
-	IPC_M_USB_HCD_CONTROL_READ_STATUS,
-	
-	/* async methods */
+	IPC_M_USB_HCD_TRANSACTION_SIZE = IPC_FIRST_USER_METHOD,
 	
 	/** Asks for data buffer.
@@ -293,29 +233,5 @@
 
 
-int usb_hcd_create_phones(const char *, async_client_conn_t);
-int usb_hcd_send_data_to_function(int, usb_target_t, usb_transfer_type_t,
-    void *, size_t, usb_transaction_handle_t *);
-int usb_hcd_prepare_data_reception(int, usb_target_t, usb_transfer_type_t,
-    size_t, usb_transaction_handle_t *);
-
-
-int usb_hcd_transfer_interrupt_out(int, usb_target_t,
-    void *, size_t, usb_transaction_handle_t *);
-int usb_hcd_transfer_interrupt_in(int, usb_target_t,
-    size_t, usb_transaction_handle_t *);
-
-int usb_hcd_transfer_control_write_setup(int, usb_target_t,
-    void *, size_t, usb_transaction_handle_t *);
-int usb_hcd_transfer_control_write_data(int, usb_target_t,
-    void *, size_t, usb_transaction_handle_t *);
-int usb_hcd_transfer_control_write_status(int, usb_target_t,
-    usb_transaction_handle_t *);
-
-int usb_hcd_transfer_control_read_setup(int, usb_target_t,
-    void *, size_t, usb_transaction_handle_t *);
-int usb_hcd_transfer_control_read_data(int, usb_target_t,
-    size_t, usb_transaction_handle_t *);
-int usb_hcd_transfer_control_read_status(int, usb_target_t,
-    usb_transaction_handle_t *);
+int usb_hcd_connect(const char *);
 
 int usb_hcd_async_transfer_interrupt_out(int, usb_target_t,
Index: uspace/lib/usbvirt/main.c
===================================================================
--- uspace/lib/usbvirt/main.c	(revision af894a21f770d0fbb50043118dbc9445ae68f6c3)
+++ uspace/lib/usbvirt/main.c	(revision 1d1f8944ede1a0aa44224dfdbf374178bcb040a0)
@@ -225,5 +225,5 @@
 	
 	ipcarg_t phonehash;
-	int rc = ipc_connect_to_me(hcd_phone, 1, 0, 0, &phonehash);
+	int rc = ipc_connect_to_me(hcd_phone, 0, 0, 0, &phonehash);
 	if (rc != EOK) {
 		return rc;
Index: uspace/srv/hw/bus/usb/hcd/virtual/conn.h
===================================================================
--- uspace/srv/hw/bus/usb/hcd/virtual/conn.h	(revision af894a21f770d0fbb50043118dbc9445ae68f6c3)
+++ uspace/srv/hw/bus/usb/hcd/virtual/conn.h	(revision 1d1f8944ede1a0aa44224dfdbf374178bcb040a0)
@@ -40,5 +40,5 @@
 #include "devices.h"
 
-void connection_handler_host(ipcarg_t, int);
+void connection_handler_host(ipcarg_t);
 void connection_handler_device(ipcarg_t, virtdev_connection_t *);
 
Index: uspace/srv/hw/bus/usb/hcd/virtual/connhost.c
===================================================================
--- uspace/srv/hw/bus/usb/hcd/virtual/connhost.c	(revision af894a21f770d0fbb50043118dbc9445ae68f6c3)
+++ uspace/srv/hw/bus/usb/hcd/virtual/connhost.c	(revision 1d1f8944ede1a0aa44224dfdbf374178bcb040a0)
@@ -41,25 +41,20 @@
 #include "hc.h"
 
-static usb_transaction_handle_t g_handle_seed = 1;
-static usb_transaction_handle_t create_transaction_handle(int phone)
-{
-	return g_handle_seed++;
-}
-
 typedef struct {
-	int phone;
-	usb_transaction_handle_t handle;
-} transaction_details_t;
-
-
-/** Callback for outgoing transaction.
- */
-static void out_callback(void * buffer, size_t len, usb_transaction_outcome_t outcome, void * arg)
-{
-	dprintf(2, "out_callback(buffer, %u, %d, %p)", len, outcome, arg);
-	
-	transaction_details_t * trans = (transaction_details_t *)arg;
-	
-	async_msg_2(trans->phone, IPC_M_USB_HCD_DATA_SENT, trans->handle, outcome);
+	ipc_callid_t caller;
+	void *buffer;
+	size_t size;
+} async_transaction_t;
+
+static void async_out_callback(void * buffer, size_t len,
+    usb_transaction_outcome_t outcome, void * arg)
+{
+	async_transaction_t * trans = (async_transaction_t *)arg;
+	
+	dprintf(2, "async_out_callback(buffer, %u, %d, %p) -> %x",
+	    len, outcome, arg, trans->caller);
+	
+	// FIXME - answer according to outcome
+	ipc_answer_1(trans->caller, EOK, 0);
 	
 	free(trans);
@@ -67,49 +62,8 @@
 		free(buffer);
 	}
-}
-
-/** Callback for incoming transaction.
- */
-static void in_callback(void * buffer, size_t len, usb_transaction_outcome_t outcome, void * arg)
-{
-	dprintf(2, "in_callback(buffer, %u, %d, %p)", len, outcome, arg);
-	transaction_details_t * trans = (transaction_details_t *)arg;
-	
-	ipc_call_t answer_data;
-	ipcarg_t answer_rc;
-	aid_t req;
-	int rc;
-	
-	req = async_send_3(trans->phone,
-	    IPC_M_USB_HCD_DATA_RECEIVED,
-	    trans->handle, outcome,
-	    len,
-	    &answer_data);
-	
-	if (len > 0) {
-		rc = async_data_write_start(trans->phone, buffer, len);
-		if (rc != EOK) {
-			async_wait_for(req, NULL);
-			goto leave;
-		}
-	}
-	
-	async_wait_for(req, &answer_rc);
-	rc = (int)answer_rc;
-	if (rc != EOK) {
-		goto leave;
-	}
-	
-leave:
-	free(trans);
-	if (buffer != NULL) {
-		free(buffer);
-	}
-}
-
-/** Handle data from host to function.
- */
-static void handle_data_to_function(ipc_callid_t iid, ipc_call_t icall,
-    bool setup_transaction, int callback_phone)
+	dprintf(4, "async_out_callback answered");
+}
+
+static void async_to_device(ipc_callid_t iid, ipc_call_t icall, bool setup_transaction)
 {
 	size_t expected_len = IPC_GET_ARG3(icall);
@@ -119,14 +73,6 @@
 	};
 	
-	dprintf(1, "pretending transfer to function (dev=%d:%d)",
-	    target.address, target.endpoint);
-	
-	if (callback_phone == -1) {
-		ipc_answer_0(iid, ENOENT);
-		return;
-	}
-	
-	usb_transaction_handle_t handle
-	    = create_transaction_handle(callback_phone);
+	dprintf(1, "async_to_device: dev=%d:%d, size=%d, iid=%x",
+	    target.address, target.endpoint, expected_len, iid);
 	
 	size_t len = 0;
@@ -143,19 +89,41 @@
 	}
 	
-	transaction_details_t * trans = malloc(sizeof(transaction_details_t));
-	trans->phone = callback_phone;
-	trans->handle = handle;
+	async_transaction_t * trans = malloc(sizeof(async_transaction_t));
+	trans->caller = iid;
+	trans->buffer = NULL;
+	trans->size = 0;
 	
 	hc_add_transaction_to_device(setup_transaction, target,
 	    buffer, len,
-	    out_callback, trans);
-	
-	ipc_answer_1(iid, EOK, handle);
-	dprintf(2, "transfer to function scheduled (handle %d)", handle);
-}
-
-/** Handle data from function to host.
- */
-static void handle_data_from_function(ipc_callid_t iid, ipc_call_t icall, int callback_phone)
+	    async_out_callback, trans);
+	
+	dprintf(2, "async transaction to device scheduled (%p)", trans);
+}
+
+static void async_in_callback(void * buffer, size_t len,
+    usb_transaction_outcome_t outcome, void * arg)
+{	
+	async_transaction_t * trans = (async_transaction_t *)arg;
+	
+	dprintf(2, "async_in_callback(buffer, %u, %d, %p) -> %x",
+	    len, outcome, arg, trans->caller);
+	
+	trans->buffer = buffer;
+	trans->size = len;
+	
+	ipc_callid_t caller = trans->caller;
+	
+	if (buffer == NULL) {
+		free(trans);
+		trans = NULL;
+	}
+	
+	
+	// FIXME - answer according to outcome
+	ipc_answer_1(caller, EOK, (ipcarg_t)trans);
+	dprintf(4, "async_in_callback answered (%#x)", (ipcarg_t)trans);
+}
+
+static void async_from_device(ipc_callid_t iid, ipc_call_t icall)
 {
 	usb_target_t target = {
@@ -165,125 +133,4 @@
 	size_t len = IPC_GET_ARG3(icall);
 	
-	dprintf(1, "pretending transfer from function (dev=%d:%d)",
-	    target.address, target.endpoint);
-	
-	if (callback_phone == -1) {
-		ipc_answer_0(iid, ENOENT);
-		return;
-	}
-	
-	usb_transaction_handle_t handle
-	    = create_transaction_handle(callback_phone);
-	
-	void * buffer = NULL;
-	if (len > 0) {
-		buffer = malloc(len);
-	}
-	
-	transaction_details_t * trans = malloc(sizeof(transaction_details_t));
-	trans->phone = callback_phone;
-	trans->handle = handle;
-	
-	hc_add_transaction_from_device(target,
-	    buffer, len,
-	    in_callback, trans);
-	
-	ipc_answer_1(iid, EOK, handle);
-	dprintf(2, "transfer from function scheduled (handle %d)", handle);
-}
-
-
-typedef struct {
-	ipc_callid_t caller;
-	void *buffer;
-	size_t size;
-} async_transaction_t;
-
-static void async_out_callback(void * buffer, size_t len,
-    usb_transaction_outcome_t outcome, void * arg)
-{
-	async_transaction_t * trans = (async_transaction_t *)arg;
-	
-	dprintf(2, "async_out_callback(buffer, %u, %d, %p) -> %x",
-	    len, outcome, arg, trans->caller);
-	
-	// FIXME - answer according to outcome
-	ipc_answer_1(trans->caller, EOK, 0);
-	
-	free(trans);
-	if (buffer) {
-		free(buffer);
-	}
-	dprintf(4, "async_out_callback answered");
-}
-
-static void async_to_device(ipc_callid_t iid, ipc_call_t icall, bool setup_transaction)
-{
-	size_t expected_len = IPC_GET_ARG3(icall);
-	usb_target_t target = {
-		.address = IPC_GET_ARG1(icall),
-		.endpoint = IPC_GET_ARG2(icall)
-	};
-	
-	dprintf(1, "async_to_device: dev=%d:%d, size=%d, iid=%x",
-	    target.address, target.endpoint, expected_len, iid);
-	
-	size_t len = 0;
-	void * buffer = NULL;
-	if (expected_len > 0) {
-		int rc = async_data_write_accept(&buffer, false,
-		    1, USB_MAX_PAYLOAD_SIZE,
-		    0, &len);
-		
-		if (rc != EOK) {
-			ipc_answer_0(iid, rc);
-			return;
-		}
-	}
-	
-	async_transaction_t * trans = malloc(sizeof(async_transaction_t));
-	trans->caller = iid;
-	trans->buffer = NULL;
-	trans->size = 0;
-	
-	hc_add_transaction_to_device(setup_transaction, target,
-	    buffer, len,
-	    async_out_callback, trans);
-	
-	dprintf(2, "async transaction to device scheduled (%p)", trans);
-}
-
-static void async_in_callback(void * buffer, size_t len,
-    usb_transaction_outcome_t outcome, void * arg)
-{	
-	async_transaction_t * trans = (async_transaction_t *)arg;
-	
-	dprintf(2, "async_in_callback(buffer, %u, %d, %p) -> %x",
-	    len, outcome, arg, trans->caller);
-	
-	trans->buffer = buffer;
-	trans->size = len;
-	
-	ipc_callid_t caller = trans->caller;
-	
-	if (buffer == NULL) {
-		free(trans);
-		trans = NULL;
-	}
-	
-	
-	// FIXME - answer according to outcome
-	ipc_answer_1(caller, EOK, (ipcarg_t)trans);
-	dprintf(4, "async_in_callback answered (%#x)", (ipcarg_t)trans);
-}
-
-static void async_from_device(ipc_callid_t iid, ipc_call_t icall)
-{
-	usb_target_t target = {
-		.address = IPC_GET_ARG1(icall),
-		.endpoint = IPC_GET_ARG2(icall)
-	};
-	size_t len = IPC_GET_ARG3(icall);
-	
 	dprintf(1, "async_from_device: dev=%d:%d, size=%d, iid=%x",
 	    target.address, target.endpoint, len, iid);
@@ -345,10 +192,7 @@
  *
  * @param phone_hash Incoming phone hash.
- * @param host_phone Callback phone to host.
- */
-void connection_handler_host(ipcarg_t phone_hash, int host_phone)
-{
-	assert(host_phone > 0);
-	
+ */
+void connection_handler_host(ipcarg_t phone_hash)
+{
 	dprintf(0, "host connected through phone %#x", phone_hash);
 	
@@ -368,6 +212,8 @@
 		
 		switch (IPC_GET_METHOD(call)) {
+
+			/* standard IPC methods */
+
 			case IPC_M_PHONE_HUNGUP:
-				ipc_hangup(host_phone);
 				ipc_answer_0(callid, EOK);
 				dprintf(0, "phone%#x: host hung-up",
@@ -379,39 +225,10 @@
 				break;
 			
+
+			/* USB methods */
+
 			case IPC_M_USB_HCD_TRANSACTION_SIZE:
 				ipc_answer_1(callid, EOK, USB_MAX_PAYLOAD_SIZE);
 				break;
-			
-			/* callback-result methods */
-			
-			case IPC_M_USB_HCD_INTERRUPT_OUT:
-				handle_data_to_function(callid, call,
-				    false, host_phone);
-				break;
-				
-			case IPC_M_USB_HCD_INTERRUPT_IN:
-				handle_data_from_function(callid, call, host_phone);
-				break;
-			
-			case IPC_M_USB_HCD_CONTROL_WRITE_SETUP:
-				handle_data_to_function(callid, call,
-				    true, host_phone);
-				break;
-				
-			case IPC_M_USB_HCD_CONTROL_WRITE_DATA:
-				handle_data_to_function(callid, call,
-				    false, host_phone);
-				break;
-				
-			case IPC_M_USB_HCD_CONTROL_WRITE_STATUS:
-				handle_data_from_function(callid, call, host_phone);
-				break;
-			
-			case IPC_M_USB_HCD_CONTROL_READ_SETUP:
-				handle_data_to_function(callid, call,
-				    true, host_phone);
-				break;
-			
-			/* async methods */
 			
 			case IPC_M_USB_HCD_GET_BUFFER_ASYNC:
@@ -436,4 +253,5 @@
 				break;
 			
+
 			/* end of known methods */
 			
Index: uspace/srv/hw/bus/usb/hcd/virtual/hcd.c
===================================================================
--- uspace/srv/hw/bus/usb/hcd/virtual/hcd.c	(revision af894a21f770d0fbb50043118dbc9445ae68f6c3)
+++ uspace/srv/hw/bus/usb/hcd/virtual/hcd.c	(revision 1d1f8944ede1a0aa44224dfdbf374178bcb040a0)
@@ -52,41 +52,45 @@
 
 
+static dev_handle_t handle_virtual_device;
+static dev_handle_t handle_host_driver;
+
 static void client_connection(ipc_callid_t iid, ipc_call_t *icall)
 {
 	ipcarg_t phone_hash = icall->in_phone_hash;
+	dev_handle_t handle = (dev_handle_t)IPC_GET_ARG1(*icall);
 	
-	ipc_answer_0(iid, EOK);
-	
-	while (true) {
-		ipc_callid_t callid; 
-		ipc_call_t call; 
-		
-		callid = async_get_call(&call);
-		
+	if (handle == handle_host_driver) {
 		/*
-		 * We can do nothing until we have the callback phone.
-		 * Thus, we will wait for the callback and start processing
-		 * after that.
+		 * We can connect host controller driver immediately.
 		 */
-		int method = (int) IPC_GET_METHOD(call);
-		
-		if (method == IPC_M_PHONE_HUNGUP) {
-			ipc_answer_0(callid, EOK);
-			return;
-		}
-		
-		if (method == IPC_M_CONNECT_TO_ME) {
-			int kind = IPC_GET_ARG1(call);
-			int callback = IPC_GET_ARG5(call);
-			
+		ipc_answer_0(iid, EOK);
+		connection_handler_host(phone_hash);
+	} else if (handle == handle_virtual_device) {
+		ipc_answer_0(iid, EOK);
+
+		while (true) {
 			/*
-			 * Determine whether host connected to us
-			 * or a device.
+			 * We need to wait for callback request to allow
+			 * connection of virtual device.
 			 */
-			if (kind == 0) {
+			ipc_callid_t callid;
+			ipc_call_t call;
+
+			callid = async_get_call(&call);
+
+			/*
+			 * We can do nothing until we have the callback phone.
+			 * Thus, we will wait for the callback and start processing
+			 * after that.
+			 */
+			int method = (int) IPC_GET_METHOD(call);
+
+			if (method == IPC_M_PHONE_HUNGUP) {
 				ipc_answer_0(callid, EOK);
-				connection_handler_host(phone_hash, callback);
 				return;
-			} else if (kind == 1) {
+			}
+
+			if (method == IPC_M_CONNECT_TO_ME) {
+				int callback = IPC_GET_ARG5(call);
 				virtdev_connection_t *dev
 				    = virtdev_add_device(callback);
@@ -100,16 +104,19 @@
 				virtdev_destroy_device(dev);
 				return;
-			} else {
-				ipc_answer_0(callid, EINVAL);
-				ipc_hangup(callback);
-				return;
 			}
+
+			/*
+			 * No other methods could be served now.
+			 */
+			dprintf_inval_call(1, call, phone_hash);
+			ipc_answer_0(callid, ENOTSUP);
 		}
-		
+	} else {
 		/*
-		 * No other methods could be served now.
+		 * Hmmm, someone else just tried to connect to us.
+		 * Kick him out ;-).
 		 */
-		dprintf_inval_call(1, call, phone_hash);
-		ipc_answer_0(callid, ENOTSUP);
+		ipc_answer_0(iid, ENOTSUP);
+		return;
 	}
 }
@@ -135,15 +142,24 @@
 	}
 
-	rc = devmap_device_register(DEVMAP_PATH, NULL);
+	rc = devmap_device_register(DEVMAP_PATH_HC, &handle_host_driver);
 	if (rc != EOK) {
 		printf("%s: unable to register device %s (%s).\n",
-		    NAME, DEVMAP_PATH, str_error(rc));
+		    NAME, DEVMAP_PATH_HC, str_error(rc));
 		return 1;
 	}
 	
+	rc = devmap_device_register(DEVMAP_PATH_DEV, &handle_virtual_device);
+	if (rc != EOK) {
+		printf("%s: unable to register device %s (%s).\n",
+		    NAME, DEVMAP_PATH_DEV, str_error(rc));
+		return 1;
+	}
+
 	hub_init();
 	
-	printf("%s: accepting connections [devmap=%s, debug=%d].\n", NAME,
-	    DEVMAP_PATH, debug_level);
+	printf("%s: accepting connections [debug=%d]\n", NAME, debug_level);
+	printf("%s:  -> host controller at %s\n", NAME, DEVMAP_PATH_HC);
+	printf("%s:  -> virtual hub at %s\n", NAME, DEVMAP_PATH_DEV);
+
 	hc_manager();
 	
Index: uspace/srv/hw/bus/usb/hcd/virtual/vhcd.h
===================================================================
--- uspace/srv/hw/bus/usb/hcd/virtual/vhcd.h	(revision af894a21f770d0fbb50043118dbc9445ae68f6c3)
+++ uspace/srv/hw/bus/usb/hcd/virtual/vhcd.h	(revision 1d1f8944ede1a0aa44224dfdbf374178bcb040a0)
@@ -37,7 +37,9 @@
 
 #define NAME "hcd-virt"
+#define NAME_DEV "hcd-virt-dev"
 #define NAMESPACE "usb"
 
-#define DEVMAP_PATH NAMESPACE "/" NAME
+#define DEVMAP_PATH_HC NAMESPACE "/" NAME
+#define DEVMAP_PATH_DEV NAMESPACE "/" NAME_DEV
 
 extern int debug_level;
