Index: uspace/app/usbinfo/info.c
===================================================================
--- uspace/app/usbinfo/info.c	(revision 9078de8f0a6be74cfa097a346f41d6518d2cccb1)
+++ uspace/app/usbinfo/info.c	(revision 48fe0c90a4fbb334db7fb4784868741b778b4f5b)
@@ -42,4 +42,5 @@
 #include <usb/classes/classes.h>
 #include <usb/classes/hid.h>
+#include <usb/classes/hub.h>
 #include "usbinfo.h"
 
@@ -119,7 +120,8 @@
     usb_standard_configuration_descriptor_t *descriptor)
 {
-	printf("%sConfiguration #%d (%zu interfaces)\n", prefix,
+	printf("%sConfiguration #%d (%zu interfaces, total %zuB)\n", prefix,
 	    (int) descriptor->configuration_number,
-	    (size_t) descriptor->interface_count);
+	    (size_t) descriptor->interface_count,
+	    (size_t) descriptor->total_length);
 }
 
@@ -156,6 +158,13 @@
 }
 
-
-static void dump_descriptor_tree_brief_callback(uint8_t *descriptor,
+static void dump_descriptor_tree_brief_hub(const char *prefix,
+    usb_hub_descriptor_header_t *descriptor)
+{
+	printf("%shub (%d ports)\n", prefix,
+	    (int) descriptor->port_count);
+}
+
+
+static void dump_descriptor_tree_callback(uint8_t *descriptor,
     size_t depth, void *arg)
 {
@@ -174,4 +183,9 @@
 		if (descr_size >= sizeof(descriptor_type)) { \
 			callback(indent, (descriptor_type *) descriptor); \
+			if (arg != NULL) { \
+				usb_dump_standard_descriptor(stdout, \
+				    get_indent(depth +2), "\n", \
+				    descriptor, descr_size); \
+			} \
 		} else { \
 			descr_type = -1; \
@@ -194,4 +208,11 @@
 		    usb_standard_hid_descriptor_t,
 		    dump_descriptor_tree_brief_hid);
+		/*
+		 * Probably useless, hub descriptor shall not be part of
+		 * configuration descriptor.
+		 */
+		_BRANCH(USB_DESCTYPE_HUB,
+		    usb_hub_descriptor_header_t,
+		    dump_descriptor_tree_brief_hub);
 
 		default:
@@ -206,12 +227,24 @@
 void dump_descriptor_tree_brief(usbinfo_device_t *dev)
 {
-	dump_descriptor_tree_brief_callback((uint8_t *)&dev->device_descriptor,
+	dump_descriptor_tree_callback((uint8_t *)&dev->device_descriptor,
 	    (size_t) -1, NULL);
 	usb_dp_walk_simple(dev->full_configuration_descriptor,
 	    dev->full_configuration_descriptor_size,
 	    usb_dp_standard_descriptor_nesting,
-	    dump_descriptor_tree_brief_callback,
+	    dump_descriptor_tree_callback,
 	    NULL);
 }
+
+void dump_descriptor_tree_full(usbinfo_device_t *dev)
+{
+	dump_descriptor_tree_callback((uint8_t *)&dev->device_descriptor,
+	    (size_t) -1, dev);
+	usb_dp_walk_simple(dev->full_configuration_descriptor,
+	    dev->full_configuration_descriptor_size,
+	    usb_dp_standard_descriptor_nesting,
+	    dump_descriptor_tree_callback,
+	    dev);
+}
+
 
 void dump_strings(usbinfo_device_t *dev)
Index: uspace/app/usbinfo/main.c
===================================================================
--- uspace/app/usbinfo/main.c	(revision 9078de8f0a6be74cfa097a346f41d6518d2cccb1)
+++ uspace/app/usbinfo/main.c	(revision 48fe0c90a4fbb334db7fb4784868741b778b4f5b)
@@ -134,4 +134,5 @@
 	_OPTION("-m --match-ids", "Print match ids generated for the device.");
 	_OPTION("-t --descriptor-tree", "Print descriptor tree.");
+	_OPTION("-T --descriptor-tree-full", "Print detailed descriptor tree");
 	_OPTION("-s --strings", "Try to print all string descriptors.");
 
@@ -149,8 +150,9 @@
 	{"match-ids", no_argument, NULL, 'm'},
 	{"descriptor-tree", no_argument, NULL, 't'},
+	{"descriptor-tree-full", no_argument, NULL, 'T'},
 	{"strings", no_argument, NULL, 's'},
 	{0, 0, NULL, 0}
 };
-static const char *short_options = "himts";
+static const char *short_options = "himtTs";
 
 static usbinfo_action_t actions[] = {
@@ -168,4 +170,9 @@
 		.opt = 't',
 		.action = dump_descriptor_tree_brief,
+		.active = false
+	},
+	{
+		.opt = 'T',
+		.action = dump_descriptor_tree_full,
 		.active = false
 	},
Index: uspace/app/usbinfo/usbinfo.h
===================================================================
--- uspace/app/usbinfo/usbinfo.h	(revision 9078de8f0a6be74cfa097a346f41d6518d2cccb1)
+++ uspace/app/usbinfo/usbinfo.h	(revision 48fe0c90a4fbb334db7fb4784868741b778b4f5b)
@@ -82,4 +82,5 @@
 void dump_device_match_ids(usbinfo_device_t *);
 void dump_descriptor_tree_brief(usbinfo_device_t *);
+void dump_descriptor_tree_full(usbinfo_device_t *);
 void dump_strings(usbinfo_device_t *);
 
Index: uspace/lib/usb/include/usb/classes/hub.h
===================================================================
--- uspace/lib/usb/include/usb/classes/hub.h	(revision 9078de8f0a6be74cfa097a346f41d6518d2cccb1)
+++ uspace/lib/usb/include/usb/classes/hub.h	(revision 48fe0c90a4fbb334db7fb4784868741b778b4f5b)
@@ -60,4 +60,19 @@
 } usb_hub_class_feature_t;
 
+/** Header of standard hub descriptor without the "variadic" part. */
+typedef struct {
+	/** Descriptor length. */
+	uint8_t length;
+	/** Descriptor type (0x29). */
+	uint8_t descriptor_type;
+	/** Number of downstream ports. */
+	uint8_t port_count;
+	/** Characteristics bitmask. */
+	uint16_t characteristics;
+	/** Time from power-on to stabilization of current on the port. */
+	uint8_t power_good_time;
+	/** Maximum current requirements in mA. */
+	uint8_t max_current;
+} __attribute__ ((packed)) usb_hub_descriptor_header_t;
 
 /**
Index: uspace/lib/usb/include/usb/request.h
===================================================================
--- uspace/lib/usb/include/usb/request.h	(revision 9078de8f0a6be74cfa097a346f41d6518d2cccb1)
+++ uspace/lib/usb/include/usb/request.h	(revision 48fe0c90a4fbb334db7fb4784868741b778b4f5b)
@@ -94,4 +94,10 @@
     uint16_t, uint16_t, void *, size_t, size_t *);
 
+int usb_request_get_status(usb_endpoint_pipe_t *, usb_request_recipient_t,
+    uint16_t, uint16_t *);
+int usb_request_clear_feature(usb_endpoint_pipe_t *, usb_request_type_t,
+    usb_request_recipient_t, uint16_t, uint16_t);
+int usb_request_set_feature(usb_endpoint_pipe_t *, usb_request_type_t,
+    usb_request_recipient_t, uint16_t, uint16_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,
@@ -108,5 +114,10 @@
 int usb_request_get_full_configuration_descriptor_alloc(usb_endpoint_pipe_t *,
     int, void **, size_t *);
+int usb_request_set_descriptor(usb_endpoint_pipe_t *, usb_request_type_t,
+    usb_request_recipient_t, uint8_t, uint8_t, uint16_t, void *, size_t);
+int usb_request_get_configuration(usb_endpoint_pipe_t *, uint8_t *);
 int usb_request_set_configuration(usb_endpoint_pipe_t *, uint8_t);
+int usb_request_get_interface(usb_endpoint_pipe_t *, uint8_t, uint8_t *);
+int usb_request_set_interface(usb_endpoint_pipe_t *, uint8_t, uint8_t);
 
 int usb_request_get_supported_languages(usb_endpoint_pipe_t *,
Index: uspace/lib/usb/src/request.c
===================================================================
--- uspace/lib/usb/src/request.c	(revision 9078de8f0a6be74cfa097a346f41d6518d2cccb1)
+++ uspace/lib/usb/src/request.c	(revision 48fe0c90a4fbb334db7fb4784868741b778b4f5b)
@@ -157,4 +157,97 @@
 }
 
+/** Retrieve status of a USB device.
+ *
+ * @param[in] pipe Control endpoint pipe (session must be already started).
+ * @param[in] index Recipient index (in native endianness).
+ * @param[in] recipient Recipient of the GET_STATUS request.
+ * @param[out] status Recipient status (in native endianness).
+ * @return Error code.
+ */
+int usb_request_get_status(usb_endpoint_pipe_t *pipe,
+    usb_request_recipient_t recipient, uint16_t index,
+    uint16_t *status)
+{
+	if ((recipient == USB_REQUEST_RECIPIENT_DEVICE) && (index != 0)) {
+		return EINVAL;
+	}
+
+	if (status == NULL) {
+		return EBADMEM;
+	}
+
+	uint16_t status_usb_endianess;
+	size_t data_transfered_size;
+	int rc = usb_control_request_get(pipe, USB_REQUEST_TYPE_STANDARD,
+	    recipient, USB_DEVREQ_GET_STATUS, 0, uint16_host2usb(index),
+	    &status_usb_endianess, 2, &data_transfered_size);
+	if (rc != EOK) {
+		return rc;
+	}
+	if (data_transfered_size != 2) {
+		return ELIMIT;
+	}
+
+	*status = uint16_usb2host(status_usb_endianess);
+
+	return EOK;
+}
+
+/** Clear or disable specific device feature.
+ *
+ * @param[in] pipe Control endpoint pipe (session must be already started).
+ * @param[in] request_type Request type (standard/class/vendor).
+ * @param[in] recipient Recipient of the CLEAR_FEATURE request.
+ * @param[in] feature_selector Feature selector (in native endianness).
+ * @param[in] index Recipient index (in native endianness).
+ * @return Error code.
+ */
+int usb_request_clear_feature(usb_endpoint_pipe_t *pipe,
+    usb_request_type_t request_type, usb_request_recipient_t recipient,
+    uint16_t feature_selector, uint16_t index)
+{
+	if (request_type == USB_REQUEST_TYPE_STANDARD) {
+		if ((recipient == USB_REQUEST_RECIPIENT_DEVICE)
+		    && (index != 0)) {
+			return EINVAL;
+		}
+	}
+
+	int rc = usb_control_request_set(pipe, request_type, recipient,
+	    USB_DEVREQ_CLEAR_FEATURE,
+	    uint16_host2usb(feature_selector), uint16_host2usb(index),
+	    NULL, 0);
+
+	return rc;
+}
+
+/** Set or enable specific device feature.
+ *
+ * @param[in] pipe Control endpoint pipe (session must be already started).
+ * @param[in] request_type Request type (standard/class/vendor).
+ * @param[in] recipient Recipient of the SET_FEATURE request.
+ * @param[in] feature_selector Feature selector (in native endianness).
+ * @param[in] index Recipient index (in native endianness).
+ * @return Error code.
+ */
+int usb_request_set_feature(usb_endpoint_pipe_t *pipe,
+    usb_request_type_t request_type, usb_request_recipient_t recipient,
+    uint16_t feature_selector, uint16_t index)
+{
+	if (request_type == USB_REQUEST_TYPE_STANDARD) {
+		if ((recipient == USB_REQUEST_RECIPIENT_DEVICE)
+		    && (index != 0)) {
+			return EINVAL;
+		}
+	}
+
+	int rc = usb_control_request_set(pipe, request_type, recipient,
+	    USB_DEVREQ_SET_FEATURE,
+	    uint16_host2usb(feature_selector), uint16_host2usb(index),
+	    NULL, 0);
+
+	return rc;
+}
+
 /** Change address of connected device.
  * This function automatically updates the backing connection to point to
@@ -473,4 +566,71 @@
 }
 
+/** Update existing or add new USB descriptor to 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] recipient Request recipient (device/interface/endpoint).
+ * @param[in] descriptor_type Descriptor type (device/configuration/HID/...).
+ * @param[in] descriptor_index Descriptor index.
+ * @param[in] language Language index (in native endianness).
+ * @param[in] buffer Buffer with the new descriptor (in USB endianness).
+ * @param[in] size Size of the @p buffer in bytes (in native endianness).
+ * @return Error code.
+ */
+int usb_request_set_descriptor(usb_endpoint_pipe_t *pipe,
+    usb_request_type_t request_type, usb_request_recipient_t recipient,
+    uint8_t descriptor_type, uint8_t descriptor_index,
+    uint16_t language,
+    void *buffer, size_t size)
+{
+	if (buffer == NULL) {
+		return EBADMEM;
+	}
+	if (size == 0) {
+		return EINVAL;
+	}
+
+	/* FIXME: proper endianness. */
+	uint16_t wValue = descriptor_index | (descriptor_type << 8);
+
+	return usb_control_request_set(pipe,
+	    request_type, recipient,
+	    USB_DEVREQ_SET_DESCRIPTOR,
+	    wValue, language,
+	    buffer, size);
+}
+
+/** Get current configuration value of USB device.
+ *
+ * @param[in] pipe Control endpoint pipe (session must be already started).
+ * @param[out] configuration_value Current configuration value.
+ * @return Error code.
+ */
+int usb_request_get_configuration(usb_endpoint_pipe_t *pipe,
+    uint8_t *configuration_value)
+{
+	uint8_t value;
+	size_t actual_size;
+
+	int rc = usb_control_request_get(pipe,
+	    USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE,
+	    USB_DEVREQ_GET_CONFIGURATION,
+	    0, 0,
+	    &value, 1, &actual_size);
+
+	if (rc != EOK) {
+		return rc;
+	}
+	if (actual_size != 1) {
+		return ELIMIT;
+	}
+
+	if (configuration_value != NULL) {
+		*configuration_value = value;
+	}
+
+	return EOK;
+}
+
 /** Set configuration of USB device.
  *
@@ -488,4 +648,55 @@
 	    USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE,
 	    USB_DEVREQ_SET_CONFIGURATION, config_value, 0,
+	    NULL, 0);
+}
+
+/** Get selected alternate setting for USB interface.
+ *
+ * @param[in] pipe Control endpoint pipe (session must be already started).
+ * @param[in] interface_index Interface index.
+ * @param[out] alternate_setting Alternate setting for the interface.
+ * @return Error code.
+ */
+int usb_request_get_interface(usb_endpoint_pipe_t *pipe,
+    uint8_t interface_index, uint8_t *alternate_setting)
+{
+	uint8_t value;
+	size_t actual_size;
+
+	int rc = usb_control_request_get(pipe,
+	    USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_INTERFACE,
+	    USB_DEVREQ_GET_INTERFACE,
+	    0, uint16_host2usb((uint16_t) interface_index),
+	    &value, 1, &actual_size);
+
+	if (rc != EOK) {
+		return rc;
+	}
+	if (actual_size != 1) {
+		return ELIMIT;
+	}
+
+	if (alternate_setting != NULL) {
+		*alternate_setting = value;
+	}
+
+	return EOK;
+}
+
+/** Select alternate setting for USB interface.
+ *
+ * @param[in] pipe Control endpoint pipe (session must be already started).
+ * @param[in] interface_index Interface index.
+ * @param[in] alternate_setting Alternate setting to select.
+ * @return Error code.
+ */
+int usb_request_set_interface(usb_endpoint_pipe_t *pipe,
+    uint8_t interface_index, uint8_t alternate_setting)
+{
+	return usb_control_request_set(pipe,
+	    USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_INTERFACE,
+	    USB_DEVREQ_SET_INTERFACE,
+	    uint16_host2usb((uint16_t) alternate_setting),
+	    uint16_host2usb((uint16_t) interface_index),
 	    NULL, 0);
 }
