Index: uspace/drv/usbhid/hid.h
===================================================================
--- uspace/drv/usbhid/hid.h	(revision ad4562c21a6aaf832290f2af3b3d56a515bc3437)
+++ uspace/drv/usbhid/hid.h	(revision 882f8b1f6e16985c6dd0f4a889ed0772379831c2)
@@ -70,6 +70,4 @@
 typedef struct {
 	ddf_dev_t *device;
-	usb_hid_configuration_t *conf;
-	usb_hid_report_parser_t *parser;
 
 	usb_device_connection_t wire;
@@ -77,7 +75,15 @@
 	usb_endpoint_pipe_t poll_pipe;
 	
+	uint16_t iface;
+	
+	uint8_t *report_desc;
+	usb_hid_report_parser_t *parser;
+	
 	uint8_t *keycodes;
 	size_t keycode_count;
 	uint8_t modifiers;
+	
+	unsigned mods;
+	unsigned lock_keys;
 } usb_hid_dev_kbd_t;
 
Index: uspace/drv/usbhid/main.c
===================================================================
--- uspace/drv/usbhid/main.c	(revision ad4562c21a6aaf832290f2af3b3d56a515bc3437)
+++ uspace/drv/usbhid/main.c	(revision 882f8b1f6e16985c6dd0f4a889ed0772379831c2)
@@ -52,7 +52,8 @@
 #include <io/console.h>
 #include <stdint.h>
+#include <usb/dp.h>
 #include "hid.h"
-#include "descparser.h"
-#include "descdump.h"
+//#include "descparser.h"
+//#include "descdump.h"
 #include "conv.h"
 #include "layout.h"
@@ -62,6 +63,8 @@
 #define NAME "usbhid"
 
-#define GUESSED_POLL_ENDPOINT 1
+//#define GUESSED_POLL_ENDPOINT 1
 #define BOOTP_REPORT_SIZE 6
+
+static unsigned DEFAULT_ACTIVE_MODS = KM_NUM_LOCK;
 
 /** Keyboard polling endpoint description for boot protocol class. */
@@ -144,5 +147,5 @@
  * TODO: put to device?
  */
-static unsigned mods = KM_NUM_LOCK;
+//static unsigned mods = KM_NUM_LOCK;
 
 /** Currently pressed lock keys. We track these to tackle autorepeat.  
@@ -150,5 +153,5 @@
  * TODO: put to device? 
  */
-static unsigned lock_keys;
+//static unsigned lock_keys;
 
 #define NUM_LAYOUTS 3
@@ -195,5 +198,5 @@
 }
 
-static void usbkbd_req_set_protocol(usb_hid_dev_kbd_t *kbd_dev, uint16_t iface,
+static void usbkbd_req_set_protocol(usb_hid_dev_kbd_t *kbd_dev,
     usb_hid_protocol_t protocol)
 {
@@ -207,9 +210,10 @@
 	}
 
-	usb_log_debug("Sending Set_Protocol request to the device.\n");
+	usb_log_debug("Sending Set_Protocol request to the device ("
+	    "protocol: %d, iface: %d).\n", protocol, kbd_dev->iface);
 	
 	rc = usb_control_request_set(&kbd_dev->ctrl_pipe, 
 	    USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE, 
-	    USB_HIDREQ_SET_PROTOCOL, protocol, iface, NULL, 0);
+	    USB_HIDREQ_SET_PROTOCOL, protocol, kbd_dev->iface, NULL, 0);
 
 	sess_rc = usb_endpoint_pipe_end_session(&kbd_dev->ctrl_pipe);
@@ -228,20 +232,21 @@
 }
 
-static void usbkbd_set_led(unsigned mods, usb_hid_dev_kbd_t *kbd_dev) 
-{
-	uint8_t buffer[BUFFER_SIZE];
-	int rc= 0;
-	
+static void usbkbd_set_led(usb_hid_dev_kbd_t *kbd_dev) 
+{
+	uint8_t buffer[BUFFER_OUT_SIZE];
+	int rc= 0, i;
+	
+	memset(buffer, 0, BUFFER_OUT_SIZE);
 	uint8_t leds = 0;
 
-	if (mods & KM_NUM_LOCK) {
+	if (kbd_dev->mods & KM_NUM_LOCK) {
 		leds |= USB_HID_LED_NUM_LOCK;
 	}
 	
-	if (mods & KM_CAPS_LOCK) {
+	if (kbd_dev->mods & KM_CAPS_LOCK) {
 		leds |= USB_HID_LED_CAPS_LOCK;
 	}
 	
-	if (mods & KM_SCROLL_LOCK) {
+	if (kbd_dev->mods & KM_SCROLL_LOCK) {
 		leds |= USB_HID_LED_SCROLL_LOCK;
 	}
@@ -250,6 +255,7 @@
 	
 	usb_log_debug("Creating output report.\n");
+	usb_log_debug("Leds: 0x%x\n", leds);
 	if ((rc = usb_hid_boot_keyboard_output_report(
-	    leds, buffer, BUFFER_SIZE)) != EOK) {
+	    leds, buffer, BUFFER_OUT_SIZE)) != EOK) {
 		usb_log_warning("Error composing output report to the keyboard:"
 		    "%s.\n", str_error(rc));
@@ -257,7 +263,15 @@
 	}
 	
-	// TODO: determine what interface to use!! (now set to 1)
-	usbkbd_req_set_report(kbd_dev, 1, USB_HID_REPORT_TYPE_OUTPUT, buffer, 
-	    BUFFER_SIZE);
+	usb_log_debug("Output report buffer: ");
+	for (i = 0; i < BUFFER_OUT_SIZE; ++i) {
+		usb_log_debug("0x%x ", buffer[i]);
+	}
+	usb_log_debug("\n");
+	
+	uint16_t value = 0;
+	value |= (USB_HID_REPORT_TYPE_OUTPUT << 8);
+
+	usbkbd_req_set_report(kbd_dev, kbd_dev->iface, value, buffer, 
+	    BUFFER_OUT_SIZE);
 }
 
@@ -280,7 +294,7 @@
 	if (mod_mask != 0) {
 		if (type == KEY_PRESS)
-			mods = mods | mod_mask;
+			kbd_dev->mods = kbd_dev->mods | mod_mask;
 		else
-			mods = mods & ~mod_mask;
+			kbd_dev->mods = kbd_dev->mods & ~mod_mask;
 	}
 
@@ -294,6 +308,6 @@
 	if (mod_mask != 0) {
 		usb_log_debug2("\n\nChanging mods and lock keys\n");
-		usb_log_debug2("\nmods before: 0x%x\n", mods);
-		usb_log_debug2("\nLock keys before:0x%x\n\n", lock_keys);
+		usb_log_debug2("\nmods before: 0x%x\n", kbd_dev->mods);
+		usb_log_debug2("\nLock keys before:0x%x\n\n", kbd_dev->lock_keys);
 		
 		if (type == KEY_PRESS) {
@@ -304,24 +318,20 @@
 			 * up the lock state.
 			 */
-			mods = mods ^ (mod_mask & ~lock_keys);
-			lock_keys = lock_keys | mod_mask;
+			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. */
- 			usbkbd_set_led(mods, kbd_dev);
+ 			usbkbd_set_led(kbd_dev);
 		} else {
 			usb_log_debug2("\nKey released.\n");
-			lock_keys = lock_keys & ~mod_mask;
-		}
-	}
-/*
-	usb_log_debug2("type: %d\n", type);
-	usb_log_debug2("mods: 0x%x\n", mods);
-	usb_log_debug2("keycode: %u\n", key);
-*/
-	usb_log_debug2("\n\nmods after: 0x%x\n", mods);
-	usb_log_debug2("\nLock keys after: 0x%x\n\n", lock_keys);
-	
-	if (type == KEY_PRESS && (mods & KM_LCTRL) &&
-		key == KC_F1) {
+			kbd_dev->lock_keys = kbd_dev->lock_keys & ~mod_mask;
+		}
+	}
+
+	usb_log_debug2("\n\nmods after: 0x%x\n", kbd_dev->mods);
+	usb_log_debug2("\nLock keys after: 0x%x\n\n", kbd_dev->lock_keys);
+	
+	if (type == KEY_PRESS && (kbd_dev->mods & KM_LCTRL) && key == KC_F1) {
 		active_layout = 0;
 		layout[active_layout]->reset();
@@ -329,6 +339,5 @@
 	}
 
-	if (type == KEY_PRESS && (mods & KM_LCTRL) &&
-		key == KC_F2) {
+	if (type == KEY_PRESS && (kbd_dev->mods & KM_LCTRL) && key == KC_F2) {
 		active_layout = 1;
 		layout[active_layout]->reset();
@@ -336,6 +345,5 @@
 	}
 
-	if (type == KEY_PRESS && (mods & KM_LCTRL) &&
-		key == KC_F3) {
+	if (type == KEY_PRESS && (kbd_dev->mods & KM_LCTRL) && key == KC_F3) {
 		active_layout = 2;
 		layout[active_layout]->reset();
@@ -345,5 +353,5 @@
 	ev.type = type;
 	ev.key = key;
-	ev.mods = mods;
+	ev.mods = kbd_dev->mods;
 	
 	if (ev.mods & KM_NUM_LOCK) {
@@ -506,36 +514,122 @@
  * Kbd functions
  */
-static int usbkbd_get_report_descriptor(usb_hid_dev_kbd_t *kbd_dev)
-{
-	// iterate over all configurations and interfaces
-	// TODO: more configurations!!
-	unsigned i;
-	for (i = 0; i < kbd_dev->conf->config_descriptor.interface_count; ++i) {
-		// TODO: endianness
-		uint16_t length =  kbd_dev->conf->interfaces[i].hid_desc.
-		    report_desc_info.length;
-		size_t actual_size = 0;
-
-		// allocate space for the report descriptor
-		kbd_dev->conf->interfaces[i].report_desc = 
-		    (uint8_t *)malloc(length);
+//static int usbkbd_get_report_descriptor(usb_hid_dev_kbd_t *kbd_dev)
+//{
+//	// iterate over all configurations and interfaces
+//	// TODO: more configurations!!
+//	unsigned i;
+//	for (i = 0; i < kbd_dev->conf->config_descriptor.interface_count; ++i) {
+//		// TODO: endianness
+//		uint16_t length =  kbd_dev->conf->interfaces[i].hid_desc.
+//		    report_desc_info.length;
+//		size_t actual_size = 0;
+
+//		// allocate space for the report descriptor
+//		kbd_dev->conf->interfaces[i].report_desc = 
+//		    (uint8_t *)malloc(length);
 		
-		// get the descriptor from the device
-		int rc = usb_request_get_descriptor(&kbd_dev->ctrl_pipe,
-		    USB_REQUEST_TYPE_CLASS, USB_DESCTYPE_HID_REPORT,
-		    i, 0,
-		    kbd_dev->conf->interfaces[i].report_desc, length,
-		    &actual_size);
-
-		if (rc != EOK) {
-			return rc;
-		}
-
-		assert(actual_size == length);
-
-		//dump_hid_class_descriptor(0, USB_DESCTYPE_HID_REPORT, 
-		//    kbd_dev->conf->interfaces[i].report_desc, length);
-	}
-
+//		// get the descriptor from the device
+//		int rc = usb_request_get_descriptor(&kbd_dev->ctrl_pipe,
+//		    USB_REQUEST_TYPE_CLASS, USB_DESCTYPE_HID_REPORT,
+//		    i, 0,
+//		    kbd_dev->conf->interfaces[i].report_desc, length,
+//		    &actual_size);
+
+//		if (rc != EOK) {
+//			return rc;
+//		}
+
+//		assert(actual_size == length);
+
+//		//dump_hid_class_descriptor(0, USB_DESCTYPE_HID_REPORT, 
+//		//    kbd_dev->conf->interfaces[i].report_desc, length);
+//	}
+
+//	return EOK;
+//}
+
+static int usbkbd_get_report_descriptor(usb_hid_dev_kbd_t *kbd_dev, 
+    uint8_t *config_desc, size_t config_desc_size, uint8_t *iface_desc)
+{
+	assert(kbd_dev != NULL);
+	assert(config_desc != NULL);
+	assert(config_desc_size != 0);
+	assert(iface_desc != NULL);
+	
+	usb_dp_parser_t parser =  {
+		.nesting = usb_dp_standard_descriptor_nesting
+	};
+	
+	usb_dp_parser_data_t parser_data = {
+		.data = config_desc,
+		.size = config_desc_size,
+		.arg = NULL
+	};
+	
+	/*
+	 * First nested descriptor of interface descriptor.
+	 */
+	uint8_t *d = 
+	    usb_dp_get_nested_descriptor(&parser, &parser_data, iface_desc);
+	
+	/*
+	 * Search through siblings until the HID descriptor is found.
+	 */
+	while (d != NULL && *(d + 1) != USB_DESCTYPE_HID) {
+		d = usb_dp_get_sibling_descriptor(&parser, &parser_data, 
+		    iface_desc, d);
+	}
+	
+	if (d == NULL) {
+		usb_log_fatal("No HID descriptor found!\n");
+		return ENOENT;
+	}
+	
+	if (*d != sizeof(usb_standard_hid_descriptor_t)) {
+		usb_log_fatal("HID descriptor hass wrong size (%u, expected %u"
+		    ")\n", *d, sizeof(usb_standard_hid_descriptor_t));
+		return EINVAL;
+	}
+	
+	usb_standard_hid_descriptor_t *hid_desc = 
+	    (usb_standard_hid_descriptor_t *)d;
+	
+	uint16_t length =  hid_desc->report_desc_info.length;
+	size_t actual_size = 0;
+
+	/*
+	 * Allocate space for the report descriptor.
+	 */
+	kbd_dev->report_desc = (uint8_t *)malloc(length);
+	if (kbd_dev->report_desc == NULL) {
+		usb_log_fatal("Failed to allocate space for Report descriptor."
+		    "\n");
+		return ENOMEM;
+	}
+	
+	usb_log_debug("Getting Report descriptor, expected size: %u\n", length);
+	
+	/*
+	 * Get the descriptor from the device.
+	 */
+	int rc = usb_request_get_descriptor(&kbd_dev->ctrl_pipe,
+	    USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_INTERFACE,
+	    USB_DESCTYPE_HID_REPORT, 0,
+	    kbd_dev->iface, kbd_dev->report_desc, length, &actual_size);
+
+	if (rc != EOK) {
+		return rc;
+	}
+
+	if (actual_size != length) {
+		free(kbd_dev->report_desc);
+		kbd_dev->report_desc = NULL;
+		usb_log_fatal("Report descriptor has wrong size (%u, expected "
+		    "%u)\n", actual_size, length);
+		return EINVAL;
+	}
+	
+	usb_log_debug("Done.\n");
+	
 	return EOK;
 }
@@ -588,31 +682,40 @@
 	    descriptors, config_desc.total_length,
 	    &kbd_dev->wire);
+	
 	if (rc != EOK) {
 		usb_log_error("Failed to initialize poll pipe: %s.\n",
 		    str_error(rc));
+		free(descriptors);
 		return rc;
 	}
+	
 	if (!endpoint_mapping[0].present) {
 		usb_log_warning("Not accepting device, " \
 		    "not boot-protocol keyboard.\n");
+		free(descriptors);
 		return EREFUSED;
 	}
-
-	kbd_dev->conf = (usb_hid_configuration_t *)calloc(1, 
-	    sizeof(usb_hid_configuration_t));
-	if (kbd_dev->conf == NULL) {
+	
+	usb_log_debug("Accepted device. Saving interface, and getting Report"
+	    " descriptor.\n");
+	
+	/*
+	 * Save assigned interface number.
+	 */
+	if (endpoint_mapping[0].interface_no < 0) {
+		usb_log_error("Bad interface number.\n");
 		free(descriptors);
-		return ENOMEM;
-	}
-	
-	/*rc = usbkbd_parse_descriptors(descriptors, transferred, kbd_dev->conf);
+		return EINVAL;
+	}
+	
+	kbd_dev->iface = endpoint_mapping[0].interface_no;
+	
+	assert(endpoint_mapping[0].interface != NULL);
+	
+	rc = usbkbd_get_report_descriptor(kbd_dev, descriptors, transferred,
+	    (uint8_t *)endpoint_mapping[0].interface);
+	
 	free(descriptors);
-	if (rc != EOK) {
-		usb_log_warning("Problem with parsing standard descriptors.\n");
-		return rc;
-	}
-
-	// get and report descriptors*/
-	rc = usbkbd_get_report_descriptor(kbd_dev);
+	
 	if (rc != EOK) {
 		usb_log_warning("Problem with parsing REPORT descriptor.\n");
@@ -620,16 +723,6 @@
 	}
 	
-	//usbkbd_print_config(kbd_dev->conf);
-
-	/*
-	 * TODO: 
-	 * 1) select one configuration (lets say the first)
-	 * 2) how many interfaces?? how to select one??
-	 *    ("The default setting for an interface is always alternate 
-	 *      setting zero.")
-	 * 3) find endpoint which is IN and INTERRUPT (parse), save its number
-	 *    as the endpoint for polling
-	 */
-
+	usb_log_debug("Done parsing descriptors.\n");
+	
 	return EOK;
 }
@@ -671,13 +764,10 @@
 
 	/*
-	 * will need all descriptors:
-	 * 1) choose one configuration from configuration descriptors
-	 *    (set it to the device)
-	 * 2) set endpoints from endpoint descriptors
-	 */
-
-	// TODO: get descriptors, parse descriptors and save endpoints
+	 * Get descriptors, parse descriptors and save endpoints.
+	 */
 	usb_endpoint_pipe_start_session(&kbd_dev->ctrl_pipe);
+	
 	rc = usbkbd_process_descriptors(kbd_dev);
+	
 	usb_endpoint_pipe_end_session(&kbd_dev->ctrl_pipe);
 	if (rc != EOK) {
@@ -685,5 +775,5 @@
 	}
 	
-	// save the size of the report
+	// save the size of the report (boot protocol report by default)
 	kbd_dev->keycode_count = BOOTP_REPORT_SIZE;
 	kbd_dev->keycodes = (uint8_t *)calloc(
@@ -695,13 +785,13 @@
 	}
 	
-	// set configuration to the first one
-	// TODO: handle case with no configurations
-	usb_endpoint_pipe_start_session(&kbd_dev->ctrl_pipe);
-	usb_request_set_configuration(&kbd_dev->ctrl_pipe, 
-	    kbd_dev->conf->config_descriptor.configuration_number);
-	usb_endpoint_pipe_end_session(&kbd_dev->ctrl_pipe);
+	kbd_dev->modifiers = 0;
+	kbd_dev->mods = DEFAULT_ACTIVE_MODS;
+	kbd_dev->lock_keys = 0;
 	
 	// set boot protocol
-	usbkbd_req_set_protocol(kbd_dev, 1, USB_HID_PROTOCOL_BOOT);
+	usbkbd_req_set_protocol(kbd_dev, USB_HID_PROTOCOL_BOOT);
+	
+	// set LEDs according to internal setup (NUM LOCK enabled)
+	usbkbd_set_led(kbd_dev);
 	
 	return kbd_dev;
@@ -743,5 +833,5 @@
 
 	while (true) {
-		async_usleep(1000 * 1000);
+		async_usleep(1000 * 10);
 
 		sess_rc = usb_endpoint_pipe_start_session(&kbd_dev->poll_pipe);
