Index: uspace/drv/usbhid/descdump.h
===================================================================
--- uspace/drv/usbhid/descdump.h	(revision ec293a8d0aa0085cc90df7f82c25a5a08fbbbc59)
+++ uspace/drv/usbhid/descdump.h	(revision bbc7d83ef6c6ca6c02bb6836dfc8b328cd8b7d52)
@@ -37,5 +37,5 @@
 #define USBHID_DESCDUMP_H_
 
-#include <usb/classes/hid.h>
+#include "hid.h"
 
 void dump_standard_configuration_descriptor(
Index: uspace/drv/usbhid/descparser.h
===================================================================
--- uspace/drv/usbhid/descparser.h	(revision ec293a8d0aa0085cc90df7f82c25a5a08fbbbc59)
+++ uspace/drv/usbhid/descparser.h	(revision bbc7d83ef6c6ca6c02bb6836dfc8b328cd8b7d52)
@@ -37,5 +37,5 @@
 #define USBHID_DESCPARSER_H_
 
-#include <usb/classes/hid.h>
+#include "hid.h"
 
 int usbkbd_parse_descriptors(const uint8_t *data, size_t size,
Index: uspace/drv/usbhid/hid.h
===================================================================
--- uspace/drv/usbhid/hid.h	(revision bbc7d83ef6c6ca6c02bb6836dfc8b328cd8b7d52)
+++ uspace/drv/usbhid/hid.h	(revision bbc7d83ef6c6ca6c02bb6836dfc8b328cd8b7d52)
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/** @file
+ * Common definitions.
+ */
+
+#ifndef USBHID_HID_H_
+#define USBHID_HID_H_
+
+#include <usb/classes/hid.h>
+#include <driver.h>
+#include <usb/pipes.h>
+
+/**
+ *
+ */
+typedef struct {
+	usb_standard_interface_descriptor_t iface_desc;
+	usb_standard_endpoint_descriptor_t *endpoints;
+	usb_standard_hid_descriptor_t hid_desc;
+	uint8_t *report_desc;
+	//usb_standard_hid_class_descriptor_info_t *class_desc_info;
+	//uint8_t **class_descs;
+} usb_hid_iface_t;
+
+/**
+ *
+ */
+typedef struct {
+	usb_standard_configuration_descriptor_t config_descriptor;
+	usb_hid_iface_t *interfaces;
+} usb_hid_configuration_t;
+
+/**
+ * @brief USB/HID keyboard device type.
+ *
+ * Quite dummy right now.
+ */
+typedef struct {
+	device_t *device;
+	usb_hid_configuration_t *conf;
+	usb_address_t address;
+	usb_hid_report_parser_t *parser;
+
+	usb_device_connection_t wire;
+	usb_endpoint_pipe_t poll_pipe;
+} usb_hid_dev_kbd_t;
+
+// TODO: more configurations!
+
+#endif
Index: uspace/drv/usbhid/main.c
===================================================================
--- uspace/drv/usbhid/main.c	(revision ec293a8d0aa0085cc90df7f82c25a5a08fbbbc59)
+++ uspace/drv/usbhid/main.c	(revision bbc7d83ef6c6ca6c02bb6836dfc8b328cd8b7d52)
@@ -43,4 +43,5 @@
 #include <io/console.h>
 #include <errno.h>
+#include <str_error.h>
 #include <fibril.h>
 #include <usb/classes/hid.h>
@@ -49,4 +50,5 @@
 #include <usb/descriptor.h>
 #include <io/console.h>
+#include "hid.h"
 #include "descparser.h"
 #include "descdump.h"
@@ -379,6 +381,5 @@
 	if (rc < 0) {
 		printf("Problem setting phone to HC.\n");
-		free(kbd_dev);
-		return NULL;
+		goto error_leave;
 	}
 
@@ -386,6 +387,5 @@
 	if (rc < 0) {
 		printf("Problem getting address of the device.\n");
-		free(kbd_dev);
-		return NULL;
+		goto error_leave;
 	}
 
@@ -397,7 +397,4 @@
 //	}
 
-	// default endpoint
-	kbd_dev->poll_endpoint = GUESSED_POLL_ENDPOINT;
-	
 	/*
 	 * will need all descriptors:
@@ -410,5 +407,33 @@
 	usbkbd_process_descriptors(kbd_dev);
 
+
+
+	/*
+	 * Initialize the backing connection to the host controller.
+	 */
+	rc = usb_device_connection_initialize(&kbd_dev->wire, dev);
+	if (rc != EOK) {
+		printf("Problem initializing connection to device: %s.\n",
+		    str_error(rc));
+		goto error_leave;
+	}
+
+	/*
+	 * Initialize device pipes.
+	 */
+	rc = usb_endpoint_pipe_initialize(&kbd_dev->poll_pipe, &kbd_dev->wire,
+	    GUESSED_POLL_ENDPOINT, USB_TRANSFER_INTERRUPT, USB_DIRECTION_IN);
+	if (rc != EOK) {
+		printf("Failed to initialize interrupt in pipe: %s.\n",
+		    str_error(rc));
+		goto error_leave;
+	}
+
+
 	return kbd_dev;
+
+error_leave:
+	free(kbd_dev);
+	return NULL;
 }
 
@@ -435,20 +460,7 @@
 static void usbkbd_poll_keyboard(usb_hid_dev_kbd_t *kbd_dev)
 {
-	int rc;
-	usb_handle_t handle;
+	int rc, sess_rc;
 	uint8_t buffer[BUFFER_SIZE];
 	size_t actual_size;
-	//usb_endpoint_t poll_endpoint = 1;
-
-//	usb_address_t my_address = usb_drv_get_my_address(dev->parent_phone,
-//	    dev);
-//	if (my_address < 0) {
-//		return;
-//	}
-
-	usb_target_t poll_target = {
-		.address = kbd_dev->address,
-		.endpoint = kbd_dev->poll_endpoint
-	};
 
 	printf("Polling keyboard...\n");
@@ -456,15 +468,25 @@
 	while (true) {
 		async_usleep(1000 * 1000 * 2);
-		rc = usb_drv_async_interrupt_in(kbd_dev->device->parent_phone,
-		    poll_target, buffer, BUFFER_SIZE, &actual_size, &handle);
+
+		sess_rc = usb_endpoint_pipe_start_session(&kbd_dev->poll_pipe);
+		if (sess_rc != EOK) {
+			printf("Failed to start a session: %s.\n",
+			    str_error(sess_rc));
+			continue;
+		}
+
+		rc = usb_endpoint_pipe_read(&kbd_dev->poll_pipe, buffer,
+		    BUFFER_SIZE, &actual_size);
+		sess_rc = usb_endpoint_pipe_end_session(&kbd_dev->poll_pipe);
 
 		if (rc != EOK) {
-			printf("Error in usb_drv_async_interrupt_in(): %d\n", rc);
+			printf("Error polling the keyboard: %s.\n",
+			    str_error(rc));
 			continue;
 		}
 
-		rc = usb_drv_async_wait_for(handle);
-		if (rc != EOK) {
-			printf("Error in usb_drv_async_wait_for(): %d\n", rc);
+		if (sess_rc != EOK) {
+			printf("Error closing session: %s.\n",
+			    str_error(sess_rc));
 			continue;
 		}
Index: uspace/drv/vhc/connhost.c
===================================================================
--- uspace/drv/vhc/connhost.c	(revision ec293a8d0aa0085cc90df7f82c25a5a08fbbbc59)
+++ uspace/drv/vhc/connhost.c	(revision bbc7d83ef6c6ca6c02bb6836dfc8b328cd8b7d52)
@@ -42,4 +42,5 @@
 #include "hc.h"
 
+
 typedef struct {
 	usb_direction_t direction;
@@ -47,11 +48,27 @@
 	usbhc_iface_transfer_in_callback_t in_callback;
 	device_t *dev;
+	size_t reported_size;
 	void *arg;
 } transfer_info_t;
 
+typedef struct {
+	usb_direction_t direction;
+	usb_target_t target;
+	usbhc_iface_transfer_out_callback_t out_callback;
+	usbhc_iface_transfer_in_callback_t in_callback;
+	device_t *dev;
+	void *arg;
+	void *data_buffer;
+	size_t data_buffer_size;
+} control_transfer_info_t;
+
 static void universal_callback(void *buffer, size_t size,
     usb_transaction_outcome_t outcome, void *arg)
 {
 	transfer_info_t *transfer = (transfer_info_t *) arg;
+
+	if (transfer->reported_size != (size_t) -1) {
+		size = transfer->reported_size;
+	}
 
 	switch (transfer->direction) {
@@ -84,4 +101,113 @@
 	transfer->arg = arg;
 	transfer->dev = dev;
+	transfer->reported_size = (size_t) -1;
+
+	return transfer;
+}
+
+static void control_abort_prematurely(control_transfer_info_t *transfer,
+    size_t size, usb_transaction_outcome_t outcome)
+{
+	switch (transfer->direction) {
+		case USB_DIRECTION_IN:
+			transfer->in_callback(transfer->dev,
+			    outcome, size,
+			    transfer->arg);
+			break;
+		case USB_DIRECTION_OUT:
+			transfer->out_callback(transfer->dev,
+			    outcome,
+			    transfer->arg);
+			break;
+		default:
+			assert(false && "unreachable");
+			break;
+	}
+}
+
+static void control_callback_two(void *buffer, size_t size,
+    usb_transaction_outcome_t outcome, void *arg)
+{
+	control_transfer_info_t *ctrl_transfer = (control_transfer_info_t *) arg;
+
+	if (outcome != USB_OUTCOME_OK) {
+		control_abort_prematurely(ctrl_transfer, outcome, size);
+		free(ctrl_transfer);
+		return;
+	}
+
+	transfer_info_t *transfer  = create_transfer_info(ctrl_transfer->dev,
+	    ctrl_transfer->direction, ctrl_transfer->arg);
+	transfer->out_callback = ctrl_transfer->out_callback;
+	transfer->in_callback = ctrl_transfer->in_callback;
+	transfer->reported_size = size;
+
+	switch (ctrl_transfer->direction) {
+		case USB_DIRECTION_IN:
+			hc_add_transaction_to_device(false, ctrl_transfer->target,
+			    USB_TRANSFER_CONTROL,
+			    NULL, 0,
+			    universal_callback, transfer);
+			break;
+		case USB_DIRECTION_OUT:
+			hc_add_transaction_from_device(ctrl_transfer->target,
+			    USB_TRANSFER_CONTROL,
+			    NULL, 0,
+			    universal_callback, transfer);
+			break;
+		default:
+			assert(false && "unreachable");
+			break;
+	}
+
+	free(ctrl_transfer);
+}
+
+static void control_callback_one(void *buffer, size_t size,
+    usb_transaction_outcome_t outcome, void *arg)
+{
+	control_transfer_info_t *transfer = (control_transfer_info_t *) arg;
+
+	if (outcome != USB_OUTCOME_OK) {
+		control_abort_prematurely(transfer, outcome, size);
+		free(transfer);
+		return;
+	}
+
+	switch (transfer->direction) {
+		case USB_DIRECTION_IN:
+			hc_add_transaction_from_device(transfer->target,
+			    USB_TRANSFER_CONTROL,
+			    transfer->data_buffer, transfer->data_buffer_size,
+			    control_callback_two, transfer);
+			break;
+		case USB_DIRECTION_OUT:
+			hc_add_transaction_to_device(false, transfer->target,
+			    USB_TRANSFER_CONTROL,
+			    transfer->data_buffer, transfer->data_buffer_size,
+			    control_callback_two, transfer);
+			break;
+		default:
+			assert(false && "unreachable");
+			break;
+	}
+}
+
+static control_transfer_info_t *create_control_transfer_info(device_t *dev,
+    usb_direction_t direction, usb_target_t target,
+    void *data_buffer, size_t data_buffer_size,
+    void *arg)
+{
+	control_transfer_info_t *transfer
+	    = malloc(sizeof(control_transfer_info_t));
+
+	transfer->direction = direction;
+	transfer->target = target;
+	transfer->in_callback = NULL;
+	transfer->out_callback = NULL;
+	transfer->arg = arg;
+	transfer->dev = dev;
+	transfer->data_buffer = data_buffer;
+	transfer->data_buffer_size = data_buffer_size;
 
 	return transfer;
@@ -193,4 +319,21 @@
 }
 
+static int control_write(device_t *dev, usb_target_t target,
+    void *setup_packet, size_t setup_packet_size,
+    void *data, size_t data_size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	control_transfer_info_t *transfer
+	    = create_control_transfer_info(dev, USB_DIRECTION_OUT, target,
+	    data, data_size, arg);
+	transfer->out_callback = callback;
+
+	hc_add_transaction_to_device(true, target, USB_TRANSFER_CONTROL,
+	    setup_packet, setup_packet_size,
+	    control_callback_one, transfer);
+
+	return EOK;
+}
+
 static int control_read_setup(device_t *dev, usb_target_t target,
     void *data, size_t size,
@@ -217,4 +360,21 @@
 	    NULL, 0,
 	    callback, arg);
+}
+
+static int control_read(device_t *dev, usb_target_t target,
+    void *setup_packet, size_t setup_packet_size,
+    void *data, size_t data_size,
+    usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	control_transfer_info_t *transfer
+	    = create_control_transfer_info(dev, USB_DIRECTION_IN, target,
+	    data, data_size, arg);
+	transfer->in_callback = callback;
+
+	hc_add_transaction_to_device(true, target, USB_TRANSFER_CONTROL,
+	    setup_packet, setup_packet_size,
+	    control_callback_one, transfer);
+
+	return EOK;
 }
 
@@ -290,7 +450,11 @@
 	.control_write_status = control_write_status,
 
+	.control_write = control_write,
+
 	.control_read_setup = control_read_setup,
 	.control_read_data = control_read_data,
-	.control_read_status = control_read_status
+	.control_read_status = control_read_status,
+
+	.control_read = control_read
 };
 
Index: uspace/lib/drv/generic/remote_usbhc.c
===================================================================
--- uspace/lib/drv/generic/remote_usbhc.c	(revision ec293a8d0aa0085cc90df7f82c25a5a08fbbbc59)
+++ uspace/lib/drv/generic/remote_usbhc.c	(revision bbc7d83ef6c6ca6c02bb6836dfc8b328cd8b7d52)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Vojtech Horky
+ * Copyright (c) 2010-2011 Vojtech Horky
  * All rights reserved.
  *
@@ -52,4 +52,6 @@
 static void remote_usbhc_control_read_data(device_t *, void *, ipc_callid_t, ipc_call_t *);
 static void remote_usbhc_control_read_status(device_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_control_write(device_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_control_read(device_t *, void *, ipc_callid_t, ipc_call_t *);
 static void remote_usbhc_reserve_default_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
 static void remote_usbhc_release_default_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
@@ -81,5 +83,8 @@
 	remote_usbhc_control_read_setup,
 	remote_usbhc_control_read_data,
-	remote_usbhc_control_read_status
+	remote_usbhc_control_read_status,
+
+	remote_usbhc_control_write,
+	remote_usbhc_control_read
 };
 
@@ -95,4 +100,5 @@
 	ipc_callid_t caller;
 	void *buffer;
+	void *setup_packet;
 	size_t size;
 } async_transaction_t;
@@ -297,4 +303,5 @@
 	trans->caller = callid;
 	trans->buffer = buffer;
+	trans->setup_packet = NULL;
 	trans->size = len;
 
@@ -336,4 +343,5 @@
 	trans->caller = callid;
 	trans->buffer = malloc(len);
+	trans->setup_packet = NULL;
 	trans->size = len;
 
@@ -391,4 +399,5 @@
 	trans->caller = callid;
 	trans->buffer = NULL;
+	trans->setup_packet = NULL;
 	trans->size = 0;
 
@@ -496,4 +505,109 @@
 }
 
+void remote_usbhc_control_write(device_t *device, void *iface,
+ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+	assert(usb_iface != NULL);
+
+	if (!usb_iface->control_write) {
+		ipc_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	usb_target_t target = {
+		.address = DEV_IPC_GET_ARG1(*call),
+		.endpoint = DEV_IPC_GET_ARG2(*call)
+	};
+
+	int rc;
+
+	void *setup_packet = NULL;
+	void *data_buffer = NULL;
+	size_t setup_packet_len = 0;
+	size_t data_buffer_len = 0;
+
+	rc = async_data_write_accept(&setup_packet, false,
+	    1, USB_MAX_PAYLOAD_SIZE, 0, &setup_packet_len);
+	if (rc != EOK) {
+		ipc_answer_0(callid, rc);
+		return;
+	}
+	rc = async_data_write_accept(&data_buffer, false,
+	    1, USB_MAX_PAYLOAD_SIZE, 0, &data_buffer_len);
+	if (rc != EOK) {
+		free(setup_packet);
+		ipc_answer_0(callid, rc);
+		return;
+	}
+
+	async_transaction_t *trans = malloc(sizeof(async_transaction_t));
+	trans->caller = callid;
+	trans->setup_packet = setup_packet;
+	trans->buffer = data_buffer;
+	trans->size = data_buffer_len;
+
+	rc = usb_iface->control_write(device, target,
+	    setup_packet, setup_packet_len,
+	    data_buffer, data_buffer_len,
+	    callback_out, trans);
+
+	if (rc != EOK) {
+		ipc_answer_0(callid, rc);
+		free(setup_packet);
+		free(data_buffer);
+		free(trans);
+	}
+}
+
+
+void remote_usbhc_control_read(device_t *device, void *iface,
+ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+	assert(usb_iface != NULL);
+
+	if (!usb_iface->control_read) {
+		ipc_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	size_t data_len = DEV_IPC_GET_ARG3(*call);
+	usb_target_t target = {
+		.address = DEV_IPC_GET_ARG1(*call),
+		.endpoint = DEV_IPC_GET_ARG2(*call)
+	};
+
+	int rc;
+
+	void *setup_packet = NULL;
+	size_t setup_packet_len = 0;
+
+	rc = async_data_write_accept(&setup_packet, false,
+	    1, USB_MAX_PAYLOAD_SIZE, 0, &setup_packet_len);
+	if (rc != EOK) {
+		ipc_answer_0(callid, rc);
+		return;
+	}
+
+	async_transaction_t *trans = malloc(sizeof(async_transaction_t));
+	trans->caller = callid;
+	trans->setup_packet = setup_packet;
+	trans->buffer = malloc(data_len);
+	trans->size = data_len;
+
+	rc = usb_iface->control_read(device, target,
+	    setup_packet, setup_packet_len,
+	    trans->buffer, trans->size,
+	    callback_in, trans);
+
+	if (rc != EOK) {
+		ipc_answer_0(callid, rc);
+		free(setup_packet);
+		free(trans->buffer);
+		free(trans);
+	}
+}
+
 
 
Index: uspace/lib/drv/include/usbhc_iface.h
===================================================================
--- uspace/lib/drv/include/usbhc_iface.h	(revision ec293a8d0aa0085cc90df7f82c25a5a08fbbbc59)
+++ uspace/lib/drv/include/usbhc_iface.h	(revision bbc7d83ef6c6ca6c02bb6836dfc8b328cd8b7d52)
@@ -201,4 +201,20 @@
 	IPC_M_USBHC_CONTROL_READ_STATUS,
 
+	/** Issue control WRITE transfer.
+	 * See explanation at usb_iface_funcs_t (OUT transaction) for
+	 * call parameters.
+	 * This call is immediately followed by two IPC data writes
+	 * from the caller (setup packet and actual data).
+	 */
+	IPC_M_USBHC_CONTROL_WRITE,
+
+	/** Issue control WRITE transfer.
+	 * See explanation at usb_iface_funcs_t (IN transaction) for
+	 * call parameters.
+	 * This call is immediately followed by IPC data read from the caller
+	 * (setup packet).
+	 * Actual data are retrieved through IPC_M_USBHC_GET_BUFFER.
+	 */
+	IPC_M_USBHC_CONTROL_READ,
 
 	/* IPC_M_USB_ */
@@ -249,4 +265,12 @@
 	int (*control_read_status)(device_t *, usb_target_t,
 	    usbhc_iface_transfer_out_callback_t, void *);
+
+	int (*control_write)(device_t *, usb_target_t,
+	    void *, size_t, void *, size_t,
+	    usbhc_iface_transfer_out_callback_t, void *);
+
+	int (*control_read)(device_t *, usb_target_t,
+	    void *, size_t, void *, size_t,
+	    usbhc_iface_transfer_in_callback_t, void *);
 } usbhc_iface_t;
 
Index: uspace/lib/usb/Makefile
===================================================================
--- uspace/lib/usb/Makefile	(revision ec293a8d0aa0085cc90df7f82c25a5a08fbbbc59)
+++ uspace/lib/usb/Makefile	(revision bbc7d83ef6c6ca6c02bb6836dfc8b328cd8b7d52)
@@ -43,6 +43,8 @@
 	src/hidparser.c \
 	src/localdrv.c \
+	src/pipes.c \
 	src/recognise.c \
 	src/remotedrv.c \
+	src/request.c \
 	src/usb.c \
 	src/usbdrvreq.c \
Index: uspace/lib/usb/include/usb/classes/hid.h
===================================================================
--- uspace/lib/usb/include/usb/classes/hid.h	(revision ec293a8d0aa0085cc90df7f82c25a5a08fbbbc59)
+++ uspace/lib/usb/include/usb/classes/hid.h	(revision bbc7d83ef6c6ca6c02bb6836dfc8b328cd8b7d52)
@@ -37,5 +37,4 @@
 
 #include <usb/usb.h>
-#include <driver.h>
 #include <usb/classes/hidparser.h>
 #include <usb/descriptor.h>
@@ -101,38 +100,4 @@
 } __attribute__ ((packed)) usb_standard_hid_descriptor_t;
 
-/**
- *
- */
-typedef struct {
-	usb_standard_interface_descriptor_t iface_desc;
-	usb_standard_endpoint_descriptor_t *endpoints;
-	usb_standard_hid_descriptor_t hid_desc;
-	uint8_t *report_desc;
-	//usb_standard_hid_class_descriptor_info_t *class_desc_info;
-	//uint8_t **class_descs;
-} usb_hid_iface_t;
-
-/**
- *
- */
-typedef struct {
-	usb_standard_configuration_descriptor_t config_descriptor;
-	usb_hid_iface_t *interfaces;
-} usb_hid_configuration_t;
-
-/**
- * @brief USB/HID keyboard device type.
- *
- * Quite dummy right now.
- */
-typedef struct {
-	device_t *device;
-	usb_hid_configuration_t *conf;
-	usb_address_t address;
-	usb_endpoint_t poll_endpoint;
-	usb_hid_report_parser_t *parser;
-} usb_hid_dev_kbd_t;
-
-// TODO: more configurations!
 
 #endif
Index: uspace/lib/usb/include/usb/pipes.h
===================================================================
--- uspace/lib/usb/include/usb/pipes.h	(revision bbc7d83ef6c6ca6c02bb6836dfc8b328cd8b7d52)
+++ uspace/lib/usb/include/usb/pipes.h	(revision bbc7d83ef6c6ca6c02bb6836dfc8b328cd8b7d52)
@@ -0,0 +1,119 @@
+/*
+ * 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 libusb
+ * @{
+ */
+/** @file
+ * Communication between device drivers and host controller driver.
+ */
+#ifndef LIBUSB_PIPES_H_
+#define LIBUSB_PIPES_H_
+
+#include <sys/types.h>
+#include <usb/usb.h>
+#include <ipc/devman.h>
+#include <driver.h>
+
+/**
+ * Abstraction of a physical connection to the device.
+ * This type is an abstraction of the USB wire that connects the host and
+ * the function (device).
+ */
+typedef struct {
+	/** Handle of the host controller device is connected to. */
+	devman_handle_t hc_handle;
+	/** Address of the device. */
+	usb_address_t address;
+} usb_device_connection_t;
+
+/**
+ * Abstraction of a logical connection to USB device endpoint.
+ * It encapsulates endpoint attributes (transfer type etc.) as well
+ * as information about currently running sessions.
+ * This endpoint must be bound with existing usb_device_connection_t
+ * (i.e. the wire to send data over).
+ */
+typedef struct {
+	/** The connection used for sending the data. */
+	usb_device_connection_t *wire;
+
+	/** Endpoint number. */
+	usb_endpoint_t endpoint_no;
+
+	/** Endpoint transfer type. */
+	usb_transfer_type_t transfer_type;
+
+	/** Endpoint direction. */
+	usb_direction_t direction;
+
+	/** Phone to the host controller.
+	 * Negative when no session is active.
+	 */
+	int hc_phone;
+} usb_endpoint_pipe_t;
+
+
+int usb_device_connection_initialize(usb_device_connection_t *, device_t *);
+
+int usb_endpoint_pipe_initialize(usb_endpoint_pipe_t *,
+    usb_device_connection_t *,
+    usb_endpoint_t, usb_transfer_type_t, usb_direction_t);
+int usb_endpoint_pipe_initialize_default_control(usb_endpoint_pipe_t *,
+    usb_device_connection_t *);
+
+
+int usb_endpoint_pipe_start_session(usb_endpoint_pipe_t *);
+int usb_endpoint_pipe_end_session(usb_endpoint_pipe_t *);
+
+int usb_endpoint_pipe_read(usb_endpoint_pipe_t *, void *, size_t, size_t *);
+int usb_endpoint_pipe_write(usb_endpoint_pipe_t *, void *, size_t);
+
+int usb_endpoint_pipe_control_read(usb_endpoint_pipe_t *, void *, size_t,
+    void *, size_t, size_t *);
+int usb_endpoint_pipe_control_write(usb_endpoint_pipe_t *, void *, size_t,
+    void *, size_t);
+
+
+
+int usb_endpoint_pipe_async_read(usb_endpoint_pipe_t *, void *, size_t,
+    size_t *, usb_handle_t *);
+int usb_endpoint_pipe_async_write(usb_endpoint_pipe_t *, void *, size_t,
+    usb_handle_t *);
+
+int usb_endpoint_pipe_async_control_read(usb_endpoint_pipe_t *, void *, size_t,
+    void *, size_t, size_t *, usb_handle_t *);
+int usb_endpoint_pipe_async_control_write(usb_endpoint_pipe_t *, void *, size_t,
+    void *, size_t, usb_handle_t *);
+
+int usb_endpoint_pipe_wait_for(usb_endpoint_pipe_t *, usb_handle_t);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/include/usb/request.h
===================================================================
--- uspace/lib/usb/include/usb/request.h	(revision bbc7d83ef6c6ca6c02bb6836dfc8b328cd8b7d52)
+++ uspace/lib/usb/include/usb/request.h	(revision bbc7d83ef6c6ca6c02bb6836dfc8b328cd8b7d52)
@@ -0,0 +1,48 @@
+/*
+ * 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 libusb
+ * @{
+ */
+/** @file
+ * Standard USB requests.
+ */
+#ifndef LIBUSB_REQUEST_H_
+#define LIBUSB_REQUEST_H_
+
+#include <sys/types.h>
+#include <usb/usb.h>
+#include <usb/pipes.h>
+
+int usb_request_get_descriptor(usb_endpoint_pipe_t *, usb_request_type_t,
+    uint8_t, uint8_t, uint16_t, void *, size_t, size_t *);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/include/usb/usb.h
===================================================================
--- uspace/lib/usb/include/usb/usb.h	(revision ec293a8d0aa0085cc90df7f82c25a5a08fbbbc59)
+++ uspace/lib/usb/include/usb/usb.h	(revision bbc7d83ef6c6ca6c02bb6836dfc8b328cd8b7d52)
@@ -52,5 +52,6 @@
 typedef enum {
 	USB_DIRECTION_IN,
-	USB_DIRECTION_OUT
+	USB_DIRECTION_OUT,
+	USB_DIRECTION_BOTH
 } usb_direction_t;
 
Index: uspace/lib/usb/include/usb/usbdrv.h
===================================================================
--- uspace/lib/usb/include/usb/usbdrv.h	(revision ec293a8d0aa0085cc90df7f82c25a5a08fbbbc59)
+++ uspace/lib/usb/include/usb/usbdrv.h	(revision bbc7d83ef6c6ca6c02bb6836dfc8b328cd8b7d52)
@@ -70,4 +70,7 @@
     usb_handle_t *);
 
+int usb_drv_async_control_write(int, usb_target_t,
+    void *, size_t, void *, size_t, usb_handle_t *);
+
 int usb_drv_psync_control_write_setup(int, usb_target_t, void *, size_t);
 int usb_drv_psync_control_write_data(int, usb_target_t, void *, size_t);
@@ -77,5 +80,4 @@
     void *, size_t, void *, size_t);
 
-
 int usb_drv_async_control_read_setup(int, usb_target_t,
     void *, size_t, usb_handle_t *);
@@ -84,4 +86,7 @@
 int usb_drv_async_control_read_status(int, usb_target_t,
     usb_handle_t *);
+
+int usb_drv_async_control_read(int, usb_target_t,
+    void *, size_t, void *, size_t, size_t *, usb_handle_t *);
 
 int usb_drv_psync_control_read_setup(int, usb_target_t, void *, size_t);
Index: uspace/lib/usb/src/pipes.c
===================================================================
--- uspace/lib/usb/src/pipes.c	(revision bbc7d83ef6c6ca6c02bb6836dfc8b328cd8b7d52)
+++ uspace/lib/usb/src/pipes.c	(revision bbc7d83ef6c6ca6c02bb6836dfc8b328cd8b7d52)
@@ -0,0 +1,500 @@
+/*
+ * 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 libusb
+ * @{
+ */
+/** @file
+ * Communication between device drivers and host controller driver.
+ *
+ * Note on synchronousness of the operations: there is ABSOLUTELY NO
+ * guarantee that a call to particular function will not trigger a fibril
+ * switch.
+ * The initialization functions may actually involve contacting some other
+ * task, starting/ending a session might involve asynchronous IPC and since
+ * the transfer functions uses IPC, asynchronous nature of them is obvious.
+ * The pseudo synchronous versions for the transfers internally call the
+ * asynchronous ones and so fibril switch is possible in them as well.
+ */
+#include <usb/usb.h>
+#include <usb/pipes.h>
+#include <errno.h>
+#include <assert.h>
+#include <usb/usbdrv.h>
+
+#define _PREPARE_TARGET(varname, pipe) \
+	usb_target_t varname = { \
+		.address = (pipe)->wire->address, \
+		.endpoint = (pipe)->endpoint_no \
+	}
+
+/** Initialize connection to USB device.
+ *
+ * @param connection Connection structure to be initialized.
+ * @param device Generic device backing the USB device.
+ * @return Error code.
+ */
+int usb_device_connection_initialize(usb_device_connection_t *connection,
+    device_t *device)
+{
+	assert(connection);
+	assert(device);
+
+	int rc;
+	devman_handle_t hc_handle;
+	usb_address_t my_address;
+
+	rc = usb_drv_find_hc(device, &hc_handle);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	int hc_phone = devman_device_connect(hc_handle, 0);
+	if (hc_phone < 0) {
+		return hc_phone;
+	}
+
+	my_address = usb_drv_get_my_address(hc_phone, device);
+	if (my_address < 0) {
+		return my_address;
+	}
+
+	connection->hc_handle = hc_handle;
+	connection->address = my_address;
+	return EOK;
+}
+
+
+/** Initialize USB endpoint pipe.
+ *
+ * @param pipe Endpoint pipe to be initialized.
+ * @param connection Connection to the USB device backing this pipe (the wire).
+ * @param endpoint_no Endpoint number (in USB 1.1 in range 0 to 15).
+ * @param transfer_type Transfer type (e.g. interrupt or bulk).
+ * @param direction Endpoint direction (in/out).
+ * @return Error code.
+ */
+int usb_endpoint_pipe_initialize(usb_endpoint_pipe_t *pipe,
+    usb_device_connection_t *connection, usb_endpoint_t endpoint_no,
+    usb_transfer_type_t transfer_type, usb_direction_t direction)
+{
+	assert(pipe);
+	assert(connection);
+
+	pipe->wire = connection;
+	pipe->hc_phone = -1;
+	pipe->endpoint_no = endpoint_no;
+	pipe->transfer_type = transfer_type;
+	pipe->direction = direction;
+
+	return EOK;
+}
+
+
+/** Initialize USB endpoint pipe as the default zero control pipe.
+ *
+ * @param pipe Endpoint pipe to be initialized.
+ * @param connection Connection to the USB device backing this pipe (the wire).
+ * @return Error code.
+ */
+int usb_endpoint_pipe_initialize_default_control(usb_endpoint_pipe_t *pipe,
+    usb_device_connection_t *connection)
+{
+	assert(pipe);
+	assert(connection);
+
+	int rc = usb_endpoint_pipe_initialize(pipe, connection,
+	    0, USB_TRANSFER_CONTROL, USB_DIRECTION_BOTH);
+
+	return rc;
+}
+
+
+/** Start a session on the endpoint pipe.
+ *
+ * A session is something inside what any communication occurs.
+ * It is expected that sessions would be started right before the transfer
+ * and ended - see usb_endpoint_pipe_end_session() - after the last
+ * transfer.
+ * The reason for this is that session actually opens some communication
+ * channel to the host controller (or to the physical hardware if you
+ * wish) and thus it involves acquiring kernel resources.
+ * Since they are limited, sessions shall not be longer than strictly
+ * necessary.
+ *
+ * @param pipe Endpoint pipe to start the session on.
+ * @return Error code.
+ */
+int usb_endpoint_pipe_start_session(usb_endpoint_pipe_t *pipe)
+{
+	assert(pipe);
+
+	if (pipe->hc_phone >= 0) {
+		return EBUSY;
+	}
+
+	int phone = devman_device_connect(pipe->wire->hc_handle, 0);
+	if (phone < 0) {
+		return phone;
+	}
+
+	pipe->hc_phone = phone;
+
+	return EOK;
+}
+
+
+/** Ends a session on the endpoint pipe.
+ *
+ * @see usb_endpoint_pipe_start_session
+ *
+ * @param pipe Endpoint pipe to end the session on.
+ * @return Error code.
+ */
+int usb_endpoint_pipe_end_session(usb_endpoint_pipe_t *pipe)
+{
+	assert(pipe);
+
+	if (pipe->hc_phone < 0) {
+		return ENOENT;
+	}
+
+	int rc = ipc_hangup(pipe->hc_phone);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	pipe->hc_phone = -1;
+
+	return EOK;
+}
+
+
+/** Request a read (in) transfer on an endpoint pipe.
+ *
+ * @param[in] pipe Pipe used for the transfer.
+ * @param[out] buffer Buffer where to store the data.
+ * @param[in] size Size of the buffer (in bytes).
+ * @param[out] size_transfered Number of bytes that were actually transfered.
+ * @return Error code.
+ */
+int usb_endpoint_pipe_read(usb_endpoint_pipe_t *pipe,
+    void *buffer, size_t size, size_t *size_transfered)
+{
+	assert(pipe);
+
+	int rc;
+	usb_handle_t handle;
+
+	rc = usb_endpoint_pipe_async_read(pipe, buffer, size, size_transfered,
+	    &handle);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	rc = usb_endpoint_pipe_wait_for(pipe, handle);
+	return rc;
+}
+
+/** Request a write (out) transfer on an endpoint pipe.
+ *
+ * @param[in] pipe Pipe used for the transfer.
+ * @param[in] buffer Buffer with data to transfer.
+ * @param[in] size Size of the buffer (in bytes).
+ * @return Error code.
+ */
+int usb_endpoint_pipe_write(usb_endpoint_pipe_t *pipe,
+    void *buffer, size_t size)
+{
+	assert(pipe);
+
+	int rc;
+	usb_handle_t handle;
+
+	rc = usb_endpoint_pipe_async_write(pipe, buffer, size, &handle);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	rc = usb_endpoint_pipe_wait_for(pipe, handle);
+	return rc;
+}
+
+
+/** Request a control read transfer on an endpoint pipe.
+ *
+ * This function encapsulates all three stages of a control transfer.
+ *
+ * @param[in] pipe Pipe used for the transfer.
+ * @param[in] setup_buffer Buffer with the setup packet.
+ * @param[in] setup_buffer_size Size of the setup packet (in bytes).
+ * @param[out] data_buffer Buffer for incoming data.
+ * @param[in] data_buffer_size Size of the buffer for incoming data (in bytes).
+ * @param[out] data_transfered_size Number of bytes that were actually
+ *                                  transfered during the DATA stage.
+ * @return Error code.
+ */
+int usb_endpoint_pipe_control_read(usb_endpoint_pipe_t *pipe,
+    void *setup_buffer, size_t setup_buffer_size,
+    void *data_buffer, size_t data_buffer_size, size_t *data_transfered_size)
+{
+	assert(pipe);
+
+	int rc;
+	usb_handle_t handle;
+
+	rc = usb_endpoint_pipe_async_control_read(pipe,
+	    setup_buffer, setup_buffer_size,
+	    data_buffer, data_buffer_size, data_transfered_size,
+	    &handle);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	rc = usb_endpoint_pipe_wait_for(pipe, handle);
+	return rc;
+}
+
+
+/** Request a control write transfer on an endpoint pipe.
+ *
+ * This function encapsulates all three stages of a control transfer.
+ *
+ * @param[in] pipe Pipe used for the transfer.
+ * @param[in] setup_buffer Buffer with the setup packet.
+ * @param[in] setup_buffer_size Size of the setup packet (in bytes).
+ * @param[in] data_buffer Buffer with data to be sent.
+ * @param[in] data_buffer_size Size of the buffer with outgoing data (in bytes).
+ * @return Error code.
+ */
+int usb_endpoint_pipe_control_write(usb_endpoint_pipe_t *pipe,
+    void *setup_buffer, size_t setup_buffer_size,
+    void *data_buffer, size_t data_buffer_size)
+{
+	assert(pipe);
+
+	int rc;
+	usb_handle_t handle;
+
+	rc = usb_endpoint_pipe_async_control_write(pipe,
+	    setup_buffer, setup_buffer_size,
+	    data_buffer, data_buffer_size,
+	    &handle);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	rc = usb_endpoint_pipe_wait_for(pipe, handle);
+	return rc;
+}
+
+
+/** Request a read (in) transfer on an endpoint pipe (asynchronous version).
+ *
+ * @param[in] pipe Pipe used for the transfer.
+ * @param[out] buffer Buffer where to store the data.
+ * @param[in] size Size of the buffer (in bytes).
+ * @param[out] size_transfered Number of bytes that were actually transfered.
+ * @param[out] handle Handle of the transfer.
+ * @return Error code.
+ */
+int usb_endpoint_pipe_async_read(usb_endpoint_pipe_t *pipe,
+    void *buffer, size_t size, size_t *size_transfered,
+    usb_handle_t *handle)
+{
+	assert(pipe);
+
+	if (pipe->hc_phone < 0) {
+		return EBADF;
+	}
+
+	if (pipe->direction != USB_DIRECTION_IN) {
+		return EBADF;
+	}
+
+	int rc;
+	_PREPARE_TARGET(target, pipe);
+
+	switch (pipe->transfer_type) {
+		case USB_TRANSFER_INTERRUPT:
+			rc = usb_drv_async_interrupt_in(pipe->hc_phone, target,
+			    buffer, size, size_transfered, handle);
+			break;
+		case USB_TRANSFER_CONTROL:
+			rc = EBADF;
+			break;
+		default:
+			rc = ENOTSUP;
+			break;
+	}
+
+	return rc;
+}
+
+
+/** Request a write (out) transfer on an endpoint pipe (asynchronous version).
+ *
+ * @param[in] pipe Pipe used for the transfer.
+ * @param[in] buffer Buffer with data to transfer.
+ * @param[in] size Size of the buffer (in bytes).
+ * @param[out] handle Handle of the transfer.
+ * @return Error code.
+ */
+int usb_endpoint_pipe_async_write(usb_endpoint_pipe_t *pipe,
+    void *buffer, size_t size,
+    usb_handle_t *handle)
+{
+	assert(pipe);
+
+	if (pipe->hc_phone < 0) {
+		return EBADF;
+	}
+
+	if (pipe->direction != USB_DIRECTION_OUT) {
+		return EBADF;
+	}
+
+	int rc;
+	_PREPARE_TARGET(target, pipe);
+
+	switch (pipe->transfer_type) {
+		case USB_TRANSFER_INTERRUPT:
+			rc = usb_drv_async_interrupt_out(pipe->hc_phone, target,
+			    buffer, size, handle);
+			break;
+		case USB_TRANSFER_CONTROL:
+			rc = EBADF;
+			break;
+		default:
+			rc = ENOTSUP;
+			break;
+	}
+
+	return rc;
+}
+
+
+/** Request a control read transfer on an endpoint pipe (asynchronous version).
+ *
+ * This function encapsulates all three stages of a control transfer.
+ *
+ * @param[in] pipe Pipe used for the transfer.
+ * @param[in] setup_buffer Buffer with the setup packet.
+ * @param[in] setup_buffer_size Size of the setup packet (in bytes).
+ * @param[out] data_buffer Buffer for incoming data.
+ * @param[in] data_buffer_size Size of the buffer for incoming data (in bytes).
+ * @param[out] data_transfered_size Number of bytes that were actually
+ *                                  transfered during the DATA stage.
+ * @param[out] handle Handle of the transfer.
+ * @return Error code.
+ */
+int usb_endpoint_pipe_async_control_read(usb_endpoint_pipe_t *pipe,
+    void *setup_buffer, size_t setup_buffer_size,
+    void *data_buffer, size_t data_buffer_size, size_t *data_transfered_size,
+    usb_handle_t *handle)
+{
+	assert(pipe);
+
+	if (pipe->hc_phone < 0) {
+		return EBADF;
+	}
+
+	if ((pipe->direction != USB_DIRECTION_BOTH)
+	    || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
+		return EBADF;
+	}
+
+	int rc;
+	_PREPARE_TARGET(target, pipe);
+
+	rc = usb_drv_async_control_read(pipe->hc_phone, target,
+	    setup_buffer, setup_buffer_size,
+	    data_buffer, data_buffer_size, data_transfered_size,
+	    handle);
+
+	return rc;
+}
+
+
+/** Request a control write transfer on an endpoint pipe (asynchronous version).
+ *
+ * This function encapsulates all three stages of a control transfer.
+ *
+ * @param[in] pipe Pipe used for the transfer.
+ * @param[in] setup_buffer Buffer with the setup packet.
+ * @param[in] setup_buffer_size Size of the setup packet (in bytes).
+ * @param[in] data_buffer Buffer with data to be sent.
+ * @param[in] data_buffer_size Size of the buffer with outgoing data (in bytes).
+ * @param[out] handle Handle of the transfer.
+ * @return Error code.
+ */
+int usb_endpoint_pipe_async_control_write(usb_endpoint_pipe_t *pipe,
+    void *setup_buffer, size_t setup_buffer_size,
+    void *data_buffer, size_t data_buffer_size,
+    usb_handle_t *handle)
+{
+	assert(pipe);
+
+	if (pipe->hc_phone < 0) {
+		return EBADF;
+	}
+
+	if ((pipe->direction != USB_DIRECTION_BOTH)
+	    || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
+		return EBADF;
+	}
+
+	int rc;
+	_PREPARE_TARGET(target, pipe);
+
+	rc = usb_drv_async_control_write(pipe->hc_phone, target,
+	    setup_buffer, setup_buffer_size,
+	    data_buffer, data_buffer_size,
+	    handle);
+
+	return rc;
+}
+
+/** Wait for transfer completion.
+ *
+ * The function blocks the caller fibril until the transfer associated
+ * with given @p handle is completed.
+ *
+ * @param[in] pipe Pipe the transfer executed on.
+ * @param[in] handle Transfer handle.
+ * @return Error code.
+ */
+int usb_endpoint_pipe_wait_for(usb_endpoint_pipe_t *pipe, usb_handle_t handle)
+{
+	return usb_drv_async_wait_for(handle);
+}
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/request.c
===================================================================
--- uspace/lib/usb/src/request.c	(revision bbc7d83ef6c6ca6c02bb6836dfc8b328cd8b7d52)
+++ uspace/lib/usb/src/request.c	(revision bbc7d83ef6c6ca6c02bb6836dfc8b328cd8b7d52)
@@ -0,0 +1,121 @@
+/*
+ * 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 libusb
+ * @{
+ */
+/** @file
+ * Standard USB requests (implementation).
+ */
+#include <usb/request.h>
+#include <usb/devreq.h>
+#include <errno.h>
+
+/** Prepare setup packet.
+ *
+ * @param name Variable name with the setup packet.
+ * @param p_direction Data transfer direction.
+ * @param p_type Request type (standard/class/vendor)
+ * @param p_recipient Recipient of the request.
+ * @param p_request Request.
+ * @param p_value wValue field of setup packet.
+ * @param p_index wIndex field of setup packet.
+ * @param p_length Length of extra data.
+ */
+#define PREPARE_SETUP_PACKET(name, p_direction, p_type, p_recipient, \
+    p_request, p_value, p_index, p_length) \
+	usb_device_request_setup_packet_t name = { \
+		.request_type = \
+			((p_direction) == USB_DIRECTION_IN ? 128 : 0) \
+			| ((p_type) << 5) \
+			| (p_recipient), \
+		.request = (p_request), \
+		{ .value = (p_value) }, \
+		.index = (p_index), \
+		.length = (p_length) \
+	}
+
+/** Prepare setup packet.
+ *
+ * @param name Variable name with the setup packet.
+ * @param p_direction Data transfer direction.
+ * @param p_type Request type (standard/class/vendor)
+ * @param p_recipient Recipient of the request.
+ * @param p_request Request.
+ * @param p_value_low wValue field of setup packet (low byte).
+ * @param p_value_high wValue field of setup packet (high byte).
+ * @param p_index wIndex field of setup packet.
+ * @param p_length Length of extra data.
+ */
+#define PREPARE_SETUP_PACKET_LOHI(name, p_direction, p_type, p_recipient, \
+    p_request, p_value_low, p_value_high, p_index, p_length) \
+	PREPARE_SETUP_PACKET(name, p_direction, p_type, p_recipient, \
+	    p_request, (p_value_low) | ((p_value_high) << 8), \
+	    p_index, p_length)
+
+
+/** Retrieve USB descriptor of a USB device.
+ *
+ * @param[in] pipe Control endpoint pipe (session must be already started).
+ * @param[in] request_type Request type (standard/class/vendor).
+ * @param[in] descriptor_type Descriptor type (device/configuration/HID/...).
+ * @param[in] descriptor_index Descriptor index.
+ * @param[in] language Language index.
+ * @param[out] buffer Buffer where to store the retrieved descriptor.
+ * @param[in] size Size of the @p buffer.
+ * @param[out] actual_size Number of bytes actually transferred.
+ * @return Error code.
+ */
+int usb_request_get_descriptor(usb_endpoint_pipe_t *pipe,
+    usb_request_type_t request_type,
+    uint8_t descriptor_type, uint8_t descriptor_index,
+    uint16_t language,
+    void *buffer, size_t size, size_t *actual_size)
+{
+	if (buffer == NULL) {
+		return EBADMEM;
+	}
+	if (size == 0) {
+		return EINVAL;
+	}
+
+	PREPARE_SETUP_PACKET_LOHI(setup_packet, USB_DIRECTION_IN,
+	    request_type, USB_REQUEST_RECIPIENT_DEVICE,
+	    USB_DEVREQ_GET_DESCRIPTOR, descriptor_index, descriptor_type,
+	    language, size);
+
+	int rc = usb_endpoint_pipe_control_read(pipe,
+	    &setup_packet, sizeof(setup_packet),
+	    buffer, size, actual_size);
+
+	return rc;
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/usbdrv.c
===================================================================
--- uspace/lib/usb/src/usbdrv.c	(revision ec293a8d0aa0085cc90df7f82c25a5a08fbbbc59)
+++ uspace/lib/usb/src/usbdrv.c	(revision bbc7d83ef6c6ca6c02bb6836dfc8b328cd8b7d52)
@@ -495,4 +495,54 @@
 }
 
+/** Issue whole control write transfer. */
+int usb_drv_async_control_write(int phone, usb_target_t target,
+    void *setup_packet, size_t setup_packet_size,
+    void *buffer, size_t buffer_size,
+    usb_handle_t *handle)
+{
+	// FIXME - check input parameters instead of asserting them
+	assert(phone > 0);
+	assert(setup_packet != NULL);
+	assert(setup_packet_size > 0);
+	assert(buffer != NULL);
+	assert(buffer_size > 0);
+	assert(handle != NULL);
+
+	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,
+	    DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_CONTROL_WRITE,
+	    target.address, target.endpoint,
+	    &transfer->reply);
+
+	rc = async_data_write_start(phone, setup_packet, setup_packet_size);
+	if (rc != EOK) {
+		async_wait_for(transfer->request, NULL);
+		return rc;
+	}
+
+	rc = async_data_write_start(phone, buffer, buffer_size);
+	if (rc != EOK) {
+		async_wait_for(transfer->request, NULL);
+		return rc;
+	}
+
+	*handle = (usb_handle_t) transfer;
+
+	return EOK;
+}
+
 /** Start control read transfer. */
 int usb_drv_async_control_read_setup(int phone, usb_target_t target,
@@ -530,4 +580,49 @@
 }
 
+/** Issue whole control read transfer. */
+int usb_drv_async_control_read(int phone, usb_target_t target,
+    void *setup_packet, size_t setup_packet_size,
+    void *buffer, size_t buffer_size, size_t *actual_size,
+    usb_handle_t *handle)
+{
+	// FIXME - check input parameters instead of asserting them
+	assert(phone > 0);
+	assert(setup_packet != NULL);
+	assert(setup_packet_size > 0);
+	assert(buffer != NULL);
+	assert(buffer_size > 0);
+	assert(handle != NULL);
+
+	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 = buffer_size;
+	transfer->phone = phone;
+
+	int rc;
+
+	transfer->request = async_send_4(phone,
+	    DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_CONTROL_READ,
+	    target.address, target.endpoint,
+	    buffer_size,
+	    &transfer->reply);
+
+	rc = async_data_write_start(phone, setup_packet, setup_packet_size);
+	if (rc != EOK) {
+		async_wait_for(transfer->request, NULL);
+		return rc;
+	}
+
+	*handle = (usb_handle_t) transfer;
+
+	return EOK;
+}
+
 /**
  * @}
