Index: uspace/lib/usbvirt/Makefile
===================================================================
--- uspace/lib/usbvirt/Makefile	(revision 954ea70e3458816f21ae5183cb92e63c3a8875e8)
+++ uspace/lib/usbvirt/Makefile	(revision 7a7bfeb30fdd348b34bb92383e98a63c4fff1346)
@@ -35,7 +35,7 @@
 SOURCES = \
 	ctrlpipe.c \
-	incoming.c \
 	main.c \
-	stdreq.c
+	stdreq.c \
+	transaction.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/usbvirt/ctrlpipe.c
===================================================================
--- uspace/lib/usbvirt/ctrlpipe.c	(revision 954ea70e3458816f21ae5183cb92e63c3a8875e8)
+++ uspace/lib/usbvirt/ctrlpipe.c	(revision 7a7bfeb30fdd348b34bb92383e98a63c4fff1346)
@@ -53,13 +53,12 @@
 
 
-
-int control_pipe(void *buffer, size_t size)
+int control_pipe(usbvirt_control_transfer_t *transfer)
 {
-	if (size < sizeof(usb_device_request_setup_packet_t)) {
+	if (transfer->request_size < sizeof(usb_device_request_setup_packet_t)) {
 		return ENOMEM;
 	}
 	
-	usb_device_request_setup_packet_t *request = (usb_device_request_setup_packet_t *) buffer;
-	uint8_t *remaining_data = ((uint8_t *) request) + sizeof(usb_device_request_setup_packet_t);
+	usb_device_request_setup_packet_t *request = (usb_device_request_setup_packet_t *) transfer->request;
+	uint8_t *remaining_data = transfer->data;
 	
 	int type = request_get_type(request->request_type);
@@ -80,6 +79,4 @@
 			break;
 	}
-	
-	device->send_data(device, 0, NULL, 0);
 	
 	if (dev_new_address != -1) {
Index: uspace/lib/usbvirt/device.h
===================================================================
--- uspace/lib/usbvirt/device.h	(revision 954ea70e3458816f21ae5183cb92e63c3a8875e8)
+++ uspace/lib/usbvirt/device.h	(revision 7a7bfeb30fdd348b34bb92383e98a63c4fff1346)
@@ -41,4 +41,5 @@
 
 struct usbvirt_device;
+struct usbvirt_control_transfer;
 
 typedef int (*usbvirt_on_device_request_t)(struct usbvirt_device *dev,
@@ -70,6 +71,18 @@
 	/** Callback for class-specific USB request. */
 	usbvirt_on_device_request_t on_class_device_request;
+	
+	int (*on_control_transfer)(struct usbvirt_device *dev,
+	    usb_endpoint_t endpoint, struct usbvirt_control_transfer *transfer);
+	
 	/** Callback for all other incoming data. */
 	int (*on_data)(struct usbvirt_device *dev,
+	    usb_endpoint_t endpoint, void *buffer, size_t size);
+	
+	/** Callback for host request for data. */
+	int (*on_data_request)(struct usbvirt_device *dev,
+	    usb_endpoint_t endpoint, void *buffer, size_t size, size_t *actual_size);
+	
+	/** Decides direction of control transfer. */
+	usb_direction_t (*decide_control_transfer_direction)(
 	    usb_endpoint_t endpoint, void *buffer, size_t size);
 } usbvirt_device_ops_t;
@@ -117,4 +130,14 @@
 } usbvirt_device_state_t;
 
+/** Information about on-going control transfer.
+ */
+typedef struct usbvirt_control_transfer {
+	usb_direction_t direction;
+	void *request;
+	size_t request_size;
+	void *data;
+	size_t data_size;
+} usbvirt_control_transfer_t;
+
 /** Virtual USB device. */
 typedef struct usbvirt_device {
@@ -122,10 +145,8 @@
 	usbvirt_device_ops_t *ops;
 	
-	/** Send data to HC.
-	 * @warning Do not change after initializing with
-	 * usbvirt_device_init().
-	 * This function is here merely to make the interface more OOP.
+	
+	/** Reply onto control transfer.
 	 */
-	int (*send_data)(struct usbvirt_device *dev,
+	int (*control_transfer_reply)(struct usbvirt_device *dev,
 	    usb_endpoint_t endpoint, void *buffer, size_t size);
 	
@@ -153,12 +174,12 @@
 	int device_id_;
 	
-	/** Main routine called when data is received from HC.
-	 * @warning Do not change after initializing with
-	 * usbvirt_device_init().
-	 * This function is here merely to make the interface more OOP.
-	 */
-	int (*receive_data)(struct usbvirt_device *dev,
+	int (*transaction_out)(struct usbvirt_device *dev,
 	    usb_endpoint_t endpoint, void *buffer, size_t size);
+	int (*transaction_setup)(struct usbvirt_device *dev,
+	    usb_endpoint_t endpoint, void *buffer, size_t size);
+	int (*transaction_in)(struct usbvirt_device *dev,
+	    usb_endpoint_t endpoint, void *buffer, size_t size, size_t *data_size);
 	
+	usbvirt_control_transfer_t current_control_transfers[USB11_ENDPOINT_MAX];
 } usbvirt_device_t;
 
Index: uspace/lib/usbvirt/hub.h
===================================================================
--- uspace/lib/usbvirt/hub.h	(revision 954ea70e3458816f21ae5183cb92e63c3a8875e8)
+++ uspace/lib/usbvirt/hub.h	(revision 7a7bfeb30fdd348b34bb92383e98a63c4fff1346)
@@ -41,5 +41,8 @@
 typedef enum {
 	IPC_M_USBVIRT_DATA_TO_DEVICE = IPC_FIRST_USER_METHOD,
-	IPC_M_USBVIRT_DATA_FROM_DEVICE
+	IPC_M_USBVIRT_DATA_FROM_DEVICE,
+	IPC_M_USBVIRT_TRANSACTION_SETUP,
+	IPC_M_USBVIRT_TRANSACTION_OUT,
+	IPC_M_USBVIRT_TRANSACTION_IN,
 } usbvirt_device_method_t;
 
Index: uspace/lib/usbvirt/incoming.c
===================================================================
--- uspace/lib/usbvirt/incoming.c	(revision 954ea70e3458816f21ae5183cb92e63c3a8875e8)
+++ 	(revision )
@@ -1,62 +1,0 @@
-/*
- * Copyright (c) 2010 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 usb
- * @{
- */
-/** @file
- * @brief General handling of data transfer.
- */
-#include <errno.h>
-
-#include "device.h"
-#include "private.h"
-
-int handle_incoming_data(struct usbvirt_device *dev,
-    usb_endpoint_t endpoint, void *buffer, size_t size)
-{
-	/*
-	 * Endpoint zero is device control pipe.
-	 */
-	if (endpoint == 0) {
-		return control_pipe(buffer, size);
-	}
-	
-	/*
-	 * Any other endpoint will be handled by general handler.
-	 */
-	if (device->ops->on_data) {
-		return device->ops->on_data(device, endpoint, buffer, size);
-	} else {
-		return ENOTSUP;
-	}
-}
-
-/**
- * @}
- */
Index: uspace/lib/usbvirt/main.c
===================================================================
--- uspace/lib/usbvirt/main.c	(revision 954ea70e3458816f21ae5183cb92e63c3a8875e8)
+++ uspace/lib/usbvirt/main.c	(revision 7a7bfeb30fdd348b34bb92383e98a63c4fff1346)
@@ -38,4 +38,5 @@
 #include <errno.h>
 #include <stdlib.h>
+#include <mem.h>
 
 #include "hub.h"
@@ -47,10 +48,9 @@
 usbvirt_device_t *device = NULL;
 
-
-static void handle_data_to_device(ipc_callid_t iid, ipc_call_t icall)
+static void handle_setup_transaction(ipc_callid_t iid, ipc_call_t icall)
 {
 	usb_address_t address = IPC_GET_ARG1(icall);
 	usb_endpoint_t endpoint = IPC_GET_ARG2(icall);
-	size_t expected_len = IPC_GET_ARG5(icall);
+	size_t expected_len = IPC_GET_ARG3(icall);
 	
 	if (address != device->address) {
@@ -59,11 +59,55 @@
 	}
 	
+	if ((endpoint < 0) || (endpoint >= USB11_ENDPOINT_MAX)) {
+		ipc_answer_0(iid, EINVAL);
+		return;
+	}
+	
+	if (expected_len == 0) {
+		ipc_answer_0(iid, EINVAL);
+		return;
+	}
+	
 	size_t len = 0;
 	void * buffer = NULL;
+	int rc = async_data_write_accept(&buffer, false,
+	    1, USB_MAX_PAYLOAD_SIZE, 0, &len);
+		
+	if (rc != EOK) {
+		ipc_answer_0(iid, rc);
+		return;
+	}
+	
+	rc = device->transaction_setup(device, endpoint, buffer, len);
+	
+	ipc_answer_0(iid, rc);
+}
+
+
+static void handle_out_transaction(ipc_callid_t iid, ipc_call_t icall)
+{
+	usb_address_t address = IPC_GET_ARG1(icall);
+	usb_endpoint_t endpoint = IPC_GET_ARG2(icall);
+	size_t expected_len = IPC_GET_ARG3(icall);
+	
+	if (address != device->address) {
+		ipc_answer_0(iid, EADDRNOTAVAIL);
+		return;
+	}
+	
+	if ((endpoint < 0) || (endpoint >= USB11_ENDPOINT_MAX)) {
+		ipc_answer_0(iid, EINVAL);
+		return;
+	}
+	
+	int rc = EOK;
+	
+	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);
-		
+		rc = async_data_write_accept(&buffer, false,
+		    1, USB_MAX_PAYLOAD_SIZE, 0, &len);
+			
 		if (rc != EOK) {
 			ipc_answer_0(iid, rc);
@@ -72,5 +116,5 @@
 	}
 	
-	device->receive_data(device, endpoint, buffer, len);
+	rc = device->transaction_out(device, endpoint, buffer, len);
 	
 	if (buffer != NULL) {
@@ -78,6 +122,47 @@
 	}
 	
-	ipc_answer_0(iid, EOK);
-}
+	ipc_answer_0(iid, rc);
+}
+
+
+
+static void handle_in_transaction(ipc_callid_t iid, ipc_call_t icall)
+{
+	usb_address_t address = IPC_GET_ARG1(icall);
+	usb_endpoint_t endpoint = IPC_GET_ARG2(icall);
+	size_t expected_len = IPC_GET_ARG3(icall);
+	
+	if (address != device->address) {
+		ipc_answer_0(iid, EADDRNOTAVAIL);
+		return;
+	}
+	
+	if ((endpoint < 0) || (endpoint >= USB11_ENDPOINT_MAX)) {
+		ipc_answer_0(iid, EINVAL);
+		return;
+	}
+	
+	int rc = EOK;
+	
+	void *buffer = expected_len > 0 ? malloc(expected_len) : NULL;
+	size_t len;
+	
+	rc = device->transaction_in(device, endpoint, buffer, expected_len, &len);
+	/*
+	 * If the request was processed, we will send data back.
+	 */
+	if (rc == EOK) {
+		size_t receive_len;
+		if (!async_data_read_receive(&iid, &receive_len)) {
+			ipc_answer_0(iid, EINVAL);
+			return;
+		}
+		async_data_read_finalize(iid, buffer, receive_len);
+	}
+	
+	ipc_answer_0(iid, rc);
+}
+
+
 
 static void callback_connection(ipc_callid_t iid, ipc_call_t *icall)
@@ -95,6 +180,14 @@
 				return;
 			
-			case IPC_M_USBVIRT_DATA_TO_DEVICE:
-				handle_data_to_device(callid, call);
+			case IPC_M_USBVIRT_TRANSACTION_SETUP:
+				handle_setup_transaction(callid, call);
+				break;
+			
+			case IPC_M_USBVIRT_TRANSACTION_OUT:
+				handle_out_transaction(callid, call);
+				break;
+				
+			case IPC_M_USBVIRT_TRANSACTION_IN:
+				handle_in_transaction(callid, call);
 				break;
 			
@@ -106,51 +199,38 @@
 }
 
+static int control_transfer_reply(struct usbvirt_device *device,
+	    usb_endpoint_t endpoint, void *buffer, size_t size)
+{
+	usbvirt_control_transfer_t *transfer = &device->current_control_transfers[endpoint];
+	if (transfer->data != NULL) {
+		free(transfer->data);
+	}
+	transfer->data = malloc(size);
+	memcpy(transfer->data, buffer, size);
+	transfer->data_size = size;
+	
+	return EOK;
+}
+
 static void device_init(usbvirt_device_t *dev)
 {
-	dev->send_data = usbvirt_data_to_host;
-	dev->receive_data = handle_incoming_data;
+	dev->transaction_out = transaction_out;
+	dev->transaction_setup = transaction_setup;
+	dev->transaction_in = transaction_in;
+	
+	dev->control_transfer_reply = control_transfer_reply;
+	
 	dev->state = USBVIRT_STATE_DEFAULT;
 	dev->address = 0;
-}
-
-int usbvirt_data_to_host(struct usbvirt_device *dev,
-    usb_endpoint_t endpoint, void *buffer, size_t size)
-{
-	int phone = dev->vhcd_phone_;
-	
-	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,
-	    IPC_M_USBVIRT_DATA_FROM_DEVICE,
-	    dev->address,
-	    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;
-	}
-	
-	return EOK;
+	
+	size_t i;
+	for (i = 0; i < USB11_ENDPOINT_MAX; i++) {
+		usbvirt_control_transfer_t *transfer = &dev->current_control_transfers[i];
+		transfer->direction = 0;
+		transfer->request = NULL;
+		transfer->request_size = 0;
+		transfer->data = NULL;
+		transfer->data_size = 0;
+	}
 }
 
Index: uspace/lib/usbvirt/private.h
===================================================================
--- uspace/lib/usbvirt/private.h	(revision 954ea70e3458816f21ae5183cb92e63c3a8875e8)
+++ uspace/lib/usbvirt/private.h	(revision 7a7bfeb30fdd348b34bb92383e98a63c4fff1346)
@@ -54,5 +54,5 @@
     usb_endpoint_t endpoint, void *buffer, size_t size);
 
-int control_pipe(void *buffer, size_t size);
+int control_pipe(usbvirt_control_transfer_t *transfer);
 
 int handle_std_request(usb_device_request_setup_packet_t *request, uint8_t *data);
@@ -60,4 +60,11 @@
 extern usb_address_t dev_new_address;
 
+int transaction_setup(usbvirt_device_t *device, usb_endpoint_t endpoint,
+    void *buffer, size_t size);
+int transaction_out(usbvirt_device_t *device, usb_endpoint_t endpoint,
+    void *buffer, size_t size);
+int transaction_in(usbvirt_device_t *device, usb_endpoint_t endpoint,
+    void *buffer, size_t size, size_t *data_size);
+
 #endif
 /**
Index: uspace/lib/usbvirt/stdreq.c
===================================================================
--- uspace/lib/usbvirt/stdreq.c	(revision 954ea70e3458816f21ae5183cb92e63c3a8875e8)
+++ uspace/lib/usbvirt/stdreq.c	(revision 7a7bfeb30fdd348b34bb92383e98a63c4fff1346)
@@ -57,5 +57,5 @@
 	if ((type == USB_DESCTYPE_DEVICE) && (index == 0)) {
 		if (device->descriptors && device->descriptors->device) {
-			return device->send_data(device, 0,
+			return device->control_transfer_reply(device, 0,
 			    device->descriptors->device,
 			    device->descriptors->device->length);
@@ -95,6 +95,6 @@
 		}
 		
-		int rc = device->send_data(device, 0, all_data,
-		    config->descriptor->total_length);
+		int rc = device->control_transfer_reply(device, 0,
+		    all_data, config->descriptor->total_length);
 		
 		free(all_data);
Index: uspace/lib/usbvirt/transaction.c
===================================================================
--- uspace/lib/usbvirt/transaction.c	(revision 7a7bfeb30fdd348b34bb92383e98a63c4fff1346)
+++ uspace/lib/usbvirt/transaction.c	(revision 7a7bfeb30fdd348b34bb92383e98a63c4fff1346)
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2010 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 usb
+ * @{
+ */
+/** @file
+ * @brief Transaction processing.
+ */
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <mem.h>
+
+#include "private.h"
+
+static usb_direction_t setup_transaction_direction(usb_endpoint_t, void *, size_t);
+static void process_control_transfer(usb_endpoint_t, usbvirt_control_transfer_t *);
+
+int transaction_setup(usbvirt_device_t *device, usb_endpoint_t endpoint,
+    void *buffer, size_t size)
+{
+	usbvirt_control_transfer_t *transfer = &device->current_control_transfers[endpoint];
+	
+	if (transfer->request != NULL) {
+		free(transfer->request);
+	}
+	if (transfer->data != NULL) {
+		free(transfer->data);
+	}
+	
+	transfer->direction = setup_transaction_direction(endpoint,
+	    buffer, size);
+	transfer->request = buffer;
+	transfer->request_size = size;
+	transfer->data = NULL;
+	transfer->data_size = 0;
+	
+	return EOK;
+}
+
+int transaction_out(usbvirt_device_t *device, usb_endpoint_t endpoint,
+    void *buffer, size_t size)
+{
+	/*
+	 * First check whether it is a transaction over control pipe.
+	 */
+	usbvirt_control_transfer_t *transfer = &device->current_control_transfers[endpoint];
+	if (transfer->request != NULL) {
+		if (transfer->direction == USB_DIRECTION_OUT) {
+			/*
+			 * For out transactions, append the data to the buffer.
+			 */
+			uint8_t *new_buffer = (uint8_t *) malloc(transfer->data_size + size);
+			if (transfer->data) {
+				memcpy(new_buffer, transfer->data, transfer->data_size);
+			}
+			memcpy(new_buffer + transfer->data_size, buffer, size);
+			
+			if (transfer->data) {
+				free(transfer->data);
+			}
+			transfer->data = new_buffer;
+			transfer->data_size += size;
+		} else {
+			/*
+			 * For in transactions, this means end of the
+			 * transaction.
+			 */
+			free(transfer->request);
+			if (transfer->data) {
+				free(transfer->data);
+			}
+			transfer->request = NULL;
+			transfer->request_size = 0;
+			transfer->data = NULL;
+			transfer->data_size = 0;
+		}
+		
+		return EOK;
+	}
+	
+	/*
+	 * Otherwise, announce that some data has come.
+	 */
+	if (device->ops && device->ops->on_data) {
+		return device->ops->on_data(device, endpoint, buffer, size);
+	} else {
+		return ENOTSUP;
+	}
+}
+
+int transaction_in(usbvirt_device_t *device, usb_endpoint_t endpoint,
+    void *buffer, size_t size, size_t *data_size)
+{
+	/*
+	 * First check whether it is a transaction over control pipe.
+	 */
+	usbvirt_control_transfer_t *transfer = &device->current_control_transfers[endpoint];
+	if (transfer->request != NULL) {
+		if (transfer->direction == USB_DIRECTION_OUT) {
+			/*
+			 * This means end of input data.
+			 */
+			process_control_transfer(endpoint, transfer);
+		} else {
+			/*
+			 * For in transactions, this means sending next part
+			 * of the buffer.
+			 */
+			// TODO: implement
+		}
+		
+		return EOK;
+	}
+	
+	if (size == 0) {
+		return EINVAL;
+	}
+	
+	int rc = 1;
+	
+	if (device->ops && device->ops->on_data_request) {
+		rc = device->ops->on_data_request(device, endpoint, buffer, size, data_size);
+	}
+	
+	return rc;
+}
+
+
+static usb_direction_t setup_transaction_direction(usb_endpoint_t endpoint,
+    void *data, size_t size)
+{
+	int direction = -1;
+	if (device->ops && device->ops->decide_control_transfer_direction) {
+		direction = device->ops->decide_control_transfer_direction(endpoint,
+		    data, size);
+	}
+	
+	/*
+	 * If the user-supplied routine have not handled the direction
+	 * (or simply was not provided) we will guess, hoping that it 
+	 * uses same format as standard request on control pipe zero.
+	 */
+	if (direction < 0) {
+		if (size > 0) {
+			uint8_t *ptr = (uint8_t *) data;
+			if ((ptr[0] & 128) == 128) {
+				direction = USB_DIRECTION_IN;
+			} else {
+				direction = USB_DIRECTION_OUT;
+			}
+		} else {
+			/* This shall not happen anyway. */
+			direction = USB_DIRECTION_OUT;
+		}
+	}
+	
+	return (usb_direction_t) direction;
+}
+
+static void process_control_transfer(usb_endpoint_t endpoint,
+    usbvirt_control_transfer_t *transfer)
+{
+	int rc = EFORWARD;
+	
+	if (device->ops && device->ops->on_control_transfer) {
+		rc = device->ops->on_control_transfer(device, endpoint, transfer);
+	}
+	
+	if (rc == EFORWARD) {
+		if (endpoint == 0) {
+			rc = control_pipe(transfer);
+		}
+	}
+}
+
+/**
+ * @}
+ */
