Index: uspace/lib/usb/src/devdrv.c
===================================================================
--- uspace/lib/usb/src/devdrv.c	(revision 0b4e7ca5837665462dd121f3429fdf63fd6d33d7)
+++ uspace/lib/usb/src/devdrv.c	(revision 0cec844d322f50cced98388fe8d510b61d40b3ce)
@@ -262,5 +262,5 @@
 	    &dev->descriptors.configuration_size);
 	if (rc != EOK) {
-		usb_log_error("Failed retrieving configuration descriptor: %s.\n",
+		usb_log_error("Failed retrieving configuration descriptor: %s. %s\n",
 		    dev->ddf_dev->name, str_error(rc));
 		return rc;
Index: uspace/lib/usb/src/hidparser.c
===================================================================
--- uspace/lib/usb/src/hidparser.c	(revision 0b4e7ca5837665462dd121f3429fdf63fd6d33d7)
+++ uspace/lib/usb/src/hidparser.c	(revision 0cec844d322f50cced98388fe8d510b61d40b3ce)
@@ -31,5 +31,5 @@
  */
 /** @file
- * @brief HID parser implementation.
+ * HID report descriptor and report data parser implementation.
  */
 #include <usb/classes/hidparser.h>
@@ -40,10 +40,16 @@
 #include <usb/debug.h>
 
+/** */
 #define USB_HID_NEW_REPORT_ITEM 1
+
+/** */
 #define USB_HID_NO_ACTION		2
+
+/** */
 #define USB_HID_UNKNOWN_TAG		-99
 
-#define BAD_HACK_USAGE_PAGE		0x07
-
+/*
+ * Private descriptor parser functions
+ */
 int usb_hid_report_parse_tag(uint8_t tag, uint8_t class, const uint8_t *data, size_t item_size,
                              usb_hid_report_item_t *report_item, usb_hid_report_path_t *usage_path);
@@ -58,10 +64,15 @@
 int usb_hid_report_reset_local_items();
 void usb_hid_free_report_list(link_t *head);
+
+/*
+ * Data translation private functions
+ */
 int32_t usb_hid_report_tag_data_int32(const uint8_t *data, size_t size);
 inline size_t usb_hid_count_item_offset(usb_hid_report_item_t * report_item, size_t offset);
 int usb_hid_translate_data(usb_hid_report_item_t *item, const uint8_t *data, size_t j);
+int32_t usb_hid_translate_data_reverse(usb_hid_report_item_t *item, int32_t value);
 int usb_pow(int a, int b);
 
-
+// TODO: tohle ma bejt asi jinde
 int usb_pow(int a, int b)
 {
@@ -80,13 +91,16 @@
 
 /**
- *
+ * Initialize the report descriptor parser structure
+ *
+ * @param parser Report descriptor parser structure
+ * @return Error code
  */
 int usb_hid_parser_init(usb_hid_report_parser_t *parser)
 {
-   if(parser == NULL) {
-	return EINVAL;
-   }
-
-    list_initialize(&(parser->input));
+	if(parser == NULL) {
+		return EINVAL;
+	}
+
+	list_initialize(&(parser->input));
     list_initialize(&(parser->output));
     list_initialize(&(parser->feature));
@@ -164,10 +178,7 @@
 					// store current usage path
 					report_item->usage_path = usage_path;
-
-					// new current usage path 
-					tmp_usage_path = usb_hid_report_path();
 					
-					// copy old path to the new one
-					usb_hid_report_path_clone(tmp_usage_path, usage_path);
+					// clone path to the new one
+					tmp_usage_path = usb_hid_report_path_clone(usage_path);
 
 					// swap
@@ -304,4 +315,5 @@
 
 /**
+ * Parse one tag of the report descriptor
  *
  * @param Tag to parse
@@ -391,5 +403,4 @@
  * @return Error code
  */
-
 int usb_hid_report_parse_global_tag(uint8_t tag, const uint8_t *data, size_t item_size,
                              usb_hid_report_item_t *report_item, usb_hid_report_path_t *usage_path)
@@ -520,5 +531,5 @@
  * Prints content of given list of report items.
  *
- * @param List of report items
+ * @param List of report items (usb_hid_report_item_t)
  * @return void
  */
@@ -552,8 +563,5 @@
 			path = path->next;
 		}
-		
-		
-//		usb_log_debug("\tUSAGE: %X\n", report_item->usage);
-//		usb_log_debug("\tUSAGE PAGE: %X\n", report_item->usage_page);
+				
 		usb_log_debug("\tLOGMIN: %X\n", report_item->logical_minimum);
 		usb_log_debug("\tLOGMAX: %X\n", report_item->logical_maximum);		
@@ -570,7 +578,7 @@
 }
 /**
- * Prints content of given descriptor in human readable format.
- *
- * @param Parsed descriptor to print
+ * Prints content of given report descriptor in human readable format.
+ *
+ * @param parser Parsed descriptor to print
  * @return void
  */
@@ -595,5 +603,6 @@
  * Releases whole linked list of report items
  *
- * 
+ * @param head Head of list of report descriptor items (usb_hid_report_item_t)
+ * @return void
  */
 void usb_hid_free_report_list(link_t *head)
@@ -627,8 +636,8 @@
 }
 
-/** Free the HID report parser structure 
+/** Frees the HID report descriptor parser structure 
  *
  * @param parser Opaque HID report parser structure
- * @return Error code
+ * @return void
  */
 void usb_hid_free_report_parser(usb_hid_report_parser_t *parser)
@@ -660,9 +669,4 @@
     const usb_hid_report_in_callbacks_t *callbacks, void *arg)
 {
-	/*
-	 *
-	 * only key codes (usage page 0x07) will be processed
-	 * other usages will be ignored 
-	 */
 	link_t *list_item;
 	usb_hid_report_item_t *item;
@@ -676,7 +680,6 @@
 		return EINVAL;
 	}
-
-	
-	// get the size of result keycodes array
+	
+	/* get the size of result array */
 	key_count = usb_hid_report_input_length(parser, path, flags);
 
@@ -685,5 +688,5 @@
 	}
 
-	// read data		
+	/* read data */
 	list_item = parser->input.next;	   
 	while(list_item != &(parser->input)) {
@@ -719,5 +722,12 @@
 }
 
-
+/**
+ * Translate data from the report as specified in report descriptor
+ *
+ * @param item Report descriptor item with definition of translation
+ * @param data Data to translate
+ * @param j Index of processed field in report descriptor item
+ * @return Translated data
+ */
 int usb_hid_translate_data(usb_hid_report_item_t *item, const uint8_t *data, size_t j)
 {
@@ -796,16 +806,24 @@
 }
 
-int usb_hid_report_input_length(const usb_hid_report_parser_t *parser,
+/**
+ *
+ *
+ * @param parser
+ * @param path
+ * @param flags
+ * @return
+ */
+size_t usb_hid_report_input_length(const usb_hid_report_parser_t *parser,
 	usb_hid_report_path_t *path, int flags)
 {	
-	int ret = 0;
+	size_t ret = 0;
 	link_t *item;
 	usb_hid_report_item_t *report_item;
 
 	if(parser == NULL) {
-		return EINVAL;
-	}
-	
-	item = (&parser->input)->next;
+		return 0;
+	}
+	
+	item = parser->input.next;
 	while(&parser->input != item) {
 		report_item = list_get_instance(item, usb_hid_report_item_t, link);
@@ -824,4 +842,8 @@
 /**
  * 
+ * @param usage_path
+ * @param usage_page
+ * @param usage
+ * @return
  */
 int usb_hid_report_path_append_item(usb_hid_report_path_t *usage_path, 
@@ -845,4 +867,6 @@
 /**
  *
+ * @param usage_path
+ * @return
  */
 void usb_hid_report_remove_last_item(usb_hid_report_path_t *usage_path)
@@ -860,4 +884,6 @@
 /**
  *
+ * @param usage_path
+ * @return
  */
 void usb_hid_report_null_last_item(usb_hid_report_path_t *usage_path)
@@ -873,4 +899,8 @@
 /**
  *
+ * @param usage_path
+ * @param tag
+ * @param data
+ * @return
  */
 void usb_hid_report_set_last_item(usb_hid_report_path_t *usage_path, int32_t tag, int32_t data)
@@ -894,5 +924,10 @@
 
 /**
- *
+ * 
+ *
+ * @param report_path
+ * @param path
+ * @param flags
+ * @return
  */
 int usb_hid_report_compare_usage_path(usb_hid_report_path_t *report_path, 
@@ -949,5 +984,5 @@
 			break;
 
-		/* given path must be the end of the report one*/
+		/* compare with only the end of path*/
 		case USB_HID_PATH_COMPARE_END:
 				report_link = report_path->link.prev;
@@ -992,4 +1027,5 @@
 /**
  *
+ * @return
  */
 usb_hid_report_path_t *usb_hid_report_path(void)
@@ -1009,4 +1045,6 @@
 /**
  *
+ * @param path
+ * @return void
  */
 void usb_hid_report_path_free(usb_hid_report_path_t *path)
@@ -1019,14 +1057,21 @@
 
 /**
- *
- */
-int	usb_hid_report_path_clone(usb_hid_report_path_t *new_usage_path, usb_hid_report_path_t *usage_path)
+ * Clone content of given usage path to the new one
+ *
+ * @param usage_path
+ * @return
+ */
+usb_hid_report_path_t *usb_hid_report_path_clone(usb_hid_report_path_t *usage_path)
 {
 	usb_hid_report_usage_path_t *path_item;
 	link_t *path_link;
-
+	usb_hid_report_path_t *new_usage_path = usb_hid_report_path ();
+
+	if(new_usage_path == NULL){
+		return NULL;
+	}
 	
 	if(list_empty(&usage_path->link)){
-		return EOK;
+		return new_usage_path;
 	}
 
@@ -1039,7 +1084,242 @@
 	}
 
+	return new_usage_path;
+}
+
+
+/*** OUTPUT API **/
+
+/** Allocates output report buffer
+ *
+ * @param parser
+ * @param size
+ * @return
+ */
+uint8_t *usb_hid_report_output(usb_hid_report_parser_t *parser, size_t *size)
+{
+	if(parser == NULL) {
+		*size = 0;
+		return NULL;
+	}
+	
+	// read the last output report item
+	usb_hid_report_item_t *last;
+	link_t *link;
+
+	link = parser->output.prev;
+	if(link != &parser->output) {
+		last = list_get_instance(link, usb_hid_report_item_t, link);
+		*size = (last->offset + (last->size * last->count)) / 8;
+
+		uint8_t *buffer = malloc(sizeof(uint8_t) * (*size));
+		memset(buffer, 0, sizeof(uint8_t) * (*size));
+		usb_log_debug("output buffer: %s\n", usb_debug_str_buffer(buffer, *size, 0));
+
+		return buffer;
+	}
+	else {
+		*size = 0;		
+		return NULL;
+	}
+}
+
+
+/** Frees output report buffer
+ *
+ * @param output Output report buffer
+ * @return
+ */
+void usb_hid_report_output_free(uint8_t *output)
+
+{
+	if(output != NULL) {
+		free (output);
+	}
+}
+
+/** Returns size of output for given usage path 
+ *
+ * @param parser
+ * @param path
+ * @param flags
+ * @return
+ */
+size_t usb_hid_report_output_size(usb_hid_report_parser_t *parser,
+                                  usb_hid_report_path_t *path, int flags)
+{
+	size_t ret = 0;
+	link_t *item;
+	usb_hid_report_item_t *report_item;
+
+	if(parser == NULL) {
+		return 0;
+	}
+	
+	item = parser->output.next;
+	while(&parser->output != item) {
+		report_item = list_get_instance(item, usb_hid_report_item_t, link);
+		if(!USB_HID_ITEM_FLAG_CONSTANT(report_item->item_flags) &&
+		   (usb_hid_report_compare_usage_path(report_item->usage_path, path, flags) == EOK)) {
+			ret += report_item->count;
+		}
+
+		item = item->next;
+	} 
+
+	return ret;
+	
+}
+
+/** Updates the output report buffer by translated given data 
+ *
+ * @param parser
+ * @param path
+ * @param flags
+ * @param buffer
+ * @param size
+ * @param data
+ * @param data_size
+ * @return
+ */
+int usb_hid_report_output_translate(usb_hid_report_parser_t *parser,
+                                    usb_hid_report_path_t *path, int flags,
+                                    uint8_t *buffer, size_t size,
+                                    int32_t *data, size_t data_size)
+{
+	usb_hid_report_item_t *report_item;
+	link_t *item;	
+	size_t idx=0;
+	int i=0;
+	int32_t value=0;
+	int offset;
+	int length;
+	int32_t tmp_value;
+	
+	if(parser == NULL) {
+		return EINVAL;
+	}
+
+	usb_log_debug("OUTPUT BUFFER: %s\n", usb_debug_str_buffer(buffer,size, 0));
+	usb_log_debug("OUTPUT DATA[0]: %d, DATA[1]: %d, DATA[2]: %d\n", data[0], data[1], data[2]);
+
+	item = parser->output.next;	
+	while(item != &parser->output) {
+		report_item = list_get_instance(item, usb_hid_report_item_t, link);
+
+		for(i=0; i<report_item->count; i++) {
+
+			if(idx >= data_size) {
+				break;
+			}
+
+			if((USB_HID_ITEM_FLAG_VARIABLE(report_item->item_flags) == 0) ||
+				((report_item->usage_minimum == 0) && (report_item->usage_maximum == 0))) {
+					
+//				// variable item
+				value = usb_hid_translate_data_reverse(report_item, data[idx++]);
+				offset = report_item->offset + (i * report_item->size);
+				length = report_item->size;
+			}
+			else {
+				//bitmap
+				value += usb_hid_translate_data_reverse(report_item, data[idx++]);
+				offset = report_item->offset;
+				length = report_item->size * report_item->count;
+			}
+
+			if((offset/8) == ((offset+length-1)/8)) {
+				// je to v jednom bytu
+				if(((size_t)(offset/8) >= size) || ((size_t)(offset+length-1)/8) >= size) {
+					break; // TODO ErrorCode
+				}
+
+				size_t shift = offset%8;
+
+				value = value << shift;							
+				value = value & (((1 << length)-1) << shift);
+				
+				uint8_t mask = 0;
+				mask = 0xff - (((1 << length) - 1) << shift);
+				buffer[offset/8] = (buffer[offset/8] & mask) | value;
+			}
+			else {
+				// je to ve dvou!! FIXME: melo by to umet delsi jak 2
+
+				// konec prvniho -- dolni x bitu
+				tmp_value = value;
+				tmp_value = tmp_value & ((1 << (8-(offset%8)))-1);				
+				tmp_value = tmp_value << (offset%8);
+
+				uint8_t mask = 0;
+				mask = ~(((1 << (8-(offset%8)))-1) << (offset%8));
+				buffer[offset/8] = (buffer[offset/8] & mask) | tmp_value;
+
+				// a ted druhej -- hornich length-x bitu
+				value = value >> (8 - (offset % 8));
+				value = value & ((1 << (length - (8 - (offset % 8)))) - 1);
+				
+				mask = ((1 << (length - (8 - (offset % 8)))) - 1);
+				buffer[(offset+length-1)/8] = (buffer[(offset+length-1)/8] & mask) | value;
+			}
+
+		}
+
+		item = item->next;
+	}
+
+	usb_log_debug("OUTPUT BUFFER: %s\n", usb_debug_str_buffer(buffer,size, 0));
+
 	return EOK;
 }
 
+/**
+ *
+ * @param item
+ * @param value
+ * @return
+ */
+int32_t usb_hid_translate_data_reverse(usb_hid_report_item_t *item, int value)
+{
+	int ret=0;
+	int resolution;
+
+	if(USB_HID_ITEM_FLAG_CONSTANT(item->item_flags)) {
+		ret = item->logical_minimum;
+	}
+
+	if((USB_HID_ITEM_FLAG_VARIABLE(item->item_flags) == 0)) {
+
+		// variable item
+		if((item->physical_minimum == 0) && (item->physical_maximum == 0)) {
+			item->physical_minimum = item->logical_minimum;
+			item->physical_maximum = item->logical_maximum;
+		}
+
+		if(item->physical_maximum == item->physical_minimum){
+		    resolution = 1;
+		}
+		else {
+		    resolution = (item->logical_maximum - item->logical_minimum) /
+			((item->physical_maximum - item->physical_minimum) *
+			(usb_pow(10,(item->unit_exponent))));
+		}
+
+		ret = ((value - item->physical_minimum) * resolution) + item->logical_minimum;
+	}
+	else {
+		// bitmapa
+		if(value == 0) {
+			ret = 0;
+		}
+		else {
+			size_t bitmap_idx = (value - item->usage_minimum);
+			ret = 1 << bitmap_idx;
+		}
+	}
+
+
+	return ret;
+}
+
 
 /**
Index: uspace/lib/usb/src/host/bandwidth.c
===================================================================
--- uspace/lib/usb/src/host/bandwidth.c	(revision 0cec844d322f50cced98388fe8d510b61d40b3ce)
+++ uspace/lib/usb/src/host/bandwidth.c	(revision 0cec844d322f50cced98388fe8d510b61d40b3ce)
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * 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.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <usb/host/bandwidth.h>
+
+typedef struct {
+	usb_address_t address;
+	usb_endpoint_t endpoint;
+	usb_direction_t direction;
+} __attribute__((aligned (sizeof(unsigned long)))) transfer_t;
+/*----------------------------------------------------------------------------*/
+typedef struct {
+	transfer_t transfer;
+	link_t link;
+	bool used;
+	size_t required;
+} transfer_status_t;
+/*----------------------------------------------------------------------------*/
+#define BUCKET_COUNT 7
+#define MAX_KEYS (sizeof(transfer_t) / sizeof(unsigned long))
+/*----------------------------------------------------------------------------*/
+static hash_index_t transfer_hash(unsigned long key[])
+{
+	hash_index_t hash = 0;
+	unsigned i = 0;
+	for (;i < MAX_KEYS; ++i) {
+		hash ^= key[i];
+	}
+	hash %= BUCKET_COUNT;
+	return hash;
+}
+/*----------------------------------------------------------------------------*/
+static int transfer_compare(
+    unsigned long key[], hash_count_t keys, link_t *item)
+{
+	assert(item);
+	transfer_status_t *status =
+	    hash_table_get_instance(item, transfer_status_t, link);
+	const size_t bytes =
+	    keys < MAX_KEYS ? keys * sizeof(unsigned long) : sizeof(transfer_t);
+	return bcmp(key, &status->transfer, bytes);
+}
+/*----------------------------------------------------------------------------*/
+static void transfer_remove(link_t *item)
+{
+	assert(item);
+	transfer_status_t *status =
+	    hash_table_get_instance(item, transfer_status_t, link);
+	assert(status);
+	free(status);
+}
+/*----------------------------------------------------------------------------*/
+hash_table_operations_t op = {
+	.hash = transfer_hash,
+	.compare = transfer_compare,
+	.remove_callback = transfer_remove,
+};
+/*----------------------------------------------------------------------------*/
+size_t bandwidth_count_usb11(usb_speed_t speed, usb_transfer_type_t type,
+    size_t size, size_t max_packet_size)
+{
+	const unsigned packet_count =
+	    (size + max_packet_size - 1) / max_packet_size;
+	/* TODO: It may be that ISO and INT transfers use only one data packet
+	 * per transaction, but I did not find text in UB spec that confirms
+	 * this */
+	/* NOTE: All data packets will be considered to be max_packet_size */
+	switch (speed)
+	{
+	case USB_SPEED_LOW:
+		assert(type == USB_TRANSFER_INTERRUPT);
+		/* Protocol overhead 13B
+		 * (3 SYNC bytes, 3 PID bytes, 2 Endpoint + CRC bytes, 2
+		 * CRC bytes, and a 3-byte interpacket delay)
+		 * see USB spec page 45-46. */
+		/* Speed penalty 8: low speed is 8-times slower*/
+		return packet_count * (13 + max_packet_size) * 8;
+	case USB_SPEED_FULL:
+		/* Interrupt transfer overhead see above
+		 * or page 45 of USB spec */
+		if (type == USB_TRANSFER_INTERRUPT)
+			return packet_count * (13 + max_packet_size);
+
+		assert(type == USB_TRANSFER_ISOCHRONOUS);
+		/* Protocol overhead 9B
+		 * (2 SYNC bytes, 2 PID bytes, 2 Endpoint + CRC bytes, 2 CRC
+		 * bytes, and a 1-byte interpacket delay)
+		 * see USB spec page 42 */
+		return packet_count * (9 + max_packet_size);
+	default:
+		return 0;
+	}
+}
+/*----------------------------------------------------------------------------*/
+int bandwidth_init(bandwidth_t *instance, size_t bandwidth,
+    size_t (*usage_fnc)(usb_speed_t, usb_transfer_type_t, size_t, size_t))
+{
+	assert(instance);
+	fibril_mutex_initialize(&instance->guard);
+	instance->free = bandwidth;
+	instance->usage_fnc = usage_fnc;
+	bool ht =
+	    hash_table_create(&instance->reserved, BUCKET_COUNT, MAX_KEYS, &op);
+	return ht ? EOK : ENOMEM;
+}
+/*----------------------------------------------------------------------------*/
+void bandwidth_destroy(bandwidth_t *instance)
+{
+	hash_table_destroy(&instance->reserved);
+}
+/*----------------------------------------------------------------------------*/
+int bandwidth_reserve(bandwidth_t *instance, usb_address_t address,
+    usb_endpoint_t endpoint, usb_direction_t direction, usb_speed_t speed,
+    usb_transfer_type_t transfer_type, size_t max_packet_size, size_t size,
+    unsigned interval)
+{
+	if (transfer_type != USB_TRANSFER_ISOCHRONOUS &&
+	    transfer_type != USB_TRANSFER_INTERRUPT) {
+		return ENOTSUP;
+	}
+
+	assert(instance);
+	assert(instance->usage_fnc);
+
+	transfer_t trans = {
+		.address = address,
+		.endpoint = endpoint,
+		.direction = direction,
+	};
+	fibril_mutex_lock(&instance->guard);
+	const size_t required =
+	    instance->usage_fnc(speed, transfer_type, size, max_packet_size);
+
+	if (required > instance->free) {
+		fibril_mutex_unlock(&instance->guard);
+		return ENOSPC;
+	}
+
+	link_t *item =
+	    hash_table_find(&instance->reserved, (unsigned long*)&trans);
+	if (item != NULL) {
+		fibril_mutex_unlock(&instance->guard);
+		return EEXISTS;
+	}
+
+	transfer_status_t *status = malloc(sizeof(transfer_status_t));
+	if (status == NULL) {
+		fibril_mutex_unlock(&instance->guard);
+		return ENOMEM;
+	}
+
+	status->transfer = trans;
+	status->required = required;
+	status->used = false;
+	link_initialize(&status->link);
+
+	hash_table_insert(&instance->reserved,
+	    (unsigned long*)&status->transfer, &status->link);
+	instance->free -= required;
+	fibril_mutex_unlock(&instance->guard);
+	return EOK;
+	/* TODO: compute bandwidth used */
+}
+/*----------------------------------------------------------------------------*/
+int bandwidth_release(bandwidth_t *instance, usb_address_t address,
+    usb_endpoint_t endpoint, usb_direction_t direction)
+{
+	assert(instance);
+	transfer_t trans = {
+		.address = address,
+		.endpoint = endpoint,
+		.direction = direction,
+	};
+	fibril_mutex_lock(&instance->guard);
+	link_t *item =
+	    hash_table_find(&instance->reserved, (unsigned long*)&trans);
+	if (item == NULL) {
+		fibril_mutex_unlock(&instance->guard);
+		return EINVAL;
+	}
+
+	transfer_status_t *status =
+	    hash_table_get_instance(item, transfer_status_t, link);
+
+	instance->free += status->required;
+
+	hash_table_remove(&instance->reserved,
+	    (unsigned long*)&trans, MAX_KEYS);
+
+	fibril_mutex_unlock(&instance->guard);
+	return EOK;
+	/* TODO: compute bandwidth freed */
+}
+/*----------------------------------------------------------------------------*/
+int bandwidth_use(bandwidth_t *instance, usb_address_t address,
+    usb_endpoint_t endpoint, usb_direction_t direction)
+{
+	assert(instance);
+	transfer_t trans = {
+		.address = address,
+		.endpoint = endpoint,
+		.direction = direction,
+	};
+	fibril_mutex_lock(&instance->guard);
+	link_t *item =
+	    hash_table_find(&instance->reserved, (unsigned long*)&trans);
+	int ret = EOK;
+	if (item != NULL) {
+		transfer_status_t *status =
+		    hash_table_get_instance(item, transfer_status_t, link);
+		assert(status);
+		if (status->used) {
+			ret = EINPROGRESS;
+		}
+		status->used = true;
+	} else {
+		ret = EINVAL;
+	}
+	fibril_mutex_unlock(&instance->guard);
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+int bandwidth_free(bandwidth_t *instance, usb_address_t address,
+    usb_endpoint_t endpoint, usb_direction_t direction)
+{
+	assert(instance);
+	transfer_t trans = {
+		.address = address,
+		.endpoint = endpoint,
+		.direction = direction,
+	};
+	fibril_mutex_lock(&instance->guard);
+	link_t *item =
+	    hash_table_find(&instance->reserved, (unsigned long*)&trans);
+	int ret = EOK;
+	if (item != NULL) {
+		transfer_status_t *status =
+		    hash_table_get_instance(item, transfer_status_t, link);
+		assert(status);
+		if (!status->used) {
+			ret = ENOENT;
+		}
+		status->used = false;
+	} else {
+		ret = EINVAL;
+	}
+	fibril_mutex_unlock(&instance->guard);
+	return ret;
+}
Index: uspace/lib/usb/src/host/device_keeper.c
===================================================================
--- uspace/lib/usb/src/host/device_keeper.c	(revision 0b4e7ca5837665462dd121f3429fdf63fd6d33d7)
+++ uspace/lib/usb/src/host/device_keeper.c	(revision 0cec844d322f50cced98388fe8d510b61d40b3ce)
@@ -54,5 +54,5 @@
 	for (; i < USB_ADDRESS_COUNT; ++i) {
 		instance->devices[i].occupied = false;
-		instance->devices[i].control_used = false;
+		instance->devices[i].control_used = 0;
 		instance->devices[i].handle = 0;
 		instance->devices[i].toggle_status[0] = 0;
@@ -311,21 +311,24 @@
 /*----------------------------------------------------------------------------*/
 void usb_device_keeper_use_control(usb_device_keeper_t *instance,
-    usb_address_t address)
-{
-	assert(instance);
-	fibril_mutex_lock(&instance->guard);
-	while (instance->devices[address].control_used) {
+    usb_target_t target)
+{
+	assert(instance);
+	const uint16_t ep = 1 << target.endpoint;
+	fibril_mutex_lock(&instance->guard);
+	while (instance->devices[target.address].control_used & ep) {
 		fibril_condvar_wait(&instance->change, &instance->guard);
 	}
-	instance->devices[address].control_used = true;
+	instance->devices[target.address].control_used |= ep;
 	fibril_mutex_unlock(&instance->guard);
 }
 /*----------------------------------------------------------------------------*/
 void usb_device_keeper_release_control(usb_device_keeper_t *instance,
-    usb_address_t address)
-{
-	assert(instance);
-	fibril_mutex_lock(&instance->guard);
-	instance->devices[address].control_used = false;
+    usb_target_t target)
+{
+	assert(instance);
+	const uint16_t ep = 1 << target.endpoint;
+	fibril_mutex_lock(&instance->guard);
+	assert((instance->devices[target.address].control_used & ep) != 0);
+	instance->devices[target.address].control_used &= ~ep;
 	fibril_mutex_unlock(&instance->guard);
 	fibril_condvar_signal(&instance->change);
Index: uspace/lib/usb/src/request.c
===================================================================
--- uspace/lib/usb/src/request.c	(revision 0b4e7ca5837665462dd121f3429fdf63fd6d33d7)
+++ uspace/lib/usb/src/request.c	(revision 0cec844d322f50cced98388fe8d510b61d40b3ce)
@@ -529,5 +529,4 @@
 		return rc;
 	}
-
 	if (bare_config.descriptor_type != USB_DESCTYPE_CONFIGURATION) {
 		return ENOENT;
