Index: uspace/drv/ohci/root_hub.c
===================================================================
--- uspace/drv/ohci/root_hub.c	(revision 7dfc06fa1782dda3da24feb0e244e9bfadcc016e)
+++ uspace/drv/ohci/root_hub.c	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -47,20 +47,19 @@
  *	standart device descriptor for ohci root hub
  */
-static const usb_standard_device_descriptor_t ohci_rh_device_descriptor =
-{
-		.configuration_count = 1,
-		.descriptor_type = USB_DESCTYPE_DEVICE,
-		.device_class = USB_CLASS_HUB,
-		.device_protocol = 0,
-		.device_subclass = 0,
-		.device_version = 0,
-		.length = sizeof(usb_standard_device_descriptor_t),
-		/// \TODO this value is guessed
-		.max_packet_size = 8,
-		.vendor_id = 0x16db,
-		.product_id = 0x0001,
-		/// \TODO these values migt be different
-		.str_serial_number = 0,
-		.usb_spec_version = 0x110,
+static const usb_standard_device_descriptor_t ohci_rh_device_descriptor = {
+	.configuration_count = 1,
+	.descriptor_type = USB_DESCTYPE_DEVICE,
+	.device_class = USB_CLASS_HUB,
+	.device_protocol = 0,
+	.device_subclass = 0,
+	.device_version = 0,
+	.length = sizeof (usb_standard_device_descriptor_t),
+	/// \TODO this value is guessed
+	.max_packet_size = 8,
+	.vendor_id = 0x16db,
+	.product_id = 0x0001,
+	/// \TODO these values migt be different
+	.str_serial_number = 0,
+	.usb_spec_version = 0x110,
 };
 
@@ -69,12 +68,11 @@
  * for ohci root hubs
  */
-static const usb_standard_configuration_descriptor_t ohci_rh_conf_descriptor =
-{
+static const usb_standard_configuration_descriptor_t ohci_rh_conf_descriptor = {
 	/// \TODO some values are default or guessed
-	.attributes = 1<<7,
+	.attributes = 1 << 7,
 	.configuration_number = 1,
 	.descriptor_type = USB_DESCTYPE_CONFIGURATION,
 	.interface_count = 1,
-	.length = sizeof(usb_standard_configuration_descriptor_t),
+	.length = sizeof (usb_standard_configuration_descriptor_t),
 	.max_power = 100,
 	.str_configuration = 0,
@@ -84,6 +82,5 @@
  * standart ohci root hub interface descriptor
  */
-static const usb_standard_interface_descriptor_t ohci_rh_iface_descriptor =
-{
+static const usb_standard_interface_descriptor_t ohci_rh_iface_descriptor = {
 	.alternate_setting = 0,
 	.descriptor_type = USB_DESCTYPE_INTERFACE,
@@ -94,5 +91,5 @@
 	.interface_protocol = 0,
 	.interface_subclass = 0,
-	.length = sizeof(usb_standard_interface_descriptor_t),
+	.length = sizeof (usb_standard_interface_descriptor_t),
 	.str_interface = 0,
 };
@@ -101,10 +98,9 @@
  * standart ohci root hub endpoint descriptor
  */
-static const usb_standard_endpoint_descriptor_t ohci_rh_ep_descriptor =
-{
+static const usb_standard_endpoint_descriptor_t ohci_rh_ep_descriptor = {
 	.attributes = USB_TRANSFER_INTERRUPT,
 	.descriptor_type = USB_DESCTYPE_ENDPOINT,
-	.endpoint_address = 1 + (1<<7),
-	.length = sizeof(usb_standard_endpoint_descriptor_t),
+	.endpoint_address = 1 + (1 << 7),
+	.length = sizeof (usb_standard_endpoint_descriptor_t),
 	.max_packet_size = 8,
 	.poll_interval = 255,
@@ -112,6 +108,6 @@
 
 static const uint32_t hub_clear_feature_valid_mask =
-	(1 << USB_HUB_FEATURE_C_HUB_LOCAL_POWER) +
-	(1 << USB_HUB_FEATURE_C_HUB_OVER_CURRENT);
+	(1 << USB_HUB_FEATURE_C_HUB_LOCAL_POWER) |
+(1 << USB_HUB_FEATURE_C_HUB_OVER_CURRENT);
 
 static const uint32_t hub_clear_feature_by_writing_one_mask =
@@ -121,28 +117,149 @@
 	(1 << USB_HUB_FEATURE_C_HUB_OVER_CURRENT);
 
-	
+
 static const uint32_t hub_set_feature_direct_mask =
 	(1 << USB_HUB_FEATURE_C_HUB_OVER_CURRENT);
 
 static const uint32_t port_set_feature_valid_mask =
-	(1 << USB_HUB_FEATURE_PORT_ENABLE) +
-	(1 << USB_HUB_FEATURE_PORT_SUSPEND) +
-	(1 << USB_HUB_FEATURE_PORT_RESET) +
-	(1 << USB_HUB_FEATURE_PORT_POWER);
+	(1 << USB_HUB_FEATURE_PORT_ENABLE) |
+(1 << USB_HUB_FEATURE_PORT_SUSPEND) |
+(1 << USB_HUB_FEATURE_PORT_RESET) |
+(1 << USB_HUB_FEATURE_PORT_POWER);
 
 static const uint32_t port_clear_feature_valid_mask =
-	(1 << USB_HUB_FEATURE_PORT_CONNECTION) +
-	(1 << USB_HUB_FEATURE_PORT_SUSPEND) +
-	(1 << USB_HUB_FEATURE_PORT_OVER_CURRENT) +
-	(1 << USB_HUB_FEATURE_PORT_POWER) +
-	(1 << USB_HUB_FEATURE_C_PORT_CONNECTION) +
-	(1 << USB_HUB_FEATURE_C_PORT_ENABLE) +
-	(1 << USB_HUB_FEATURE_C_PORT_SUSPEND) +
-	(1 << USB_HUB_FEATURE_C_PORT_OVER_CURRENT) +
-	(1 << USB_HUB_FEATURE_C_PORT_RESET);
-//note that USB_HUB_FEATURE_PORT_POWER bit is translated into USB_HUB_FEATURE_PORT_LOW_SPEED
-
-
-
+	(1 << USB_HUB_FEATURE_PORT_CONNECTION) |
+(1 << USB_HUB_FEATURE_PORT_SUSPEND) |
+(1 << USB_HUB_FEATURE_PORT_OVER_CURRENT) |
+(1 << USB_HUB_FEATURE_PORT_POWER) |
+(1 << USB_HUB_FEATURE_C_PORT_CONNECTION) |
+(1 << USB_HUB_FEATURE_C_PORT_ENABLE) |
+(1 << USB_HUB_FEATURE_C_PORT_SUSPEND) |
+(1 << USB_HUB_FEATURE_C_PORT_OVER_CURRENT) |
+(1 << USB_HUB_FEATURE_C_PORT_RESET);
+//note that USB_HUB_FEATURE_PORT_POWER bit is translated into
+//USB_HUB_FEATURE_PORT_LOW_SPEED
+
+static const uint32_t port_status_change_mask =
+(1<< USB_HUB_FEATURE_C_PORT_CONNECTION) |
+(1<< USB_HUB_FEATURE_C_PORT_ENABLE) |
+(1<< USB_HUB_FEATURE_C_PORT_OVER_CURRENT) |
+(1<< USB_HUB_FEATURE_C_PORT_RESET) |
+(1<< USB_HUB_FEATURE_C_PORT_SUSPEND);
+
+
+static void usb_create_serialized_hub_descriptor(rh_t *instance,
+	uint8_t ** out_result,
+	size_t * out_size);
+
+static void rh_init_descriptors(rh_t *instance);
+
+static int process_get_port_status_request(rh_t *instance, uint16_t port,
+	usb_transfer_batch_t * request);
+
+static int process_get_hub_status_request(rh_t *instance,
+	usb_transfer_batch_t * request);
+
+static int process_get_status_request(rh_t *instance,
+	usb_transfer_batch_t * request);
+
+static void create_interrupt_mask(rh_t *instance, void ** buffer,
+	size_t * buffer_size);
+
+static int process_get_descriptor_request(rh_t *instance,
+	usb_transfer_batch_t *request);
+
+static int process_get_configuration_request(rh_t *instance,
+	usb_transfer_batch_t *request);
+
+static int process_hub_feature_set_request(rh_t *instance, uint16_t feature);
+
+static int process_hub_feature_clear_request(rh_t *instance,
+	uint16_t feature);
+
+static int process_port_feature_set_request(rh_t *instance,
+	uint16_t feature, uint16_t port);
+
+static int process_port_feature_clear_request(rh_t *instance,
+	uint16_t feature, uint16_t port);
+
+static int process_address_set_request(rh_t *instance,
+	uint16_t address);
+
+static int process_request_with_output(rh_t *instance,
+	usb_transfer_batch_t *request);
+
+static int process_request_with_input(rh_t *instance,
+	usb_transfer_batch_t *request);
+
+static int process_request_without_data(rh_t *instance,
+	usb_transfer_batch_t *request);
+
+static int process_ctrl_request(rh_t *instance, usb_transfer_batch_t *request);
+
+
+
+
+
+/** Root hub initialization
+ * @return Error code.
+ */
+int rh_init(rh_t *instance, ddf_dev_t *dev, ohci_regs_t *regs) {
+	assert(instance);
+	//instance->address = -1;
+	instance->registers = regs;
+	instance->device = dev;
+	instance->port_count = instance->registers->rh_desc_a & 0xff;
+	rh_init_descriptors(instance);
+	// set port power mode to no-power-switching
+	instance->registers->rh_desc_a =
+		instance->registers->rh_desc_a | (1<<9);
+
+	usb_log_info("OHCI root hub with %d ports.\n", instance->port_count);
+
+	//start generic usb hub driver
+
+	/* TODO: implement */
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+
+/**
+ * process root hub request
+ *
+ * @param instance root hub instance
+ * @param request structure containing both request and response information
+ * @return error code
+ */
+int rh_request(rh_t *instance, usb_transfer_batch_t *request) {
+	assert(instance);
+	assert(request);
+	int opResult;
+	if (request->transfer_type == USB_TRANSFER_CONTROL) {
+		usb_log_info("Root hub got CONTROL packet\n");
+		opResult = process_ctrl_request(instance, request);
+	} else if (request->transfer_type == USB_TRANSFER_INTERRUPT) {
+		usb_log_info("Root hub got INTERRUPT packet\n");
+		void * buffer;
+		create_interrupt_mask(instance, &buffer,
+			&(request->transfered_size));
+		memcpy(request->transport_buffer, buffer,
+			request->transfered_size);
+		opResult = EOK;
+	} else {
+		opResult = EINVAL;
+	}
+	usb_transfer_batch_finish_error(request, opResult);
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+
+void rh_interrupt(rh_t *instance) {
+	usb_log_info("Whoa whoa wait, I`m not supposed to receive any "
+		"interrupts, am I?\n");
+	/* TODO: implement? */
+}
+/*----------------------------------------------------------------------------*/
 
 /**
@@ -157,14 +274,14 @@
  */
 static void usb_create_serialized_hub_descriptor(rh_t *instance,
-		uint8_t ** out_result,
-		size_t * out_size) {
+	uint8_t ** out_result,
+	size_t * out_size) {
 	//base size
 	size_t size = 7;
 	//variable size according to port count
 	size_t var_size = instance->port_count / 8 +
-			((instance->port_count % 8 > 0) ? 1 : 0);
+		((instance->port_count % 8 > 0) ? 1 : 0);
 	size += 2 * var_size;
 	uint8_t * result = (uint8_t*) malloc(size);
-	bzero(result,size);
+	bzero(result, size);
 	//size
 	result[0] = size;
@@ -174,9 +291,9 @@
 	uint32_t hub_desc_reg = instance->registers->rh_desc_a;
 	result[3] =
-			((hub_desc_reg >> 8) %2) +
-			(((hub_desc_reg >> 9) %2) << 1) +
-			(((hub_desc_reg >> 10) %2) << 2) +
-			(((hub_desc_reg >> 11) %2) << 3) +
-			(((hub_desc_reg >> 12) %2) << 4);
+		((hub_desc_reg >> 8) % 2) +
+		(((hub_desc_reg >> 9) % 2) << 1) +
+		(((hub_desc_reg >> 10) % 2) << 2) +
+		(((hub_desc_reg >> 11) % 2) << 3) +
+		(((hub_desc_reg >> 12) % 2) << 4);
 	result[4] = 0;
 	result[5] = /*descriptor->pwr_on_2_good_time*/ 50;
@@ -185,6 +302,8 @@
 	int port;
 	for (port = 1; port <= instance->port_count; ++port) {
-		result[7 + port/8] +=
-				((instance->registers->rh_desc_b >> port)%2) << (port%8);
+		uint8_t is_non_removable =
+			instance->registers->rh_desc_b >> port % 2;
+		result[7 + port / 8] +=
+			is_non_removable << (port % 8);
 	}
 	size_t i;
@@ -195,5 +314,5 @@
 	(*out_size) = size;
 }
-
+/*----------------------------------------------------------------------------*/
 
 /** initialize hub descriptors
@@ -203,60 +322,38 @@
  * @instance root hub instance
  */
-static void rh_init_descriptors(rh_t *instance){
+static void rh_init_descriptors(rh_t *instance) {
 	memcpy(&instance->descriptors.device, &ohci_rh_device_descriptor,
-		sizeof(ohci_rh_device_descriptor)
-	);
+		sizeof (ohci_rh_device_descriptor)
+		);
 	usb_standard_configuration_descriptor_t descriptor;
-	memcpy(&descriptor,&ohci_rh_conf_descriptor,
-			sizeof(ohci_rh_conf_descriptor));
+	memcpy(&descriptor, &ohci_rh_conf_descriptor,
+		sizeof (ohci_rh_conf_descriptor));
 	uint8_t * hub_descriptor;
 	size_t hub_desc_size;
 	usb_create_serialized_hub_descriptor(instance, &hub_descriptor,
-			&hub_desc_size);
+		&hub_desc_size);
 
 	descriptor.total_length =
-			sizeof(usb_standard_configuration_descriptor_t)+
-			sizeof(usb_standard_endpoint_descriptor_t)+
-			sizeof(usb_standard_interface_descriptor_t)+
-			hub_desc_size;
-	
+		sizeof (usb_standard_configuration_descriptor_t) +
+		sizeof (usb_standard_endpoint_descriptor_t) +
+		sizeof (usb_standard_interface_descriptor_t) +
+		hub_desc_size;
+
 	uint8_t * full_config_descriptor =
-			(uint8_t*) malloc(descriptor.total_length);
-	memcpy(full_config_descriptor, &descriptor, sizeof(descriptor));
-	memcpy(full_config_descriptor + sizeof(descriptor),
-			&ohci_rh_iface_descriptor, sizeof(ohci_rh_iface_descriptor));
-	memcpy(full_config_descriptor + sizeof(descriptor) +
-				sizeof(ohci_rh_iface_descriptor),
-			&ohci_rh_ep_descriptor, sizeof(ohci_rh_ep_descriptor));
-	memcpy(full_config_descriptor + sizeof(descriptor) +
-				sizeof(ohci_rh_iface_descriptor) +
-				sizeof(ohci_rh_ep_descriptor),
-			hub_descriptor, hub_desc_size);
-	
+		(uint8_t*) malloc(descriptor.total_length);
+	memcpy(full_config_descriptor, &descriptor, sizeof (descriptor));
+	memcpy(full_config_descriptor + sizeof (descriptor),
+		&ohci_rh_iface_descriptor, sizeof (ohci_rh_iface_descriptor));
+	memcpy(full_config_descriptor + sizeof (descriptor) +
+		sizeof (ohci_rh_iface_descriptor),
+		&ohci_rh_ep_descriptor, sizeof (ohci_rh_ep_descriptor));
+	memcpy(full_config_descriptor + sizeof (descriptor) +
+		sizeof (ohci_rh_iface_descriptor) +
+		sizeof (ohci_rh_ep_descriptor),
+		hub_descriptor, hub_desc_size);
+
 	instance->descriptors.configuration = full_config_descriptor;
 	instance->descriptors.configuration_size = descriptor.total_length;
 }
-
-/** Root hub initialization
- * @return Error code.
- */
-int rh_init(rh_t *instance, ddf_dev_t *dev, ohci_regs_t *regs)
-{
-	assert(instance);
-	instance->address = -1;
-	instance->registers = regs;
-	instance->device = dev;
-	instance->port_count = instance->registers->rh_desc_a & 0xff;
-	rh_init_descriptors(instance);
-	/// \TODO set port power mode
-
-
-	usb_log_info("OHCI root hub with %d ports.\n", instance->port_count);
-
-	//start generic usb hub driver
-	
-	/* TODO: implement */
-	return EOK;
-}
 /*----------------------------------------------------------------------------*/
 
@@ -272,12 +369,21 @@
  */
 static int process_get_port_status_request(rh_t *instance, uint16_t port,
-		usb_transfer_batch_t * request){
-	if(port<1 || port>instance->port_count)
-		return EINVAL;
-	uint32_t * uint32_buffer = (uint32_t*)request->transport_buffer;
+	usb_transfer_batch_t * request) {
+	if (port < 1 || port > instance->port_count)
+		return EINVAL;
+	uint32_t * uint32_buffer = (uint32_t*) request->transport_buffer;
 	request->transfered_size = 4;
-	uint32_buffer[0] = instance->registers->rh_port_status[port -1];
-	return EOK;
-}
+	uint32_buffer[0] = instance->registers->rh_port_status[port - 1];
+#if 0
+	int i;
+	for (i = 0; i < instance->port_count; ++i) {
+		usb_log_debug("port status %d,x%x\n",
+			instance->registers->rh_port_status[i],
+			instance->registers->rh_port_status[i]);
+	}
+#endif
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
 
 /**
@@ -291,15 +397,13 @@
  */
 static int process_get_hub_status_request(rh_t *instance,
-		usb_transfer_batch_t * request){
-	uint32_t * uint32_buffer = (uint32_t*)request->transport_buffer;
+	usb_transfer_batch_t * request) {
+	uint32_t * uint32_buffer = (uint32_t*) request->transport_buffer;
+	request->transfered_size = 4;
 	//bits, 0,1,16,17
-	request->transfered_size = 4;
-	uint32_t mask = 1 & (1<<1) & (1<<16) & (1<<17);
+	uint32_t mask = 1 | (1 << 1) | (1 << 16) | (1 << 17);
 	uint32_buffer[0] = mask & instance->registers->rh_status;
 	return EOK;
-
-}
-
-
+}
+/*----------------------------------------------------------------------------*/
 
 /**
@@ -313,24 +417,25 @@
  */
 static int process_get_status_request(rh_t *instance,
-		usb_transfer_batch_t * request)
-{
+	usb_transfer_batch_t * request) {
 	size_t buffer_size = request->buffer_size;
 	usb_device_request_setup_packet_t * request_packet =
-			(usb_device_request_setup_packet_t*)
-			request->setup_buffer;
+		(usb_device_request_setup_packet_t*)
+		request->setup_buffer;
 
 	usb_hub_bm_request_type_t request_type = request_packet->request_type;
-	if(buffer_size<4/*request_packet->length*/){///\TODO
+	if (buffer_size < 4/*request_packet->length*/) {///\TODO
 		usb_log_warning("requested more data than buffer size\n");
 		return EINVAL;
 	}
 
-	if(request_type == USB_HUB_REQ_TYPE_GET_HUB_STATUS)
+	if (request_type == USB_HUB_REQ_TYPE_GET_HUB_STATUS)
 		return process_get_hub_status_request(instance, request);
-	if(request_type == USB_HUB_REQ_TYPE_GET_PORT_STATUS)
-		return process_get_port_status_request(instance, request_packet->index,
-				request);
+	if (request_type == USB_HUB_REQ_TYPE_GET_PORT_STATUS)
+		return process_get_port_status_request(instance,
+		request_packet->index,
+		request);
 	return ENOTSUP;
 }
+/*----------------------------------------------------------------------------*/
 
 /**
@@ -339,5 +444,6 @@
  * Result contains bitmap where bit 0 indicates change on hub and
  * bit i indicates change on i`th port (i>0). For more info see
- * Hub and Port status bitmap specification in USB specification.
+ * Hub and Port status bitmap specification in USB specification
+ * (chapter 11.13.4)
  * @param instance root hub instance
  * @param@out buffer pointer to created interrupt mas
@@ -345,26 +451,26 @@
  */
 static void create_interrupt_mask(rh_t *instance, void ** buffer,
-		size_t * buffer_size){
+	size_t * buffer_size) {
 	int bit_count = instance->port_count + 1;
-	(*buffer_size) = (bit_count / 8) + (bit_count%8==0)?0:1;
+	(*buffer_size) = (bit_count / 8) + ((bit_count % 8 == 0) ? 0 : 1);
+
 	(*buffer) = malloc(*buffer_size);
-	uint8_t * bitmap = (uint8_t*)(*buffer);
-	uint32_t mask = (1<<16) + (1<<17);
-	bzero(bitmap,(*buffer_size));
-	if(instance->registers->rh_status & mask){
+	uint8_t * bitmap = (uint8_t*) (*buffer);
+	uint32_t mask = (1 << (USB_HUB_FEATURE_C_HUB_LOCAL_POWER + 16))
+		| (1 << (USB_HUB_FEATURE_C_HUB_OVER_CURRENT + 16));
+	bzero(bitmap, (*buffer_size));
+	if (instance->registers->rh_status & mask) {
 		bitmap[0] = 1;
 	}
 	int port;
-	mask = 0;
-	int i;
-	for(i=16;i<=20;++i)
-		mask += 1<<i;
-	for(port = 1; port<=instance->port_count;++port){
-		if(mask & instance->registers->rh_port_status[port-1]){
-			bitmap[(port+1)/8] += 1<<(port%8);
-		}
-	}
-}
- 
+	mask = port_status_change_mask;
+	for (port = 1; port <= instance->port_count; ++port) {
+		if (mask & instance->registers->rh_port_status[port - 1]) {
+			bitmap[(port) / 8] += 1 << (port % 8);
+		}
+	}
+}
+/*----------------------------------------------------------------------------*/
+
 /**
  * create answer to a descriptor request
@@ -377,29 +483,31 @@
  */
 static int process_get_descriptor_request(rh_t *instance,
-		usb_transfer_batch_t *request){
+	usb_transfer_batch_t *request) {
 	usb_device_request_setup_packet_t * setup_request =
-			(usb_device_request_setup_packet_t*)request->setup_buffer;
+		(usb_device_request_setup_packet_t*) request->setup_buffer;
 	size_t size;
 	const void * result_descriptor = NULL;
 	const uint16_t setup_request_value = setup_request->value_high;
-			//(setup_request->value_low << 8);
+	//(setup_request->value_low << 8);
 	bool del = false;
-	switch (setup_request_value)
-	{
-		case USB_DESCTYPE_HUB: {
+	switch (setup_request_value) {
+		case USB_DESCTYPE_HUB:
+		{
 			uint8_t * descriptor;
 			usb_create_serialized_hub_descriptor(
 				instance, &descriptor, &size);
 			result_descriptor = descriptor;
-			if(result_descriptor) del = true;
+			if (result_descriptor) del = true;
 			break;
 		}
-		case USB_DESCTYPE_DEVICE: {
+		case USB_DESCTYPE_DEVICE:
+		{
 			usb_log_debug("USB_DESCTYPE_DEVICE\n");
 			result_descriptor = &ohci_rh_device_descriptor;
-			size = sizeof(ohci_rh_device_descriptor);
+			size = sizeof (ohci_rh_device_descriptor);
 			break;
 		}
-		case USB_DESCTYPE_CONFIGURATION: {
+		case USB_DESCTYPE_CONFIGURATION:
+		{
 			usb_log_debug("USB_DESCTYPE_CONFIGURATION\n");
 			result_descriptor = instance->descriptors.configuration;
@@ -407,39 +515,43 @@
 			break;
 		}
-		case USB_DESCTYPE_INTERFACE: {
+		case USB_DESCTYPE_INTERFACE:
+		{
 			usb_log_debug("USB_DESCTYPE_INTERFACE\n");
 			result_descriptor = &ohci_rh_iface_descriptor;
-			size = sizeof(ohci_rh_iface_descriptor);
+			size = sizeof (ohci_rh_iface_descriptor);
 			break;
 		}
-		case USB_DESCTYPE_ENDPOINT: {
+		case USB_DESCTYPE_ENDPOINT:
+		{
 			usb_log_debug("USB_DESCTYPE_ENDPOINT\n");
 			result_descriptor = &ohci_rh_ep_descriptor;
-			size = sizeof(ohci_rh_ep_descriptor);
+			size = sizeof (ohci_rh_ep_descriptor);
 			break;
 		}
-		default: {
-			usb_log_debug("USB_DESCTYPE_EINVAL %d \n",setup_request->value);
-			usb_log_debug("\ttype %d\n\trequest %d\n\tvalue %d\n\tindex %d\n\tlen %d\n ",
-					setup_request->request_type,
-					setup_request->request,
-					setup_request_value,
-					setup_request->index,
-					setup_request->length
-					);
+		default:
+		{
+			usb_log_debug("USB_DESCTYPE_EINVAL %d \n",
+				setup_request->value);
+			usb_log_debug("\ttype %d\n\trequest %d\n\tvalue "
+				"%d\n\tindex %d\n\tlen %d\n ",
+				setup_request->request_type,
+				setup_request->request,
+				setup_request_value,
+				setup_request->index,
+				setup_request->length
+				);
 			return EINVAL;
 		}
 	}
-	if(request->buffer_size < size){
+	if (request->buffer_size < size) {
 		size = request->buffer_size;
 	}
 	request->transfered_size = size;
-	memcpy(request->transport_buffer,result_descriptor,size);
-	usb_log_debug("sent desctiptor: %s\n",
-			usb_debug_str_buffer((uint8_t*)request->transport_buffer,size,size));
+	memcpy(request->transport_buffer, result_descriptor, size);
 	if (del)
 		free(result_descriptor);
 	return EOK;
 }
+/*----------------------------------------------------------------------------*/
 
 /**
@@ -451,9 +563,9 @@
  * @return error code
  */
-static int process_get_configuration_request(rh_t *instance, 
-		usb_transfer_batch_t *request){
+static int process_get_configuration_request(rh_t *instance,
+	usb_transfer_batch_t *request) {
 	//set and get configuration requests do not have any meaning, only dummy
 	//values are returned
-	if(request->buffer_size != 1)
+	if (request->buffer_size != 1)
 		return EINVAL;
 	request->transport_buffer[0] = 1;
@@ -461,8 +573,9 @@
 	return EOK;
 }
+/*----------------------------------------------------------------------------*/
 
 /**
  * process feature-enabling request on hub
- * 
+ *
  * @param instance root hub instance
  * @param feature feature selector
@@ -470,12 +583,13 @@
  */
 static int process_hub_feature_set_request(rh_t *instance,
-		uint16_t feature){
-	if(! ((1<<feature) & hub_set_feature_valid_mask))
+	uint16_t feature) {
+	if (!((1 << feature) & hub_set_feature_valid_mask))
 		return EINVAL;
 	instance->registers->rh_status =
-			(instance->registers->rh_status | (1<<feature))
-			& (~ hub_clear_feature_by_writing_one_mask);
-	return EOK;
-}
+		(instance->registers->rh_status | (1 << feature))
+		& (~hub_clear_feature_by_writing_one_mask);
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
 
 /**
@@ -487,26 +601,25 @@
  */
 static int process_hub_feature_clear_request(rh_t *instance,
-		uint16_t feature){
-	if(! ((1<<feature) & hub_clear_feature_valid_mask))
+	uint16_t feature) {
+	if (!((1 << feature) & hub_clear_feature_valid_mask))
 		return EINVAL;
 	//is the feature cleared directly?
-	if ((1<<feature) & hub_set_feature_direct_mask){
+	if ((1 << feature) & hub_set_feature_direct_mask) {
 		instance->registers->rh_status =
-			(instance->registers->rh_status & (~(1<<feature)))
-			& (~ hub_clear_feature_by_writing_one_mask);
-	}else{//the feature is cleared by writing '1'
+			(instance->registers->rh_status & (~(1 << feature)))
+			& (~hub_clear_feature_by_writing_one_mask);
+	} else {//the feature is cleared by writing '1'
 		instance->registers->rh_status =
-				(instance->registers->rh_status
-				& (~ hub_clear_feature_by_writing_one_mask))
-				| (1<<feature);
-	}
-	return EOK;
-}
-
-
+			(instance->registers->rh_status
+			& (~hub_clear_feature_by_writing_one_mask))
+			| (1 << feature);
+	}
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
 
 /**
  * process feature-enabling request on hub
- * 
+ *
  * @param instance root hub instance
  * @param feature feature selector
@@ -516,15 +629,16 @@
  */
 static int process_port_feature_set_request(rh_t *instance,
-		uint16_t feature, uint16_t port){
-	if(!((1<<feature) & port_set_feature_valid_mask))
-		return EINVAL;
-	if(port<1 || port>instance->port_count)
+	uint16_t feature, uint16_t port) {
+	if (!((1 << feature) & port_set_feature_valid_mask))
+		return EINVAL;
+	if (port < 1 || port > instance->port_count)
 		return EINVAL;
 	instance->registers->rh_port_status[port - 1] =
-			(instance->registers->rh_port_status[port - 1] | (1<<feature))
-			& (~port_clear_feature_valid_mask);
+		(instance->registers->rh_port_status[port - 1] | (1 << feature))
+		& (~port_clear_feature_valid_mask);
 	/// \TODO any error?
 	return EOK;
 }
+/*----------------------------------------------------------------------------*/
 
 /**
@@ -538,25 +652,25 @@
  */
 static int process_port_feature_clear_request(rh_t *instance,
-		uint16_t feature, uint16_t port){
-	if(!((1<<feature) & port_clear_feature_valid_mask))
-		return EINVAL;
-	if(port<1 || port>instance->port_count)
-		return EINVAL;
-	if(feature == USB_HUB_FEATURE_PORT_POWER)
+	uint16_t feature, uint16_t port) {
+	if (!((1 << feature) & port_clear_feature_valid_mask))
+		return EINVAL;
+	if (port < 1 || port > instance->port_count)
+		return EINVAL;
+	if (feature == USB_HUB_FEATURE_PORT_POWER)
 		feature = USB_HUB_FEATURE_PORT_LOW_SPEED;
-	if(feature == USB_HUB_FEATURE_PORT_SUSPEND)
+	if (feature == USB_HUB_FEATURE_PORT_SUSPEND)
 		feature = USB_HUB_FEATURE_PORT_OVER_CURRENT;
 	instance->registers->rh_port_status[port - 1] =
-			(instance->registers->rh_port_status[port - 1] 
-			& (~port_clear_feature_valid_mask))
-			| (1<<feature);
+		(instance->registers->rh_port_status[port - 1]
+		& (~port_clear_feature_valid_mask))
+		| (1 << feature);
 	/// \TODO any error?
 	return EOK;
 }
-
+/*----------------------------------------------------------------------------*/
 
 /**
  * register address to this device
- * 
+ *
  * @param instance root hub instance
  * @param address new address
@@ -564,8 +678,9 @@
  */
 static int process_address_set_request(rh_t *instance,
-		uint16_t address){
+	uint16_t address) {
 	instance->address = address;
 	return EOK;
 }
+/*----------------------------------------------------------------------------*/
 
 /**
@@ -579,16 +694,16 @@
  */
 static int process_request_with_output(rh_t *instance,
-		usb_transfer_batch_t *request){
+	usb_transfer_batch_t *request) {
 	usb_device_request_setup_packet_t * setup_request =
-			(usb_device_request_setup_packet_t*)request->setup_buffer;
-	if(setup_request->request == USB_DEVREQ_GET_STATUS){
+		(usb_device_request_setup_packet_t*) request->setup_buffer;
+	if (setup_request->request == USB_DEVREQ_GET_STATUS) {
 		usb_log_debug("USB_DEVREQ_GET_STATUS\n");
 		return process_get_status_request(instance, request);
 	}
-	if(setup_request->request == USB_DEVREQ_GET_DESCRIPTOR){
+	if (setup_request->request == USB_DEVREQ_GET_DESCRIPTOR) {
 		usb_log_debug("USB_DEVREQ_GET_DESCRIPTOR\n");
 		return process_get_descriptor_request(instance, request);
 	}
-	if(setup_request->request == USB_DEVREQ_GET_CONFIGURATION){
+	if (setup_request->request == USB_DEVREQ_GET_CONFIGURATION) {
 		usb_log_debug("USB_DEVREQ_GET_CONFIGURATION\n");
 		return process_get_configuration_request(instance, request);
@@ -596,4 +711,5 @@
 	return ENOTSUP;
 }
+/*----------------------------------------------------------------------------*/
 
 /**
@@ -607,12 +723,12 @@
  */
 static int process_request_with_input(rh_t *instance,
-		usb_transfer_batch_t *request){
+	usb_transfer_batch_t *request) {
 	usb_device_request_setup_packet_t * setup_request =
-			(usb_device_request_setup_packet_t*)request->setup_buffer;
+		(usb_device_request_setup_packet_t*) request->setup_buffer;
 	request->transfered_size = 0;
-	if(setup_request->request == USB_DEVREQ_SET_DESCRIPTOR){
+	if (setup_request->request == USB_DEVREQ_SET_DESCRIPTOR) {
 		return ENOTSUP;
 	}
-	if(setup_request->request == USB_DEVREQ_SET_CONFIGURATION){
+	if (setup_request->request == USB_DEVREQ_SET_CONFIGURATION) {
 		//set and get configuration requests do not have any meaning,
 		//only dummy values are returned
@@ -621,4 +737,5 @@
 	return ENOTSUP;
 }
+/*----------------------------------------------------------------------------*/
 
 /**
@@ -632,46 +749,50 @@
  */
 static int process_request_without_data(rh_t *instance,
-		usb_transfer_batch_t *request){
+	usb_transfer_batch_t *request) {
 	usb_device_request_setup_packet_t * setup_request =
-			(usb_device_request_setup_packet_t*)request->setup_buffer;
+		(usb_device_request_setup_packet_t*) request->setup_buffer;
 	request->transfered_size = 0;
-	if(setup_request->request == USB_DEVREQ_CLEAR_FEATURE){
-		if(setup_request->request_type == USB_HUB_REQ_TYPE_SET_HUB_FEATURE){
+	if (setup_request->request == USB_DEVREQ_CLEAR_FEATURE) {
+		if (setup_request->request_type == USB_HUB_REQ_TYPE_SET_HUB_FEATURE) {
 			usb_log_debug("USB_HUB_REQ_TYPE_SET_HUB_FEATURE\n");
 			return process_hub_feature_clear_request(instance,
-					setup_request->value);
-		}
-		if(setup_request->request_type == USB_HUB_REQ_TYPE_SET_PORT_FEATURE){
+				setup_request->value);
+		}
+		if (setup_request->request_type == USB_HUB_REQ_TYPE_SET_PORT_FEATURE) {
 			usb_log_debug("USB_HUB_REQ_TYPE_SET_PORT_FEATURE\n");
 			return process_port_feature_clear_request(instance,
-					setup_request->value,
-					setup_request->index);
+				setup_request->value,
+				setup_request->index);
 		}
 		usb_log_debug("USB_HUB_REQ_TYPE_INVALID %d\n",
-				setup_request->request_type);
-		return EINVAL;
-	}
-	if(setup_request->request == USB_DEVREQ_SET_FEATURE){
-		if(setup_request->request_type == USB_HUB_REQ_TYPE_SET_HUB_FEATURE){
+			setup_request->request_type);
+		return EINVAL;
+	}
+	if (setup_request->request == USB_DEVREQ_SET_FEATURE) {
+		if (setup_request->request_type == USB_HUB_REQ_TYPE_SET_HUB_FEATURE) {
 			usb_log_debug("USB_HUB_REQ_TYPE_SET_HUB_FEATURE\n");
 			return process_hub_feature_set_request(instance,
-					setup_request->value);
-		}
-		if(setup_request->request_type == USB_HUB_REQ_TYPE_SET_PORT_FEATURE){
+				setup_request->value);
+		}
+		if (setup_request->request_type == USB_HUB_REQ_TYPE_SET_PORT_FEATURE) {
 			usb_log_debug("USB_HUB_REQ_TYPE_SET_PORT_FEATURE\n");
 			return process_port_feature_set_request(instance,
-					setup_request->value,
-					setup_request->index);
-		}
-		usb_log_debug("USB_HUB_REQ_TYPE_INVALID %d\n",setup_request->request_type);
-		return EINVAL;
-	}
-	if(setup_request->request == USB_DEVREQ_SET_ADDRESS){
+				setup_request->value,
+				setup_request->index);
+		}
+		usb_log_debug("USB_HUB_REQ_TYPE_INVALID %d\n",
+			setup_request->request_type);
+		return EINVAL;
+	}
+	if (setup_request->request == USB_DEVREQ_SET_ADDRESS) {
 		usb_log_debug("USB_DEVREQ_SET_ADDRESS\n");
-		return process_address_set_request(instance, setup_request->value);
-	}
-	usb_log_debug("USB_DEVREQ_SET_ENOTSUP %d\n",setup_request->request_type);
+		return process_address_set_request(instance,
+			setup_request->value);
+	}
+	usb_log_debug("USB_DEVREQ_SET_ENOTSUP %d\n",
+		setup_request->request_type);
 	return ENOTSUP;
 }
+/*----------------------------------------------------------------------------*/
 
 /**
@@ -693,43 +814,49 @@
  * @return error code
  */
-static int process_ctrl_request(rh_t *instance, usb_transfer_batch_t *request){
+static int process_ctrl_request(rh_t *instance, usb_transfer_batch_t *request) {
+	if (!request->setup_buffer) {
+		usb_log_error("root hub received empty transaction?");
+		return EINVAL;
+	}
 	int opResult;
-	if (request->setup_buffer) {
-		if(sizeof(usb_device_request_setup_packet_t)>request->setup_size){
-			usb_log_error("setup packet too small\n");
-			return EINVAL;
-		}
-		usb_log_info("CTRL packet: %s.\n",
-			usb_debug_str_buffer((const uint8_t *)request->setup_buffer, 8, 8));
-		usb_device_request_setup_packet_t * setup_request =
-				(usb_device_request_setup_packet_t*)request->setup_buffer;
-		if(
-			setup_request->request == USB_DEVREQ_GET_STATUS
-			|| setup_request->request == USB_DEVREQ_GET_DESCRIPTOR
-			|| setup_request->request == USB_DEVREQ_GET_CONFIGURATION
-		){
+	if (sizeof (usb_device_request_setup_packet_t) > request->setup_size) {
+		usb_log_error("setup packet too small\n");
+		return EINVAL;
+	}
+	usb_log_info("CTRL packet: %s.\n",
+		usb_debug_str_buffer(
+		(const uint8_t *) request->setup_buffer, 8, 8));
+	usb_device_request_setup_packet_t * setup_request =
+		(usb_device_request_setup_packet_t*)
+		request->setup_buffer;
+	switch (setup_request->request) {
+		case USB_DEVREQ_GET_STATUS:
+		case USB_DEVREQ_GET_DESCRIPTOR:
+		case USB_DEVREQ_GET_CONFIGURATION:
 			usb_log_debug("processing request with output\n");
-			opResult = process_request_with_output(instance,request);
-		}else if(
-			setup_request->request == USB_DEVREQ_CLEAR_FEATURE
-			|| setup_request->request == USB_DEVREQ_SET_FEATURE
-			|| setup_request->request == USB_DEVREQ_SET_ADDRESS
-		){
-			usb_log_debug("processing request without additional data\n");
-			opResult = process_request_without_data(instance,request);
-		}else if(setup_request->request == USB_DEVREQ_SET_DESCRIPTOR
-				|| setup_request->request == USB_DEVREQ_SET_CONFIGURATION
-		){
-			usb_log_debug("processing request with input\n");
-			opResult = process_request_with_input(instance,request);
-		}else{
-			usb_log_warning("received unsuported request: %d\n",
-					setup_request->request
-					);
+			opResult = process_request_with_output(
+				instance, request);
+			break;
+		case USB_DEVREQ_CLEAR_FEATURE:
+		case USB_DEVREQ_SET_FEATURE:
+		case USB_DEVREQ_SET_ADDRESS:
+			usb_log_debug("processing request without "
+				"additional data\n");
+			opResult = process_request_without_data(
+				instance, request);
+			break;
+		case USB_DEVREQ_SET_DESCRIPTOR:
+		case USB_DEVREQ_SET_CONFIGURATION:
+			usb_log_debug("processing request with "
+				"input\n");
+			opResult = process_request_with_input(
+				instance, request);
+			break;
+		default:
+			usb_log_warning("received unsuported request: "
+				"%d\n",
+				setup_request->request
+				);
 			opResult = ENOTSUP;
-		}
-	}else{
-		usb_log_error("root hub received empty transaction?");
-		opResult = EINVAL;
 	}
 	return opResult;
@@ -737,40 +864,4 @@
 
 /**
- * process root hub request
- *
- * @param instance root hub instance
- * @param request structure containing both request and response information
- * @return error code
- */
-int rh_request(rh_t *instance, usb_transfer_batch_t *request)
-{
-	assert(instance);
-	assert(request);
-	int opResult;
-	if(request->transfer_type == USB_TRANSFER_CONTROL){
-		usb_log_info("Root hub got CONTROL packet\n");
-		opResult = process_ctrl_request(instance,request);
-	}else if(request->transfer_type == USB_TRANSFER_INTERRUPT){
-		usb_log_info("Root hub got INTERRUPT packet\n");
-		void * buffer;
-		create_interrupt_mask(instance, &buffer,
-			&(request->transfered_size));
-		memcpy(request->transport_buffer,buffer, request->transfered_size);
-		opResult = EOK;
-	}else{
-		opResult = EINVAL;
-	}
-	usb_transfer_batch_finish(request, opResult);
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-
-
-void rh_interrupt(rh_t *instance)
-{
-	usb_log_info("Whoa whoa wait, I`m not supposed to receive any interrupts, am I?\n");
-	/* TODO: implement? */
-}
-/**
  * @}
  */
Index: uspace/drv/uhci-hcd/batch.c
===================================================================
--- uspace/drv/uhci-hcd/batch.c	(revision 7dfc06fa1782dda3da24feb0e244e9bfadcc016e)
+++ uspace/drv/uhci-hcd/batch.c	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -80,12 +80,10 @@
  * transaction and callback.
  */
-usb_transfer_batch_t * batch_get(ddf_fun_t *fun, usb_target_t target,
-    usb_transfer_type_t transfer_type, size_t max_packet_size,
-    usb_speed_t speed, char *buffer, size_t buffer_size,
-    char* setup_buffer, size_t setup_size,
+usb_transfer_batch_t * batch_get(ddf_fun_t *fun, endpoint_t *ep,
+    char *buffer, size_t buffer_size, char* setup_buffer, size_t setup_size,
     usbhc_iface_transfer_in_callback_t func_in,
-    usbhc_iface_transfer_out_callback_t func_out, void *arg, endpoint_t *ep
-    )
-{
+    usbhc_iface_transfer_out_callback_t func_out, void *arg)
+{
+	assert(ep);
 	assert(func_in == NULL || func_out == NULL);
 	assert(func_in != NULL || func_out != NULL);
@@ -103,6 +101,8 @@
 	CHECK_NULL_DISPOSE_RETURN(instance,
 	    "Failed to allocate batch instance.\n");
+	usb_target_t target =
+	    { .address = ep->address, .endpoint = ep->endpoint };
 	usb_transfer_batch_init(instance, target,
-	    transfer_type, speed, max_packet_size,
+	    ep->transfer_type, ep->speed, ep->max_packet_size,
 	    buffer, NULL, buffer_size, NULL, setup_size, func_in,
 	    func_out, arg, fun, ep, NULL);
@@ -115,6 +115,7 @@
 	instance->private_data = data;
 
-	data->transfers = (buffer_size + max_packet_size - 1) / max_packet_size;
-	if (transfer_type == USB_TRANSFER_CONTROL) {
+	data->transfers =
+	    (buffer_size + ep->max_packet_size - 1) / ep->max_packet_size;
+	if (ep->transfer_type == USB_TRANSFER_CONTROL) {
 		data->transfers += 2;
 	}
@@ -178,7 +179,8 @@
 			    instance, i, data->tds[i].status);
 			td_print_status(&data->tds[i]);
-			if (instance->ep != NULL)
-				endpoint_toggle_set(instance->ep,
-				    td_toggle(&data->tds[i]));
+			assert(instance->ep != NULL);
+
+			endpoint_toggle_set(instance->ep,
+			    td_toggle(&data->tds[i]));
 			if (i > 0)
 				goto substract_ret;
Index: uspace/drv/uhci-hcd/batch.h
===================================================================
--- uspace/drv/uhci-hcd/batch.h	(revision 7dfc06fa1782dda3da24feb0e244e9bfadcc016e)
+++ uspace/drv/uhci-hcd/batch.h	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -44,18 +44,9 @@
 
 usb_transfer_batch_t * batch_get(
-    ddf_fun_t *fun,
-		usb_target_t target,
-    usb_transfer_type_t transfer_type,
-		size_t max_packet_size,
-    usb_speed_t speed,
-		char *buffer,
-		size_t size,
-		char *setup_buffer,
-		size_t setup_size,
+    ddf_fun_t *fun, endpoint_t *ep, char *buffer, size_t size,
+    char *setup_buffer, size_t setup_size,
     usbhc_iface_transfer_in_callback_t func_in,
     usbhc_iface_transfer_out_callback_t func_out,
-		void *arg,
-		endpoint_t *ep
-		);
+    void *arg);
 
 void batch_dispose(usb_transfer_batch_t *instance);
Index: uspace/drv/uhci-hcd/hc.c
===================================================================
--- uspace/drv/uhci-hcd/hc.c	(revision 7dfc06fa1782dda3da24feb0e244e9bfadcc016e)
+++ uspace/drv/uhci-hcd/hc.c	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -332,8 +332,4 @@
 	    instance->transfers[batch->speed][batch->transfer_type];
 	assert(list);
-	if (batch->transfer_type == USB_TRANSFER_CONTROL) {
-		usb_device_keeper_use_control(
-		    &instance->manager, batch->target);
-	}
 	transfer_list_add_batch(list, batch);
 
@@ -373,27 +369,5 @@
 			usb_transfer_batch_t *batch =
 			    list_get_instance(item, usb_transfer_batch_t, link);
-			switch (batch->transfer_type)
-			{
-			case USB_TRANSFER_CONTROL:
-				usb_device_keeper_release_control(
-				    &instance->manager, batch->target);
-				break;
-			case USB_TRANSFER_INTERRUPT:
-			case USB_TRANSFER_ISOCHRONOUS: {
-/*
-				int ret = bandwidth_free(&instance->bandwidth,
-				    batch->target.address,
-				    batch->target.endpoint,
-				    batch->direction);
-				if (ret != EOK)
-					usb_log_warning("Failed(%d) to free "
-					    "reserved bw: %s.\n", ret,
-					    str_error(ret));
-*/
-				}
-			default:
-				break;
-			}
-			batch->next_step(batch);
+			usb_transfer_batch_finish(batch);
 		}
 	}
Index: uspace/drv/uhci-hcd/iface.c
===================================================================
--- uspace/drv/uhci-hcd/iface.c	(revision 7dfc06fa1782dda3da24feb0e244e9bfadcc016e)
+++ uspace/drv/uhci-hcd/iface.c	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -40,4 +40,51 @@
 #include "iface.h"
 #include "hc.h"
+
+static inline int setup_batch(
+    ddf_fun_t *fun, usb_target_t target, usb_direction_t direction,
+    void *data, size_t size, void * setup_data, size_t setup_size,
+    usbhc_iface_transfer_in_callback_t in,
+    usbhc_iface_transfer_out_callback_t out, void *arg, const char* name,
+    hc_t **hc, usb_transfer_batch_t **batch)
+{
+	assert(hc);
+	assert(batch);
+	assert(fun);
+	*hc = fun_to_hc(fun);
+	assert(*hc);
+
+	size_t res_bw;
+	endpoint_t *ep = usb_endpoint_manager_get_ep(&(*hc)->ep_manager,
+	    target.address, target.endpoint, direction, &res_bw);
+	if (ep == NULL) {
+		usb_log_error("Endpoint(%d:%d) not registered for %s.\n",
+		    target.address, target.endpoint, name);
+		return ENOENT;
+	}
+
+	const size_t bw = bandwidth_count_usb11(
+	    ep->speed, ep->transfer_type, size, ep->max_packet_size);
+	if (res_bw < bw) {
+		usb_log_error("Endpoint(%d:%d) %s needs %zu bw "
+		    "but only %zu is reserved.\n",
+		    name, target.address, target.endpoint, bw, res_bw);
+		return ENOSPC;
+	}
+	usb_log_debug("%s %d:%d %zu(%zu).\n",
+	    name, target.address, target.endpoint, size, ep->max_packet_size);
+
+	assert(ep->speed ==
+	    usb_device_keeper_get_speed(&(*hc)->manager, target.address));
+//	assert(ep->max_packet_size == max_packet_size);
+//	assert(ep->transfer_type == USB_TRANSFER_CONTROL);
+
+	*batch =
+	    batch_get(fun, ep, data, size, setup_data, setup_size,
+		in, out, arg);
+	if (!batch)
+		return ENOMEM;
+	return EOK;
+}
+
 
 /** Reserve default address interface function
@@ -214,39 +261,12 @@
     size_t size, usbhc_iface_transfer_out_callback_t callback, void *arg)
 {
-	assert(fun);
-	hc_t *hc = fun_to_hc(fun);
-	assert(hc);
-
-	usb_log_debug("Interrupt OUT %d:%d %zu.\n",
-	    target.address, target.endpoint, size);
-
-	size_t res_bw;
-	endpoint_t *ep = usb_endpoint_manager_get_ep(&hc->ep_manager,
-	    target.address, target.endpoint, USB_DIRECTION_OUT, &res_bw);
-	if (ep == NULL) {
-		usb_log_error("Endpoint(%d:%d) not registered for INT OUT.\n",
-			target.address, target.endpoint);
-		return ENOENT;
-	}
-	const size_t bw = bandwidth_count_usb11(ep->speed, ep->transfer_type,
-	    size, ep->max_packet_size);
-	if (res_bw < bw)
-	{
-		usb_log_error("Endpoint(%d:%d) INT IN needs %zu bw "
-		    "but only %zu is reserved.\n",
-		    target.address, target.endpoint, bw, res_bw);
-		return ENOENT;
-	}
-	assert(ep->speed ==
-	    usb_device_keeper_get_speed(&hc->manager, target.address));
-	assert(ep->transfer_type == USB_TRANSFER_INTERRUPT);
-
-	usb_transfer_batch_t *batch =
-	    batch_get(fun, target, ep->transfer_type, ep->max_packet_size,
-	        ep->speed, data, size, NULL, 0, NULL, callback, arg, ep);
-	if (!batch)
-		return ENOMEM;
+	usb_transfer_batch_t *batch = NULL;
+	hc_t *hc = NULL;
+	int ret = setup_batch(fun, target, USB_DIRECTION_OUT, data, size,
+	    NULL, 0, NULL, callback, arg, "Interrupt OUT", &hc, &batch);
+	if (ret != EOK)
+		return ret;
 	batch_interrupt_out(batch);
-	const int ret = hc_schedule(hc, batch);
+	ret = hc_schedule(hc, batch);
 	if (ret != EOK) {
 		batch_dispose(batch);
@@ -269,40 +289,12 @@
     size_t size, usbhc_iface_transfer_in_callback_t callback, void *arg)
 {
-	assert(fun);
-	hc_t *hc = fun_to_hc(fun);
-	assert(hc);
-
-	usb_log_debug("Interrupt IN %d:%d %zu.\n",
-	    target.address, target.endpoint, size);
-
-	size_t res_bw;
-	endpoint_t *ep = usb_endpoint_manager_get_ep(&hc->ep_manager,
-	    target.address, target.endpoint, USB_DIRECTION_IN, &res_bw);
-	if (ep == NULL) {
-		usb_log_error("Endpoint(%d:%d) not registered for INT IN.\n",
-		    target.address, target.endpoint);
-		return ENOENT;
-	}
-	const size_t bw = bandwidth_count_usb11(ep->speed, ep->transfer_type,
-	    size, ep->max_packet_size);
-	if (res_bw < bw)
-	{
-		usb_log_error("Endpoint(%d:%d) INT IN needs %zu bw "
-		    "but only %zu bw is reserved.\n",
-		    target.address, target.endpoint, bw, res_bw);
-		return ENOENT;
-	}
-
-	assert(ep->speed ==
-	    usb_device_keeper_get_speed(&hc->manager, target.address));
-	assert(ep->transfer_type == USB_TRANSFER_INTERRUPT);
-
-	usb_transfer_batch_t *batch =
-	    batch_get(fun, target, ep->transfer_type, ep->max_packet_size,
-	        ep->speed, data, size, NULL, 0, callback, NULL, arg, ep);
-	if (!batch)
-		return ENOMEM;
+	usb_transfer_batch_t *batch = NULL;
+	hc_t *hc = NULL;
+	int ret = setup_batch(fun, target, USB_DIRECTION_IN, data, size,
+	    NULL, 0, callback, NULL, arg, "Interrupt IN", &hc, &batch);
+	if (ret != EOK)
+		return ret;
 	batch_interrupt_in(batch);
-	const int ret = hc_schedule(hc, batch);
+	ret = hc_schedule(hc, batch);
 	if (ret != EOK) {
 		batch_dispose(batch);
@@ -325,29 +317,12 @@
     size_t size, usbhc_iface_transfer_out_callback_t callback, void *arg)
 {
-	assert(fun);
-	hc_t *hc = fun_to_hc(fun);
-	assert(hc);
-
-	usb_log_debug("Bulk OUT %d:%d %zu.\n",
-	    target.address, target.endpoint, size);
-
-	endpoint_t *ep = usb_endpoint_manager_get_ep(&hc->ep_manager,
-	    target.address, target.endpoint, USB_DIRECTION_OUT, NULL);
-	if (ep == NULL) {
-		usb_log_error("Endpoint(%d:%d) not registered for BULK OUT.\n",
-			target.address, target.endpoint);
-		return ENOENT;
-	}
-	assert(ep->speed ==
-	    usb_device_keeper_get_speed(&hc->manager, target.address));
-	assert(ep->transfer_type == USB_TRANSFER_BULK);
-
-	usb_transfer_batch_t *batch =
-	    batch_get(fun, target, ep->transfer_type, ep->max_packet_size,
-	        ep->speed, data, size, NULL, 0, NULL, callback, arg, ep);
-	if (!batch)
-		return ENOMEM;
+	usb_transfer_batch_t *batch = NULL;
+	hc_t *hc = NULL;
+	int ret = setup_batch(fun, target, USB_DIRECTION_OUT, data, size,
+	    NULL, 0, NULL, callback, arg, "Bulk OUT", &hc, &batch);
+	if (ret != EOK)
+		return ret;
 	batch_bulk_out(batch);
-	const int ret = hc_schedule(hc, batch);
+	ret = hc_schedule(hc, batch);
 	if (ret != EOK) {
 		batch_dispose(batch);
@@ -370,28 +345,12 @@
     size_t size, usbhc_iface_transfer_in_callback_t callback, void *arg)
 {
-	assert(fun);
-	hc_t *hc = fun_to_hc(fun);
-	assert(hc);
-	usb_log_debug("Bulk IN %d:%d %zu.\n",
-	    target.address, target.endpoint, size);
-
-	endpoint_t *ep = usb_endpoint_manager_get_ep(&hc->ep_manager,
-	    target.address, target.endpoint, USB_DIRECTION_IN, NULL);
-	if (ep == NULL) {
-		usb_log_error("Endpoint(%d:%d) not registered for BULK IN.\n",
-			target.address, target.endpoint);
-		return ENOENT;
-	}
-	assert(ep->speed ==
-	    usb_device_keeper_get_speed(&hc->manager, target.address));
-	assert(ep->transfer_type == USB_TRANSFER_BULK);
-
-	usb_transfer_batch_t *batch =
-	    batch_get(fun, target, ep->transfer_type, ep->max_packet_size,
-	        ep->speed, data, size, NULL, 0, callback, NULL, arg, ep);
-	if (!batch)
-		return ENOMEM;
+	usb_transfer_batch_t *batch = NULL;
+	hc_t *hc = NULL;
+	int ret = setup_batch(fun, target, USB_DIRECTION_IN, data, size,
+	    NULL, 0, callback, NULL, arg, "Bulk IN", &hc, &batch);
+	if (ret != EOK)
+		return ret;
 	batch_bulk_in(batch);
-	const int ret = hc_schedule(hc, batch);
+	ret = hc_schedule(hc, batch);
 	if (ret != EOK) {
 		batch_dispose(batch);
@@ -417,29 +376,14 @@
     usbhc_iface_transfer_out_callback_t callback, void *arg)
 {
-	assert(fun);
-	hc_t *hc = fun_to_hc(fun);
-	assert(hc);
-	usb_speed_t speed =
-	    usb_device_keeper_get_speed(&hc->manager, target.address);
-	usb_log_debug("Control WRITE (%d) %d:%d %zu.\n",
-	    speed, target.address, target.endpoint, size);
-	endpoint_t *ep = usb_endpoint_manager_get_ep(&hc->ep_manager,
-	    target.address, target.endpoint, USB_DIRECTION_BOTH, NULL);
-	if (ep == NULL) {
-		usb_log_warning("Endpoint(%d:%d) not registered for CONTROL.\n",
-			target.address, target.endpoint);
-	}
-
-	if (setup_size != 8)
-		return EINVAL;
-
-	usb_transfer_batch_t *batch =
-	    batch_get(fun, target, USB_TRANSFER_CONTROL, ep->max_packet_size, speed,
-	        data, size, setup_data, setup_size, NULL, callback, arg, ep);
-	if (!batch)
-		return ENOMEM;
+	usb_transfer_batch_t *batch = NULL;
+	hc_t *hc = NULL;
+	int ret = setup_batch(fun, target, USB_DIRECTION_BOTH, data, size,
+	    setup_data, setup_size, NULL, callback, arg, "Control WRITE",
+	    &hc, &batch);
+	if (ret != EOK)
+		return ret;
 	usb_device_keeper_reset_if_need(&hc->manager, target, setup_data);
 	batch_control_write(batch);
-	const int ret = hc_schedule(hc, batch);
+	ret = hc_schedule(hc, batch);
 	if (ret != EOK) {
 		batch_dispose(batch);
@@ -465,25 +409,13 @@
     usbhc_iface_transfer_in_callback_t callback, void *arg)
 {
-	assert(fun);
-	hc_t *hc = fun_to_hc(fun);
-	assert(hc);
-	usb_speed_t speed =
-	    usb_device_keeper_get_speed(&hc->manager, target.address);
-
-	usb_log_debug("Control READ(%d) %d:%d %zu.\n",
-	    speed, target.address, target.endpoint, size);
-	endpoint_t *ep = usb_endpoint_manager_get_ep(&hc->ep_manager,
-	    target.address, target.endpoint, USB_DIRECTION_BOTH, NULL);
-	if (ep == NULL) {
-		usb_log_warning("Endpoint(%d:%d) not registered for CONTROL.\n",
-			target.address, target.endpoint);
-	}
-	usb_transfer_batch_t *batch =
-	    batch_get(fun, target, USB_TRANSFER_CONTROL, ep->max_packet_size, speed,
-	        data, size, setup_data, setup_size, callback, NULL, arg, ep);
-	if (!batch)
-		return ENOMEM;
+	usb_transfer_batch_t *batch = NULL;
+	hc_t *hc = NULL;
+	int ret = setup_batch(fun, target, USB_DIRECTION_BOTH, data, size,
+	    setup_data, setup_size, callback, NULL, arg, "Control READ",
+	    &hc, &batch);
+	if (ret != EOK)
+		return ret;
 	batch_control_read(batch);
-	const int ret = hc_schedule(hc, batch);
+	ret = hc_schedule(hc, batch);
 	if (ret != EOK) {
 		batch_dispose(batch);
Index: uspace/drv/uhci-hcd/transfer_list.c
===================================================================
--- uspace/drv/uhci-hcd/transfer_list.c	(revision 7dfc06fa1782dda3da24feb0e244e9bfadcc016e)
+++ uspace/drv/uhci-hcd/transfer_list.c	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -132,12 +132,8 @@
 }
 /*----------------------------------------------------------------------------*/
-/** Check list for finished batches.
- *
- * @param[in] instance List to use.
- * @return Error code
- *
- * Creates a local list of finished batches and calls next_step on each and
- * every one. This is safer because next_step may theoretically access
- * this transfer list leading to the deadlock if its done inline.
+/** Create list for finished batches.
+ *
+ * @param[in] instance List to use.
+ * @param[in] done list to fill
  */
 void transfer_list_remove_finished(transfer_list_t *instance, link_t *done)
@@ -161,5 +157,4 @@
 	}
 	fibril_mutex_unlock(&instance->guard);
-
 }
 /*----------------------------------------------------------------------------*/
@@ -176,5 +171,5 @@
 		    list_get_instance(current, usb_transfer_batch_t, link);
 		transfer_list_remove_batch(instance, batch);
-		usb_transfer_batch_finish(batch, EIO);
+		usb_transfer_batch_finish_error(batch, EIO);
 	}
 	fibril_mutex_unlock(&instance->guard);
Index: uspace/drv/uhci-rhd/root_hub.h
===================================================================
--- uspace/drv/uhci-rhd/root_hub.h	(revision 7dfc06fa1782dda3da24feb0e244e9bfadcc016e)
+++ uspace/drv/uhci-rhd/root_hub.h	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -40,5 +40,5 @@
 
 #define UHCI_ROOT_HUB_PORT_COUNT 2
-#define ROOT_HUB_WAIT_USEC 5000000 /* 5 seconds */
+#define ROOT_HUB_WAIT_USEC 250000 /* 250 miliseconds */
 
 typedef struct root_hub {
Index: uspace/drv/usbhid/Makefile
===================================================================
--- uspace/drv/usbhid/Makefile	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
+++ uspace/drv/usbhid/Makefile	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -0,0 +1,55 @@
+#
+# Copyright (c) 2010-2011 Vojtech Horky
+# 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.
+#
+
+USPACE_PREFIX = ../..
+LIBS = $(LIBDRV_PREFIX)/libdrv.a $(LIBUSB_PREFIX)/libusb.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include -I$(LIBUSB_PREFIX)/include -I.
+BINARY = usbhid
+
+STOLEN_LAYOUT_SOURCES = \
+        kbd/layout/us_qwerty.c \
+        kbd/layout/us_dvorak.c \
+        kbd/layout/cz.c
+
+SOURCES = \
+	main.c \
+	usbhid.c \
+	kbd/conv.c \
+	kbd/kbddev.c \
+	kbd/kbdrepeat.c \
+	generic/hiddev.c \
+	$(STOLEN_LAYOUT_SOURCES)
+
+EXTRA_CLEAN = $(STOLEN_LAYOUT_SOURCES)
+
+SRV_KBD = $(USPACE_PREFIX)/srv/hid/kbd
+
+include $(USPACE_PREFIX)/Makefile.common
+
+kbd/layout/%.c: $(SRV_KBD)/layout/%.c
+	ln -sfn ../../$< $@
Index: uspace/drv/usbhid/generic/hiddev.c
===================================================================
--- uspace/drv/usbhid/generic/hiddev.c	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
+++ uspace/drv/usbhid/generic/hiddev.c	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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.
+ */
+
+/** @addtogroup drvusbhid
+ * @{
+ */
+/**
+ * @file
+ * USB HID driver API.
+ */
+
+#include <usb/debug.h>
+#include <usb/classes/classes.h>
+
+#include "hiddev.h"
+
+/*----------------------------------------------------------------------------*/
+
+usb_endpoint_description_t usb_hid_generic_poll_endpoint_description = {
+	.transfer_type = USB_TRANSFER_INTERRUPT,
+	.direction = USB_DIRECTION_IN,
+	.interface_class = USB_CLASS_HID,
+	.flags = 0
+};
+
+const char *HID_GENERIC_FUN_NAME = "hid";
+const char *HID_GENERIC_CLASS_NAME = "hid";
+
+/*----------------------------------------------------------------------------*/
+
+bool usb_hid_polling_callback(usb_device_t *dev, uint8_t *buffer,
+     size_t buffer_size, void *arg)
+{
+	usb_log_debug("usb_hid_polling_callback()\n");
+	usb_debug_str_buffer(buffer, buffer_size, 0);
+	return true;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/generic/hiddev.h
===================================================================
--- uspace/drv/usbhid/generic/hiddev.h	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
+++ uspace/drv/usbhid/generic/hiddev.h	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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.
+ */
+
+/** @addtogroup drvusbhid
+ * @{
+ */
+/** @file
+ * USB HID driver API.
+ */
+
+#ifndef USB_HIDD_H_
+#define USB_HIDD_H_
+
+#include <usb/devdrv.h>
+
+usb_endpoint_description_t usb_hid_generic_poll_endpoint_description;
+
+const char *HID_GENERIC_FUN_NAME;
+const char *HID_GENERIC_CLASS_NAME;
+
+bool usb_hid_polling_callback(usb_device_t *dev, uint8_t *buffer,
+     size_t buffer_size, void *arg);
+
+#endif // USB_HIDD_H_
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/kbd.h
===================================================================
--- uspace/drv/usbhid/kbd.h	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
+++ uspace/drv/usbhid/kbd.h	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -0,0 +1,5 @@
+/*
+ * Dummy file because of shared layout sources.
+ *
+ * Do not delete.
+ */
Index: uspace/drv/usbhid/kbd/conv.c
===================================================================
--- uspace/drv/usbhid/kbd/conv.c	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
+++ uspace/drv/usbhid/kbd/conv.c	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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.
+ */
+
+/** @addtogroup drvusbhid
+ * @{
+ */
+/** @file
+ * USB scancode parser.
+ */
+
+#include <io/keycode.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <usb/debug.h>
+#include "conv.h"
+
+/**
+ * Mapping between USB HID key codes (from HID Usage Tables) and corresponding
+ * HelenOS key codes.
+ */
+static int scanmap_simple[255] = {
+
+//	[0x29] = KC_BACKTICK,
+
+//	[0x02] = KC_1,
+//	[0x03] = KC_2,
+	[0x04] = KC_A,
+	[0x05] = KC_B,
+	[0x06] = KC_C,
+	[0x07] = KC_D,
+	[0x08] = KC_E,
+	[0x09] = KC_F,
+	[0x0a] = KC_G,
+	[0x0b] = KC_H,
+	[0x0c] = KC_I,
+	[0x0d] = KC_J,
+	[0x0e] = KC_K,
+	[0x0f] = KC_L,
+	[0x10] = KC_M,
+	[0x11] = KC_N,
+	[0x12] = KC_O,
+	[0x13] = KC_P,
+	[0x14] = KC_Q,
+	[0x15] = KC_R,
+	[0x16] = KC_S,
+	[0x17] = KC_T,
+	[0x18] = KC_U,
+	[0x19] = KC_V,
+	[0x1a] = KC_W,
+	[0x1b] = KC_X,
+	[0x1c] = KC_Y,
+	[0x1d] = KC_Z,
+
+	[0x1e] = KC_1,
+	[0x1f] = KC_2,
+	[0x20] = KC_3,
+	[0x21] = KC_4,
+	[0x22] = KC_5,
+	[0x23] = KC_6,
+	[0x24] = KC_7,
+	[0x25] = KC_8,
+	[0x26] = KC_9,
+	[0x27] = KC_0,
+	
+	[0x28] = KC_ENTER,
+	[0x29] = KC_ESCAPE,
+	[0x2a] = KC_BACKSPACE,
+	[0x2b] = KC_TAB,
+	[0x2c] = KC_SPACE,
+
+	[0x2d] = KC_MINUS,  // same as DASH? (- or _)
+	[0x2e] = KC_EQUALS,
+	[0x2f] = KC_LBRACKET,
+	[0x30] = KC_RBRACKET,
+	[0x31] = KC_BACKSLASH,
+	//[0x32] = KC_,	// TODO: HASH??? maybe some as 0x31 - backslash
+	[0x33] = KC_SEMICOLON,
+	[0x34] = KC_QUOTE,  // same as APOSTROPHE? (')
+	[0x35] = KC_BACKTICK,  // same as GRAVE ACCENT?? (`)
+	[0x36] = KC_COMMA,
+	[0x37] = KC_PERIOD,
+	[0x38] = KC_SLASH,
+
+	[0x39] = KC_CAPS_LOCK,
+	
+	[0x3a] = KC_F1,
+	[0x3b] = KC_F2,
+	[0x3c] = KC_F3,
+	[0x3d] = KC_F4,
+	[0x3e] = KC_F5,
+	[0x3f] = KC_F6,
+	[0x40] = KC_F7,
+	[0x41] = KC_F8,
+	[0x42] = KC_F9,
+	[0x43] = KC_F10,
+	[0x44] = KC_F11,
+	[0x45] = KC_F12,
+	
+	[0x46] = KC_PRTSCR,
+	[0x47] = KC_SCROLL_LOCK,
+	[0x48] = KC_PAUSE,
+	[0x49] = KC_INSERT,
+	[0x4a] = KC_HOME,
+	[0x4b] = KC_PAGE_UP,
+	[0x4c] = KC_DELETE,
+	[0x4d] = KC_END,
+	[0x4e] = KC_PAGE_DOWN,
+	[0x4f] = KC_RIGHT,
+	[0x50] = KC_LEFT,
+	[0x51] = KC_DOWN,
+	[0x52] = KC_UP,
+	
+	//[0x64] = // some funny key
+	
+	[0xe0] = KC_LCTRL,
+	[0xe1] = KC_LSHIFT,
+	[0xe2] = KC_LALT,
+	//[0xe3] = KC_L	// TODO: left GUI
+	[0xe4] = KC_RCTRL,
+	[0xe5] = KC_RSHIFT,
+	[0xe6] = KC_RALT,
+	//[0xe7] = KC_R	// TODO: right GUI
+	
+	[0x53] = KC_NUM_LOCK,
+	[0x54] = KC_NSLASH,
+	[0x55] = KC_NTIMES,
+	[0x56] = KC_NMINUS,
+	[0x57] = KC_NPLUS,
+	[0x58] = KC_NENTER,
+	[0x59] = KC_N1,
+	[0x5a] = KC_N2,
+	[0x5b] = KC_N3,
+	[0x5c] = KC_N4,
+	[0x5d] = KC_N5,
+	[0x5e] = KC_N6,
+	[0x5f] = KC_N7,
+	[0x60] = KC_N8,
+	[0x61] = KC_N9,
+	[0x62] = KC_N0,
+	[0x63] = KC_NPERIOD
+	
+};
+
+/**
+ * Translate USB HID key codes (from HID Usage Tables) to generic key codes
+ * recognized by HelenOS.
+ *
+ * @param scancode USB HID key code (from HID Usage Tables).
+ * 
+ * @retval HelenOS key code corresponding to the given USB HID key code.
+ */
+unsigned int usbhid_parse_scancode(int scancode)
+{
+	unsigned int key;
+	int *map = scanmap_simple;
+	size_t map_length = sizeof(scanmap_simple) / sizeof(int);
+
+	if ((scancode < 0) || ((size_t) scancode >= map_length))
+		return -1;
+
+	key = map[scancode];
+	
+	return key;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/kbd/conv.h
===================================================================
--- uspace/drv/usbhid/kbd/conv.h	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
+++ uspace/drv/usbhid/kbd/conv.h	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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.
+ */
+
+/** @addtogroup drvusbhid
+ * @{
+ */
+/** @file
+ * USB scancode parser.
+ */
+
+#ifndef USB_KBD_CONV_H_
+#define USB_KBD_CONV_H_
+
+unsigned int usbhid_parse_scancode(int scancode);
+
+#endif /* USB_KBD_CONV_H_ */
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/kbd/kbddev.c
===================================================================
--- uspace/drv/usbhid/kbd/kbddev.c	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
+++ uspace/drv/usbhid/kbd/kbddev.c	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -0,0 +1,962 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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.
+ */
+
+/** @addtogroup drvusbhid
+ * @{
+ */
+/**
+ * @file
+ * USB HID keyboard device structure and API.
+ */
+
+#include <errno.h>
+#include <str_error.h>
+#include <stdio.h>
+
+#include <io/keycode.h>
+#include <ipc/kbd.h>
+#include <async.h>
+#include <fibril.h>
+#include <fibril_synch.h>
+
+#include <usb/usb.h>
+#include <usb/dp.h>
+#include <usb/request.h>
+#include <usb/classes/hid.h>
+#include <usb/pipes.h>
+#include <usb/debug.h>
+#include <usb/classes/hidparser.h>
+#include <usb/classes/classes.h>
+#include <usb/classes/hidut.h>
+#include <usb/classes/hidreq.h>
+#include <usb/classes/hidreport.h>
+#include <usb/classes/hid/utled.h>
+
+#include <usb/devdrv.h>
+
+#include "kbddev.h"
+
+#include "layout.h"
+#include "conv.h"
+#include "kbdrepeat.h"
+
+#include "../usbhid.h"
+
+/*----------------------------------------------------------------------------*/
+/** Default modifiers when the keyboard is initialized. */
+static const unsigned DEFAULT_ACTIVE_MODS = KM_NUM_LOCK;
+
+///** Boot protocol report size (key part). */
+//static const size_t BOOTP_REPORT_SIZE = 6;
+
+///** Boot protocol total report size. */
+//static const size_t BOOTP_BUFFER_SIZE = 8;
+
+///** Boot protocol output report size. */
+//static const size_t BOOTP_BUFFER_OUT_SIZE = 1;
+
+///** Boot protocol error key code. */
+//static const uint8_t BOOTP_ERROR_ROLLOVER = 1;
+static const uint8_t ERROR_ROLLOVER = 1;
+
+/** Default idle rate for keyboards. */
+static const uint8_t IDLE_RATE = 0;
+
+/** Delay before a pressed key starts auto-repeating. */
+static const unsigned int DEFAULT_DELAY_BEFORE_FIRST_REPEAT = 500 * 1000;
+
+/** Delay between two repeats of a pressed key when auto-repeating. */
+static const unsigned int DEFAULT_REPEAT_DELAY = 50 * 1000;
+
+/*----------------------------------------------------------------------------*/
+
+/** Keyboard polling endpoint description for boot protocol class. */
+usb_endpoint_description_t usb_hid_kbd_poll_endpoint_description = {
+	.transfer_type = USB_TRANSFER_INTERRUPT,
+	.direction = USB_DIRECTION_IN,
+	.interface_class = USB_CLASS_HID,
+	.interface_subclass = USB_HID_SUBCLASS_BOOT,
+	.interface_protocol = USB_HID_PROTOCOL_KEYBOARD,
+	.flags = 0
+};
+
+//static usb_endpoint_description_t hid_poll_endpoint_description = {
+//	.transfer_type = USB_TRANSFER_INTERRUPT,
+//	.direction = USB_DIRECTION_IN,
+//	.interface_class = USB_CLASS_HID,
+//	.flags = 0
+//};
+
+///* Array of endpoints expected on the device, NULL terminated. */
+//usb_endpoint_description_t 
+//    *usb_kbd_endpoints[USB_KBD_POLL_EP_COUNT + 1] = {
+//	&boot_poll_endpoint_description,
+//	&hid_poll_endpoint_description,
+//	NULL
+//};
+
+const char *HID_KBD_FUN_NAME = "keyboard";
+const char *HID_KBD_CLASS_NAME = "keyboard";
+
+/*----------------------------------------------------------------------------*/
+
+enum {
+	USB_KBD_BOOT_REPORT_DESCRIPTOR_SIZE = 63
+};
+
+static const uint8_t USB_KBD_BOOT_REPORT_DESCRIPTOR[
+    USB_KBD_BOOT_REPORT_DESCRIPTOR_SIZE] = {
+        0x05, 0x01,  // Usage Page (Generic Desktop),
+        0x09, 0x06,  // Usage (Keyboard),
+        0xA1, 0x01,  // Collection (Application),
+        0x75, 0x01,  //   Report Size (1),
+        0x95, 0x08,  //   Report Count (8),       
+        0x05, 0x07,  //   Usage Page (Key Codes);
+        0x19, 0xE0,  //   Usage Minimum (224),
+        0x29, 0xE7,  //   Usage Maximum (231),
+        0x15, 0x00,  //   Logical Minimum (0),
+        0x25, 0x01,  //   Logical Maximum (1),
+        0x81, 0x02,  //   Input (Data, Variable, Absolute),   ; Modifier byte
+	0x95, 0x01,  //   Report Count (1),
+        0x75, 0x08,  //   Report Size (8),
+        0x81, 0x01,  //   Input (Constant),                   ; Reserved byte
+        0x95, 0x05,  //   Report Count (5),
+        0x75, 0x01,  //   Report Size (1),
+        0x05, 0x08,  //   Usage Page (Page# for LEDs),
+        0x19, 0x01,  //   Usage Minimum (1),
+        0x29, 0x05,  //   Usage Maxmimum (5),
+        0x91, 0x02,  //   Output (Data, Variable, Absolute),  ; LED report
+        0x95, 0x01,  //   Report Count (1),
+        0x75, 0x03,  //   Report Size (3),
+        0x91, 0x01,  //   Output (Constant),              ; LED report padding
+        0x95, 0x06,  //   Report Count (6),
+        0x75, 0x08,  //   Report Size (8),
+        0x15, 0x00,  //   Logical Minimum (0),
+        0x25, 0xff,  //   Logical Maximum (255),
+        0x05, 0x07,  //   Usage Page (Key Codes),
+        0x19, 0x00,  //   Usage Minimum (0),
+        0x29, 0xff,  //   Usage Maximum (255),
+        0x81, 0x00,  //   Input (Data, Array),            ; Key arrays (6 bytes)
+        0xC0           // End Collection
+
+};
+
+/*----------------------------------------------------------------------------*/
+
+typedef enum usb_kbd_flags {
+	USB_KBD_STATUS_UNINITIALIZED = 0,
+	USB_KBD_STATUS_INITIALIZED = 1,
+	USB_KBD_STATUS_TO_DESTROY = -1
+} usb_kbd_flags;
+
+/*----------------------------------------------------------------------------*/
+/* Keyboard layouts                                                           */
+/*----------------------------------------------------------------------------*/
+
+#define NUM_LAYOUTS 3
+
+/** Keyboard layout map. */
+static layout_op_t *layout[NUM_LAYOUTS] = {
+	&us_qwerty_op,
+	&us_dvorak_op,
+	&cz_op
+};
+
+static int active_layout = 0;
+
+/*----------------------------------------------------------------------------*/
+/* Modifier constants                                                         */
+/*----------------------------------------------------------------------------*/
+/** Mapping of USB modifier key codes to generic modifier key codes. */
+static const keycode_t usbhid_modifiers_keycodes[USB_HID_MOD_COUNT] = {
+	KC_LCTRL,         /* USB_HID_MOD_LCTRL */
+	KC_LSHIFT,        /* USB_HID_MOD_LSHIFT */
+	KC_LALT,          /* USB_HID_MOD_LALT */
+	0,                /* USB_HID_MOD_LGUI */
+	KC_RCTRL,         /* USB_HID_MOD_RCTRL */
+	KC_RSHIFT,        /* USB_HID_MOD_RSHIFT */
+	KC_RALT,          /* USB_HID_MOD_RALT */
+	0,                /* USB_HID_MOD_RGUI */
+};
+
+typedef enum usbhid_lock_code {
+	USB_KBD_LOCK_NUM = 0x53,
+	USB_KBD_LOCK_CAPS = 0x39,
+	USB_KBD_LOCK_SCROLL = 0x47,
+	USB_KBD_LOCK_COUNT = 3
+} usbhid_lock_code;
+
+static const usbhid_lock_code usbhid_lock_codes[USB_KBD_LOCK_COUNT] = {
+	USB_KBD_LOCK_NUM,
+	USB_KBD_LOCK_CAPS,
+	USB_KBD_LOCK_SCROLL
+};
+
+/*----------------------------------------------------------------------------*/
+/* IPC method handler                                                         */
+/*----------------------------------------------------------------------------*/
+
+static void default_connection_handler(ddf_fun_t *, ipc_callid_t, ipc_call_t *);
+//ddf_dev_ops_t keyboard_ops = {
+//	.default_handler = default_connection_handler
+//};
+
+/** 
+ * Default handler for IPC methods not handled by DDF.
+ *
+ * Currently recognizes only one method (IPC_M_CONNECT_TO_ME), in which case it
+ * assumes the caller is the console and thus it stores IPC phone to it for 
+ * later use by the driver to notify about key events.
+ *
+ * @param fun Device function handling the call.
+ * @param icallid Call id.
+ * @param icall Call data.
+ */
+void default_connection_handler(ddf_fun_t *fun,
+    ipc_callid_t icallid, ipc_call_t *icall)
+{
+	sysarg_t method = IPC_GET_IMETHOD(*icall);
+	
+	usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)fun->driver_data;
+	
+	if (hid_dev == NULL || hid_dev->data == NULL) {
+		async_answer_0(icallid, EINVAL);
+		return;
+	}
+	
+	assert(hid_dev != NULL);
+	assert(hid_dev->data != NULL);
+	usb_kbd_t *kbd_dev = (usb_kbd_t *)hid_dev->data;
+
+	if (method == IPC_M_CONNECT_TO_ME) {
+		int callback = IPC_GET_ARG5(*icall);
+
+		if (kbd_dev->console_phone != -1) {
+			async_answer_0(icallid, ELIMIT);
+			return;
+		}
+
+		kbd_dev->console_phone = callback;
+		async_answer_0(icallid, EOK);
+		return;
+	}
+	
+	async_answer_0(icallid, EINVAL);
+}
+
+/*----------------------------------------------------------------------------*/
+/* Key processing functions                                                   */
+/*----------------------------------------------------------------------------*/
+/**
+ * Handles turning of LED lights on and off.
+ *
+ * In case of USB keyboards, the LEDs are handled in the driver, not in the 
+ * device. When there should be a change (lock key was pressed), the driver
+ * uses a Set_Report request sent to the device to set the state of the LEDs.
+ *
+ * This functions sets the LED lights according to current settings of modifiers
+ * kept in the keyboard device structure.
+ *
+ * @param kbd_dev Keyboard device structure.
+ */
+static void usb_kbd_set_led(usb_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev) 
+{
+	if (kbd_dev->output_size == 0) {
+		return;
+	}
+	
+	unsigned i = 0;
+	
+	/* Reset the LED data. */
+	memset(kbd_dev->led_data, 0, kbd_dev->led_output_size * sizeof(int32_t));
+	
+	if ((kbd_dev->mods & KM_NUM_LOCK) && (i < kbd_dev->led_output_size)) {
+		kbd_dev->led_data[i++] = USB_HID_LED_NUM_LOCK;
+	}
+	
+	if ((kbd_dev->mods & KM_CAPS_LOCK) && (i < kbd_dev->led_output_size)) {
+		kbd_dev->led_data[i++] = USB_HID_LED_CAPS_LOCK;
+	}
+	
+	if ((kbd_dev->mods & KM_SCROLL_LOCK) 
+	    && (i < kbd_dev->led_output_size)) {
+		kbd_dev->led_data[i++] = USB_HID_LED_SCROLL_LOCK;
+	}
+
+	// TODO: COMPOSE and KANA
+	
+	usb_log_debug("Creating output report.\n");
+	
+	int rc = usb_hid_report_output_translate(hid_dev->parser, 
+	    kbd_dev->led_path, 
+	    USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 
+	    kbd_dev->output_buffer, 
+	    kbd_dev->output_size, kbd_dev->led_data, kbd_dev->led_output_size);
+	
+	if (rc != EOK) {
+		usb_log_warning("Error translating LED output to output report"
+		    ".\n");
+		return;
+	}
+	
+	usb_log_debug("Output report buffer: %s\n", 
+	    usb_debug_str_buffer(kbd_dev->output_buffer, kbd_dev->output_size, 
+	        0));
+	
+	usbhid_req_set_report(&hid_dev->usb_dev->ctrl_pipe, 
+	    hid_dev->usb_dev->interface_no, USB_HID_REPORT_TYPE_OUTPUT, 
+	    kbd_dev->output_buffer, kbd_dev->output_size);
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Processes key events.
+ *
+ * @note This function was copied from AT keyboard driver and modified to suit
+ *       USB keyboard.
+ *
+ * @note Lock keys are not sent to the console, as they are completely handled
+ *       in the driver. It may, however, be required later that the driver
+ *       sends also these keys to application (otherwise it cannot use those
+ *       keys at all).
+ * 
+ * @param kbd_dev Keyboard device structure.
+ * @param type Type of the event (press / release). Recognized values: 
+ *             KEY_PRESS, KEY_RELEASE
+ * @param key Key code of the key according to HID Usage Tables.
+ */
+void usb_kbd_push_ev(usb_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev, int type, 
+    unsigned int key)
+{
+	console_event_t ev;
+	unsigned mod_mask;
+
+	/*
+	 * These parts are copy-pasted from the AT keyboard driver.
+	 *
+	 * They definitely require some refactoring, but will keep it for later
+	 * when the console and keyboard system is changed in HelenOS.
+	 */
+	switch (key) {
+	case KC_LCTRL: mod_mask = KM_LCTRL; break;
+	case KC_RCTRL: mod_mask = KM_RCTRL; break;
+	case KC_LSHIFT: mod_mask = KM_LSHIFT; break;
+	case KC_RSHIFT: mod_mask = KM_RSHIFT; break;
+	case KC_LALT: mod_mask = KM_LALT; break;
+	case KC_RALT: mod_mask = KM_RALT; break;
+	default: mod_mask = 0; break;
+	}
+
+	if (mod_mask != 0) {
+		if (type == KEY_PRESS)
+			kbd_dev->mods = kbd_dev->mods | mod_mask;
+		else
+			kbd_dev->mods = kbd_dev->mods & ~mod_mask;
+	}
+
+	switch (key) {
+	case KC_CAPS_LOCK: mod_mask = KM_CAPS_LOCK; break;
+	case KC_NUM_LOCK: mod_mask = KM_NUM_LOCK; break;
+	case KC_SCROLL_LOCK: mod_mask = KM_SCROLL_LOCK; break;
+	default: mod_mask = 0; break;
+	}
+
+	if (mod_mask != 0) {
+		if (type == KEY_PRESS) {
+			/*
+			 * Only change lock state on transition from released
+			 * to pressed. This prevents autorepeat from messing
+			 * up the lock state.
+			 */
+			unsigned int locks_old = kbd_dev->lock_keys;
+			
+			kbd_dev->mods = 
+			    kbd_dev->mods ^ (mod_mask & ~kbd_dev->lock_keys);
+			kbd_dev->lock_keys = kbd_dev->lock_keys | mod_mask;
+
+			/* Update keyboard lock indicator lights. */
+			if (kbd_dev->lock_keys != locks_old 
+			    && hid_dev != NULL) { // ugly hack
+				usb_kbd_set_led(hid_dev, kbd_dev);
+			}
+		} else {
+			kbd_dev->lock_keys = kbd_dev->lock_keys & ~mod_mask;
+		}
+	}
+
+	if (key == KC_CAPS_LOCK || key == KC_NUM_LOCK || key == KC_SCROLL_LOCK) {
+		// do not send anything to the console, this is our business
+		return;
+	}
+	
+	if (type == KEY_PRESS && (kbd_dev->mods & KM_LCTRL) && key == KC_F1) {
+		active_layout = 0;
+		layout[active_layout]->reset();
+		return;
+	}
+
+	if (type == KEY_PRESS && (kbd_dev->mods & KM_LCTRL) && key == KC_F2) {
+		active_layout = 1;
+		layout[active_layout]->reset();
+		return;
+	}
+
+	if (type == KEY_PRESS && (kbd_dev->mods & KM_LCTRL) && key == KC_F3) {
+		active_layout = 2;
+		layout[active_layout]->reset();
+		return;
+	}
+	
+	ev.type = type;
+	ev.key = key;
+	ev.mods = kbd_dev->mods;
+
+	ev.c = layout[active_layout]->parse_ev(&ev);
+
+	usb_log_debug2("Sending key %d to the console\n", ev.key);
+	if (kbd_dev->console_phone < 0) {
+		usb_log_warning(
+		    "Connection to console not ready, key discarded.\n");
+		return;
+	}
+	
+	async_msg_4(kbd_dev->console_phone, KBD_EVENT, ev.type, ev.key, 
+	    ev.mods, ev.c);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static inline int usb_kbd_is_lock(unsigned int key_code) 
+{
+	return (key_code == KC_NUM_LOCK
+	    || key_code == KC_SCROLL_LOCK
+	    || key_code == KC_CAPS_LOCK);
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Checks if some keys were pressed or released and generates key events.
+ *
+ * An event is created only when key is pressed or released. Besides handling
+ * the events (usb_kbd_push_ev()), the auto-repeat fibril is notified about
+ * key presses and releases (see usb_kbd_repeat_start() and 
+ * usb_kbd_repeat_stop()).
+ *
+ * @param kbd_dev Keyboard device structure.
+ * @param key_codes Parsed keyboard report - codes of currently pressed keys 
+ *                  according to HID Usage Tables.
+ * @param count Number of key codes in report (size of the report).
+ *
+ * @sa usb_kbd_push_ev(), usb_kbd_repeat_start(), usb_kbd_repeat_stop()
+ */
+static void usb_kbd_check_key_changes(usb_hid_dev_t *hid_dev, 
+    usb_kbd_t *kbd_dev, const uint8_t *key_codes, size_t count)
+{
+	unsigned int key;
+	unsigned int i, j;
+	
+	/*
+	 * First of all, check if the kbd have reported phantom state.
+	 *
+	 * As there is no way to distinguish keys from modifiers, we do not have
+	 * a way to check that 'all keys report Error Rollover'. We thus check
+	 * if there is at least one such error and in such case we ignore the
+	 * whole input report.
+	 */
+	i = 0;
+	while (i < count && key_codes[i] != ERROR_ROLLOVER) {
+		++i;
+	}
+	if (i != count) {
+		usb_log_debug("Phantom state occured.\n");
+		// phantom state, do nothing
+		return;
+	}
+	
+	/* TODO: quite dummy right now, think of better implementation */
+	assert(count == kbd_dev->key_count);
+	
+	/*
+	 * 1) Key releases
+	 */
+	for (j = 0; j < count; ++j) {
+		// try to find the old key in the new key list
+		i = 0;
+		while (i < kbd_dev->key_count
+		    && key_codes[i] != kbd_dev->keys[j]) {
+			++i;
+		}
+		
+		if (i == count) {
+			// not found, i.e. the key was released
+			key = usbhid_parse_scancode(kbd_dev->keys[j]);
+			if (!usb_kbd_is_lock(key)) {
+				usb_kbd_repeat_stop(kbd_dev, key);
+			}
+			usb_kbd_push_ev(hid_dev, kbd_dev, KEY_RELEASE, key);
+			usb_log_debug2("Key released: %d\n", key);
+		} else {
+			// found, nothing happens
+		}
+	}
+	
+	/*
+	 * 1) Key presses
+	 */
+	for (i = 0; i < kbd_dev->key_count; ++i) {
+		// try to find the new key in the old key list
+		j = 0;
+		while (j < count && kbd_dev->keys[j] != key_codes[i]) { 
+			++j;
+		}
+		
+		if (j == count) {
+			// not found, i.e. new key pressed
+			key = usbhid_parse_scancode(key_codes[i]);
+			usb_log_debug2("Key pressed: %d (keycode: %d)\n", key,
+			    key_codes[i]);
+			usb_kbd_push_ev(hid_dev, kbd_dev, KEY_PRESS, 
+			    key);
+			if (!usb_kbd_is_lock(key)) {
+				usb_kbd_repeat_start(kbd_dev, key);
+			}
+		} else {
+			// found, nothing happens
+		}
+	}
+	
+	memcpy(kbd_dev->keys, key_codes, count);
+
+	usb_log_debug("New stored keycodes: %s\n", 
+	    usb_debug_str_buffer(kbd_dev->keys, kbd_dev->key_count, 0));
+}
+
+/*----------------------------------------------------------------------------*/
+/* Callbacks for parser                                                       */
+/*----------------------------------------------------------------------------*/
+/**
+ * Callback function for the HID report parser.
+ *
+ * This function is called by the HID report parser with the parsed report.
+ * The parsed report is used to check if any events occured (key was pressed or
+ * released, modifier was pressed or released).
+ *
+ * @param key_codes Parsed keyboard report - codes of currently pressed keys 
+ *                  according to HID Usage Tables.
+ * @param count Number of key codes in report (size of the report).
+ * @param report_id
+ * @param arg User-specified argument. Expects pointer to the keyboard device
+ *            structure representing the keyboard.
+ *
+ * @sa usb_kbd_check_key_changes(), usb_kbd_check_modifier_changes()
+ */
+static void usb_kbd_process_keycodes(const uint8_t *key_codes, size_t count,
+    uint8_t report_id, void *arg)
+{
+	if (arg == NULL) {
+		usb_log_warning("Missing argument in callback "
+		    "usbhid_process_keycodes().\n");
+		return;
+	}
+	
+	usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)arg;
+	
+	if (hid_dev->data == NULL) {
+		usb_log_warning("Missing KBD device structure in callback.\n");
+		return;
+	}
+	
+	usb_kbd_t *kbd_dev = (usb_kbd_t *)hid_dev->data;
+
+	usb_log_debug("Got keys from parser (report id: %u): %s\n", 
+	    report_id, usb_debug_str_buffer(key_codes, count, 0));
+	
+	if (count != kbd_dev->key_count) {
+		usb_log_warning("Number of received keycodes (%d) differs from"
+		    " expected number (%d).\n", count, kbd_dev->key_count);
+		return;
+	}
+	
+	///usb_kbd_check_modifier_changes(kbd_dev, key_codes, count);
+	usb_kbd_check_key_changes(hid_dev, kbd_dev, key_codes, count);
+}
+
+/*----------------------------------------------------------------------------*/
+/* General kbd functions                                                      */
+/*----------------------------------------------------------------------------*/
+/**
+ * Processes data received from the device in form of report.
+ *
+ * This function uses the HID report parser to translate the data received from
+ * the device into generic USB HID key codes and into generic modifiers bitmap.
+ * The parser then calls the given callback (usb_kbd_process_keycodes()).
+ *
+ * @note Currently, only the boot protocol is supported.
+ *
+ * @param kbd_dev Keyboard device structure (must be initialized).
+ * @param buffer Data from the keyboard (i.e. the report).
+ * @param actual_size Size of the data from keyboard (report size) in bytes.
+ *
+ * @sa usb_kbd_process_keycodes(), usb_hid_boot_keyboard_input_report(),
+ *     usb_hid_parse_report().
+ */
+static void usb_kbd_process_data(usb_hid_dev_t *hid_dev,
+                                 uint8_t *buffer, size_t actual_size)
+{
+	assert(hid_dev->parser != NULL);
+	
+	usb_hid_report_in_callbacks_t *callbacks =
+	    (usb_hid_report_in_callbacks_t *)malloc(
+	        sizeof(usb_hid_report_in_callbacks_t));
+	
+	callbacks->keyboard = usb_kbd_process_keycodes;
+
+	usb_log_debug("Calling usb_hid_parse_report() with "
+	    "buffer %s\n", usb_debug_str_buffer(buffer, actual_size, 0));
+	
+//	int rc = usb_hid_boot_keyboard_input_report(buffer, actual_size,
+//	    callbacks, kbd_dev);
+	usb_hid_report_path_t *path = usb_hid_report_path();
+	usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_KEYBOARD, 0);
+	usb_hid_report_path_set_report_id(path, 0);
+	
+	int rc = usb_hid_parse_report(hid_dev->parser, buffer,
+	    actual_size, path, 
+	    USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 
+	    callbacks, hid_dev);
+
+	usb_hid_report_path_free(path);
+	
+	if (rc != EOK) {
+		usb_log_warning("Error in usb_hid_boot_keyboard_input_report():"
+		    "%s\n", str_error(rc));
+	}
+}
+
+/*----------------------------------------------------------------------------*/
+/* HID/KBD structure manipulation                                             */
+/*----------------------------------------------------------------------------*/
+
+static void usb_kbd_mark_unusable(usb_kbd_t *kbd_dev)
+{
+	kbd_dev->initialized = USB_KBD_STATUS_TO_DESTROY;
+}
+
+/*----------------------------------------------------------------------------*/
+
+/**
+ * Creates a new USB/HID keyboard structure.
+ *
+ * The structure returned by this function is not initialized. Use 
+ * usb_kbd_init() to initialize it prior to polling.
+ *
+ * @return New uninitialized structure for representing a USB/HID keyboard or
+ *         NULL if not successful (memory error).
+ */
+static usb_kbd_t *usb_kbd_new(void)
+{
+	usb_kbd_t *kbd_dev = 
+	    (usb_kbd_t *)calloc(1, sizeof(usb_kbd_t));
+
+	if (kbd_dev == NULL) {
+		usb_log_fatal("No memory!\n");
+		return NULL;
+	}
+	
+	kbd_dev->console_phone = -1;
+	kbd_dev->initialized = USB_KBD_STATUS_UNINITIALIZED;
+	
+	return kbd_dev;
+}
+
+/*----------------------------------------------------------------------------*/
+/* API functions                                                              */
+/*----------------------------------------------------------------------------*/
+/**
+ * Initialization of the USB/HID keyboard structure.
+ *
+ * This functions initializes required structures from the device's descriptors.
+ *
+ * During initialization, the keyboard is switched into boot protocol, the idle
+ * rate is set to 0 (infinity), resulting in the keyboard only reporting event
+ * when a key is pressed or released. Finally, the LED lights are turned on 
+ * according to the default setup of lock keys.
+ *
+ * @note By default, the keyboards is initialized with Num Lock turned on and 
+ *       other locks turned off.
+ *
+ * @param kbd_dev Keyboard device structure to be initialized.
+ * @param dev DDF device structure of the keyboard.
+ *
+ * @retval EOK if successful.
+ * @retval EINVAL if some parameter is not given.
+ * @return Other value inherited from function usbhid_dev_init().
+ */
+int usb_kbd_init(usb_hid_dev_t *hid_dev)
+{
+	usb_log_debug("Initializing HID/KBD structure...\n");
+	
+	if (hid_dev == NULL) {
+		usb_log_error("Failed to init keyboard structure: no structure"
+		    " given.\n");
+		return EINVAL;
+	}
+	
+	usb_kbd_t *kbd_dev = usb_kbd_new();
+	if (kbd_dev == NULL) {
+		usb_log_error("Error while creating USB/HID KBD device "
+		    "structure.\n");
+		return ENOMEM;  // TODO: some other code??
+	}
+	
+	/*
+	 * TODO: make more general
+	 */
+	usb_hid_report_path_t *path = usb_hid_report_path();
+	usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_KEYBOARD, 0);
+	
+	usb_hid_report_path_set_report_id(path, 0);
+	
+	kbd_dev->key_count = usb_hid_report_input_length(
+	    hid_dev->parser, path, 
+	    USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY);
+	usb_hid_report_path_free(path);
+	
+	usb_log_debug("Size of the input report: %zu\n", kbd_dev->key_count);
+	
+	kbd_dev->keys = (uint8_t *)calloc(kbd_dev->key_count, sizeof(uint8_t));
+	
+	if (kbd_dev->keys == NULL) {
+		usb_log_fatal("No memory!\n");
+		free(kbd_dev);
+		return ENOMEM;
+	}
+	
+	/*
+	 * Output report
+	 */
+	kbd_dev->output_size = 0;
+	kbd_dev->output_buffer = usb_hid_report_output(hid_dev->parser, 
+	    &kbd_dev->output_size);
+	if (kbd_dev->output_buffer == NULL && kbd_dev->output_size != 0) {
+		usb_log_warning("Error creating output report buffer.\n");
+		free(kbd_dev->keys);
+		free(kbd_dev);
+		return ENOMEM;
+	}
+	
+	usb_log_debug("Output buffer size: %zu\n", kbd_dev->output_size);
+	
+	kbd_dev->led_path = usb_hid_report_path();
+	usb_hid_report_path_append_item(
+	    kbd_dev->led_path, USB_HIDUT_PAGE_LED, 0);
+	
+	kbd_dev->led_output_size = usb_hid_report_output_size(hid_dev->parser, 
+	    kbd_dev->led_path, 
+	    USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY);
+	
+	usb_log_debug("Output report size (in items): %zu\n", 
+	    kbd_dev->led_output_size);
+	
+	kbd_dev->led_data = (int32_t *)calloc(
+	    kbd_dev->led_output_size, sizeof(int32_t));
+	
+	if (kbd_dev->led_data == NULL) {
+		usb_log_warning("Error creating buffer for LED output report."
+		    "\n");
+		free(kbd_dev->keys);
+		usb_hid_report_output_free(kbd_dev->output_buffer);
+		free(kbd_dev);
+		return ENOMEM;
+	}
+	
+	/*
+	 * Modifiers and locks
+	 */	
+	kbd_dev->modifiers = 0;
+	kbd_dev->mods = DEFAULT_ACTIVE_MODS;
+	kbd_dev->lock_keys = 0;
+	
+	/*
+	 * Autorepeat
+	 */	
+	kbd_dev->repeat.key_new = 0;
+	kbd_dev->repeat.key_repeated = 0;
+	kbd_dev->repeat.delay_before = DEFAULT_DELAY_BEFORE_FIRST_REPEAT;
+	kbd_dev->repeat.delay_between = DEFAULT_REPEAT_DELAY;
+	
+	kbd_dev->repeat_mtx = (fibril_mutex_t *)(
+	    malloc(sizeof(fibril_mutex_t)));
+	if (kbd_dev->repeat_mtx == NULL) {
+		usb_log_fatal("No memory!\n");
+		free(kbd_dev->keys);
+		usb_hid_report_output_free(kbd_dev->output_buffer);
+		free(kbd_dev);
+		return ENOMEM;
+	}
+	
+	fibril_mutex_initialize(kbd_dev->repeat_mtx);
+	
+	// save the KBD device structure into the HID device structure
+	hid_dev->data = kbd_dev;
+	
+	// set handler for incoming calls
+	hid_dev->ops.default_handler = default_connection_handler;
+	
+	/*
+	 * Set LEDs according to initial setup.
+	 * Set Idle rate
+	 */
+	usb_kbd_set_led(hid_dev, kbd_dev);
+	
+	usbhid_req_set_idle(&hid_dev->usb_dev->ctrl_pipe, 
+	    hid_dev->usb_dev->interface_no, IDLE_RATE);
+	
+	/*
+	 * Create new fibril for auto-repeat
+	 */
+	fid_t fid = fibril_create(usb_kbd_repeat_fibril, kbd_dev);
+	if (fid == 0) {
+		usb_log_error("Failed to start fibril for KBD auto-repeat");
+		return ENOMEM;
+	}
+	fibril_add_ready(fid);
+	
+	kbd_dev->initialized = USB_KBD_STATUS_INITIALIZED;
+	usb_log_debug("HID/KBD device structure initialized.\n");
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+bool usb_kbd_polling_callback(usb_device_t *dev, uint8_t *buffer,
+     size_t buffer_size, void *arg)
+{
+	if (dev == NULL || buffer == NULL || arg == NULL) {
+		// do not continue polling (???)
+		return false;
+	}
+	
+	usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)arg;
+	
+	// TODO: add return value from this function
+	usb_kbd_process_data(hid_dev, buffer, buffer_size);
+	
+	return true;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int usb_kbd_is_initialized(const usb_kbd_t *kbd_dev)
+{
+	return (kbd_dev->initialized == USB_KBD_STATUS_INITIALIZED);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int usb_kbd_is_ready_to_destroy(const usb_kbd_t *kbd_dev)
+{
+	return (kbd_dev->initialized == USB_KBD_STATUS_TO_DESTROY);
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Properly destroys the USB/HID keyboard structure.
+ *
+ * @param kbd_dev Pointer to the structure to be destroyed.
+ */
+void usb_kbd_free(usb_kbd_t **kbd_dev)
+{
+	if (kbd_dev == NULL || *kbd_dev == NULL) {
+		return;
+	}
+	
+	// hangup phone to the console
+	async_hangup((*kbd_dev)->console_phone);
+	
+	if ((*kbd_dev)->repeat_mtx != NULL) {
+		/* TODO: replace by some check and wait */
+		assert(!fibril_mutex_is_locked((*kbd_dev)->repeat_mtx));
+		free((*kbd_dev)->repeat_mtx);
+	}
+	
+	// free the output buffer
+	usb_hid_report_output_free((*kbd_dev)->output_buffer);
+
+	free(*kbd_dev);
+	*kbd_dev = NULL;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void usb_kbd_deinit(struct usb_hid_dev_t *hid_dev)
+{
+	if (hid_dev == NULL) {
+		return;
+	}
+	
+	if (hid_dev->data != NULL) {
+		usb_kbd_t *kbd_dev = (usb_kbd_t *)hid_dev->data;
+		if (usb_kbd_is_initialized(kbd_dev)) {
+			usb_kbd_mark_unusable(kbd_dev);
+		} else {
+			usb_kbd_free(&kbd_dev);
+		}
+	}
+}
+
+/*----------------------------------------------------------------------------*/
+
+int usb_kbd_set_boot_protocol(usb_hid_dev_t *hid_dev)
+{
+	int rc = usb_hid_parse_report_descriptor(hid_dev->parser, 
+	    USB_KBD_BOOT_REPORT_DESCRIPTOR, 
+	    USB_KBD_BOOT_REPORT_DESCRIPTOR_SIZE);
+	
+	if (rc != EOK) {
+		usb_log_error("Failed to parse boot report descriptor: %s\n",
+		    str_error(rc));
+		return rc;
+	}
+	
+	rc = usbhid_req_set_protocol(&hid_dev->usb_dev->ctrl_pipe, 
+	    hid_dev->usb_dev->interface_no, USB_HID_PROTOCOL_BOOT);
+	
+	if (rc != EOK) {
+		usb_log_warning("Failed to set boot protocol to the device: "
+		    "%s\n", str_error(rc));
+		return rc;
+	}
+	
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/kbd/kbddev.h
===================================================================
--- uspace/drv/usbhid/kbd/kbddev.h	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
+++ uspace/drv/usbhid/kbd/kbddev.h	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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.
+ */
+
+/** @addtogroup drvusbhid
+ * @{
+ */
+/** @file
+ * USB HID keyboard device structure and API.
+ */
+
+#ifndef USB_KBDDEV_H_
+#define USB_KBDDEV_H_
+
+#include <stdint.h>
+
+#include <fibril_synch.h>
+
+#include <usb/classes/hid.h>
+#include <usb/classes/hidparser.h>
+#include <ddf/driver.h>
+#include <usb/pipes.h>
+#include <usb/devdrv.h>
+
+#include "kbdrepeat.h"
+
+struct usb_hid_dev_t;
+
+/*----------------------------------------------------------------------------*/
+/**
+ * USB/HID keyboard device type.
+ *
+ * Holds a reference to generic USB/HID device structure and keyboard-specific
+ * data, such as currently pressed keys, modifiers and lock keys.
+ *
+ * Also holds a IPC phone to the console (since there is now no other way to 
+ * communicate with it).
+ *
+ * @note Storing active lock keys in this structure results in their setting
+ *       being device-specific.
+ */
+typedef struct usb_kbd_t {
+	/** Structure holding generic USB device information. */
+	//usbhid_dev_t *hid_dev;
+	//usb_device_t *usb_dev;
+	
+	/** Currently pressed keys (not translated to key codes). */
+	uint8_t *keys;
+	/** Count of stored keys (i.e. number of keys in the report). */
+	size_t key_count;
+	/** Currently pressed modifiers (bitmap). */
+	uint8_t modifiers;
+	
+	/** Currently active modifiers including locks. Sent to the console. */
+	unsigned mods;
+	
+	/** Currently active lock keys. */
+	unsigned lock_keys;
+	
+	/** IPC phone to the console device (for sending key events). */
+	int console_phone;
+	
+	/** Information for auto-repeat of keys. */
+	usb_kbd_repeat_t repeat;
+	
+	/** Mutex for accessing the information about auto-repeat. */
+	fibril_mutex_t *repeat_mtx;
+	
+	/** Report descriptor. */
+	//uint8_t *report_desc;
+
+	/** Report descriptor size. */
+	//size_t report_desc_size;
+	
+	uint8_t *output_buffer;
+	
+	size_t output_size;
+	
+	size_t led_output_size;
+	
+	usb_hid_report_path_t *led_path;
+	
+	int32_t *led_data;
+
+	/** HID Report parser. */
+	//usb_hid_report_parser_t *parser;
+	
+	/** State of the structure (for checking before use). 
+	 * 
+	 * 0 - not initialized
+	 * 1 - initialized
+	 * -1 - ready for destroying
+	 */
+	int initialized;
+} usb_kbd_t;
+
+/*----------------------------------------------------------------------------*/
+
+//enum {
+//	USB_KBD_POLL_EP_NO = 0,
+//	USB_HID_POLL_EP_NO = 1,
+//	USB_KBD_POLL_EP_COUNT = 2
+//};
+
+//usb_endpoint_description_t *usb_kbd_endpoints[USB_KBD_POLL_EP_COUNT + 1];
+
+//ddf_dev_ops_t keyboard_ops;
+
+usb_endpoint_description_t usb_hid_kbd_poll_endpoint_description;
+
+const char *HID_KBD_FUN_NAME;
+const char *HID_KBD_CLASS_NAME;
+
+/*----------------------------------------------------------------------------*/
+
+//usb_kbd_t *usb_kbd_new(void);
+
+int usb_kbd_init(struct usb_hid_dev_t *hid_dev);
+
+bool usb_kbd_polling_callback(usb_device_t *dev, uint8_t *buffer,
+     size_t buffer_size, void *arg);
+
+//void usb_kbd_polling_ended_callback(usb_device_t *dev, bool reason, 
+//     void *arg);
+
+int usb_kbd_is_initialized(const usb_kbd_t *kbd_dev);
+
+int usb_kbd_is_ready_to_destroy(const usb_kbd_t *kbd_dev);
+
+void usb_kbd_free(usb_kbd_t **kbd_dev);
+
+void usb_kbd_push_ev(struct usb_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev,
+    int type, unsigned int key);
+
+
+void usb_kbd_deinit(struct usb_hid_dev_t *hid_dev);
+
+int usb_kbd_set_boot_protocol(struct usb_hid_dev_t *hid_dev);
+
+#endif /* USB_KBDDEV_H_ */
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/kbd/kbdrepeat.c
===================================================================
--- uspace/drv/usbhid/kbd/kbdrepeat.c	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
+++ uspace/drv/usbhid/kbd/kbdrepeat.c	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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.
+ */
+
+/** @addtogroup drvusbhid
+ * @{
+ */
+/**
+ * @file
+ * USB HID keyboard autorepeat facilities
+ */
+
+#include <fibril_synch.h>
+#include <io/keycode.h>
+#include <io/console.h>
+#include <errno.h>
+
+#include <usb/debug.h>
+
+#include "kbdrepeat.h"
+#include "kbddev.h"
+
+
+/** Delay between auto-repeat state checks when no key is being repeated. */
+static unsigned int CHECK_DELAY = 10000;
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Main loop handling the auto-repeat of keys.
+ *
+ * This functions periodically checks if there is some key to be auto-repeated.
+ *
+ * If a new key is to be repeated, it uses the delay before first repeat stored
+ * in the keyboard structure to wait until the key has to start repeating.
+ *
+ * If the same key is still pressed, it uses the delay between repeats stored
+ * in the keyboard structure to wait until the key should be repeated.
+ * 
+ * If the currently repeated key is not pressed any more (
+ * usb_kbd_repeat_stop() was called), it stops repeating it and starts 
+ * checking again.
+ *
+ * @note For accessing the keyboard device auto-repeat information a fibril
+ *       mutex (repeat_mtx) from the @a kbd structure is used.
+ * 
+ * @param kbd Keyboard device structure.
+ */
+static void usb_kbd_repeat_loop(usb_kbd_t *kbd)
+{
+	unsigned int delay = 0;
+	
+	usb_log_debug("Starting autorepeat loop.\n");
+
+	while (true) {
+		// check if the kbd structure is usable
+		if (!usb_kbd_is_initialized(kbd)) {
+			if (usb_kbd_is_ready_to_destroy(kbd)) {
+				usb_kbd_free(&kbd);
+				assert(kbd == NULL);
+			}
+			return;
+		}
+		
+		fibril_mutex_lock(kbd->repeat_mtx);
+
+		if (kbd->repeat.key_new > 0) {
+			if (kbd->repeat.key_new == kbd->repeat.key_repeated) {
+				usb_log_debug2("Repeating key: %u.\n", 
+				    kbd->repeat.key_repeated);
+				// ugly hack with the NULL
+				usb_kbd_push_ev(NULL, kbd, KEY_PRESS, 
+				    kbd->repeat.key_repeated);
+				delay = kbd->repeat.delay_between;
+			} else {
+				usb_log_debug("New key to repeat: %u.\n", 
+				    kbd->repeat.key_new);
+				kbd->repeat.key_repeated = kbd->repeat.key_new;
+				delay = kbd->repeat.delay_before;
+			}
+		} else {
+			if (kbd->repeat.key_repeated > 0) {
+				usb_log_debug("Stopping to repeat key: %u.\n", 
+				    kbd->repeat.key_repeated);
+				kbd->repeat.key_repeated = 0;
+			}
+			delay = CHECK_DELAY;
+		}
+		fibril_mutex_unlock(kbd->repeat_mtx);
+		
+		async_usleep(delay);
+	}
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Main routine to be executed by a fibril for handling auto-repeat.
+ *
+ * Starts the loop for checking changes in auto-repeat.
+ * 
+ * @param arg User-specified argument. Expects pointer to the keyboard device
+ *            structure representing the keyboard.
+ *
+ * @retval EOK if the routine has finished.
+ * @retval EINVAL if no argument is supplied.
+ */
+int usb_kbd_repeat_fibril(void *arg)
+{
+	usb_log_debug("Autorepeat fibril spawned.\n");
+	
+	if (arg == NULL) {
+		usb_log_error("No device!\n");
+		return EINVAL;
+	}
+	
+	usb_kbd_t *kbd = (usb_kbd_t *)arg;
+	
+	usb_kbd_repeat_loop(kbd);
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Start repeating particular key.
+ *
+ * @note Only one key is repeated at any time, so calling this function 
+ *       effectively cancels auto-repeat of the current repeated key (if any)
+ *       and 'schedules' another key for auto-repeat.
+ *
+ * @param kbd Keyboard device structure.
+ * @param key Key to start repeating.
+ */
+void usb_kbd_repeat_start(usb_kbd_t *kbd, unsigned int key)
+{
+	fibril_mutex_lock(kbd->repeat_mtx);
+	kbd->repeat.key_new = key;
+	fibril_mutex_unlock(kbd->repeat_mtx);
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Stop repeating particular key.
+ *
+ * @note Only one key is repeated at any time, but this function may be called
+ *       even with key that is not currently repeated (in that case nothing 
+ *       happens).
+ *
+ * @param kbd Keyboard device structure.
+ * @param key Key to stop repeating.
+ */
+void usb_kbd_repeat_stop(usb_kbd_t *kbd, unsigned int key)
+{
+	fibril_mutex_lock(kbd->repeat_mtx);
+	if (key == kbd->repeat.key_new) {
+		kbd->repeat.key_new = 0;
+	}
+	fibril_mutex_unlock(kbd->repeat_mtx);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/kbd/kbdrepeat.h
===================================================================
--- uspace/drv/usbhid/kbd/kbdrepeat.h	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
+++ uspace/drv/usbhid/kbd/kbdrepeat.h	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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.
+ */
+
+/** @addtogroup drvusbhid
+ * @{
+ */
+/** @file
+ * USB HID keyboard autorepeat facilities
+ */
+
+#ifndef USB_KBDREPEAT_H_
+#define USB_KBDREPEAT_H_
+
+struct usb_kbd_t;
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Structure for keeping information needed for auto-repeat of keys.
+ */
+typedef struct {
+	/** Last pressed key. */
+	unsigned int key_new;
+	/** Key to be repeated. */
+	unsigned int key_repeated;
+	/** Delay before first repeat in microseconds. */
+	unsigned int delay_before;
+	/** Delay between repeats in microseconds. */
+	unsigned int delay_between;
+} usb_kbd_repeat_t;
+
+/*----------------------------------------------------------------------------*/
+
+int usb_kbd_repeat_fibril(void *arg);
+
+void usb_kbd_repeat_start(struct usb_kbd_t *kbd, unsigned int key);
+
+void usb_kbd_repeat_stop(struct usb_kbd_t *kbd, unsigned int key);
+
+#endif /* USB_KBDREPEAT_H_ */
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/kbd/layout.h
===================================================================
--- uspace/drv/usbhid/kbd/layout.h	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
+++ uspace/drv/usbhid/kbd/layout.h	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -0,0 +1,1 @@
+../layout.h
Index: uspace/drv/usbhid/kbd/main.c
===================================================================
--- uspace/drv/usbhid/kbd/main.c	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
+++ uspace/drv/usbhid/kbd/main.c	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * Copyright (c) 2011 Lubos Slovak
+ * 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.
+ */
+
+/** @addtogroup drvusbhid
+ * @{
+ */
+/**
+ * @file
+ * Main routines of USB KBD driver.
+ */
+
+#include <ddf/driver.h>
+#include <usb/debug.h>
+#include <errno.h>
+#include <str_error.h>
+
+#include <usb/devdrv.h>
+
+#include "kbddev.h"
+#include "kbdrepeat.h"
+
+/*----------------------------------------------------------------------------*/
+
+#define NAME "usbkbd"
+
+/**
+ * Function for adding a new device of type USB/HID/keyboard.
+ *
+ * This functions initializes required structures from the device's descriptors
+ * and starts new fibril for polling the keyboard for events and another one for
+ * handling auto-repeat of keys.
+ *
+ * During initialization, the keyboard is switched into boot protocol, the idle
+ * rate is set to 0 (infinity), resulting in the keyboard only reporting event
+ * when a key is pressed or released. Finally, the LED lights are turned on 
+ * according to the default setup of lock keys.
+ *
+ * @note By default, the keyboards is initialized with Num Lock turned on and 
+ *       other locks turned off.
+ * @note Currently supports only boot-protocol keyboards.
+ *
+ * @param dev Device to add.
+ *
+ * @retval EOK if successful.
+ * @retval ENOMEM if there
+ * @return Other error code inherited from one of functions usb_kbd_init(),
+ *         ddf_fun_bind() and ddf_fun_add_to_class().
+ *
+ * @sa usb_kbd_fibril(), usb_kbd_repeat_fibril()
+ */
+static int usb_kbd_try_add_device(usb_device_t *dev)
+{
+	/* Create the function exposed under /dev/devices. */
+	ddf_fun_t *kbd_fun = ddf_fun_create(dev->ddf_dev, fun_exposed, 
+	    "keyboard");
+	if (kbd_fun == NULL) {
+		usb_log_error("Could not create DDF function node.\n");
+		return ENOMEM;
+	}
+	
+	/* 
+	 * Initialize device (get and process descriptors, get address, etc.)
+	 */
+	usb_log_debug("Initializing USB/HID KBD device...\n");
+	
+	usb_kbd_t *kbd_dev = usb_kbd_new();
+	if (kbd_dev == NULL) {
+		usb_log_error("Error while creating USB/HID KBD device "
+		    "structure.\n");
+		ddf_fun_destroy(kbd_fun);
+		return ENOMEM;  // TODO: some other code??
+	}
+	
+	int rc = usb_kbd_init(kbd_dev, dev);
+	
+	if (rc != EOK) {
+		usb_log_error("Failed to initialize USB/HID KBD device.\n");
+		ddf_fun_destroy(kbd_fun);
+		usb_kbd_free(&kbd_dev);
+		return rc;
+	}	
+	
+	usb_log_debug("USB/HID KBD device structure initialized.\n");
+	
+	/*
+	 * Store the initialized keyboard device and keyboard ops
+	 * to the DDF function.
+	 */
+	kbd_fun->driver_data = kbd_dev;
+	kbd_fun->ops = &keyboard_ops;
+
+	rc = ddf_fun_bind(kbd_fun);
+	if (rc != EOK) {
+		usb_log_error("Could not bind DDF function: %s.\n",
+		    str_error(rc));
+		// TODO: Can / should I destroy the DDF function?
+		ddf_fun_destroy(kbd_fun);
+		usb_kbd_free(&kbd_dev);
+		return rc;
+	}
+	
+	rc = ddf_fun_add_to_class(kbd_fun, "keyboard");
+	if (rc != EOK) {
+		usb_log_error(
+		    "Could not add DDF function to class 'keyboard': %s.\n",
+		    str_error(rc));
+		// TODO: Can / should I destroy the DDF function?
+		ddf_fun_destroy(kbd_fun);
+		usb_kbd_free(&kbd_dev);
+		return rc;
+	}
+	
+	/*
+	 * Create new fibril for handling this keyboard
+	 */
+	//fid_t fid = fibril_create(usb_kbd_fibril, kbd_dev);
+	
+	/* Start automated polling function.
+	 * This will create a separate fibril that will query the device
+	 * for the data continuously 
+	 */
+       rc = usb_device_auto_poll(dev,
+	   /* Index of the polling pipe. */
+	   USB_KBD_POLL_EP_NO,
+	   /* Callback when data arrives. */
+	   usb_kbd_polling_callback,
+	   /* How much data to request. */
+	   dev->pipes[USB_KBD_POLL_EP_NO].pipe->max_packet_size,
+	   /* Callback when the polling ends. */
+	   usb_kbd_polling_ended_callback,
+	   /* Custom argument. */
+	   kbd_dev);
+	
+	
+	if (rc != EOK) {
+		usb_log_error("Failed to start polling fibril for `%s'.\n",
+		    dev->ddf_dev->name);
+		return rc;
+	}
+	//fibril_add_ready(fid);
+	
+	/*
+	 * Create new fibril for auto-repeat
+	 */
+	fid_t fid = fibril_create(usb_kbd_repeat_fibril, kbd_dev);
+	if (fid == 0) {
+		usb_log_error("Failed to start fibril for KBD auto-repeat");
+		return ENOMEM;
+	}
+	fibril_add_ready(fid);
+
+	(void)keyboard_ops;
+
+	/*
+	 * Hurrah, device is initialized.
+	 */
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Callback for passing a new device to the driver.
+ *
+ * @note Currently, only boot-protocol keyboards are supported by this driver.
+ *
+ * @param dev Structure representing the new device.
+ *
+ * @retval EOK if successful. 
+ * @retval EREFUSED if the device is not supported.
+ */
+static int usb_kbd_add_device(usb_device_t *dev)
+{
+	usb_log_debug("usb_kbd_add_device()\n");
+	
+	if (dev->interface_no < 0) {
+		usb_log_warning("Device is not a supported keyboard.\n");
+		usb_log_error("Failed to add USB KBD device: endpoint not "
+		    "found.\n");
+		return ENOTSUP;
+	}
+	
+	int rc = usb_kbd_try_add_device(dev);
+	
+	if (rc != EOK) {
+		usb_log_warning("Device is not a supported keyboard.\n");
+		usb_log_error("Failed to add KBD device: %s.\n",
+		    str_error(rc));
+		return rc;
+	}
+	
+	usb_log_info("Keyboard `%s' ready to use.\n", dev->ddf_dev->name);
+
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+/* Currently, the framework supports only device adding. Once the framework
+ * supports unplug, more callbacks will be added. */
+static usb_driver_ops_t usb_kbd_driver_ops = {
+        .add_device = usb_kbd_add_device,
+};
+
+
+/* The driver itself. */
+static usb_driver_t usb_kbd_driver = {
+        .name = NAME,
+        .ops = &usb_kbd_driver_ops,
+        .endpoints = usb_kbd_endpoints
+};
+
+/*----------------------------------------------------------------------------*/
+
+int main(int argc, char *argv[])
+{
+	printf(NAME ": HelenOS USB KBD driver.\n");
+
+	usb_log_enable(USB_LOG_LEVEL_DEBUG, NAME);
+
+	return usb_driver_main(&usb_kbd_driver);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/layout.h
===================================================================
--- uspace/drv/usbhid/layout.h	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
+++ uspace/drv/usbhid/layout.h	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2009 Jiri Svoboda
+ * Copyright (c) 2011 Lubos Slovak 
+ * (copied from /uspace/srv/hid/kbd/include/layout.h)
+ * 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.
+ */
+
+/** @addtogroup drvusbhid
+ * @{
+ */
+/** @file
+ * Keyboard layout.
+ */
+
+#ifndef USB_KBD_LAYOUT_H_
+#define USB_KBD_LAYOUT_H_
+
+#include <sys/types.h>
+#include <io/console.h>
+
+typedef struct {
+	void (*reset)(void);
+	wchar_t (*parse_ev)(console_event_t *);
+} layout_op_t;
+
+extern layout_op_t us_qwerty_op;
+extern layout_op_t us_dvorak_op;
+extern layout_op_t cz_op;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/main.c
===================================================================
--- uspace/drv/usbhid/main.c	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
+++ uspace/drv/usbhid/main.c	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * Copyright (c) 2011 Lubos Slovak
+ * 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.
+ */
+
+/** @addtogroup drvusbhid
+ * @{
+ */
+/**
+ * @file
+ * Main routines of USB HID driver.
+ */
+
+#include <ddf/driver.h>
+#include <usb/debug.h>
+#include <errno.h>
+#include <str_error.h>
+
+#include <usb/devdrv.h>
+
+#include "usbhid.h"
+
+/*----------------------------------------------------------------------------*/
+
+#define NAME "usbhid"
+
+/**
+ * Function for adding a new device of type USB/HID/keyboard.
+ *
+ * This functions initializes required structures from the device's descriptors
+ * and starts new fibril for polling the keyboard for events and another one for
+ * handling auto-repeat of keys.
+ *
+ * During initialization, the keyboard is switched into boot protocol, the idle
+ * rate is set to 0 (infinity), resulting in the keyboard only reporting event
+ * when a key is pressed or released. Finally, the LED lights are turned on 
+ * according to the default setup of lock keys.
+ *
+ * @note By default, the keyboards is initialized with Num Lock turned on and 
+ *       other locks turned off.
+ * @note Currently supports only boot-protocol keyboards.
+ *
+ * @param dev Device to add.
+ *
+ * @retval EOK if successful.
+ * @retval ENOMEM if there
+ * @return Other error code inherited from one of functions usb_kbd_init(),
+ *         ddf_fun_bind() and ddf_fun_add_to_class().
+ */
+static int usb_hid_try_add_device(usb_device_t *dev)
+{
+	/* 
+	 * Initialize device (get and process descriptors, get address, etc.)
+	 */
+	usb_log_debug("Initializing USB/HID device...\n");
+	
+	usb_hid_dev_t *hid_dev = usb_hid_new();
+	if (hid_dev == NULL) {
+		usb_log_error("Error while creating USB/HID device "
+		    "structure.\n");
+		return ENOMEM;
+	}
+	
+	int rc = usb_hid_init(hid_dev, dev);
+	
+	if (rc != EOK) {
+		usb_log_error("Failed to initialize USB/HID device.\n");
+		usb_hid_free(&hid_dev);
+		return rc;
+	}	
+	
+	usb_log_debug("USB/HID device structure initialized.\n");
+	
+	/* Create the function exposed under /dev/devices. */
+	ddf_fun_t *hid_fun = ddf_fun_create(dev->ddf_dev, fun_exposed, 
+	    usb_hid_get_function_name(hid_dev->device_type));
+	if (hid_fun == NULL) {
+		usb_log_error("Could not create DDF function node.\n");
+		usb_hid_free(&hid_dev);
+		return ENOMEM;
+	}
+	
+	/*
+	 * Store the initialized HID device and HID ops
+	 * to the DDF function.
+	 */
+	hid_fun->ops = &hid_dev->ops;
+	hid_fun->driver_data = hid_dev;   // TODO: maybe change to hid_dev->data
+
+	rc = ddf_fun_bind(hid_fun);
+	if (rc != EOK) {
+		usb_log_error("Could not bind DDF function: %s.\n",
+		    str_error(rc));
+		// TODO: Can / should I destroy the DDF function?
+		ddf_fun_destroy(hid_fun);
+		usb_hid_free(&hid_dev);
+		return rc;
+	}
+	
+	rc = ddf_fun_add_to_class(hid_fun, 
+	    usb_hid_get_class_name(hid_dev->device_type));
+	if (rc != EOK) {
+		usb_log_error(
+		    "Could not add DDF function to class 'hid': %s.\n",
+		    str_error(rc));
+		// TODO: Can / should I destroy the DDF function?
+		ddf_fun_destroy(hid_fun);
+		usb_hid_free(&hid_dev);
+		return rc;
+	}
+	
+	/* Start automated polling function.
+	 * This will create a separate fibril that will query the device
+	 * for the data continuously 
+	 */
+       rc = usb_device_auto_poll(dev,
+	   /* Index of the polling pipe. */
+	   hid_dev->poll_pipe_index,
+	   /* Callback when data arrives. */
+	   hid_dev->poll_callback,
+	   /* How much data to request. */
+	   dev->pipes[hid_dev->poll_pipe_index].pipe->max_packet_size,
+	   /* Callback when the polling ends. */
+	   usb_hid_polling_ended_callback,
+	   /* Custom argument. */
+	   hid_dev);
+	
+	
+	if (rc != EOK) {
+		usb_log_error("Failed to start polling fibril for `%s'.\n",
+		    dev->ddf_dev->name);
+		return rc;
+	}
+
+	/*
+	 * Hurrah, device is initialized.
+	 */
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Callback for passing a new device to the driver.
+ *
+ * @note Currently, only boot-protocol keyboards are supported by this driver.
+ *
+ * @param dev Structure representing the new device.
+ *
+ * @retval EOK if successful. 
+ * @retval EREFUSED if the device is not supported.
+ */
+static int usb_hid_add_device(usb_device_t *dev)
+{
+	usb_log_debug("usb_hid_add_device()\n");
+	
+	if (dev->interface_no < 0) {
+		usb_log_warning("Device is not a supported HID device.\n");
+		usb_log_error("Failed to add HID device: endpoints not found."
+		    "\n");
+		return ENOTSUP;
+	}
+	
+	int rc = usb_hid_try_add_device(dev);
+	
+	if (rc != EOK) {
+		usb_log_warning("Device is not a supported HID device.\n");
+		usb_log_error("Failed to add HID device: %s.\n",
+		    str_error(rc));
+		return rc;
+	}
+	
+	usb_log_info("HID device `%s' ready to use.\n", dev->ddf_dev->name);
+
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+/* Currently, the framework supports only device adding. Once the framework
+ * supports unplug, more callbacks will be added. */
+static usb_driver_ops_t usb_hid_driver_ops = {
+        .add_device = usb_hid_add_device,
+};
+
+
+/* The driver itself. */
+static usb_driver_t usb_hid_driver = {
+        .name = NAME,
+        .ops = &usb_hid_driver_ops,
+        .endpoints = usb_hid_endpoints
+};
+
+/*----------------------------------------------------------------------------*/
+
+int main(int argc, char *argv[])
+{
+	printf(NAME ": HelenOS USB HID driver.\n");
+
+	usb_log_enable(USB_LOG_LEVEL_DEBUG, NAME);
+
+	return usb_driver_main(&usb_hid_driver);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/usbhid.c
===================================================================
--- uspace/drv/usbhid/usbhid.c	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
+++ uspace/drv/usbhid/usbhid.c	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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.
+ */
+
+/** @addtogroup drvusbhid
+ * @{
+ */
+/**
+ * @file
+ * USB HID driver API.
+ */
+
+#include <usb/debug.h>
+#include <usb/classes/classes.h>
+#include <usb/classes/hid.h>
+#include <usb/classes/hidparser.h>
+#include <usb/classes/hidreport.h>
+#include <usb/classes/hidreq.h>
+#include <errno.h>
+
+#include "usbhid.h"
+
+#include "kbd/kbddev.h"
+#include "generic/hiddev.h"
+
+/*----------------------------------------------------------------------------*/
+
+/** Mouse polling endpoint description for boot protocol class. */
+static usb_endpoint_description_t usb_hid_mouse_poll_endpoint_description = {
+	.transfer_type = USB_TRANSFER_INTERRUPT,
+	.direction = USB_DIRECTION_IN,
+	.interface_class = USB_CLASS_HID,
+	.interface_subclass = USB_HID_SUBCLASS_BOOT,
+	.interface_protocol = USB_HID_PROTOCOL_MOUSE,
+	.flags = 0
+};
+
+/* Array of endpoints expected on the device, NULL terminated. */
+usb_endpoint_description_t *usb_hid_endpoints[USB_HID_POLL_EP_COUNT + 1] = {
+	&usb_hid_kbd_poll_endpoint_description,
+	&usb_hid_mouse_poll_endpoint_description,
+	&usb_hid_generic_poll_endpoint_description,
+	NULL
+};
+
+static const char *HID_MOUSE_FUN_NAME = "mouse";
+static const char *HID_MOUSE_CLASS_NAME = "mouse";
+
+/*----------------------------------------------------------------------------*/
+
+usb_hid_dev_t *usb_hid_new(void)
+{
+	usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)calloc(1,
+	    sizeof(usb_hid_dev_t));
+	
+	if (hid_dev == NULL) {
+		usb_log_fatal("No memory!\n");
+		return NULL;
+	}
+	
+	hid_dev->parser = (usb_hid_report_parser_t *)(malloc(sizeof(
+	    usb_hid_report_parser_t)));
+	if (hid_dev->parser == NULL) {
+		usb_log_fatal("No memory!\n");
+		free(hid_dev);
+		return NULL;
+	}
+	
+	return hid_dev;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static bool usb_dummy_polling_callback(usb_device_t *dev, uint8_t *buffer,
+     size_t buffer_size, void *arg)
+{
+	usb_log_debug("Dummy polling callback.\n");
+	return false;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int usb_hid_check_pipes(usb_hid_dev_t *hid_dev, usb_device_t *dev)
+{
+	if (dev->pipes[USB_HID_KBD_POLL_EP_NO].present) {
+		usb_log_debug("Found keyboard endpoint.\n");
+		
+		// save the pipe index and device type
+		hid_dev->poll_pipe_index = USB_HID_KBD_POLL_EP_NO;
+		hid_dev->device_type = USB_HID_PROTOCOL_KEYBOARD;
+		
+		// set the polling callback
+		hid_dev->poll_callback = usb_kbd_polling_callback;
+
+	} else if (dev->pipes[USB_HID_MOUSE_POLL_EP_NO].present) {
+		usb_log_debug("Found mouse endpoint.\n");
+		
+		// save the pipe index and device type
+		hid_dev->poll_pipe_index = USB_HID_MOUSE_POLL_EP_NO;
+		hid_dev->device_type = USB_HID_PROTOCOL_MOUSE;
+		
+		// set the polling callback
+		hid_dev->poll_callback = usb_dummy_polling_callback;
+		
+	} else if (dev->pipes[USB_HID_GENERIC_POLL_EP_NO].present) {
+		usb_log_debug("Found generic HID endpoint.\n");
+		
+		// save the pipe index and device type
+		hid_dev->poll_pipe_index = USB_HID_GENERIC_POLL_EP_NO;
+		hid_dev->device_type = USB_HID_PROTOCOL_NONE;
+		
+		// set the polling callback
+		hid_dev->poll_callback = usb_hid_polling_callback;
+		
+	} else {
+		usb_log_warning("None of supported endpoints found - probably"
+		    " not a supported device.\n");
+		return ENOTSUP;
+	}
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int usb_hid_init_parser(usb_hid_dev_t *hid_dev)
+{
+	/* Initialize the report parser. */
+	int rc = usb_hid_parser_init(hid_dev->parser);
+	if (rc != EOK) {
+		usb_log_error("Failed to initialize report parser.\n");
+		return rc;
+	}
+	
+	/* Get the report descriptor and parse it. */
+	rc = usb_hid_process_report_descriptor(hid_dev->usb_dev, 
+	    hid_dev->parser);
+	
+	if (rc != EOK) {
+		usb_log_warning("Could not process report descriptor.\n");
+		
+		if (hid_dev->device_type == USB_HID_PROTOCOL_KEYBOARD) {
+			usb_log_warning("Falling back to boot protocol.\n");
+			
+			rc = usb_kbd_set_boot_protocol(hid_dev);
+			
+		} else if (hid_dev->device_type == USB_HID_PROTOCOL_MOUSE) {
+			usb_log_warning("No boot protocol for mouse yet.\n");
+			rc = ENOTSUP;
+		}
+	}
+	
+	return rc;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int usb_hid_init(usb_hid_dev_t *hid_dev, usb_device_t *dev)
+{
+	int rc;
+	
+	usb_log_debug("Initializing HID structure...\n");
+	
+	if (hid_dev == NULL) {
+		usb_log_error("Failed to init HID structure: no structure given"
+		    ".\n");
+		return EINVAL;
+	}
+	
+	if (dev == NULL) {
+		usb_log_error("Failed to init HID structure: no USB device"
+		    " given.\n");
+		return EINVAL;
+	}
+	
+	/* The USB device should already be initialized, save it in structure */
+	hid_dev->usb_dev = dev;
+	
+	rc = usb_hid_check_pipes(hid_dev, dev);
+	if (rc != EOK) {
+		return rc;
+	}
+	
+	rc = usb_hid_init_parser(hid_dev);
+	if (rc != EOK) {
+		usb_log_error("Failed to initialize HID parser.\n");
+		return rc;
+	}
+	
+	switch (hid_dev->device_type) {
+	case USB_HID_PROTOCOL_KEYBOARD:
+		// initialize the keyboard structure
+		rc = usb_kbd_init(hid_dev);
+		if (rc != EOK) {
+			usb_log_warning("Failed to initialize KBD structure."
+			    "\n");
+		}
+		break;
+	case USB_HID_PROTOCOL_MOUSE:
+		break;
+	default:
+//		usbhid_req_set_idle(&hid_dev->usb_dev->ctrl_pipe, 
+//		    hid_dev->usb_dev->interface_no, 0);
+		break;
+	}
+	
+	return rc;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void usb_hid_polling_ended_callback(usb_device_t *dev, bool reason, 
+     void *arg)
+{
+	if (dev == NULL || arg == NULL) {
+		return;
+	}
+	
+	usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)arg;
+	
+	usb_hid_free(&hid_dev);
+}
+
+/*----------------------------------------------------------------------------*/
+
+const char *usb_hid_get_function_name(usb_hid_iface_protocol_t device_type)
+{
+	switch (device_type) {
+	case USB_HID_PROTOCOL_KEYBOARD:
+		return HID_KBD_FUN_NAME;
+		break;
+	case USB_HID_PROTOCOL_MOUSE:
+		return HID_MOUSE_FUN_NAME;
+		break;
+	default:
+		return HID_GENERIC_FUN_NAME;
+	}
+}
+
+/*----------------------------------------------------------------------------*/
+
+const char *usb_hid_get_class_name(usb_hid_iface_protocol_t device_type)
+{
+	switch (device_type) {
+	case USB_HID_PROTOCOL_KEYBOARD:
+		return HID_KBD_CLASS_NAME;
+		break;
+	case USB_HID_PROTOCOL_MOUSE:
+		return HID_MOUSE_CLASS_NAME;
+		break;
+	default:
+		return HID_GENERIC_CLASS_NAME;
+	}
+}
+
+/*----------------------------------------------------------------------------*/
+
+void usb_hid_free(usb_hid_dev_t **hid_dev)
+{
+	if (hid_dev == NULL || *hid_dev == NULL) {
+		return;
+	}
+	
+	switch ((*hid_dev)->device_type) {
+	case USB_HID_PROTOCOL_KEYBOARD:
+		usb_kbd_deinit(*hid_dev);
+		break;
+	case USB_HID_PROTOCOL_MOUSE:
+		break;
+	default:
+		break;
+	}
+
+	// destroy the parser
+	if ((*hid_dev)->parser != NULL) {
+		usb_hid_free_report_parser((*hid_dev)->parser);
+	}
+
+	if ((*hid_dev)->report_desc != NULL) {
+		free((*hid_dev)->report_desc);
+	}
+
+	free(*hid_dev);
+	*hid_dev = NULL;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/usbhid.h
===================================================================
--- uspace/drv/usbhid/usbhid.h	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
+++ uspace/drv/usbhid/usbhid.h	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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.
+ */
+
+/** @addtogroup drvusbhid
+ * @{
+ */
+/** @file
+ * USB HID driver API.
+ */
+
+#ifndef USB_USBHID_H_
+#define USB_USBHID_H_
+
+#include <stdint.h>
+
+#include <usb/classes/hidparser.h>
+#include <ddf/driver.h>
+#include <usb/pipes.h>
+#include <usb/devdrv.h>
+#include <usb/classes/hid.h>
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Structure for holding general HID device data.
+ */
+typedef struct usb_hid_dev_t {
+	/** Structure holding generic USB device information. */
+	usb_device_t *usb_dev;
+	
+	/** @todo What is this actually? */
+	ddf_dev_ops_t ops;
+	
+	/** Index of the polling pipe in usb_hid_endpoints array. */
+	int poll_pipe_index;
+	
+	/** Function to be called when data arrives from the device. */
+	usb_polling_callback_t poll_callback;
+	
+	/** Report descriptor. */
+	uint8_t *report_desc;
+
+	/** Report descriptor size. */
+	size_t report_desc_size;
+	
+	/** HID Report parser. */
+	usb_hid_report_parser_t *parser;
+	
+	/** Arbitrary data (e.g. a special structure for handling keyboard). */
+	void *data;
+	
+	/** Type of the device (keyboard, mouse, generic HID device). */
+	usb_hid_iface_protocol_t device_type;
+} usb_hid_dev_t;
+
+/*----------------------------------------------------------------------------*/
+
+enum {
+	USB_HID_KBD_POLL_EP_NO = 0,
+	USB_HID_MOUSE_POLL_EP_NO = 1,
+	USB_HID_GENERIC_POLL_EP_NO = 2,
+	USB_HID_POLL_EP_COUNT = 3
+};
+
+usb_endpoint_description_t *usb_hid_endpoints[USB_HID_POLL_EP_COUNT + 1];
+
+/*----------------------------------------------------------------------------*/
+
+usb_hid_dev_t *usb_hid_new(void);
+
+int usb_hid_init(usb_hid_dev_t *hid_dev, usb_device_t *dev);
+
+void usb_hid_polling_ended_callback(usb_device_t *dev, bool reason, 
+     void *arg);
+
+const char *usb_hid_get_function_name(usb_hid_iface_protocol_t device_type);
+
+const char *usb_hid_get_class_name(usb_hid_iface_protocol_t device_type);
+
+void usb_hid_free(usb_hid_dev_t **hid_dev);
+
+#endif /* USB_USBHID_H_ */
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/usbhid.ma
===================================================================
--- uspace/drv/usbhid/usbhid.ma	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
+++ uspace/drv/usbhid/usbhid.ma	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -0,0 +1,3 @@
+100 usb&interface&class=HID&subclass=0x01&protocol=0x01
+100 usb&interface&class=HID&subclass=0x01&protocol=0x02
+100 usb&interface&class=HID
Index: uspace/drv/usbkbd/kbddev.c
===================================================================
--- uspace/drv/usbkbd/kbddev.c	(revision 7dfc06fa1782dda3da24feb0e244e9bfadcc016e)
+++ uspace/drv/usbkbd/kbddev.c	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -265,4 +265,8 @@
 static void usb_kbd_set_led(usb_kbd_t *kbd_dev) 
 {
+	if (kbd_dev->output_size == 0) {
+		return;
+	}
+	
 	unsigned i = 0;
 	
@@ -288,5 +292,7 @@
 	
 	int rc = usb_hid_report_output_translate(kbd_dev->parser, 
-	    kbd_dev->led_path, USB_HID_PATH_COMPARE_END, kbd_dev->output_buffer, 
+	    kbd_dev->led_path, 
+	    USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 
+	    kbd_dev->output_buffer, 
 	    kbd_dev->output_size, kbd_dev->led_data, kbd_dev->led_output_size);
 	
@@ -539,5 +545,5 @@
  *                  according to HID Usage Tables.
  * @param count Number of key codes in report (size of the report).
- * @param modifiers Bitmap of modifiers (Ctrl, Alt, Shift, GUI).
+ * @param report_id
  * @param arg User-specified argument. Expects pointer to the keyboard device
  *            structure representing the keyboard.
@@ -546,5 +552,5 @@
  */
 static void usb_kbd_process_keycodes(const uint8_t *key_codes, size_t count,
-    uint8_t modifiers, void *arg)
+    uint8_t report_id, void *arg)
 {
 	if (arg == NULL) {
@@ -557,6 +563,6 @@
 	assert(kbd_dev != NULL);
 
-	usb_log_debug("Got keys from parser: %s\n", 
-	    usb_debug_str_buffer(key_codes, count, 0));
+	usb_log_debug("Got keys from parser (report id: %u): %s\n", 
+	    report_id, usb_debug_str_buffer(key_codes, count, 0));
 	
 	if (count != kbd_dev->key_count) {
@@ -608,7 +614,10 @@
 	usb_hid_report_path_t *path = usb_hid_report_path();
 	usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_KEYBOARD, 0);
+	usb_hid_report_path_set_report_id(path, 0);
 	
 	int rc = usb_hid_parse_report(kbd_dev->parser, buffer,
-	    actual_size, path, USB_HID_PATH_COMPARE_STRICT, callbacks, kbd_dev);
+	    actual_size, path, 
+	    USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 
+	    callbacks, kbd_dev);
 
 	usb_hid_report_path_free (path);
@@ -758,6 +767,10 @@
 	usb_hid_report_path_t *path = usb_hid_report_path();
 	usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_KEYBOARD, 0);
+	
+	usb_hid_report_path_set_report_id(path, 0);
+	
 	kbd_dev->key_count = usb_hid_report_input_length(
-	    kbd_dev->parser, path, USB_HID_PATH_COMPARE_STRICT);
+	    kbd_dev->parser, path, 
+	    USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY);
 	usb_hid_report_path_free (path);
 	
@@ -777,5 +790,5 @@
 	kbd_dev->output_buffer = usb_hid_report_output(kbd_dev->parser, 
 	    &kbd_dev->output_size);
-	if (kbd_dev->output_buffer == NULL) {
+	if (kbd_dev->output_buffer == NULL && kbd_dev->output_size != 0) {
 		usb_log_warning("Error creating output report buffer.\n");
 		free(kbd_dev->keys);
@@ -790,5 +803,6 @@
 	
 	kbd_dev->led_output_size = usb_hid_report_output_size(kbd_dev->parser, 
-	    kbd_dev->led_path, USB_HID_PATH_COMPARE_END);
+	    kbd_dev->led_path, 
+	    USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY);
 	
 	usb_log_debug("Output report size (in items): %zu\n", 
Index: uspace/drv/usbkbd/main.c
===================================================================
--- uspace/drv/usbkbd/main.c	(revision 7dfc06fa1782dda3da24feb0e244e9bfadcc016e)
+++ uspace/drv/usbkbd/main.c	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -33,5 +33,5 @@
 /**
  * @file
- * Main routines of USB HID driver.
+ * Main routines of USB KBD driver.
  */
 
@@ -75,5 +75,5 @@
  * @sa usb_kbd_fibril(), usb_kbd_repeat_fibril()
  */
-static int usbhid_try_add_device(usb_device_t *dev)
+static int usb_kbd_try_add_device(usb_device_t *dev)
 {
 	/* Create the function exposed under /dev/devices. */
@@ -105,5 +105,5 @@
 		usb_kbd_free(&kbd_dev);
 		return rc;
-	}	
+	}
 	
 	usb_log_debug("USB/HID KBD device structure initialized.\n");
@@ -195,20 +195,20 @@
  * @retval EREFUSED if the device is not supported.
  */
-static int usbhid_add_device(usb_device_t *dev)
+static int usb_kbd_add_device(usb_device_t *dev)
 {
-	usb_log_debug("usbhid_add_device()\n");
+	usb_log_debug("usb_kbd_add_device()\n");
 	
 	if (dev->interface_no < 0) {
 		usb_log_warning("Device is not a supported keyboard.\n");
-		usb_log_error("Failed to add HID device: endpoint not found."
-		    "\n");
+		usb_log_error("Failed to add USB KBD device: endpoint not "
+		    "found.\n");
 		return ENOTSUP;
 	}
 	
-	int rc = usbhid_try_add_device(dev);
+	int rc = usb_kbd_try_add_device(dev);
 	
 	if (rc != EOK) {
 		usb_log_warning("Device is not a supported keyboard.\n");
-		usb_log_error("Failed to add HID device: %s.\n",
+		usb_log_error("Failed to add KBD device: %s.\n",
 		    str_error(rc));
 		return rc;
@@ -224,13 +224,13 @@
 /* Currently, the framework supports only device adding. Once the framework
  * supports unplug, more callbacks will be added. */
-static usb_driver_ops_t usbhid_driver_ops = {
-        .add_device = usbhid_add_device,
+static usb_driver_ops_t usb_kbd_driver_ops = {
+        .add_device = usb_kbd_add_device,
 };
 
 
 /* The driver itself. */
-static usb_driver_t usbhid_driver = {
+static usb_driver_t usb_kbd_driver = {
         .name = NAME,
-        .ops = &usbhid_driver_ops,
+        .ops = &usb_kbd_driver_ops,
         .endpoints = usb_kbd_endpoints
 };
@@ -238,24 +238,11 @@
 /*----------------------------------------------------------------------------*/
 
-//static driver_ops_t kbd_driver_ops = {
-//	.add_device = usbhid_add_device,
-//};
-
-///*----------------------------------------------------------------------------*/
-
-//static driver_t kbd_driver = {
-//	.name = NAME,
-//	.driver_ops = &kbd_driver_ops
-//};
-
-/*----------------------------------------------------------------------------*/
-
 int main(int argc, char *argv[])
 {
-	printf(NAME ": HelenOS USB HID driver.\n");
+	printf(NAME ": HelenOS USB KBD driver.\n");
 
 	usb_log_enable(USB_LOG_LEVEL_DEBUG, NAME);
 
-	return usb_driver_main(&usbhid_driver);
+	return usb_driver_main(&usb_kbd_driver);
 }
 
Index: uspace/drv/usbkbd/usbkbd.ma
===================================================================
--- uspace/drv/usbkbd/usbkbd.ma	(revision 7dfc06fa1782dda3da24feb0e244e9bfadcc016e)
+++ uspace/drv/usbkbd/usbkbd.ma	(revision c6cb76d97feb5d033f3029669b5388f0ed7b023c)
@@ -1,2 +1,1 @@
-100 usb&interface&class=HID&subclass=0x01&protocol=0x01
-10 usb&interface&class=HID
+10 usb&interface&class=HID&subclass=0x01&protocol=0x01
