Index: uspace/lib/usb/hcd.c
===================================================================
--- uspace/lib/usb/hcd.c	(revision 23cb44b4470f76dd953fedf15da7a42f59fac14d)
+++ uspace/lib/usb/hcd.c	(revision 2185776425a406b08bd1bc13dcb72da629db02f3)
@@ -35,8 +35,17 @@
 #include "hcd.h"
 #include <devmap.h>
+#include <stdlib.h>
 #include <fcntl.h>
 #include <vfs/vfs.h>
 #include <errno.h>
 
+typedef struct {
+	int phone;
+	void *buffer;
+	size_t size;
+	size_t *size_transferred;
+	ipc_call_t reply;
+	aid_t request;
+} transfer_info_t;
 
 #define NAMESPACE "usb"
@@ -339,4 +348,278 @@
 
 
+
+
+/*
+ * =================
+ * async versions of the above functions
+ * =================
+ */
+ 
+static int async_send_buffer(int phone, int method,
+    usb_target_t target,
+    void *buffer, size_t size,
+    usb_handle_t *handle)
+{
+	if (phone < 0) {
+		return EINVAL;
+	}
+	
+	if ((buffer == NULL) && (size > 0)) {
+		return EINVAL;
+	}
+	
+	if (handle == NULL) {
+		return EINVAL;
+	}
+
+	transfer_info_t *transfer
+	    = (transfer_info_t *) malloc(sizeof(transfer_info_t));
+	if (transfer == NULL) {
+		return ENOMEM;
+	}
+	
+	transfer->size_transferred = NULL;
+	transfer->buffer = NULL;
+	transfer->size = 0;
+	transfer->phone = phone;
+
+	int rc;
+	
+	transfer->request = async_send_3(phone,
+	    method,
+	    target.address, target.endpoint,
+	    size,
+	    &transfer->reply);
+	
+	if (size > 0) {
+		rc = async_data_write_start(phone, buffer, size);
+		if (rc != EOK) {
+			async_wait_for(transfer->request, NULL);
+			return rc;
+		}
+	}
+	
+	*handle = (usb_handle_t) transfer;
+	
+	return EOK;
+}
+
+static int async_recv_buffer(int phone, int method,
+    usb_target_t target,
+    void *buffer, size_t size, size_t *actual_size,
+    usb_handle_t *handle)
+{
+	if (phone < 0) {
+		return EINVAL;
+	}
+	
+	if ((buffer == NULL) && (size > 0)) {
+		return EINVAL;
+	}
+	
+	if (handle == NULL) {
+		return EINVAL;
+	}
+
+	transfer_info_t *transfer
+	    = (transfer_info_t *) malloc(sizeof(transfer_info_t));
+	if (transfer == NULL) {
+		return ENOMEM;
+	}
+	
+	transfer->size_transferred = actual_size;
+	transfer->buffer = buffer;
+	transfer->size = size;
+	transfer->phone = phone;
+	
+	transfer->request = async_send_3(phone,
+	    method,
+	    target.address, target.endpoint,
+	    size,
+	    &transfer->reply);
+	
+	*handle = (usb_handle_t) transfer;
+	
+	return EOK;
+}
+
+static int read_buffer_in(int phone, ipcarg_t hash,
+    void *buffer, size_t size, size_t *actual_size)
+{
+	ipc_call_t answer_data;
+	ipcarg_t answer_rc;
+	aid_t req;
+	int rc;
+	
+	req = async_send_1(phone,
+	    IPC_M_USB_HCD_GET_BUFFER_ASYNC,
+	    hash,
+	    &answer_data);
+	
+	rc = async_data_read_start(phone, buffer, size);
+	if (rc != EOK) {
+		async_wait_for(req, NULL);
+		return EINVAL;
+	}
+	
+	async_wait_for(req, &answer_rc);
+	rc = (int)answer_rc;
+	
+	if (rc != EOK) {
+		return rc;
+	}
+	
+	*actual_size = IPC_GET_ARG1(answer_data);
+	
+	return EOK;
+}
+
+
+int usb_hcd_async_wait_for(usb_handle_t handle)
+{
+	if (handle == 0) {
+		return EBADMEM;
+	}
+	
+	int rc = EOK;
+	
+	transfer_info_t *transfer = (transfer_info_t *) handle;
+	
+	ipcarg_t answer_rc;
+	async_wait_for(transfer->request, &answer_rc);
+	
+	if (answer_rc != EOK) {
+		rc = (int) answer_rc;
+		goto leave;
+	}
+	
+	/*
+	 * If the buffer is not NULL, we must accept some data.
+	 */
+	if ((transfer->buffer != NULL) && (transfer->size > 0)) {
+		/*
+		 * The buffer hash identifies the data on the server
+		 * side.
+		 * We will use it when actually reading-in the data.
+		 */
+		ipcarg_t buffer_hash = IPC_GET_ARG1(transfer->reply);
+		if (buffer_hash == 0) {
+			rc = ENOENT;
+			goto leave;
+		}
+		
+		size_t actual_size;
+		rc = read_buffer_in(transfer->phone, buffer_hash,
+		    transfer->buffer, transfer->size, &actual_size);
+		
+		if (rc != EOK) {
+			goto leave;
+		}
+		
+		if (transfer->size_transferred) {
+			*(transfer->size_transferred) = actual_size;
+		}
+	}
+	
+leave:
+	free(transfer);
+	
+	return rc;
+}
+
+int usb_hcd_async_transfer_interrupt_out(int hcd_phone,
+    usb_target_t target,
+    void *buffer, size_t size,
+    usb_handle_t *handle)
+{
+	return async_send_buffer(hcd_phone,
+	    IPC_M_USB_HCD_INTERRUPT_OUT_ASYNC,
+	    target,
+	    buffer, size,
+	    handle);
+}
+
+int usb_hcd_async_transfer_interrupt_in(int hcd_phone,
+    usb_target_t target,
+    void *buffer, size_t size, size_t *actual_size,
+    usb_handle_t *handle)
+{
+	return async_recv_buffer(hcd_phone,
+	    IPC_M_USB_HCD_INTERRUPT_IN_ASYNC,
+	    target,
+	    buffer, size, actual_size,
+	    handle);
+}
+
+int usb_hcd_async_transfer_control_write_setup(int hcd_phone,
+    usb_target_t target,
+    void *buffer, size_t size,
+    usb_handle_t *handle)
+{
+	return async_send_buffer(hcd_phone,
+	    IPC_M_USB_HCD_CONTROL_WRITE_SETUP_ASYNC,
+	    target,
+	    buffer, size,
+	    handle);
+}
+
+int usb_hcd_async_transfer_control_write_data(int hcd_phone,
+    usb_target_t target,
+    void *buffer, size_t size,
+    usb_handle_t *handle)
+{
+	return async_send_buffer(hcd_phone,
+	    IPC_M_USB_HCD_CONTROL_WRITE_DATA_ASYNC,
+	    target,
+	    buffer, size,
+	    handle);
+}
+
+int usb_hcd_async_transfer_control_write_status(int hcd_phone,
+    usb_target_t target,
+    usb_handle_t *handle)
+{
+	return async_recv_buffer(hcd_phone,
+	    IPC_M_USB_HCD_CONTROL_WRITE_STATUS_ASYNC,
+	    target,
+	    NULL, 0, NULL,
+	    handle);
+}
+
+int usb_hcd_async_transfer_control_read_setup(int hcd_phone,
+    usb_target_t target,
+    void *buffer, size_t size,
+    usb_handle_t *handle)
+{
+	return async_send_buffer(hcd_phone,
+	    IPC_M_USB_HCD_CONTROL_READ_SETUP_ASYNC,
+	    target,
+	    buffer, size,
+	    handle);
+}
+
+int usb_hcd_async_transfer_control_read_data(int hcd_phone,
+    usb_target_t target,
+    void *buffer, size_t size, size_t *actual_size,
+    usb_handle_t *handle)
+{
+	return async_recv_buffer(hcd_phone,
+	    IPC_M_USB_HCD_CONTROL_READ_DATA_ASYNC,
+	    target,
+	    buffer, size, actual_size,
+	    handle);
+}
+
+int usb_hcd_async_transfer_control_read_status(int hcd_phone,
+    usb_target_t target,
+    usb_handle_t *handle)
+{
+	return async_send_buffer(hcd_phone,
+	    IPC_M_USB_HCD_CONTROL_READ_STATUS_ASYNC,
+	    target,
+	    NULL, 0,
+	    handle);
+}
+
 /**
  * @}
Index: uspace/lib/usb/hcd.h
===================================================================
--- uspace/lib/usb/hcd.h	(revision 23cb44b4470f76dd953fedf15da7a42f59fac14d)
+++ uspace/lib/usb/hcd.h	(revision 2185776425a406b08bd1bc13dcb72da629db02f3)
@@ -156,4 +156,17 @@
 	IPC_M_USB_HCD_CONTROL_READ_DATA,
 	IPC_M_USB_HCD_CONTROL_READ_STATUS,
+	
+	IPC_M_USB_HCD_GET_BUFFER_ASYNC,
+	
+	IPC_M_USB_HCD_INTERRUPT_OUT_ASYNC,
+	IPC_M_USB_HCD_INTERRUPT_IN_ASYNC,
+	
+	IPC_M_USB_HCD_CONTROL_WRITE_SETUP_ASYNC,
+	IPC_M_USB_HCD_CONTROL_WRITE_DATA_ASYNC,
+	IPC_M_USB_HCD_CONTROL_WRITE_STATUS_ASYNC,
+	
+	IPC_M_USB_HCD_CONTROL_READ_SETUP_ASYNC,
+	IPC_M_USB_HCD_CONTROL_READ_DATA_ASYNC,
+	IPC_M_USB_HCD_CONTROL_READ_STATUS_ASYNC,
 	/* IPC_M_USB_HCD_ */
 } usb_hcd_method_t;
@@ -215,4 +228,25 @@
     usb_transaction_handle_t *);
 
+int usb_hcd_async_transfer_interrupt_out(int, usb_target_t,
+    void *, size_t, usb_handle_t *);
+int usb_hcd_async_transfer_interrupt_in(int, usb_target_t,
+    void *, size_t, size_t *, usb_handle_t *);
+
+int usb_hcd_async_transfer_control_write_setup(int, usb_target_t,
+    void *, size_t, usb_handle_t *);
+int usb_hcd_async_transfer_control_write_data(int, usb_target_t,
+    void *, size_t, usb_handle_t *);
+int usb_hcd_async_transfer_control_write_status(int, usb_target_t,
+    usb_handle_t *);
+
+int usb_hcd_async_transfer_control_read_setup(int, usb_target_t,
+    void *, size_t, usb_handle_t *);
+int usb_hcd_async_transfer_control_read_data(int, usb_target_t,
+    void *, size_t, size_t *, usb_handle_t *);
+int usb_hcd_async_transfer_control_read_status(int, usb_target_t,
+    usb_handle_t *);
+
+int usb_hcd_async_wait_for(usb_handle_t);
+
 #endif
 /**
Index: uspace/lib/usb/usb.h
===================================================================
--- uspace/lib/usb/usb.h	(revision 23cb44b4470f76dd953fedf15da7a42f59fac14d)
+++ uspace/lib/usb/usb.h	(revision 2185776425a406b08bd1bc13dcb72da629db02f3)
@@ -37,4 +37,5 @@
 
 #include <sys/types.h>
+#include <ipc/ipc.h>
 
 /** USB transfer type. */
@@ -83,4 +84,9 @@
 }
 
+/** General handle type.
+ * Used by various USB functions as opaque handle.
+ */
+typedef ipcarg_t usb_handle_t;
+
 #endif
 /**
Index: uspace/srv/hw/bus/usb/hcd/virtual/connhost.c
===================================================================
--- uspace/srv/hw/bus/usb/hcd/virtual/connhost.c	(revision 23cb44b4470f76dd953fedf15da7a42f59fac14d)
+++ uspace/srv/hw/bus/usb/hcd/virtual/connhost.c	(revision 2185776425a406b08bd1bc13dcb72da629db02f3)
@@ -52,4 +52,5 @@
 } transaction_details_t;
 
+
 /** Callback for outgoing transaction.
  */
@@ -193,4 +194,148 @@
 
 
+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);
+	
+	void * buffer = NULL;
+	if (len > 0) {
+		buffer = malloc(len);
+	}
+	
+	async_transaction_t * trans = malloc(sizeof(async_transaction_t));
+	trans->caller = iid;
+	trans->buffer = NULL;
+	trans->size = 0;
+	
+	hc_add_transaction_from_device(target,
+	    buffer, len,
+	    async_in_callback, trans);
+	
+	dprintf(2, "async transfer from device scheduled (%p)", trans);
+}
+
+static void async_get_buffer(ipc_callid_t iid, ipc_call_t icall)
+{
+	ipcarg_t buffer_hash = IPC_GET_ARG1(icall);
+	async_transaction_t * trans = (async_transaction_t *)buffer_hash;
+	if (trans == NULL) {
+		ipc_answer_0(iid, ENOENT);
+		return;
+	}
+	if (trans->buffer == NULL) {
+		ipc_answer_0(iid, EINVAL);
+		free(trans);
+		return;
+	}
+	
+	ipc_callid_t callid;
+	size_t accepted_size;
+	if (!async_data_read_receive(&callid, &accepted_size)) {
+		ipc_answer_0(iid, EINVAL);
+		return;
+	}
+	
+	if (accepted_size > trans->size) {
+		accepted_size = trans->size;
+	}
+	async_data_read_finalize(callid, trans->buffer, accepted_size);
+	
+	ipc_answer_1(iid, EOK, accepted_size);
+	
+	free(trans->buffer);
+	free(trans);
+}
+
 
 /** Connection handler for communcation with host.
@@ -214,4 +359,11 @@
 		
 		callid = async_get_call(&call);
+		
+		dprintf(6, "host on %#x calls [%x: %u (%u, %u, %u, %u, %u)]",
+		    phone_hash,
+		    callid,
+		    IPC_GET_METHOD(call),
+		    IPC_GET_ARG1(call), IPC_GET_ARG2(call), IPC_GET_ARG3(call),
+		    IPC_GET_ARG4(call), IPC_GET_ARG5(call));
 		
 		switch (IPC_GET_METHOD(call)) {
@@ -231,4 +383,5 @@
 				break;
 			
+			/* callback-result methods */
 			
 			case IPC_M_USB_HCD_INTERRUPT_OUT:
@@ -259,7 +412,29 @@
 				    true, host_phone);
 				break;
-				
-			case IPC_M_USB_HCD_CONTROL_READ_DATA:
-			case IPC_M_USB_HCD_CONTROL_READ_STATUS:
+			
+			/* async methods */
+			
+			case IPC_M_USB_HCD_GET_BUFFER_ASYNC:
+				async_get_buffer(callid, call);
+				break;
+	
+			case IPC_M_USB_HCD_INTERRUPT_OUT_ASYNC:
+			case IPC_M_USB_HCD_CONTROL_WRITE_DATA_ASYNC:
+			case IPC_M_USB_HCD_CONTROL_READ_STATUS_ASYNC:
+				async_to_device(callid, call, false);
+				break;
+			
+			case IPC_M_USB_HCD_CONTROL_WRITE_SETUP_ASYNC:
+			case IPC_M_USB_HCD_CONTROL_READ_SETUP_ASYNC:
+				async_to_device(callid, call, true);
+				break;
+			
+			case IPC_M_USB_HCD_INTERRUPT_IN_ASYNC:
+			case IPC_M_USB_HCD_CONTROL_WRITE_STATUS_ASYNC:
+			case IPC_M_USB_HCD_CONTROL_READ_DATA_ASYNC:
+				async_from_device(callid, call);
+				break;
+			
+			/* end of known methods */
 			
 			default:
Index: uspace/srv/hw/bus/usb/hcd/virtual/devices.c
===================================================================
--- uspace/srv/hw/bus/usb/hcd/virtual/devices.c	(revision 23cb44b4470f76dd953fedf15da7a42f59fac14d)
+++ uspace/srv/hw/bus/usb/hcd/virtual/devices.c	(revision 2185776425a406b08bd1bc13dcb72da629db02f3)
@@ -147,4 +147,6 @@
 	if (virthub_dev.address == transaction->target.address) {
 		size_t tmp;
+		dprintf(3, "sending `%s' transaction to hub",
+		    usbvirt_str_transaction_type(transaction->type));
 		switch (transaction->type) {
 			case USBVIRT_TRANSACTION_SETUP:
@@ -170,4 +172,5 @@
 				break;
 		}
+		dprintf(4, "transaction on hub processed...");
 	}
 	
