Index: uspace/app/vuhid/main.c
===================================================================
--- uspace/app/vuhid/main.c	(revision 42e217243c8630a28314b93123cef778a33d968e)
+++ uspace/app/vuhid/main.c	(revision beee81a7687467f9672b71143423415145ae7160)
@@ -194,4 +194,6 @@
 	printf("Terminating...\n");
 	
+	usbvirt_device_unplug(&hid_dev);
+
 	return 0;
 }
Index: uspace/drv/vhc/transfer.c
===================================================================
--- uspace/drv/vhc/transfer.c	(revision 42e217243c8630a28314b93123cef778a33d968e)
+++ uspace/drv/vhc/transfer.c	(revision beee81a7687467f9672b71143423415145ae7160)
@@ -135,5 +135,4 @@
 		if (transfer->direction == USB_DIRECTION_IN) {
 			rc = usbvirt_ipc_send_control_read(phone,
-			    transfer->endpoint,
 			    transfer->setup_buffer, transfer->setup_buffer_size,
 			    transfer->data_buffer, transfer->data_buffer_size,
@@ -142,5 +141,4 @@
 			assert(transfer->direction == USB_DIRECTION_OUT);
 			rc = usbvirt_ipc_send_control_write(phone,
-			    transfer->endpoint,
 			    transfer->setup_buffer, transfer->setup_buffer_size,
 			    transfer->data_buffer, transfer->data_buffer_size);
Index: uspace/lib/usbvirt/include/usbvirt/device.h
===================================================================
--- uspace/lib/usbvirt/include/usbvirt/device.h	(revision 42e217243c8630a28314b93123cef778a33d968e)
+++ uspace/lib/usbvirt/include/usbvirt/device.h	(revision beee81a7687467f9672b71143423415145ae7160)
@@ -194,7 +194,12 @@
 	 */
 	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 42e217243c8630a28314b93123cef778a33d968e)
+++ uspace/lib/usbvirt/include/usbvirt/ipc.h	(revision beee81a7687467f9672b71143423415145ae7160)
@@ -46,10 +46,12 @@
 	IPC_M_USBVIRT_CONTROL_WRITE,
 	IPC_M_USBVIRT_INTERRUPT_IN,
-	IPC_M_USBVIRT_INTERRUPT_OUT
+	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/device.c
===================================================================
--- uspace/lib/usbvirt/src/device.c	(revision 42e217243c8630a28314b93123cef778a33d968e)
+++ uspace/lib/usbvirt/src/device.c	(revision beee81a7687467f9672b71143423415145ae7160)
@@ -44,6 +44,12 @@
 #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)
 {
@@ -82,4 +88,8 @@
 	devman_handle_t handle;
 
+	if (DEV != NULL) {
+		return ELIMIT;
+	}
+
 	rc = devman_device_get_handle(vhc_path, &handle, 0);
 	if (rc != EOK) {
@@ -94,16 +104,22 @@
 
 	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;
 	}
 
-
-
-	return EOK;
+	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_dev.c
===================================================================
--- uspace/lib/usbvirt/src/ipc_dev.c	(revision 42e217243c8630a28314b93123cef778a33d968e)
+++ uspace/lib/usbvirt/src/ipc_dev.c	(revision beee81a7687467f9672b71143423415145ae7160)
@@ -43,4 +43,10 @@
 #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)
@@ -67,9 +73,13 @@
 }
 
+/** 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)
 {
-	//usb_endpoint_t endpoint = IPC_GET_ARG1(*icall);
-
 	int rc;
 
@@ -118,8 +128,14 @@
 }
 
+/** 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_ARG2(*icall);
+	size_t data_buffer_len = IPC_GET_ARG1(*icall);
 	int rc;
 
@@ -129,5 +145,5 @@
 
 	rc = async_data_write_accept(&setup_packet, false,
-	    1, 1024, 0, &setup_packet_len);
+	    1, 0, 0, &setup_packet_len);
 	if (rc != EOK) {
 		async_answer_0(iid, rc);
@@ -137,5 +153,5 @@
 	if (data_buffer_len > 0) {
 		rc = async_data_write_accept(&data_buffer, false,
-		    1, 1024, 0, &data_buffer_len);
+		    1, 0, 0, &data_buffer_len);
 		if (rc != EOK) {
 			async_answer_0(iid, rc);
@@ -149,11 +165,22 @@
 
 	async_answer_0(iid, rc);
-}
-
-static void ipc_interrupt_in(usbvirt_device_t *dev,
+
+	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);
-	usb_transfer_type_t transfer_type = IPC_GET_ARG2(*icall);
 
 	int rc;
@@ -189,9 +216,15 @@
 }
 
-static void ipc_interrupt_out(usbvirt_device_t *dev,
+/** 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);
-	usb_transfer_type_t transfer_type = IPC_GET_ARG2(*icall);
 
 	void *data_buffer = NULL;
@@ -199,5 +232,5 @@
 
 	int rc = async_data_write_accept(&data_buffer, false,
-	    1, 1024, 0, &data_buffer_size);
+	    1, 0, 0, &data_buffer_size);
 	if (rc != EOK) {
 		async_answer_0(iid, rc);
@@ -213,31 +246,46 @@
 }
 
-
+/** 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_interrupt_in(dev, callid, call);
-			break;
-
-		case IPC_M_USBVIRT_INTERRUPT_OUT:
-			ipc_interrupt_out(dev, callid, call);
-			break;
-
-		default:
-			return false;
+	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;
 	}
 
Index: uspace/lib/usbvirt/src/ipc_hc.c
===================================================================
--- uspace/lib/usbvirt/src/ipc_hc.c	(revision 42e217243c8630a28314b93123cef778a33d968e)
+++ uspace/lib/usbvirt/src/ipc_hc.c	(revision beee81a7687467f9672b71143423415145ae7160)
@@ -54,10 +54,20 @@
  * @return Error code.
  */
-int usbvirt_ipc_send_control_read(int phone, usb_endpoint_t ep,
+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)
 {
-	aid_t opening_request = async_send_1(phone,
-	    IPC_M_USBVIRT_CONTROL_READ, ep, NULL);
+	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;
@@ -98,5 +108,7 @@
 	}
 
-	*data_transfered_size = IPC_GET_ARG2(data_request_call);
+	if (data_transfered_size != NULL) {
+		*data_transfered_size = IPC_GET_ARG2(data_request_call);
+	}
 
 	return EOK;
@@ -113,10 +125,20 @@
  * @return Error code.
  */
-int usbvirt_ipc_send_control_write(int phone, usb_endpoint_t ep,
+int usbvirt_ipc_send_control_write(int phone,
     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 (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;
@@ -159,9 +181,31 @@
     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;
-	}
+	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;
@@ -210,6 +254,26 @@
     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 (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;
