Index: uspace/lib/drv/generic/remote_usbhc.c
===================================================================
--- uspace/lib/drv/generic/remote_usbhc.c	(revision 621afdb4b44504ffb996f05acf3aad6ffeceb1ff)
+++ uspace/lib/drv/generic/remote_usbhc.c	(revision 9e4f6a7e1c10baea8ba3e894f009649772e90555)
@@ -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,7 +100,39 @@
 	ipc_callid_t caller;
 	void *buffer;
+	void *setup_packet;
 	size_t size;
 } async_transaction_t;
 
+static void async_transaction_destroy(async_transaction_t *trans)
+{
+	if (trans == NULL) {
+		return;
+	}
+
+	if (trans->setup_packet != NULL) {
+		free(trans->setup_packet);
+	}
+	if (trans->buffer != NULL) {
+		free(trans->buffer);
+	}
+
+	free(trans);
+}
+
+static async_transaction_t *async_transaction_create(ipc_callid_t caller)
+{
+	async_transaction_t *trans = malloc(sizeof(async_transaction_t));
+	if (trans == NULL) {
+		return NULL;
+	}
+
+	trans->caller = caller;
+	trans->buffer = NULL;
+	trans->setup_packet = NULL;
+	trans->size = 0;
+
+	return trans;
+}
+
 void remote_usbhc_get_address(device_t *device, void *iface,
     ipc_callid_t callid, ipc_call_t *call)
@@ -130,5 +167,5 @@
 	if (trans->buffer == NULL) {
 		ipc_answer_0(callid, EINVAL);
-		free(trans);
+		async_transaction_destroy(trans);
 		return;
 	}
@@ -138,4 +175,5 @@
 	if (!async_data_read_receive(&cid, &accepted_size)) {
 		ipc_answer_0(callid, EINVAL);
+		async_transaction_destroy(trans);
 		return;
 	}
@@ -148,6 +186,5 @@
 	ipc_answer_1(callid, EOK, accepted_size);
 
-	free(trans->buffer);
-	free(trans);
+	async_transaction_destroy(trans);
 }
 
@@ -242,8 +279,7 @@
 	async_transaction_t *trans = (async_transaction_t *)arg;
 
-	// FIXME - answer according to outcome
 	ipc_answer_0(trans->caller, outcome);
 
-	free(trans);
+	async_transaction_destroy(trans);
 }
 
@@ -253,8 +289,12 @@
 	async_transaction_t *trans = (async_transaction_t *)arg;
 
-	// FIXME - answer according to outcome
-	ipc_answer_1(trans->caller, outcome, (sysarg_t)trans);
+	if (outcome != USB_OUTCOME_OK) {
+		ipc_answer_0(trans->caller, outcome);
+		async_transaction_destroy(trans);
+		return;
+	}
 
 	trans->size = actual_size;
+	ipc_answer_1(trans->caller, USB_OUTCOME_OK, (sysarg_t)trans);
 }
 
@@ -294,18 +334,22 @@
 	}
 
-	async_transaction_t *trans = malloc(sizeof(async_transaction_t));
-	trans->caller = callid;
-	trans->buffer = buffer;
-	trans->size = len;
-
-	int rc = transfer_func(device, target, buffer, len,
-	    callback_out, trans);
-
-	if (rc != EOK) {
-		ipc_answer_0(callid, rc);
+	async_transaction_t *trans = async_transaction_create(callid);
+	if (trans == NULL) {
 		if (buffer != NULL) {
 			free(buffer);
 		}
-		free(trans);
+		ipc_answer_0(callid, ENOMEM);
+		return;
+	}
+
+	trans->buffer = buffer;
+	trans->size = len;
+
+	int rc = transfer_func(device, target, buffer, len,
+	    callback_out, trans);
+
+	if (rc != EOK) {
+		ipc_answer_0(callid, rc);
+		async_transaction_destroy(trans);
 	}
 }
@@ -333,6 +377,9 @@
 	};
 
-	async_transaction_t *trans = malloc(sizeof(async_transaction_t));
-	trans->caller = callid;
+	async_transaction_t *trans = async_transaction_create(callid);
+	if (trans == NULL) {
+		ipc_answer_0(callid, ENOMEM);
+		return;
+	}
 	trans->buffer = malloc(len);
 	trans->size = len;
@@ -343,6 +390,5 @@
 	if (rc != EOK) {
 		ipc_answer_0(callid, rc);
-		free(trans->buffer);
-		free(trans);
+		async_transaction_destroy(trans);
 	}
 }
@@ -388,8 +434,9 @@
 	};
 
-	async_transaction_t *trans = malloc(sizeof(async_transaction_t));
-	trans->caller = callid;
-	trans->buffer = NULL;
-	trans->size = 0;
+	async_transaction_t *trans = async_transaction_create(callid);
+	if (trans == NULL) {
+		ipc_answer_0(callid, ENOMEM);
+		return;
+	}
 
 	int rc;
@@ -410,7 +457,6 @@
 	if (rc != EOK) {
 		ipc_answer_0(callid, rc);
-		free(trans);
-	}
-	return;
+		async_transaction_destroy(trans);
+	}
 }
 
@@ -496,4 +542,119 @@
 }
 
+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) {
+		ipc_answer_0(callid, rc);
+		free(setup_packet);
+		return;
+	}
+
+	async_transaction_t *trans = async_transaction_create(callid);
+	if (trans == NULL) {
+		ipc_answer_0(callid, ENOMEM);
+		free(setup_packet);
+		free(data_buffer);
+		return;
+	}
+	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);
+		async_transaction_destroy(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 = async_transaction_create(callid);
+	if (trans == NULL) {
+		ipc_answer_0(callid, ENOMEM);
+		free(setup_packet);
+		return;
+	}
+	trans->setup_packet = setup_packet;
+	trans->size = data_len;
+	trans->buffer = malloc(data_len);
+	if (trans->buffer == NULL) {
+		ipc_answer_0(callid, ENOMEM);
+		async_transaction_destroy(trans);
+		return;
+	}
+
+	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);
+		async_transaction_destroy(trans);
+	}
+}
+
 
 
Index: uspace/lib/drv/include/usbhc_iface.h
===================================================================
--- uspace/lib/drv/include/usbhc_iface.h	(revision 621afdb4b44504ffb996f05acf3aad6ffeceb1ff)
+++ uspace/lib/drv/include/usbhc_iface.h	(revision 9e4f6a7e1c10baea8ba3e894f009649772e90555)
@@ -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 621afdb4b44504ffb996f05acf3aad6ffeceb1ff)
+++ uspace/lib/usb/Makefile	(revision 9e4f6a7e1c10baea8ba3e894f009649772e90555)
@@ -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 621afdb4b44504ffb996f05acf3aad6ffeceb1ff)
+++ uspace/lib/usb/include/usb/classes/hid.h	(revision 9e4f6a7e1c10baea8ba3e894f009649772e90555)
@@ -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 621afdb4b44504ffb996f05acf3aad6ffeceb1ff)
+++ uspace/lib/usb/include/usb/debug.h	(revision 9e4f6a7e1c10baea8ba3e894f009649772e90555)
@@ -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 9e4f6a7e1c10baea8ba3e894f009649772e90555)
+++ uspace/lib/usb/include/usb/pipes.h	(revision 9e4f6a7e1c10baea8ba3e894f009649772e90555)
@@ -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 9e4f6a7e1c10baea8ba3e894f009649772e90555)
+++ uspace/lib/usb/include/usb/request.h	(revision 9e4f6a7e1c10baea8ba3e894f009649772e90555)
@@ -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 621afdb4b44504ffb996f05acf3aad6ffeceb1ff)
+++ uspace/lib/usb/include/usb/usb.h	(revision 9e4f6a7e1c10baea8ba3e894f009649772e90555)
@@ -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 621afdb4b44504ffb996f05acf3aad6ffeceb1ff)
+++ uspace/lib/usb/include/usb/usbdrv.h	(revision 9e4f6a7e1c10baea8ba3e894f009649772e90555)
@@ -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/debug.c
===================================================================
--- uspace/lib/usb/src/debug.c	(revision 621afdb4b44504ffb996f05acf3aad6ffeceb1ff)
+++ uspace/lib/usb/src/debug.c	(revision 9e4f6a7e1c10baea8ba3e894f009649772e90555)
@@ -67,4 +67,5 @@
 /** Serialization mutex for logging functions. */
 static FIBRIL_MUTEX_INITIALIZE(log_serializer);
+static FILE *log_stream = NULL;
 
 /** Find or create new tag with given name.
@@ -171,4 +172,12 @@
 	log_prefix = message_prefix;
 	log_level = level;
+	if (log_stream == NULL) {
+		char *fname;
+		int rc = asprintf(&fname, "/log/%s", message_prefix);
+		if (rc > 0) {
+			log_stream = fopen(fname, "w");
+			free(fname);
+		}
+	}
 }
 
@@ -197,8 +206,4 @@
 void usb_log_printf(usb_log_level_t level, const char *format, ...)
 {
-	if (level > log_level) {
-		return;
-	}
-
 	FILE *stream = NULL;
 	switch (level) {
@@ -216,7 +221,23 @@
 	va_start(args, format);
 
+	/*
+	 * Serialize access to log files.
+	 * Always print to log file, to screen print only when the enabled
+	 * log level is high enough.
+	 */
 	fibril_mutex_lock(&log_serializer);
-	fprintf(stream, "[%s]%s: ", log_prefix, log_level_name(level));
-	vfprintf(stream, format, args);
+
+	const char *level_name = log_level_name(level);
+
+	if (log_stream != NULL) {
+		fprintf(log_stream, "[%s]%s: ", log_prefix, level_name);
+		vfprintf(log_stream, format, args);
+	}
+
+	if (level <= log_level) {
+		fprintf(stream, "[%s]%s: ", log_prefix, level_name);
+		vfprintf(stream, format, args);
+	}
+
 	fibril_mutex_unlock(&log_serializer);
 
Index: uspace/lib/usb/src/pipes.c
===================================================================
--- uspace/lib/usb/src/pipes.c	(revision 9e4f6a7e1c10baea8ba3e894f009649772e90555)
+++ uspace/lib/usb/src/pipes.c	(revision 9e4f6a7e1c10baea8ba3e894f009649772e90555)
@@ -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 9e4f6a7e1c10baea8ba3e894f009649772e90555)
+++ uspace/lib/usb/src/request.c	(revision 9e4f6a7e1c10baea8ba3e894f009649772e90555)
@@ -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 621afdb4b44504ffb996f05acf3aad6ffeceb1ff)
+++ uspace/lib/usb/src/usbdrv.c	(revision 9e4f6a7e1c10baea8ba3e894f009649772e90555)
@@ -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;
+}
+
 /**
  * @}
