Index: uspace/app/usbinfo/dump.c
===================================================================
--- uspace/app/usbinfo/dump.c	(revision 0b314096809e841d815b7cedeaf1988722db8c0e)
+++ uspace/app/usbinfo/dump.c	(revision 1537ba692c6a1d183fd2f4d2b059f99dc92fa4ae)
@@ -96,4 +96,5 @@
 void dump_usb_descriptor(uint8_t *descriptor, size_t size)
 {
+	printf("Device descriptor:\n");
 	usb_dump_standard_descriptor(stdout, get_indent(0), "\n",
 	    descriptor, size);
Index: uspace/app/usbinfo/info.c
===================================================================
--- uspace/app/usbinfo/info.c	(revision 0b314096809e841d815b7cedeaf1988722db8c0e)
+++ uspace/app/usbinfo/info.c	(revision 1537ba692c6a1d183fd2f4d2b059f99dc92fa4ae)
@@ -38,8 +38,23 @@
 #include <errno.h>
 #include <usb/usbdrv.h>
+#include <usb/pipes.h>
+#include <usb/request.h>
 #include "usbinfo.h"
 
-int dump_device(int hc_phone, usb_address_t address)
+int dump_device(devman_handle_t hc_handle, usb_address_t address)
 {
+	int rc;
+	usb_device_connection_t wire;
+	usb_endpoint_pipe_t ctrl_pipe;
+	ctrl_pipe.hc_phone = -1;
+
+	int hc_phone = devman_device_connect(hc_handle, 0);
+	if (hc_phone < 0) {
+		fprintf(stderr,
+		    NAME ": failed to connect to host controller (%zu): %s.\n",
+		        (size_t) hc_handle, str_error(hc_phone));
+		return hc_phone;
+	}
+
 	/*
 	 * Dump information about possible match ids.
@@ -47,12 +62,37 @@
 	match_id_list_t match_id_list;
 	init_match_ids(&match_id_list);
-	int rc = usb_drv_create_device_match_ids(hc_phone, &match_id_list, address);
+	rc = usb_drv_create_device_match_ids(hc_phone, &match_id_list, address);
 	if (rc != EOK) {
 		fprintf(stderr,
 		    NAME ": failed to fetch match ids of the device: %s.\n",
 		    str_error(rc));
-		return rc;
+		goto leave;
 	}
 	dump_match_ids(&match_id_list);
+
+	/*
+	 * Initialize pipes.
+	 */
+	rc = usb_device_connection_initialize(&wire, hc_handle, address);
+	if (rc != EOK) {
+		fprintf(stderr,
+		    NAME ": failed to create connection to the device: %s.\n",
+		    str_error(rc));
+		goto leave;
+	}
+	rc = usb_endpoint_pipe_initialize_default_control(&ctrl_pipe, &wire);
+	if (rc != EOK) {
+		fprintf(stderr,
+		    NAME ": failed to create default control pipe: %s.\n",
+		    str_error(rc));
+		goto leave;
+	}
+	rc = usb_endpoint_pipe_start_session(&ctrl_pipe);
+	if (rc != EOK) {
+		fprintf(stderr,
+		    NAME ": failed to start session on control pipe: %s.\n",
+		    str_error(rc));
+		goto leave;
+	}
 
 	/*
@@ -60,15 +100,10 @@
 	 */
 	usb_standard_device_descriptor_t device_descriptor;
-	usb_dprintf(NAME, 1,
-	    "usb_drv_req_get_device_descriptor(%d, %d, %p)\n",
-	    hc_phone, (int) address, &device_descriptor);
-
-	rc = usb_drv_req_get_device_descriptor(hc_phone, address,
-	    &device_descriptor);
+	rc = usb_request_get_device_descriptor(&ctrl_pipe, &device_descriptor);
 	if (rc != EOK) {
 		fprintf(stderr,
 		    NAME ": failed to fetch standard device descriptor: %s.\n",
 		    str_error(rc));
-		return rc;
+		goto leave;
 	}
 	dump_usb_descriptor((uint8_t *)&device_descriptor, sizeof(device_descriptor));
@@ -79,25 +114,16 @@
 	usb_standard_configuration_descriptor_t config_descriptor;
 	int config_index = 0;
-	usb_dprintf(NAME, 1,
-	    "usb_drv_req_get_bare_configuration_descriptor(%d, %d, %d, %p)\n",
-	    hc_phone, (int) address, config_index, &config_descriptor);
-
-	rc = usb_drv_req_get_bare_configuration_descriptor(hc_phone, address,
-	    config_index, &config_descriptor );
+	rc = usb_request_get_bare_configuration_descriptor(&ctrl_pipe,
+	    config_index, &config_descriptor);
 	if (rc != EOK) {
 		fprintf(stderr,
 		    NAME ": failed to fetch standard configuration descriptor: %s.\n",
 		    str_error(rc));
-		return rc;
+		goto leave;
 	}
 	//dump_standard_configuration_descriptor(config_index, &config_descriptor);
 
 	void *full_config_descriptor = malloc(config_descriptor.total_length);
-	usb_dprintf(NAME, 1,
-	    "usb_drv_req_get_full_configuration_descriptor(%d, %d, %d, %p, %zu)\n",
-	    hc_phone, (int) address, config_index,
-	    full_config_descriptor, config_descriptor.total_length);
-
-	rc = usb_drv_req_get_full_configuration_descriptor(hc_phone, address,
+	rc = usb_request_get_full_configuration_descriptor(&ctrl_pipe,
 	    config_index,
 	    full_config_descriptor, config_descriptor.total_length, NULL);
@@ -106,5 +132,5 @@
 		    NAME ": failed to fetch full configuration descriptor: %s.\n",
 		    str_error(rc));
-		return rc;
+		goto leave;
 	}
 
@@ -112,5 +138,11 @@
 	    config_descriptor.total_length);
 
-	return EOK;
+	rc = EOK;
+leave:
+	/* Ignoring errors here. */
+	ipc_hangup(hc_phone);
+	usb_endpoint_pipe_end_session(&ctrl_pipe);
+
+	return rc;
 }
 
Index: uspace/app/usbinfo/main.c
===================================================================
--- uspace/app/usbinfo/main.c	(revision 0b314096809e841d815b7cedeaf1988722db8c0e)
+++ uspace/app/usbinfo/main.c	(revision 1537ba692c6a1d183fd2f4d2b059f99dc92fa4ae)
@@ -77,72 +77,32 @@
 }
 
-static int set_new_host_controller(int *phone, const char *path)
+static int get_host_controller_handle(const char *path,
+    devman_handle_t *hc_handle)
 {
 	int rc;
-	int tmp_phone;
 
-	if (path[0] != '/') {
-		int hc_class_index = (int) strtol(path, NULL, 10);
-		char *dev_path;
-		rc = asprintf(&dev_path, "class/usbhc\\%d", hc_class_index);
-		if (rc < 0) {
-			internal_error(rc);
-			return rc;
-		}
-		devmap_handle_t handle;
-		rc = devmap_device_get_handle(dev_path, &handle, 0);
-		if (rc < 0) {
-			fprintf(stderr,
-			    NAME ": failed getting handle of `devman://%s'.\n",
-			    dev_path);
-			free(dev_path);
-			return rc;
-		}
-		tmp_phone = devmap_device_connect(handle, 0);
-		if (tmp_phone < 0) {
-			fprintf(stderr,
-			    NAME ": could not connect to `%s'.\n",
-			    dev_path);
-			free(dev_path);
-			return tmp_phone;
-		}
-		free(dev_path);
-	} else {
-		devman_handle_t handle;
-		rc = devman_device_get_handle(path, &handle, 0);
-		if (rc != EOK) {
-			fprintf(stderr,
-			    NAME ": failed getting handle of `devmap::/%s'.\n",
-			    path);
-			return rc;
-		}
-		tmp_phone = devman_device_connect(handle, 0);
-		if (tmp_phone < 0) {
-			fprintf(stderr,
-			    NAME ": could not connect to `%s'.\n",
-			    path);
-			return tmp_phone;
-		}
+	devman_handle_t handle;
+	rc = devman_device_get_handle(path, &handle, 0);
+	if (rc != EOK) {
+		fprintf(stderr,
+		    NAME ": failed getting handle of `devman::/%s'.\n",
+		    path);
+		return rc;
 	}
-
-	*phone = tmp_phone;
+	*hc_handle = handle;
 
 	return EOK;
 }
 
-static int connect_with_address(int hc_phone, const char *str_address)
+static int get_device_address(const char *str_address, usb_address_t *address)
 {
-	usb_address_t address = (usb_address_t) strtol(str_address, NULL, 0);
-	if ((address < 0) || (address >= USB11_ADDRESS_MAX)) {
+	usb_address_t addr = (usb_address_t) strtol(str_address, NULL, 0);
+	if ((addr < 0) || (addr >= USB11_ADDRESS_MAX)) {
 		fprintf(stderr, NAME ": USB address out of range.\n");
 		return ERANGE;
 	}
 
-	if (hc_phone < 0) {
-		fprintf(stderr, NAME ": no active host controller.\n");
-		return ENOENT;
-	}
-
-	return dump_device(hc_phone, address);
+	*address = addr;
+	return EOK;
 }
 
@@ -150,5 +110,6 @@
 int main(int argc, char *argv[])
 {
-	int hc_phone = -1;
+	devman_handle_t hc_handle = (devman_handle_t) -1;
+	usb_address_t device_address = (usb_address_t) -1;
 
 	if (argc <= 1) {
@@ -175,5 +136,6 @@
 			case 'a':
 			case ACTION_DEVICE_ADDRESS: {
-				int rc = connect_with_address(hc_phone, optarg);
+				int rc = get_device_address(optarg,
+				    &device_address);
 				if (rc != EOK) {
 					return rc;
@@ -184,6 +146,6 @@
 			case 't':
 			case ACTION_HOST_CONTROLLER: {
-				int rc = set_new_host_controller(&hc_phone,
-				    optarg);
+				int rc = get_host_controller_handle(optarg,
+				   &hc_handle);
 				if (rc != EOK) {
 					return rc;
@@ -202,4 +164,12 @@
 	} while (i != -1);
 
+	if ((hc_handle == (devman_handle_t) -1)
+	    || (device_address == (usb_address_t) -1)) {
+		fprintf(stderr, NAME ": no target specified.\n");
+		return EINVAL;
+	}
+
+	dump_device(hc_handle, device_address);
+
 	return 0;
 }
Index: uspace/app/usbinfo/usbinfo.h
===================================================================
--- uspace/app/usbinfo/usbinfo.h	(revision 0b314096809e841d815b7cedeaf1988722db8c0e)
+++ uspace/app/usbinfo/usbinfo.h	(revision 1537ba692c6a1d183fd2f4d2b059f99dc92fa4ae)
@@ -47,5 +47,5 @@
 void dump_match_ids(match_id_list_t *matches);
 void dump_usb_descriptor(uint8_t *, size_t);
-int dump_device(int, usb_address_t);
+int dump_device(devman_handle_t, usb_address_t);
 void dump_descriptor_tree(uint8_t *, size_t);
 
Index: uspace/drv/usbhid/descdump.h
===================================================================
--- uspace/drv/usbhid/descdump.h	(revision 0b314096809e841d815b7cedeaf1988722db8c0e)
+++ uspace/drv/usbhid/descdump.h	(revision 1537ba692c6a1d183fd2f4d2b059f99dc92fa4ae)
@@ -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 0b314096809e841d815b7cedeaf1988722db8c0e)
+++ uspace/drv/usbhid/descparser.h	(revision 1537ba692c6a1d183fd2f4d2b059f99dc92fa4ae)
@@ -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 1537ba692c6a1d183fd2f4d2b059f99dc92fa4ae)
+++ uspace/drv/usbhid/hid.h	(revision 1537ba692c6a1d183fd2f4d2b059f99dc92fa4ae)
@@ -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_hid_report_parser_t *parser;
+
+	usb_device_connection_t wire;
+	usb_endpoint_pipe_t ctrl_pipe;
+	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 0b314096809e841d815b7cedeaf1988722db8c0e)
+++ uspace/drv/usbhid/main.c	(revision 1537ba692c6a1d183fd2f4d2b059f99dc92fa4ae)
@@ -43,10 +43,12 @@
 #include <io/console.h>
 #include <errno.h>
+#include <str_error.h>
 #include <fibril.h>
 #include <usb/classes/hid.h>
 #include <usb/classes/hidparser.h>
-#include <usb/devreq.h>
+#include <usb/request.h>
 #include <usb/descriptor.h>
 #include <io/console.h>
+#include "hid.h"
 #include "descparser.h"
 #include "descdump.h"
@@ -278,7 +280,8 @@
 		
 		// get the descriptor from the device
-		int rc = usb_drv_req_get_descriptor(kbd_dev->device->parent_phone,
-		    kbd_dev->address, USB_REQUEST_TYPE_CLASS, USB_DESCTYPE_HID_REPORT, 
-		    0, i, kbd_dev->conf->interfaces[i].report_desc, length, 
+		int rc = usb_request_get_descriptor(&kbd_dev->ctrl_pipe,
+		    USB_REQUEST_TYPE_CLASS, USB_DESCTYPE_HID_REPORT,
+		    i, 0,
+		    kbd_dev->conf->interfaces[i].report_desc, length,
 		    &actual_size);
 
@@ -301,6 +304,7 @@
 	usb_standard_configuration_descriptor_t config_desc;
 	
-	int rc = usb_drv_req_get_bare_configuration_descriptor(
-	    kbd_dev->device->parent_phone, kbd_dev->address, 0, &config_desc);
+	int rc;
+	rc = usb_request_get_bare_configuration_descriptor(&kbd_dev->ctrl_pipe,
+	    0, &config_desc);
 	
 	if (rc != EOK) {
@@ -316,6 +320,6 @@
 	size_t transferred = 0;
 	// get full configuration descriptor
-	rc = usb_drv_req_get_full_configuration_descriptor(
-	    kbd_dev->device->parent_phone, kbd_dev->address, 0, descriptors,
+	rc = usb_request_get_full_configuration_descriptor(&kbd_dev->ctrl_pipe,
+	    0, descriptors,
 	    config_desc.total_length, &transferred);
 	
@@ -364,4 +368,6 @@
 static usb_hid_dev_kbd_t *usbkbd_init_device(device_t *dev)
 {
+	int rc;
+
 	usb_hid_dev_kbd_t *kbd_dev = (usb_hid_dev_kbd_t *)calloc(1, 
 	    sizeof(usb_hid_dev_kbd_t));
@@ -374,33 +380,36 @@
 	kbd_dev->device = dev;
 
-	// get phone to my HC and save it as my parent's phone
-	// TODO: maybe not a good idea if DDF will use parent_phone
-	int rc = kbd_dev->device->parent_phone = usb_drv_hc_connect_auto(dev, 0);
-	if (rc < 0) {
-		printf("Problem setting phone to HC.\n");
-		free(kbd_dev);
-		return NULL;
-	}
-
-	rc = kbd_dev->address = usb_drv_get_my_address(dev->parent_phone, dev);
-	if (rc < 0) {
-		printf("Problem getting address of the device.\n");
-		free(kbd_dev);
-		return NULL;
-	}
-
-	// doesn't matter now that we have no address
-//	if (kbd_dev->address < 0) {
-//		fprintf(stderr, NAME ": No device address!\n");
-//		free(kbd_dev);
-//		return NULL;
-//	}
-
-	// default endpoint
-	kbd_dev->poll_endpoint = GUESSED_POLL_ENDPOINT;
-	
+	/*
+	 * Initialize the backing connection to the host controller.
+	 */
+	rc = usb_device_connection_initialize_from_device(&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_default_control(&kbd_dev->ctrl_pipe,
+	    &kbd_dev->wire);
+	if (rc != EOK) {
+		printf("Failed to initialize default control pipe: %s.\n",
+		    str_error(rc));
+		goto error_leave;
+	}
+
+	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;
+	}
+
 	/*
 	 * will need all descriptors:
-	 * 1) choose one configuration from configuration descriptors 
+	 * 1) choose one configuration from configuration descriptors
 	 *    (set it to the device)
 	 * 2) set endpoints from endpoint descriptors
@@ -408,7 +417,13 @@
 
 	// TODO: get descriptors, parse descriptors and save endpoints
+	usb_endpoint_pipe_start_session(&kbd_dev->ctrl_pipe);
 	usbkbd_process_descriptors(kbd_dev);
+	usb_endpoint_pipe_end_session(&kbd_dev->ctrl_pipe);
 
 	return kbd_dev;
+
+error_leave:
+	free(kbd_dev);
+	return NULL;
 }
 
@@ -435,20 +450,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 +458,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 0b314096809e841d815b7cedeaf1988722db8c0e)
+++ uspace/drv/vhc/connhost.c	(revision 1537ba692c6a1d183fd2f4d2b059f99dc92fa4ae)
@@ -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 0b314096809e841d815b7cedeaf1988722db8c0e)
+++ uspace/lib/drv/generic/remote_usbhc.c	(revision 1537ba692c6a1d183fd2f4d2b059f99dc92fa4ae)
@@ -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 0b314096809e841d815b7cedeaf1988722db8c0e)
+++ uspace/lib/drv/include/usbhc_iface.h	(revision 1537ba692c6a1d183fd2f4d2b059f99dc92fa4ae)
@@ -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 0b314096809e841d815b7cedeaf1988722db8c0e)
+++ uspace/lib/usb/Makefile	(revision 1537ba692c6a1d183fd2f4d2b059f99dc92fa4ae)
@@ -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 0b314096809e841d815b7cedeaf1988722db8c0e)
+++ uspace/lib/usb/include/usb/classes/hid.h	(revision 1537ba692c6a1d183fd2f4d2b059f99dc92fa4ae)
@@ -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/debug.h
===================================================================
--- uspace/lib/usb/include/usb/debug.h	(revision 0b314096809e841d815b7cedeaf1988722db8c0e)
+++ uspace/lib/usb/include/usb/debug.h	(revision 1537ba692c6a1d183fd2f4d2b059f99dc92fa4ae)
@@ -47,10 +47,11 @@
 /** Logging level. */
 typedef enum {
-    USB_LOG_LEVEL_FATAL,
-    USB_LOG_LEVEL_ERROR,
-    USB_LOG_LEVEL_WARNING,
-    USB_LOG_LEVEL_INFO,
-    USB_LOG_LEVEL_DEBUG,
-    USB_LOG_LEVEL_DEBUG2
+	USB_LOG_LEVEL_FATAL,
+	USB_LOG_LEVEL_ERROR,
+	USB_LOG_LEVEL_WARNING,
+	USB_LOG_LEVEL_INFO,
+	USB_LOG_LEVEL_DEBUG,
+	USB_LOG_LEVEL_DEBUG2,
+	USB_LOG_LEVEL_MAX
 } usb_log_level_t;
 
Index: uspace/lib/usb/include/usb/pipes.h
===================================================================
--- uspace/lib/usb/include/usb/pipes.h	(revision 1537ba692c6a1d183fd2f4d2b059f99dc92fa4ae)
+++ uspace/lib/usb/include/usb/pipes.h	(revision 1537ba692c6a1d183fd2f4d2b059f99dc92fa4ae)
@@ -0,0 +1,122 @@
+/*
+ * 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_from_device(usb_device_connection_t *,
+    device_t *);
+int usb_device_connection_initialize(usb_device_connection_t *,
+    devman_handle_t, usb_address_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 1537ba692c6a1d183fd2f4d2b059f99dc92fa4ae)
+++ uspace/lib/usb/include/usb/request.h	(revision 1537ba692c6a1d183fd2f4d2b059f99dc92fa4ae)
@@ -0,0 +1,65 @@
+/*
+ * 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>
+#include <usb/descriptor.h>
+
+int usb_control_request_set(usb_endpoint_pipe_t *,
+    usb_request_type_t, usb_request_recipient_t, uint8_t,
+    uint16_t, uint16_t, void *, size_t);
+
+int usb_control_request_get(usb_endpoint_pipe_t *,
+    usb_request_type_t, usb_request_recipient_t, uint8_t,
+    uint16_t, uint16_t, void *, size_t, size_t *);
+
+int usb_request_set_address(usb_endpoint_pipe_t *, usb_address_t);
+int usb_request_get_descriptor(usb_endpoint_pipe_t *, usb_request_type_t,
+    uint8_t, uint8_t, uint16_t, void *, size_t, size_t *);
+int usb_request_get_device_descriptor(usb_endpoint_pipe_t *,
+    usb_standard_device_descriptor_t *);
+int usb_request_get_bare_configuration_descriptor(usb_endpoint_pipe_t *, int,
+    usb_standard_configuration_descriptor_t *);
+int usb_request_get_full_configuration_descriptor(usb_endpoint_pipe_t *, int,
+    void *, size_t, size_t *);
+int usb_request_set_configuration(usb_endpoint_pipe_t *, uint8_t);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/include/usb/usb.h
===================================================================
--- uspace/lib/usb/include/usb/usb.h	(revision 0b314096809e841d815b7cedeaf1988722db8c0e)
+++ uspace/lib/usb/include/usb/usb.h	(revision 1537ba692c6a1d183fd2f4d2b059f99dc92fa4ae)
@@ -37,5 +37,19 @@
 
 #include <sys/types.h>
+#include <byteorder.h>
 #include <ipc/ipc.h>
+
+/** Convert 16bit value from native (host) endianness to USB endianness. */
+#define uint16_host2usb(n) host2uint16_t_le((n))
+
+/** Convert 32bit value from native (host) endianness to USB endianness. */
+#define uint32_host2usb(n) host2uint32_t_le((n))
+
+/** Convert 16bit value from USB endianness into native (host) one. */
+#define uint16_usb2host(n) uint16_t_le2host((n))
+
+/** Convert 32bit value from USB endianness into native (host) one. */
+#define uint32_usb2host(n) uint32_t_le2host((n))
+
 
 /** USB transfer type. */
@@ -52,5 +66,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 0b314096809e841d815b7cedeaf1988722db8c0e)
+++ uspace/lib/usb/include/usb/usbdrv.h	(revision 1537ba692c6a1d183fd2f4d2b059f99dc92fa4ae)
@@ -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 1537ba692c6a1d183fd2f4d2b059f99dc92fa4ae)
+++ uspace/lib/usb/src/pipes.c	(revision 1537ba692c6a1d183fd2f4d2b059f99dc92fa4ae)
@@ -0,0 +1,526 @@
+/*
+ * 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_from_device(
+    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) {
+		rc = my_address;
+		goto leave;
+	}
+
+	rc = usb_device_connection_initialize(connection,
+	    hc_handle, my_address);
+
+leave:
+	ipc_hangup(hc_phone);
+	return rc;
+}
+
+/** Initialize connection to USB device.
+ *
+ * @param connection Connection structure to be initialized.
+ * @param host_controller_handle Devman handle of host controller device is
+ * 	connected to.
+ * @param device_address Device USB address.
+ * @return Error code.
+ */
+int usb_device_connection_initialize(usb_device_connection_t *connection,
+    devman_handle_t host_controller_handle, usb_address_t device_address)
+{
+	assert(connection);
+
+	if ((device_address < 0) || (device_address >= USB11_ADDRESS_MAX)) {
+		return EINVAL;
+	}
+
+	connection->hc_handle = host_controller_handle;
+	connection->address = device_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 1537ba692c6a1d183fd2f4d2b059f99dc92fa4ae)
+++ uspace/lib/usb/src/request.c	(revision 1537ba692c6a1d183fd2f4d2b059f99dc92fa4ae)
@@ -0,0 +1,359 @@
+/*
+ * 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>
+
+#define MAX_DATA_LENGTH ((size_t)(0xFFFF))
+
+/** Generic wrapper for SET requests using standard control request format.
+ *
+ * @see usb_endpoint_pipe_control_write
+ *
+ * @param pipe Pipe used for the communication.
+ * @param request_type Request type (standard/class/vendor).
+ * @param recipient Request recipient (e.g. device or endpoint).
+ * @param request Actual request (e.g. GET_DESCRIPTOR).
+ * @param value Value of @c wValue field of setup packet
+ * 	(must be in USB endianness).
+ * @param index Value of @c wIndex field of setup packet
+ * 	(must be in USB endianness).
+ * @param data Data to be sent during DATA stage
+ * 	(expected to be in USB endianness).
+ * @param data_size Size of the @p data buffer (in native endianness).
+ * @return Error code.
+ * @retval EBADMEM @p pipe is NULL.
+ * @retval EBADMEM @p data is NULL and @p data_size is not zero.
+ * @retval ERANGE Data buffer too large.
+ */
+int usb_control_request_set(usb_endpoint_pipe_t *pipe,
+    usb_request_type_t request_type, usb_request_recipient_t recipient,
+    uint8_t request,
+    uint16_t value, uint16_t index,
+    void *data, size_t data_size)
+{
+	if (pipe == NULL) {
+		return EBADMEM;
+	}
+
+	if (data_size > MAX_DATA_LENGTH) {
+		return ERANGE;
+	}
+
+	if ((data_size > 0) && (data == NULL)) {
+		return EBADMEM;
+	}
+
+	/*
+	 * TODO: check that @p request_type and @p recipient are
+	 * within ranges.
+	 */
+
+	usb_device_request_setup_packet_t setup_packet;
+	setup_packet.request_type = (request_type << 5) | recipient;
+	setup_packet.request = request;
+	setup_packet.value = value;
+	setup_packet.index = index;
+	setup_packet.length = (uint16_t) data_size;
+
+	int rc = usb_endpoint_pipe_control_write(pipe,
+	    &setup_packet, sizeof(setup_packet),
+	    data, data_size);
+
+	return rc;
+}
+
+ /** Generic wrapper for GET requests using standard control request format.
+  *
+  * @see usb_endpoint_pipe_control_read
+  *
+  * @param pipe Pipe used for the communication.
+  * @param request_type Request type (standard/class/vendor).
+  * @param recipient Request recipient (e.g. device or endpoint).
+  * @param request Actual request (e.g. GET_DESCRIPTOR).
+  * @param value Value of @c wValue field of setup packet
+  * 	(must be in USB endianness).
+  * @param index Value of @c wIndex field of setup packet
+  *	(must be in USB endianness).
+  * @param data Buffer where to store data accepted during the DATA stage.
+  *	(they will come in USB endianess).
+  * @param data_size Size of the @p data buffer
+  * 	(in native endianness).
+  * @param actual_data_size Actual size of transfered data
+  * 	(in native endianness).
+  * @return Error code.
+  * @retval EBADMEM @p pipe is NULL.
+  * @retval EBADMEM @p data is NULL and @p data_size is not zero.
+  * @retval ERANGE Data buffer too large.
+  */
+int usb_control_request_get(usb_endpoint_pipe_t *pipe,
+    usb_request_type_t request_type, usb_request_recipient_t recipient,
+    uint8_t request,
+    uint16_t value, uint16_t index,
+    void *data, size_t data_size, size_t *actual_data_size)
+{
+	if (pipe == NULL) {
+		return EBADMEM;
+	}
+
+	if (data_size > MAX_DATA_LENGTH) {
+		return ERANGE;
+	}
+
+	if ((data_size > 0) && (data == NULL)) {
+		return EBADMEM;
+	}
+
+	/*
+	 * TODO: check that @p request_type and @p recipient are
+	 * within ranges.
+	 */
+
+	usb_device_request_setup_packet_t setup_packet;
+	setup_packet.request_type = 128 | (request_type << 5) | recipient;
+	setup_packet.request = request;
+	setup_packet.value = value;
+	setup_packet.index = index;
+	setup_packet.length = (uint16_t) data_size;
+
+	int rc = usb_endpoint_pipe_control_read(pipe,
+	    &setup_packet, sizeof(setup_packet),
+	    data, data_size, actual_data_size);
+
+	return rc;
+}
+
+/** Change address of connected device.
+ * This function automatically updates the backing connection to point to
+ * the new address.
+ *
+ * @see usb_drv_reserve_default_address
+ * @see usb_drv_release_default_address
+ * @see usb_drv_request_address
+ * @see usb_drv_release_address
+ * @see usb_drv_bind_address
+ *
+ * @param pipe Control endpoint pipe (session must be already started).
+ * @param new_address New USB address to be set (in native endianness).
+ * @return Error code.
+ */
+int usb_request_set_address(usb_endpoint_pipe_t *pipe,
+    usb_address_t new_address)
+{
+	if ((new_address < 0) || (new_address >= USB11_ADDRESS_MAX)) {
+		return EINVAL;
+	}
+
+	uint16_t addr = uint16_host2usb((uint16_t)new_address);
+
+	int rc = usb_control_request_set(pipe,
+	    USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE,
+	    USB_DEVREQ_SET_ADDRESS,
+	    addr, 0,
+	    NULL, 0);
+
+	if (rc != EOK) {
+		return rc;
+	}
+
+	assert(pipe->wire != NULL);
+	/* TODO: prevent other from accessing wire now. */
+	pipe->wire->address = new_address;
+
+	return EOK;
+}
+
+/** 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;
+	}
+
+	uint16_t wValue = descriptor_index | (descriptor_type << 8);
+
+	return usb_control_request_get(pipe,
+	    request_type, USB_REQUEST_RECIPIENT_DEVICE,
+	    USB_DEVREQ_GET_DESCRIPTOR,
+	    wValue, language,
+	    buffer, size, actual_size);
+}
+
+/** Retrieve standard device descriptor of a USB device.
+ *
+ * @param[in] pipe Control endpoint pipe (session must be already started).
+ * @param[out] descriptor Storage for the device descriptor.
+ * @return Error code.
+ */
+int usb_request_get_device_descriptor(usb_endpoint_pipe_t *pipe,
+    usb_standard_device_descriptor_t *descriptor)
+{
+	if (descriptor == NULL) {
+		return EBADMEM;
+	}
+
+	size_t actually_transferred = 0;
+	usb_standard_device_descriptor_t descriptor_tmp;
+	int rc = usb_request_get_descriptor(pipe,
+	    USB_REQUEST_TYPE_STANDARD, USB_DESCTYPE_DEVICE,
+	    0, 0,
+	    &descriptor_tmp, sizeof(descriptor_tmp),
+	    &actually_transferred);
+
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/* Verify that all data has been transferred. */
+	if (actually_transferred < sizeof(descriptor_tmp)) {
+		return ELIMIT;
+	}
+
+	/* Everything is okay, copy the descriptor. */
+	memcpy(descriptor, &descriptor_tmp,
+	    sizeof(descriptor_tmp));
+
+	return EOK;
+}
+
+/** Retrieve configuration descriptor of a USB device.
+ *
+ * The function does not retrieve additional data binded with configuration
+ * descriptor (such as its interface and endpoint descriptors) - use
+ * usb_request_get_full_configuration_descriptor() instead.
+ *
+ * @param[in] pipe Control endpoint pipe (session must be already started).
+ * @param[in] index Descriptor index.
+ * @param[out] descriptor Storage for the device descriptor.
+ * @return Error code.
+ */
+int usb_request_get_bare_configuration_descriptor(usb_endpoint_pipe_t *pipe,
+    int index, usb_standard_configuration_descriptor_t *descriptor)
+{
+	if (descriptor == NULL) {
+		return EBADMEM;
+	}
+
+	if ((index < 0) || (index > 0xFF)) {
+		return ERANGE;
+	}
+
+	size_t actually_transferred = 0;
+	usb_standard_configuration_descriptor_t descriptor_tmp;
+	int rc = usb_request_get_descriptor(pipe,
+	    USB_REQUEST_TYPE_STANDARD, USB_DESCTYPE_CONFIGURATION,
+	    index, 0,
+	    &descriptor_tmp, sizeof(descriptor_tmp),
+	    &actually_transferred);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/* Verify that all data has been transferred. */
+	if (actually_transferred < sizeof(descriptor_tmp)) {
+		return ELIMIT;
+	}
+
+	/* Everything is okay, copy the descriptor. */
+	memcpy(descriptor, &descriptor_tmp,
+	    sizeof(descriptor_tmp));
+
+	return EOK;
+}
+
+/** Retrieve full configuration descriptor of a USB device.
+ *
+ * @warning The @p buffer might be touched (i.e. its contents changed)
+ * even when error occurs.
+ *
+ * @param[in] pipe Control endpoint pipe (session must be already started).
+ * @param[in] index Descriptor index.
+ * @param[out] descriptor Storage for the device descriptor.
+ * @param[in] descriptor_size Size of @p descriptor buffer.
+ * @param[out] actual_size Number of bytes actually transferred.
+ * @return Error code.
+ */
+int usb_request_get_full_configuration_descriptor(usb_endpoint_pipe_t *pipe,
+    int index, void *descriptor, size_t descriptor_size, size_t *actual_size)
+{
+	if ((index < 0) || (index > 0xFF)) {
+		return ERANGE;
+	}
+
+	return usb_request_get_descriptor(pipe,
+	    USB_REQUEST_TYPE_STANDARD, USB_DESCTYPE_CONFIGURATION,
+	    index, 0,
+	    descriptor, descriptor_size, actual_size);
+}
+
+/** Set configuration of USB device.
+ *
+ * @param pipe Control endpoint pipe (session must be already started).
+ * @param configuration_value New configuration value.
+ * @return Error code.
+ */
+int usb_request_set_configuration(usb_endpoint_pipe_t *pipe,
+    uint8_t configuration_value)
+{
+	uint16_t config_value
+	    = uint16_host2usb((uint16_t) configuration_value);
+
+	return usb_control_request_set(pipe,
+	    USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE,
+	    USB_DEVREQ_SET_CONFIGURATION, config_value, 0,
+	    NULL, 0);
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/usbdrv.c
===================================================================
--- uspace/lib/usb/src/usbdrv.c	(revision 0b314096809e841d815b7cedeaf1988722db8c0e)
+++ uspace/lib/usb/src/usbdrv.c	(revision 1537ba692c6a1d183fd2f4d2b059f99dc92fa4ae)
@@ -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;
+}
+
 /**
  * @}
