Index: .bzrignore
===================================================================
--- .bzrignore	(revision 5857be2e40c022b415aeaa6c8bbe900f882d56be)
+++ .bzrignore	(revision baa9d5d9c02542344eba05d79f989e06f17a1879)
@@ -93,4 +93,5 @@
 ./uspace/drv/usbhub/usbhub
 ./uspace/drv/usbhid/usbhid
+./uspace/drv/usbkbd/usbkbd
 ./uspace/drv/usbmid/usbmid
 ./uspace/drv/usbmouse/usbmouse
Index: uspace/drv/usbmid/explore.c
===================================================================
--- uspace/drv/usbmid/explore.c	(revision 5857be2e40c022b415aeaa6c8bbe900f882d56be)
+++ uspace/drv/usbmid/explore.c	(revision baa9d5d9c02542344eba05d79f989e06f17a1879)
@@ -48,21 +48,33 @@
 };
 
-/** Find starting indexes of all interface descriptors in a configuration.
- *
- * @param config_descriptor Full configuration descriptor.
- * @param config_descriptor_size Size of @p config_descriptor in bytes.
- * @param interface_positions Array where to store indexes of interfaces.
- * @param interface_count Size of @p interface_positions array.
- * @return Number of found interfaces.
- * @retval (size_t)-1 Error occured.
- */
-static size_t find_interface_descriptors(uint8_t *config_descriptor,
-    size_t config_descriptor_size,
-    size_t *interface_positions, size_t interface_count)
+/** Tell whether given interface is already in the list.
+ *
+ * @param list List of usbmid_interface_t members to be searched.
+ * @param interface_no Interface number caller is looking for.
+ * @return Interface @p interface_no is already present in the list.
+ */
+static bool interface_in_list(link_t *list, int interface_no)
 {
-	if (interface_count == 0) {
-		return (size_t) -1;
-	}
-
+	link_t *l;
+	for (l = list->next; l != list; l = l->next) {
+		usbmid_interface_t *iface
+		    = list_get_instance(l, usbmid_interface_t, link);
+		if (iface->interface_no == interface_no) {
+			return true;
+		}
+	}
+
+	return false;
+}
+
+/** Create list of interfaces from configuration descriptor.
+ *
+ * @param config_descriptor Configuration descriptor.
+ * @param config_descriptor_size Size of configuration descriptor in bytes.
+ * @param list List where to add the interfaces.
+ */
+static void create_interfaces(uint8_t *config_descriptor,
+    size_t config_descriptor_size, link_t *list)
+{
 	usb_dp_parser_data_t data = {
 		.data = config_descriptor,
@@ -75,30 +87,43 @@
 	};
 
-	uint8_t *interface = usb_dp_get_nested_descriptor(&parser, &data,
+	uint8_t *interface_ptr = usb_dp_get_nested_descriptor(&parser, &data,
 	    data.data);
-	if (interface == NULL) {
-		return (size_t) -1;
-	}
-	if (interface[1] != USB_DESCTYPE_INTERFACE) {
-		return (size_t) -1;
-	}
-
-	size_t found_interfaces = 0;
-	interface_positions[found_interfaces] = interface - config_descriptor;
-	found_interfaces++;
-
-	while (interface != NULL) {
-		interface = usb_dp_get_sibling_descriptor(&parser, &data,
-		    data.data, interface);
-		if ((interface != NULL)
-		    && (found_interfaces < interface_count)
-		    && (interface[1] == USB_DESCTYPE_INTERFACE)) {
-			interface_positions[found_interfaces]
-			    = interface - config_descriptor;
-			found_interfaces++;
-		}
-	}
-
-	return found_interfaces;
+	if (interface_ptr == NULL) {
+		return;
+	}
+
+	do {
+		if (interface_ptr[1] != USB_DESCTYPE_INTERFACE) {
+			goto next_descriptor;
+		}
+
+		usb_standard_interface_descriptor_t *interface
+		    = (usb_standard_interface_descriptor_t *) interface_ptr;
+
+		/* Skip alternate interfaces. */
+		if (!interface_in_list(list, interface->interface_number)) {
+			usbmid_interface_t *iface
+			    = malloc(sizeof(usbmid_interface_t));
+			if (iface == NULL) {
+				break;
+			}
+			link_initialize(&iface->link);
+			iface->fun = NULL;
+			iface->interface_no = interface->interface_number;
+			iface->interface = interface;
+
+			list_append(&iface->link, list);
+		}
+
+		/* TODO: add the alternatives and create match ids from them
+		 * as well.
+		 */
+
+next_descriptor:
+		interface_ptr = usb_dp_get_sibling_descriptor(&parser, &data,
+		    data.data, interface_ptr);
+
+	} while (interface_ptr != NULL);
+
 }
 
@@ -130,23 +155,4 @@
 	    (usb_standard_configuration_descriptor_t *) config_descriptor_raw;
 
-	size_t *interface_descriptors
-	    = malloc(sizeof(size_t) * config_descriptor->interface_count);
-	if (interface_descriptors == NULL) {
-		usb_log_error("Out of memory (wanted %zuB).\n",
-		    sizeof(size_t) * config_descriptor->interface_count);
-		free(config_descriptor_raw);
-		return false;
-	}
-	size_t interface_descriptors_count
-	    = find_interface_descriptors(
-	    config_descriptor_raw, config_descriptor_size,
-	    interface_descriptors, config_descriptor->interface_count);
-
-	if (interface_descriptors_count == (size_t) -1) {
-		usb_log_error("Problem parsing configuration descriptor.\n");
-		free(interface_descriptors);
-		return false;
-	}
-
 	/* Select the first configuration */
 	rc = usb_request_set_configuration(&dev->ctrl_pipe,
@@ -155,8 +161,6 @@
 		usb_log_error("Failed to set device configuration: %s.\n",
 		    str_error(rc));
-		free(interface_descriptors);
-		return false;
-	}
-
+		return false;
+	}
 
 	/* Create control function */
@@ -164,5 +168,4 @@
 	if (ctl_fun == NULL) {
 		usb_log_error("Failed to create control function.\n");
-		free(interface_descriptors);
 		return false;
 	}
@@ -174,21 +177,25 @@
 		usb_log_error("Failed to bind control function: %s.\n",
 		    str_error(rc));
-		free(interface_descriptors);
-		return false;
-	}
-
-	/* Spawn interface children */
-	size_t i;
-	for (i = 0; i < interface_descriptors_count; i++) {
-		usb_standard_interface_descriptor_t *interface
-		    = (usb_standard_interface_descriptor_t *)
-		    (config_descriptor_raw + interface_descriptors[i]);
-		usb_log_debug2("Interface descriptor at index %zu (type %d).\n",
-		    interface_descriptors[i], (int) interface->descriptor_type);
+		return false;
+	}
+
+	/* Create interface children. */
+	link_t interface_list;
+	list_initialize(&interface_list);
+	create_interfaces(config_descriptor_raw, config_descriptor_size,
+	    &interface_list);
+
+	link_t *link;
+	for (link = interface_list.next; link != &interface_list;
+	    link = link->next) {
+		usbmid_interface_t *iface = list_get_instance(link,
+		    usbmid_interface_t, link);
+
 		usb_log_info("Creating child for interface %d (%s).\n",
-		    (int) interface->interface_number,
-		    usb_str_class(interface->interface_class));
-		rc = usbmid_spawn_interface_child(dev, &dev->descriptors.device,
-		    interface);
+		    (int) iface->interface_no,
+		    usb_str_class(iface->interface->interface_class));
+
+		rc = usbmid_spawn_interface_child(dev, iface,
+		    &dev->descriptors.device, iface->interface);
 		if (rc != EOK) {
 			usb_log_error("Failed to create interface child: %s.\n",
Index: uspace/drv/usbmid/usbmid.c
===================================================================
--- uspace/drv/usbmid/usbmid.c	(revision 5857be2e40c022b415aeaa6c8bbe900f882d56be)
+++ uspace/drv/usbmid/usbmid.c	(revision baa9d5d9c02542344eba05d79f989e06f17a1879)
@@ -79,30 +79,9 @@
 };
 
-/** Create new interface for USB MID device.
- *
- * @param fun Backing generic DDF device function (representing interface).
- * @param iface_no Interface number.
- * @return New interface.
- * @retval NULL Error occured.
- */
-usbmid_interface_t *usbmid_interface_create(ddf_fun_t *fun, int iface_no)
-{
-	usbmid_interface_t *iface = malloc(sizeof(usbmid_interface_t));
-	if (iface == NULL) {
-		usb_log_error("Out of memory (wanted %zuB).\n",
-		    sizeof(usbmid_interface_t));
-		return NULL;
-	}
-
-	iface->fun = fun;
-	iface->interface_no = iface_no;
-
-	return iface;
-}
-
 
 /** Spawn new child device from one interface.
  *
  * @param parent Parent MID device.
+ * @param iface Interface information.
  * @param device_descriptor Device descriptor.
  * @param interface_descriptor Interface descriptor.
@@ -110,4 +89,5 @@
  */
 int usbmid_spawn_interface_child(usb_device_t *parent,
+    usbmid_interface_t *iface,
     const usb_standard_device_descriptor_t *device_descriptor,
     const usb_standard_interface_descriptor_t *interface_descriptor)
@@ -115,5 +95,4 @@
 	ddf_fun_t *child = NULL;
 	char *child_name = NULL;
-	usbmid_interface_t *child_as_interface = NULL;
 	int rc;
 
@@ -137,14 +116,7 @@
 	}
 
+	iface->fun = child;
 
-
-	child_as_interface = usbmid_interface_create(child,
-	    (int) interface_descriptor->interface_number);
-	if (child_as_interface == NULL) {
-		rc = ENOMEM;
-		goto error_leave;
-	}
-
-	child->driver_data = child_as_interface;
+	child->driver_data = iface;
 	child->ops = &child_device_ops;
 
@@ -172,7 +144,4 @@
 		free(child_name);
 	}
-	if (child_as_interface != NULL) {
-		free(child_as_interface);
-	}
 
 	return rc;
Index: uspace/drv/usbmid/usbmid.h
===================================================================
--- uspace/drv/usbmid/usbmid.h	(revision 5857be2e40c022b415aeaa6c8bbe900f882d56be)
+++ uspace/drv/usbmid/usbmid.h	(revision baa9d5d9c02542344eba05d79f989e06f17a1879)
@@ -37,4 +37,5 @@
 #define USBMID_H_
 
+#include <adt/list.h>
 #include <ddf/driver.h>
 #include <usb/usb.h>
@@ -49,12 +50,14 @@
 	/** Function container. */
 	ddf_fun_t *fun;
-
+	/** Interface descriptor. */
+	usb_standard_interface_descriptor_t *interface;
 	/** Interface number. */
 	int interface_no;
+	/** List link. */
+	link_t link;
 } usbmid_interface_t;
 
-usbmid_interface_t *usbmid_interface_create(ddf_fun_t *, int);
 bool usbmid_explore_device(usb_device_t *);
-int usbmid_spawn_interface_child(usb_device_t *,
+int usbmid_spawn_interface_child(usb_device_t *, usbmid_interface_t *,
     const usb_standard_device_descriptor_t *,
     const usb_standard_interface_descriptor_t *);
Index: uspace/lib/usb/include/usb/devdrv.h
===================================================================
--- uspace/lib/usb/include/usb/devdrv.h	(revision 5857be2e40c022b415aeaa6c8bbe900f882d56be)
+++ uspace/lib/usb/include/usb/devdrv.h	(revision baa9d5d9c02542344eba05d79f989e06f17a1879)
@@ -47,4 +47,27 @@
 } usb_device_descriptors_t;
 
+/** Wrapper for data related to alternate interface setting.
+ * The pointers will typically point inside configuration descriptor and
+ * thus you shall not deallocate them.
+ */
+typedef struct {
+	/** Interface descriptor. */
+	usb_standard_interface_descriptor_t *interface;
+	/** Pointer to start of descriptor tree bound with this interface. */
+	uint8_t *nested_descriptors;
+	/** Size of data pointed by nested_descriptors in bytes. */
+	size_t nested_descriptors_size;
+} usb_alternate_interface_descriptors_t;
+
+/** Alternate interface settings. */
+typedef struct {
+	/** Array of alternate interfaces descriptions. */
+	usb_alternate_interface_descriptors_t *alternatives;
+	/** Size of @c alternatives array. */
+	size_t alternative_count;
+	/** Index of currently selected one. */
+	size_t current;
+} usb_alternate_interfaces_t;
+
 /** USB device structure. */
 typedef struct {
@@ -56,4 +79,6 @@
 	 */
 	usb_endpoint_mapping_t *pipes;
+	/** Number of other endpoint pipes. */
+	size_t pipes_count;
 	/** Current interface.
 	 * Usually, drivers operate on single interface only.
@@ -61,4 +86,10 @@
 	 */
 	int interface_no;
+
+	/** Alternative interfaces.
+	 * Set to NULL when the driver controls whole device
+	 * (i.e. more (or any) interfaces).
+	 */
+	usb_alternate_interfaces_t *alternate_interfaces;
 
 	/** Some useful descriptors. */
@@ -92,9 +123,32 @@
 	 */
 	const char *name;
-	/** Expected endpoints description, excluding default control endpoint.
+	/** Expected endpoints description.
+	 * This description shall exclude default control endpoint (pipe zero)
+	 * and must be NULL terminated.
+	 * When only control endpoint is expected, you may set NULL directly
+	 * without creating one item array containing NULL.
 	 *
-	 * It MUST be of size expected_enpoints_count(excluding default ctrl) + 1
-	 * where the last record MUST BE NULL, otherwise catastrophic things may
-	 * happen.
+	 * When the driver expect single interrupt in endpoint,
+	 * the initialization may look like this:
+\code
+static usb_endpoint_description_t poll_endpoint_description = {
+	.transfer_type = USB_TRANSFER_INTERRUPT,
+	.direction = USB_DIRECTION_IN,
+	.interface_class = USB_CLASS_HUB,
+	.interface_subclass = 0,
+	.interface_protocol = 0,
+	.flags = 0
+};
+
+static usb_endpoint_description_t *hub_endpoints[] = {
+	&poll_endpoint_description,
+	NULL
+};
+
+static usb_driver_t hub_driver = {
+	.endpoints = hub_endpoints,
+	...
+};
+\endcode
 	 */
 	usb_endpoint_description_t **endpoints;
@@ -105,8 +159,10 @@
 int usb_driver_main(usb_driver_t *);
 
+int usb_device_select_interface(usb_device_t *, uint8_t,
+    usb_endpoint_description_t **);
+
 typedef bool (*usb_polling_callback_t)(usb_device_t *,
     uint8_t *, size_t, void *);
 typedef void (*usb_polling_terminted_callback_t)(usb_device_t *, bool, void *);
-
 
 int usb_device_auto_poll(usb_device_t *, size_t,
Index: uspace/lib/usb/include/usb/pipes.h
===================================================================
--- uspace/lib/usb/include/usb/pipes.h	(revision 5857be2e40c022b415aeaa6c8bbe900f882d56be)
+++ uspace/lib/usb/include/usb/pipes.h	(revision baa9d5d9c02542344eba05d79f989e06f17a1879)
@@ -107,4 +107,6 @@
 	/** Interface number the endpoint must belong to (-1 for any). */
 	int interface_no;
+	/** Alternate interface setting to choose. */
+	int interface_setting;
 	/** Found descriptor fitting the description. */
 	usb_standard_endpoint_descriptor_t *descriptor;
Index: uspace/lib/usb/src/devdrv.c
===================================================================
--- uspace/lib/usb/src/devdrv.c	(revision 5857be2e40c022b415aeaa6c8bbe900f882d56be)
+++ uspace/lib/usb/src/devdrv.c	(revision baa9d5d9c02542344eba05d79f989e06f17a1879)
@@ -36,4 +36,5 @@
 #include <usb/request.h>
 #include <usb/debug.h>
+#include <usb/dp.h>
 #include <errno.h>
 #include <str_error.h>
@@ -86,12 +87,12 @@
  * @return Number of pipes (excluding default control pipe).
  */
-static size_t count_other_pipes(usb_driver_t *drv)
+static size_t count_other_pipes(usb_endpoint_description_t **endpoints)
 {
 	size_t count = 0;
-	if (drv->endpoints == NULL) {
+	if (endpoints == NULL) {
 		return 0;
 	}
 
-	while (drv->endpoints[count] != NULL) {
+	while (endpoints[count] != NULL) {
 		count++;
 	}
@@ -106,10 +107,14 @@
  * @return Error code.
  */
-static int initialize_other_pipes(usb_driver_t *drv, usb_device_t *dev)
+static int initialize_other_pipes(usb_endpoint_description_t **endpoints,
+    usb_device_t *dev)
 {
 	int rc;
-	dev->interface_no = usb_device_get_assigned_interface(dev->ddf_dev);
-
-	size_t pipe_count = count_other_pipes(drv);
+
+	size_t pipe_count = count_other_pipes(endpoints);
+	if (pipe_count == 0) {
+		return EOK;
+	}
+
 	dev->pipes = malloc(sizeof(usb_endpoint_mapping_t) * pipe_count);
 	if (dev->pipes == NULL) {
@@ -133,6 +138,7 @@
 		}
 
-		dev->pipes[i].description = drv->endpoints[i];
+		dev->pipes[i].description = endpoints[i];
 		dev->pipes[i].interface_no = dev->interface_no;
+		dev->pipes[i].interface_setting = 0;
 	}
 
@@ -178,4 +184,6 @@
 	usb_hc_connection_close(&hc_conn);
 
+	dev->pipes_count = pipe_count;
+
 	return EOK;
 
@@ -227,4 +235,7 @@
 	}
 
+	/* Get our interface. */
+	dev->interface_no = usb_device_get_assigned_interface(dev->ddf_dev);
+
 	/*
 	 * For further actions, we need open session on default control pipe.
@@ -257,5 +268,5 @@
 
 	if (driver->endpoints != NULL) {
-		rc = initialize_other_pipes(driver, dev);
+		rc = initialize_other_pipes(driver->endpoints, dev);
 	}
 
@@ -271,4 +282,128 @@
 
 	return rc;
+}
+
+/** Count number of alternate settings of a interface.
+ *
+ * @param config_descr Full configuration descriptor.
+ * @param config_descr_size Size of @p config_descr in bytes.
+ * @param interface_no Interface number.
+ * @return Number of alternate interfaces for @p interface_no interface.
+ */
+static size_t count_alternate_interfaces(uint8_t *config_descr,
+    size_t config_descr_size, int interface_no)
+{
+	assert(config_descr != NULL);
+	usb_dp_parser_t dp_parser = {
+		.nesting = usb_dp_standard_descriptor_nesting
+	};
+	usb_dp_parser_data_t dp_data = {
+		.data = config_descr,
+		.size = config_descr_size,
+		.arg = NULL
+	};
+
+	size_t alternate_count = 0;
+
+	uint8_t *iface_ptr = usb_dp_get_nested_descriptor(&dp_parser,
+	    &dp_data, config_descr);
+	while (iface_ptr != NULL) {
+		usb_standard_interface_descriptor_t *iface
+		    = (usb_standard_interface_descriptor_t *) iface_ptr;
+		if (iface->descriptor_type == USB_DESCTYPE_INTERFACE) {
+			if (iface->interface_number == interface_no) {
+				alternate_count++;
+			}
+		}
+		iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser, &dp_data,
+		    config_descr, iface_ptr);
+	}
+
+	return alternate_count;
+}
+
+/** Initialize structures related to alternate interfaces.
+ *
+ * @param dev Device where alternate settings shall be initialized.
+ * @return Error code.
+ */
+static int initialize_alternate_interfaces(usb_device_t *dev)
+{
+	if (dev->interface_no < 0) {
+		dev->alternate_interfaces = NULL;
+		return EOK;
+	}
+
+	usb_alternate_interfaces_t *alternates
+	    = malloc(sizeof(usb_alternate_interfaces_t));
+
+	if (alternates == NULL) {
+		return ENOMEM;
+	}
+
+	alternates->alternative_count
+	    = count_alternate_interfaces(dev->descriptors.configuration,
+	    dev->descriptors.configuration_size, dev->interface_no);
+
+	if (alternates->alternative_count == 0) {
+		free(alternates);
+		return ENOENT;
+	}
+
+	alternates->alternatives = malloc(alternates->alternative_count
+	    * sizeof(usb_alternate_interface_descriptors_t));
+	if (alternates->alternatives == NULL) {
+		free(alternates);
+		return ENOMEM;
+	}
+
+	alternates->current = 0;
+
+	usb_dp_parser_t dp_parser = {
+		.nesting = usb_dp_standard_descriptor_nesting
+	};
+	usb_dp_parser_data_t dp_data = {
+		.data = dev->descriptors.configuration,
+		.size = dev->descriptors.configuration_size,
+		.arg = NULL
+	};
+
+	usb_alternate_interface_descriptors_t *cur_alt_iface
+	    = &alternates->alternatives[0];
+
+	uint8_t *iface_ptr = usb_dp_get_nested_descriptor(&dp_parser,
+	    &dp_data, dp_data.data);
+	while (iface_ptr != NULL) {
+		usb_standard_interface_descriptor_t *iface
+		    = (usb_standard_interface_descriptor_t *) iface_ptr;
+		if ((iface->descriptor_type != USB_DESCTYPE_INTERFACE)
+		    || (iface->interface_number != dev->interface_no)) {
+			iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser,
+			    &dp_data,
+			    dp_data.data, iface_ptr);
+			continue;
+		}
+
+		cur_alt_iface->interface = iface;
+		cur_alt_iface->nested_descriptors = iface_ptr + sizeof(*iface);
+
+		/* Find next interface to count size of nested descriptors. */
+		iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser, &dp_data,
+		    dp_data.data, iface_ptr);
+		if (iface_ptr == NULL) {
+			uint8_t *next = dp_data.data + dp_data.size;
+			cur_alt_iface->nested_descriptors_size
+			    = next - cur_alt_iface->nested_descriptors;
+		} else {
+			cur_alt_iface->nested_descriptors_size
+			    = iface_ptr - cur_alt_iface->nested_descriptors;
+		}
+
+		cur_alt_iface++;
+	}
+
+	dev->alternate_interfaces = alternates;
+
+	return EOK;
 }
 
@@ -301,4 +436,7 @@
 	dev->descriptors.configuration = NULL;
 
+	dev->pipes_count = 0;
+	dev->pipes = NULL;
+
 	rc = initialize_pipes(dev);
 	if (rc != EOK) {
@@ -307,5 +445,97 @@
 	}
 
+	(void) initialize_alternate_interfaces(dev);
+
 	return driver->ops->add_device(dev);
+}
+
+/** Destroy existing pipes of a USB device.
+ *
+ * @param dev Device where to destroy the pipes.
+ * @return Error code.
+ */
+static int destroy_current_pipes(usb_device_t *dev)
+{
+	size_t i;
+	int rc;
+
+	/* TODO: this shall be done under some device mutex. */
+
+	/* First check that no session is opened. */
+	for (i = 0; i < dev->pipes_count; i++) {
+		if (usb_pipe_is_session_started(dev->pipes[i].pipe)) {
+			return EBUSY;
+		}
+	}
+
+	/* Prepare connection to HC. */
+	usb_hc_connection_t hc_conn;
+	rc = usb_hc_connection_initialize_from_device(&hc_conn, dev->ddf_dev);
+	if (rc != EOK) {
+		return rc;
+	}
+	rc = usb_hc_connection_open(&hc_conn);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/* Destroy the pipes. */
+	for (i = 0; i < dev->pipes_count; i++) {
+		usb_pipe_unregister(dev->pipes[i].pipe, &hc_conn);
+		free(dev->pipes[i].pipe);
+	}
+
+	usb_hc_connection_close(&hc_conn);
+
+	free(dev->pipes);
+	dev->pipes = NULL;
+	dev->pipes_count = 0;
+
+	return EOK;
+}
+
+/** Change interface setting of a device.
+ * This function selects new alternate setting of an interface by issuing
+ * proper USB command to the device and also creates new USB pipes
+ * under @c dev->pipes.
+ *
+ * @warning This function is intended for drivers working at interface level.
+ * For drivers controlling the whole device, you need to change interface
+ * manually using usb_request_set_interface() and creating new pipes
+ * with usb_pipe_initialize_from_configuration().
+ *
+ * @param dev USB device.
+ * @param alternate_setting Alternate setting to choose.
+ * @param endpoints New endpoint descriptions.
+ * @return Error code.
+ */
+int usb_device_select_interface(usb_device_t *dev, uint8_t alternate_setting,
+    usb_endpoint_description_t **endpoints)
+{
+	if (dev->interface_no < 0) {
+		return EINVAL;
+	}
+
+	int rc;
+
+	/* TODO: more transactional behavior. */
+
+	/* Destroy existing pipes. */
+	rc = destroy_current_pipes(dev);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/* Change the interface itself. */
+	rc = usb_request_set_interface(&dev->ctrl_pipe, dev->interface_no,
+	    alternate_setting);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/* Create new pipes. */
+	rc = initialize_other_pipes(endpoints, dev);
+
+	return rc;
 }
 
Index: uspace/lib/usb/src/pipesinit.c
===================================================================
--- uspace/lib/usb/src/pipesinit.c	(revision 5857be2e40c022b415aeaa6c8bbe900f882d56be)
+++ uspace/lib/usb/src/pipesinit.c	(revision baa9d5d9c02542344eba05d79f989e06f17a1879)
@@ -121,5 +121,5 @@
     usb_endpoint_mapping_t *mapping, size_t mapping_count,
     usb_endpoint_description_t *found_endpoint,
-    int interface_number)
+    int interface_number, int interface_setting)
 {
 	while (mapping_count > 0) {
@@ -127,8 +127,13 @@
 		    || (mapping->interface_no == interface_number);
 
+		bool interface_setting_fits = (mapping->interface_setting < 0)
+		    || (mapping->interface_setting == interface_setting);
+
 		bool endpoint_descriptions_fits = endpoint_fits_description(
 		    mapping->description, found_endpoint);
 
-		if (interface_number_fits && endpoint_descriptions_fits) {
+		if (interface_number_fits
+		    && interface_setting_fits
+		    && endpoint_descriptions_fits) {
 			return mapping;
 		}
@@ -181,5 +186,6 @@
 	 */
 	usb_endpoint_mapping_t *ep_mapping = find_endpoint_mapping(mapping,
-	    mapping_count, &description, interface->interface_number);
+	    mapping_count, &description,
+	    interface->interface_number, interface->alternate_setting);
 	if (ep_mapping == NULL) {
 		return ENOENT;
