Index: uspace/lib/usb/include/usb/classes/hidparser.h
===================================================================
--- uspace/lib/usb/include/usb/classes/hidparser.h	(revision 7dfc06fa1782dda3da24feb0e244e9bfadcc016e)
+++ uspace/lib/usb/include/usb/classes/hidparser.h	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -88,7 +88,9 @@
 	/** */	
 	int depth;	
+	uint8_t report_id;
 	
 	/** */	
 	link_t link;
+
 } usb_hid_report_path_t;
 
@@ -155,4 +157,9 @@
 	/** */	
 	link_t feature;
+	
+	int use_report_id;
+
+	/** */
+ 	link_t stack;
 } usb_hid_report_parser_t;	
 
@@ -166,5 +173,5 @@
 	 * @param arg Custom argument.
 	 */
-	void (*keyboard)(const uint8_t *key_codes, size_t count, const uint8_t modifiers, void *arg);
+	void (*keyboard)(const uint8_t *key_codes, size_t count, const uint8_t report_id, void *arg);
 } usb_hid_report_in_callbacks_t;
 
@@ -269,4 +276,7 @@
 
 /** */
+int usb_hid_report_path_set_report_id(usb_hid_report_path_t *usage_path, uint8_t report_id);
+
+/** */
 int usb_hid_report_path_append_item(usb_hid_report_path_t *usage_path, int32_t usage_page, int32_t usage);
 
Index: uspace/lib/usb/include/usb/host/batch.h
===================================================================
--- uspace/lib/usb/include/usb/host/batch.h	(revision 7dfc06fa1782dda3da24feb0e244e9bfadcc016e)
+++ uspace/lib/usb/include/usb/host/batch.h	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -92,5 +92,13 @@
 void usb_transfer_batch_call_in(usb_transfer_batch_t *instance);
 void usb_transfer_batch_call_out(usb_transfer_batch_t *instance);
-void usb_transfer_batch_finish(usb_transfer_batch_t *instance, int error);
+void usb_transfer_batch_finish(usb_transfer_batch_t *instance);
+
+static inline void usb_transfer_batch_finish_error(
+    usb_transfer_batch_t *instance, int error)
+{
+	assert(instance);
+	instance->error = error;
+	usb_transfer_batch_finish(instance);
+}
 
 #endif
Index: uspace/lib/usb/include/usb/host/device_keeper.h
===================================================================
--- uspace/lib/usb/include/usb/host/device_keeper.h	(revision 7dfc06fa1782dda3da24feb0e244e9bfadcc016e)
+++ uspace/lib/usb/include/usb/host/device_keeper.h	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -96,11 +96,4 @@
 usb_speed_t usb_device_keeper_get_speed(usb_device_keeper_t *instance,
     usb_address_t address);
-
-void usb_device_keeper_use_control(usb_device_keeper_t *instance,
-    usb_target_t target);
-
-void usb_device_keeper_release_control(usb_device_keeper_t *instance,
-    usb_target_t target);
-
 #endif
 /**
Index: uspace/lib/usb/include/usb/host/endpoint.h
===================================================================
--- uspace/lib/usb/include/usb/host/endpoint.h	(revision 7dfc06fa1782dda3da24feb0e244e9bfadcc016e)
+++ uspace/lib/usb/include/usb/host/endpoint.h	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -39,4 +39,6 @@
 #include <bool.h>
 #include <adt/list.h>
+#include <fibril_synch.h>
+
 #include <usb/usb.h>
 
@@ -48,6 +50,8 @@
 	usb_speed_t speed;
 	size_t max_packet_size;
-	bool active;
 	unsigned toggle:1;
+	fibril_mutex_t guard;
+	fibril_condvar_t avail;
+	volatile bool active;
 	link_t same_device_eps;
 } endpoint_t;
@@ -58,4 +62,8 @@
 
 void endpoint_destroy(endpoint_t *instance);
+
+void endpoint_use(endpoint_t *instance);
+
+void endpoint_release(endpoint_t *instance);
 
 int endpoint_toggle_get(endpoint_t *instance);
Index: uspace/lib/usb/src/devpoll.c
===================================================================
--- uspace/lib/usb/src/devpoll.c	(revision 7dfc06fa1782dda3da24feb0e244e9bfadcc016e)
+++ uspace/lib/usb/src/devpoll.c	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -66,4 +66,10 @@
 	usb_pipe_t *pipe
 	    = polling_data->dev->pipes[polling_data->pipe_index].pipe;
+	
+	usb_log_debug("Pipe interface number: %d, protocol: %d, subclass: %d, max packet size: %d\n", 
+	    polling_data->dev->pipes[polling_data->pipe_index].interface_no,
+	    polling_data->dev->pipes[polling_data->pipe_index].description->interface_protocol,
+	    polling_data->dev->pipes[polling_data->pipe_index].description->interface_subclass,
+	    pipe->max_packet_size);
 
 	size_t failed_attempts = 0;
@@ -83,4 +89,11 @@
 		/* Quit the session regardless of errors. */
 		usb_pipe_end_session(pipe);
+		
+//		if (rc == ESTALL) {
+//			usb_log_debug("Seding clear feature...\n");
+//			usb_request_clear_feature(pipe, USB_REQUEST_TYPE_STANDARD,
+//			  USB_REQUEST_RECIPIENT_ENDPOINT, 0, pipe->endpoint_no);
+//			continue;
+//		}
 
 		if (rc != EOK) {
Index: uspace/lib/usb/src/hidparser.c
===================================================================
--- uspace/lib/usb/src/hidparser.c	(revision 7dfc06fa1782dda3da24feb0e244e9bfadcc016e)
+++ uspace/lib/usb/src/hidparser.c	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -64,5 +64,5 @@
 int usb_hid_report_reset_local_items();
 void usb_hid_free_report_list(link_t *head);
-
+usb_hid_report_item_t *usb_hid_report_item_clone(const usb_hid_report_item_t *item);
 /*
  * Data translation private functions
@@ -106,4 +106,7 @@
     list_initialize(&(parser->feature));
 
+	list_initialize(&(parser->stack));
+
+	parser->use_report_id = 0;
     return EOK;   
 }
@@ -186,4 +189,8 @@
 					tmp_usage_path = NULL;
 
+					usb_hid_report_path_set_report_id(report_item->usage_path, report_item->id);	
+					if(report_item->id != 0){
+						parser->use_report_id = 1;
+					}
 					
 					switch(tag) {
@@ -215,11 +222,22 @@
 					if(!(new_report_item = malloc(sizeof(usb_hid_report_item_t)))) {
 						return ENOMEM;
-					}
+					}					
 					memcpy(new_report_item,report_item, sizeof(usb_hid_report_item_t));
+					link_initialize(&(new_report_item->link));
+					
 					/* reset local items */
 					new_report_item->usage_minimum = 0;
 					new_report_item->usage_maximum = 0;
+					new_report_item->designator_index = 0;
+					new_report_item->designator_minimum = 0;
+					new_report_item->designator_maximum = 0;
+					new_report_item->string_index = 0;
+					new_report_item->string_minimum = 0;
+					new_report_item->string_maximum = 0;
+
+					/* reset usage from current usage path */
+					usb_hid_report_usage_path_t *path = list_get_instance(&usage_path->link, usb_hid_report_usage_path_t, link);
+					path->usage = 0;
 					
-					link_initialize(&(new_report_item->link));
 					report_item = new_report_item;
 										
@@ -227,9 +245,17 @@
 				case USB_HID_REPORT_TAG_PUSH:
 					// push current state to stack
-					// not yet implemented
+					new_report_item = usb_hid_report_item_clone(report_item);
+					list_prepend (&parser->stack, &new_report_item->link);
+					
 					break;
 				case USB_HID_REPORT_TAG_POP:
 					// restore current state from stack
-					// not yet implemented						   
+					if(list_empty (&parser->stack)) {
+						return EINVAL;
+					}
+					
+					report_item = list_get_instance(&parser->stack, usb_hid_report_item_t, link);
+					list_remove (parser->stack.next);
+					
 					break;
 					
@@ -647,4 +673,6 @@
 	}
 
+	parser->use_report_id = 0;
+
 	usb_hid_free_report_list(&parser->input);
 	usb_hid_free_report_list(&parser->output);
@@ -676,4 +704,5 @@
 	size_t i=0;
 	size_t j=0;
+	uint8_t report_id = 0;
 
 	if(parser == NULL) {
@@ -686,4 +715,9 @@
 	if(!(keys = malloc(sizeof(uint8_t) * key_count))){
 		return ENOMEM;
+	}
+
+	if(parser->use_report_id != 0) {
+		report_id = data[0];
+		usb_hid_report_path_set_report_id(path, report_id);
 	}
 
@@ -693,4 +727,5 @@
 
 		item = list_get_instance(list_item, usb_hid_report_item_t, link);
+
 		if(!USB_HID_ITEM_FLAG_CONSTANT(item->item_flags) && 
 		   (usb_hid_report_compare_usage_path(item->usage_path, path, flags) == EOK)) {
@@ -715,5 +750,5 @@
 	}
 
-	callbacks->keyboard(keys, key_count, 0, arg);
+	callbacks->keyboard(keys, key_count, report_id, arg);
 	   
 	free(keys);	
@@ -739,5 +774,5 @@
 	int32_t mask;
 	const uint8_t *foo;
-	
+
 	// now only common numbers llowed
 	if(item->size > 32) {
@@ -758,5 +793,10 @@
 		(usb_pow(10,(item->unit_exponent))));
 	}
+
 	offset = item->offset + (j * item->size);
+	if(item->id != 0) {
+		offset += 8;
+		usb_log_debug("MOVED OFFSET BY 1Byte, REPORT_ID(%d)\n", item->id);
+	}
 	
 	// FIXME
@@ -942,4 +982,8 @@
 
 	int only_page;
+
+	if(report_path->report_id != path->report_id) {
+		return 1;
+	}
 
 	if(path->depth == 0){
@@ -1038,4 +1082,5 @@
 	else {
 		path->depth = 0;
+		path->report_id = 0;
 		list_initialize(&path->link);
 		return path;
@@ -1155,5 +1200,5 @@
 		return 0;
 	}
-	
+
 	item = parser->output.next;
 	while(&parser->output != item) {
@@ -1195,7 +1240,13 @@
 	int length;
 	int32_t tmp_value;
+	size_t offset_prefix = 0;
 	
 	if(parser == NULL) {
 		return EINVAL;
+	}
+
+	if(parser->use_report_id != 0) {
+		buffer[0] = path->report_id;
+		offset_prefix = 8;
 	}
 
@@ -1218,5 +1269,5 @@
 //				// variable item
 				value = usb_hid_translate_data_reverse(report_item, data[idx++]);
-				offset = report_item->offset + (i * report_item->size);
+				offset = report_item->offset + (i * report_item->size) + offset_prefix;
 				length = report_item->size;
 			}
@@ -1224,5 +1275,5 @@
 				//bitmap
 				value += usb_hid_translate_data_reverse(report_item, data[idx++]);
-				offset = report_item->offset;
+				offset = report_item->offset + offset_prefix;
 				length = report_item->size * report_item->count;
 			}
@@ -1323,4 +1374,28 @@
 
 
+int usb_hid_report_path_set_report_id(usb_hid_report_path_t *path, uint8_t report_id)
+{
+	if(path == NULL){
+		return EINVAL;
+	}
+
+	path->report_id = report_id;
+	return EOK;
+}
+
+
+usb_hid_report_item_t *usb_hid_report_item_clone(const usb_hid_report_item_t *item)
+{
+	usb_hid_report_item_t *new_report_item;
+	
+	if(!(new_report_item = malloc(sizeof(usb_hid_report_item_t)))) {
+		return NULL;
+	}					
+	memcpy(new_report_item,item, sizeof(usb_hid_report_item_t));
+	link_initialize(&(new_report_item->link));
+
+	return new_report_item;
+}
+
 /**
  * @}
Index: uspace/lib/usb/src/hidreport.c
===================================================================
--- uspace/lib/usb/src/hidreport.c	(revision 7dfc06fa1782dda3da24feb0e244e9bfadcc016e)
+++ uspace/lib/usb/src/hidreport.c	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -80,4 +80,5 @@
 		d = usb_dp_get_sibling_descriptor(&parser, &parser_data, 
 		    dev->descriptors.configuration, d);
+		++i;
 	}
 	
Index: uspace/lib/usb/src/host/batch.c
===================================================================
--- uspace/lib/usb/src/host/batch.c	(revision 7dfc06fa1782dda3da24feb0e244e9bfadcc016e)
+++ uspace/lib/usb/src/host/batch.c	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -79,4 +79,5 @@
 	instance->error = EOK;
 	instance->ep = ep;
+	endpoint_use(instance->ep);
 }
 /*----------------------------------------------------------------------------*/
@@ -86,8 +87,9 @@
  *
  */
-void usb_transfer_batch_finish(usb_transfer_batch_t *instance, int error)
+void usb_transfer_batch_finish(usb_transfer_batch_t *instance)
 {
 	assert(instance);
-	instance->error = error;
+	assert(instance->ep);
+	endpoint_release(instance->ep);
 	instance->next_step(instance);
 }
Index: uspace/lib/usb/src/host/device_keeper.c
===================================================================
--- uspace/lib/usb/src/host/device_keeper.c	(revision 7dfc06fa1782dda3da24feb0e244e9bfadcc016e)
+++ uspace/lib/usb/src/host/device_keeper.c	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -264,29 +264,4 @@
 	return instance->devices[address].speed;
 }
-/*----------------------------------------------------------------------------*/
-void usb_device_keeper_use_control(
-    usb_device_keeper_t *instance, 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[target.address].control_used |= ep;
-	fibril_mutex_unlock(&instance->guard);
-}
-/*----------------------------------------------------------------------------*/
-void usb_device_keeper_release_control(
-    usb_device_keeper_t *instance, 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/host/endpoint.c
===================================================================
--- uspace/lib/usb/src/host/endpoint.c	(revision 7dfc06fa1782dda3da24feb0e244e9bfadcc016e)
+++ uspace/lib/usb/src/host/endpoint.c	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -34,4 +34,5 @@
  */
 
+#include <assert.h>
 #include <errno.h>
 #include <usb/host/endpoint.h>
@@ -49,4 +50,7 @@
 	instance->max_packet_size = max_packet_size;
 	instance->toggle = 0;
+	instance->active = false;
+	fibril_mutex_initialize(&instance->guard);
+	fibril_condvar_initialize(&instance->avail);
 	link_initialize(&instance->same_device_eps);
 	return EOK;
@@ -56,6 +60,26 @@
 {
 	assert(instance);
+	assert(!instance->active);
 	list_remove(&instance->same_device_eps);
 	free(instance);
+}
+/*----------------------------------------------------------------------------*/
+void endpoint_use(endpoint_t *instance)
+{
+	assert(instance);
+	fibril_mutex_lock(&instance->guard);
+	while (instance->active)
+		fibril_condvar_wait(&instance->avail, &instance->guard);
+	instance->active = true;
+	fibril_mutex_unlock(&instance->guard);
+}
+/*----------------------------------------------------------------------------*/
+void endpoint_release(endpoint_t *instance)
+{
+	assert(instance);
+	fibril_mutex_lock(&instance->guard);
+	instance->active = false;
+	fibril_mutex_unlock(&instance->guard);
+	fibril_condvar_signal(&instance->avail);
 }
 /*----------------------------------------------------------------------------*/
Index: uspace/lib/usb/src/hub.c
===================================================================
--- uspace/lib/usb/src/hub.c	(revision 7dfc06fa1782dda3da24feb0e244e9bfadcc016e)
+++ uspace/lib/usb/src/hub.c	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -178,6 +178,11 @@
  * error codes than those listed as return codes by this function itself).
  *
+ * The @p connection representing connection with host controller does not
+ * need to be started.
+ * This function duplicates the connection to allow simultaneous calls of
+ * this function (i.e. from different fibrils).
+ *
  * @param[in] parent Parent device (i.e. the hub device).
- * @param[in] connection Opened connection to host controller.
+ * @param[in] connection Connection to host controller.
  * @param[in] dev_speed New device speed.
  * @param[in] enable_port Function for enabling signaling through the port the
@@ -206,20 +211,33 @@
     ddf_dev_ops_t *dev_ops, void *new_dev_data, ddf_fun_t **new_fun)
 {
-	CHECK_CONNECTION(connection);
+	assert(connection != NULL);
+	// FIXME: this is awful, we are accessing directly the structure.
+	usb_hc_connection_t hc_conn = {
+		.hc_handle = connection->hc_handle,
+		.hc_phone = -1
+	};
+
+	int rc;
+
+	rc = usb_hc_connection_open(&hc_conn);
+	if (rc != EOK) {
+		return rc;
+	}
+
 
 	/*
 	 * Request new address.
 	 */
-	usb_address_t dev_addr = usb_hc_request_address(connection, dev_speed);
+	usb_address_t dev_addr = usb_hc_request_address(&hc_conn, dev_speed);
 	if (dev_addr < 0) {
+		usb_hc_connection_close(&hc_conn);
 		return EADDRNOTAVAIL;
 	}
 
-	int rc;
 
 	/*
 	 * Reserve the default address.
 	 */
-	rc = usb_hc_reserve_default_address(connection, dev_speed);
+	rc = usb_hc_reserve_default_address(&hc_conn, dev_speed);
 	if (rc != EOK) {
 		rc = EBUSY;
@@ -241,5 +259,5 @@
 	usb_device_connection_t dev_conn;
 	rc = usb_device_connection_initialize_on_default_address(&dev_conn,
-	    connection);
+	    &hc_conn);
 	if (rc != EOK) {
 		rc = ENOTCONN;
@@ -258,5 +276,5 @@
 	 * endpoint.
 	 */
-	rc = usb_pipe_register(&ctrl_pipe, 0, connection);
+	rc = usb_pipe_register(&ctrl_pipe, 0, &hc_conn);
 	if (rc != EOK) {
 		rc = EREFUSED;
@@ -286,5 +304,5 @@
 	 * Register the control endpoint for the new device.
 	 */
-	rc = usb_pipe_register(&ctrl_pipe, 0, connection);
+	rc = usb_pipe_register(&ctrl_pipe, 0, &hc_conn);
 	if (rc != EOK) {
 		rc = EREFUSED;
@@ -295,10 +313,10 @@
 	 * Release the original endpoint.
 	 */
-	unregister_control_endpoint_on_default_address(connection);
+	unregister_control_endpoint_on_default_address(&hc_conn);
 
 	/*
 	 * Once the address is changed, we can return the default address.
 	 */
-	usb_hc_release_default_address(connection);
+	usb_hc_release_default_address(&hc_conn);
 
 
@@ -325,5 +343,5 @@
 		.handle = child_handle
 	};
-	rc = usb_hc_register_device(connection, &new_device);
+	rc = usb_hc_register_device(&hc_conn, &new_device);
 	if (rc != EOK) {
 		rc = EDESTADDRREQ;
@@ -354,11 +372,13 @@
 
 leave_unregister_endpoint:
-	usb_pipe_unregister(&ctrl_pipe, connection);
+	usb_pipe_unregister(&ctrl_pipe, &hc_conn);
 
 leave_release_default_address:
-	usb_hc_release_default_address(connection);
+	usb_hc_release_default_address(&hc_conn);
 
 leave_release_free_address:
-	usb_hc_unregister_device(connection, dev_addr);
+	usb_hc_unregister_device(&hc_conn, dev_addr);
+
+	usb_hc_connection_close(&hc_conn);
 
 	return rc;
