Index: uspace/app/usbinfo/dump.c
===================================================================
--- uspace/app/usbinfo/dump.c	(revision 040068c0910154c4052a0e9373bba53ede538e39)
+++ uspace/app/usbinfo/dump.c	(revision cdc1aa18afaed6b849ea18a1d3d187821e9f05b1)
@@ -47,4 +47,5 @@
 
 #define INDENT "  "
+#define BYTES_PER_LINE 12
 
 #define BCD_INT(a) (((unsigned int)(a)) / 256)
@@ -53,4 +54,18 @@
 #define BCD_FMT "%x.%x"
 #define BCD_ARGS(a) BCD_INT((a)), BCD_FRAC((a))
+
+void dump_buffer(const char *msg, const uint8_t *buffer, size_t length)
+{
+	printf("%s\n", msg);
+
+	size_t i;
+	for (i = 0; i < length; i++) {
+		printf("  0x%02X", buffer[i]);
+		if (((i > 0) && (((i+1) % BYTES_PER_LINE) == 0))
+		    || (i + 1 == length)) {
+			printf("\n");
+		}
+	}
+}
 
 void dump_standard_device_descriptor(usb_standard_device_descriptor_t *d)
@@ -75,4 +90,27 @@
 }
 
+void dump_standard_configuration_descriptor(
+    int index, usb_standard_configuration_descriptor_t *d)
+{
+	bool self_powered = d->attributes & 64;
+	bool remote_wakeup = d->attributes & 32;
+	
+	printf("Standard configuration descriptor #%d\n", index);
+	printf(INDENT "bLength = %d\n", d->length);
+	printf(INDENT "bDescriptorType = 0x%02x\n", d->descriptor_type);
+	printf(INDENT "wTotalLength = %d\n", d->total_length);
+	printf(INDENT "bNumInterfaces = %d\n", d->interface_count);
+	printf(INDENT "bConfigurationValue = %d\n", d->configuration_number);
+	printf(INDENT "iConfiguration = %d\n", d->str_configuration);
+	printf(INDENT "bmAttributes = %d [%s%s%s]\n", d->attributes,
+	    self_powered ? "self-powered" : "",
+	    (self_powered & remote_wakeup) ? ", " : "",
+	    remote_wakeup ? "remote-wakeup" : "");
+	printf(INDENT "MaxPower = %d (%dmA)\n", d->max_power,
+	    2 * d->max_power);
+	// printf(INDENT " = %d\n", d->);
+}
+
+
 /** @}
  */
Index: uspace/app/usbinfo/main.c
===================================================================
--- uspace/app/usbinfo/main.c	(revision 040068c0910154c4052a0e9373bba53ede538e39)
+++ uspace/app/usbinfo/main.c	(revision cdc1aa18afaed6b849ea18a1d3d187821e9f05b1)
@@ -44,9 +44,14 @@
 #include "usbinfo.h"
 
+#define DEFAULT_HOST_CONTROLLER_PATH "/virt/usbhc"
+
 static void print_usage(char *app_name)
 {
 	printf(NAME ": query USB devices for descriptors\n\n");
 	printf("Usage: %s /path/to/hc usb-address\n where\n", app_name);
-	printf("   /path/to/hc   Devman path to USB host controller\n");
+	printf("   /path/to/hc   Devman path to USB host controller " \
+	    "(use `-' for\n");
+	printf("                   default HC at `%s').\n",
+	    DEFAULT_HOST_CONTROLLER_PATH);
 	printf("   usb-address   USB address of device to be queried\n");
 	printf("\n");
@@ -68,5 +73,5 @@
 }
 
-int main(int argc, char * argv[])
+int main(int argc, char *argv[])
 {
 	if (argc != 3) {
@@ -81,4 +86,7 @@
 	 * Connect to given host controller driver.
 	 */
+	if (str_cmp(hc_path, "-") == 0) {
+		hc_path = (char *) DEFAULT_HOST_CONTROLLER_PATH;
+	}
 	int hc_phone = connect_to_hc(hc_path);
 	if (hc_phone < 0) {
@@ -107,5 +115,5 @@
 	 */
 	usb_standard_device_descriptor_t device_descriptor;
-	usb_dprintf("usbinfo", 1,
+	usb_dprintf(NAME, 1,
 	    "usb_drv_req_get_device_descriptor(%d, %d, %p)\n",
 	    hc_phone, (int) address, &device_descriptor);
@@ -121,4 +129,41 @@
 	dump_standard_device_descriptor(&device_descriptor);
 
+	/*
+	 * Get first configuration descriptor and dump it.
+	 */
+	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 );
+	if (rc != EOK) {
+		fprintf(stderr,
+		    NAME ": failed to fetch standard configuration descriptor: %s.\n",
+		    str_error(rc));
+		return rc;
+	}
+	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,
+	    config_index,
+	    full_config_descriptor, config_descriptor.total_length, NULL);
+	if (rc != EOK) {
+		fprintf(stderr,
+		    NAME ": failed to fetch full configuration descriptor: %s.\n",
+		    str_error(rc));
+		return rc;
+	}
+	dump_buffer("Full configuration descriptor:",
+	    full_config_descriptor, config_descriptor.total_length);
 
 	return EOK;
Index: uspace/app/usbinfo/usbinfo.h
===================================================================
--- uspace/app/usbinfo/usbinfo.h	(revision 040068c0910154c4052a0e9373bba53ede538e39)
+++ uspace/app/usbinfo/usbinfo.h	(revision cdc1aa18afaed6b849ea18a1d3d187821e9f05b1)
@@ -43,5 +43,8 @@
 #define NAME "usbinfo"
 
+void dump_buffer(const char *, const uint8_t *, size_t);
 void dump_standard_device_descriptor(usb_standard_device_descriptor_t *);
+void dump_standard_configuration_descriptor(int, 
+    usb_standard_configuration_descriptor_t *);
 
 #endif
Index: uspace/lib/usb/include/usb/devreq.h
===================================================================
--- uspace/lib/usb/include/usb/devreq.h	(revision 040068c0910154c4052a0e9373bba53ede538e39)
+++ uspace/lib/usb/include/usb/devreq.h	(revision cdc1aa18afaed6b849ea18a1d3d187821e9f05b1)
@@ -38,4 +38,6 @@
 #include <ipc/ipc.h>
 #include <async.h>
+#include <usb/usb.h>
+#include <usb/descriptor.h>
 
 /** Standard device request. */
@@ -83,4 +85,13 @@
 } __attribute__ ((packed)) usb_device_request_setup_packet_t;
 
+int usb_drv_req_set_address(int, usb_address_t, usb_address_t);
+int usb_drv_req_get_device_descriptor(int, usb_address_t,
+    usb_standard_device_descriptor_t *);
+int usb_drv_req_get_bare_configuration_descriptor(int, usb_address_t, int,
+    usb_standard_configuration_descriptor_t *);
+int usb_drv_req_get_full_configuration_descriptor(int, usb_address_t, int,
+    void *, size_t, size_t *);
+
+
 #endif
 /**
Index: uspace/lib/usb/include/usb/usbdrv.h
===================================================================
--- uspace/lib/usb/include/usb/usbdrv.h	(revision 040068c0910154c4052a0e9373bba53ede538e39)
+++ uspace/lib/usb/include/usb/usbdrv.h	(revision cdc1aa18afaed6b849ea18a1d3d187821e9f05b1)
@@ -72,4 +72,7 @@
 int usb_drv_psync_control_write_status(int, usb_target_t);
 
+int usb_drv_psync_control_write(int, usb_target_t,
+    void *, size_t, void *, size_t);
+
 
 int usb_drv_async_control_read_setup(int, usb_target_t,
@@ -84,11 +87,11 @@
 int usb_drv_psync_control_read_status(int, usb_target_t);
 
+int usb_drv_psync_control_read(int, usb_target_t,
+    void *, size_t, void *, size_t, size_t *);
+
+
 
 int usb_drv_async_wait_for(usb_handle_t);
 
-
-int usb_drv_req_set_address(int, usb_address_t, usb_address_t);
-int usb_drv_req_get_device_descriptor(int, usb_address_t,
-    usb_standard_device_descriptor_t *);
 
 #endif
Index: uspace/lib/usb/src/drvpsync.c
===================================================================
--- uspace/lib/usb/src/drvpsync.c	(revision 040068c0910154c4052a0e9373bba53ede538e39)
+++ uspace/lib/usb/src/drvpsync.c	(revision cdc1aa18afaed6b849ea18a1d3d187821e9f05b1)
@@ -100,4 +100,42 @@
 
 
+/** Perform complete control write transaction over USB.
+ *
+ * The DATA stage is performed only when @p data is not NULL and
+ * @p data_size is greater than zero.
+ *
+ * @param phone Open phone to host controller.
+ * @param target Target device and endpoint.
+ * @param setup_packet Setup packet data.
+ * @param setup_packet_size Size of the setup packet.
+ * @param data Data to be sent.
+ * @param data_size Size of the @p data buffer.
+ * @return Error code.
+ */
+int usb_drv_psync_control_write(int phone, usb_target_t target,
+    void *setup_packet, size_t setup_packet_size,
+    void *data, size_t data_size)
+{
+	int rc;
+	
+	rc = usb_drv_psync_control_write_setup(phone, target,
+	    setup_packet, setup_packet_size);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	if ((data != NULL) && (data_size > 0)) {
+		rc = usb_drv_psync_control_write_data(phone, target,
+		    data, data_size);
+		if (rc != EOK) {
+			return rc;
+		}
+	}
+
+	rc = usb_drv_psync_control_write_status(phone, target);
+
+	return rc;
+}
+
 
 int usb_drv_psync_control_read_setup(int phone, usb_target_t target,
@@ -137,4 +175,43 @@
 }
 
+
+/** Perform complete control read transaction over USB.
+ *
+ * @param phone Open phone to host controller.
+ * @param target Target device and endpoint.
+ * @param setup_packet Setup packet data.
+ * @param setup_packet_size Size of the setup packet.
+ * @param data Storage for read data.
+ * @param data_size Size of the @p data buffer.
+ * @param actual_data_size Storage for number of actually transferred data from
+ *        device.
+ * @return Error code.
+ */
+int usb_drv_psync_control_read(int phone, usb_target_t target,
+    void *setup_packet, size_t setup_packet_size,
+    void *data, size_t data_size, size_t *actual_data_size)
+{
+	int rc;
+	
+	rc = usb_drv_psync_control_read_setup(phone, target,
+	    setup_packet, setup_packet_size);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	rc = usb_drv_psync_control_read_data(phone, target,
+	    data, data_size, actual_data_size);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	rc = usb_drv_psync_control_read_status(phone, target);
+
+	return rc;
+}
+
+
+
+
 /**
  * @}
Index: uspace/lib/usb/src/usbdrvreq.c
===================================================================
--- uspace/lib/usb/src/usbdrvreq.c	(revision 040068c0910154c4052a0e9373bba53ede538e39)
+++ uspace/lib/usb/src/usbdrvreq.c	(revision cdc1aa18afaed6b849ea18a1d3d187821e9f05b1)
@@ -67,29 +67,8 @@
 	setup_packet.value = new_address;
 
-	usb_handle_t handle;
-	int rc;
-
-	/* Start the control write transfer. */
-	rc = usb_drv_async_control_write_setup(phone, target,
-	    &setup_packet, sizeof(setup_packet), &handle);
-	if (rc != EOK) {
-		return rc;
-	}
-	rc = usb_drv_async_wait_for(handle);
-	if (rc != EOK) {
-		return rc;
-	}
-
-	/* Finish the control write transfer. */
-	rc = usb_drv_async_control_write_status(phone, target, &handle);
-	if (rc != EOK) {
-		return rc;
-	}
-	rc = usb_drv_async_wait_for(handle);
-	if (rc != EOK) {
-		return rc;
-	}
-
-	return EOK;
+	int rc = usb_drv_psync_control_write(phone, target,
+	    &setup_packet, sizeof(setup_packet), NULL, 0);
+
+	return rc;
 }
 
@@ -125,55 +104,137 @@
 	setup_packet.value_low = 0;
 
-	usb_handle_t handle;
-	int rc;
-
-	/* Start the control read transfer. */
-	rc = usb_drv_async_control_read_setup(phone, target,
-	    &setup_packet, sizeof(usb_device_request_setup_packet_t), &handle);
+	/* Prepare local descriptor. */
+	size_t actually_transferred = 0;
+	usb_standard_device_descriptor_t descriptor_tmp;
+
+	/* Perform the control read transaction. */
+	int rc = usb_drv_psync_control_read(phone, target,
+	    &setup_packet, sizeof(setup_packet),
+	    &descriptor_tmp, sizeof(descriptor_tmp), &actually_transferred);
+
 	if (rc != EOK) {
 		return rc;
 	}
-	rc = usb_drv_async_wait_for(handle);
+
+	/* 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 connected USB device.
+ *
+ * The function does not retrieve additional data binded with configuration
+ * descriptor (such as its interface and endpoint descriptors) - use
+ * usb_drv_req_get_full_configuration_descriptor() instead.
+ *
+ * @param[in] phone Open phone to HC driver.
+ * @param[in] address Device USB address.
+ * @param[in] index Configuration descriptor index.
+ * @param[out] descriptor Storage for the configuration descriptor.
+ * @return Error code.
+ * @retval EBADMEM @p descriptor is NULL.
+ */
+int usb_drv_req_get_bare_configuration_descriptor(int phone,
+    usb_address_t address, int index,
+    usb_standard_configuration_descriptor_t *descriptor)
+{
+	if (descriptor == NULL) {
+		return EBADMEM;
+	}
+
+	/* Prepare the target. */
+	usb_target_t target = {
+		.address = address,
+		.endpoint = 0
+	};
+
+	/* Prepare the setup packet. */
+	usb_device_request_setup_packet_t setup_packet = {
+		.request_type = 128,
+		.request = USB_DEVREQ_GET_DESCRIPTOR,
+		.index = 0,
+		.length = sizeof(usb_standard_device_descriptor_t)
+	};
+	setup_packet.value_high = USB_DESCTYPE_CONFIGURATION;
+	setup_packet.value_low = index;
+
+	/* Prepare local descriptor. */
+	size_t actually_transferred = 0;
+	usb_standard_configuration_descriptor_t descriptor_tmp;
+
+	/* Perform the control read transaction. */
+	int rc = usb_drv_psync_control_read(phone, target,
+	    &setup_packet, sizeof(setup_packet),
+	    &descriptor_tmp, sizeof(descriptor_tmp), &actually_transferred);
+
 	if (rc != EOK) {
 		return rc;
 	}
 
-	/* Retrieve the descriptor. */
-	size_t actually_transferred = 0;
-	usb_standard_device_descriptor_t descriptor_tmp;
-	rc = usb_drv_async_control_read_data(phone, target,
-	    &descriptor_tmp, sizeof(usb_standard_device_descriptor_t),
-	    &actually_transferred, &handle);
-	if (rc != EOK) {
-		return rc;
-	}
-	rc = usb_drv_async_wait_for(handle);
-	if (rc != EOK) {
-		return rc;
-	}
-
-	/* Finish the control read transfer. */
-	rc = usb_drv_async_control_read_status(phone, target, &handle);
-	if (rc != EOK) {
-		return rc;
-	}
-	rc = usb_drv_async_wait_for(handle);
-	if (rc != EOK) {
-		return rc;
-	}
-
-	if (actually_transferred < sizeof(usb_standard_device_descriptor_t)) {
+	/* Verify that all data has been transferred. */
+	if (actually_transferred < sizeof(descriptor_tmp)) {
 		return ELIMIT;
 	}
 
-	/*
-	 * Everything is okay, copy the descriptor.
-	 */
+	/* Everything is okay, copy the descriptor. */
 	memcpy(descriptor, &descriptor_tmp,
-	    sizeof(usb_standard_device_descriptor_t));
+	    sizeof(descriptor_tmp));
 
 	return EOK;
 }
 
+/** Retrieve full configuration descriptor of connected USB device.
+ *
+ * @warning The @p buffer might be touched (i.e. its contents changed)
+ * even when error occurres.
+ *
+ * @param[in] phone Open phone to HC driver.
+ * @param[in] address Device USB address.
+ * @param[in] index Configuration descriptor index.
+ * @param[out] buffer Buffer for the whole configuration descriptor.
+ * @param[in] buffer_size Size of the prepared @p buffer.
+ * @param[out] actual_buffer_size Bytes actually transfered.
+ * @return Error code.
+ * @retval EBADMEM @p descriptor is NULL.
+ */
+int usb_drv_req_get_full_configuration_descriptor(int phone,
+    usb_address_t address, int index,
+    void *buffer, size_t buffer_size, size_t *actual_buffer_size)
+{
+	if (buffer == NULL) {
+		return EBADMEM;
+	}
+
+	/* Prepare the target. */
+	usb_target_t target = {
+		.address = address,
+		.endpoint = 0
+	};
+
+	/* Prepare the setup packet. */
+	usb_device_request_setup_packet_t setup_packet = {
+		.request_type = 128,
+		.request = USB_DEVREQ_GET_DESCRIPTOR,
+		.index = 0,
+		.length = sizeof(usb_standard_device_descriptor_t)
+	};
+	setup_packet.value_high = USB_DESCTYPE_CONFIGURATION;
+	setup_packet.value_low = index;
+
+	/* Perform the control read transaction. */
+	int rc = usb_drv_psync_control_read(phone, target,
+	    &setup_packet, sizeof(setup_packet),
+	    buffer, buffer_size, actual_buffer_size);
+
+	return rc;
+}
 
 
