Index: uspace/app/mkbd/main.c
===================================================================
--- uspace/app/mkbd/main.c	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/app/mkbd/main.c	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -69,5 +69,5 @@
 	int rc = usb_hid_report_init(*report);
 	if (rc != EOK) {
-		usb_hid_free_report(*report);
+		usb_hid_report_deinit(*report);
 		*report = NULL;
 		return rc;
@@ -79,5 +79,5 @@
 	    &report_desc_size);
 	if (rc != EOK) {
-		usb_hid_free_report(*report);
+		usb_hid_report_deinit(*report);
 		*report = NULL;
 		return rc;
@@ -85,5 +85,5 @@
 	
 	if (report_desc_size == 0) {
-		usb_hid_free_report(*report);
+		usb_hid_report_deinit(*report);
 		*report = NULL;
 		// TODO: other error code?
@@ -93,5 +93,5 @@
 	uint8_t *desc = (uint8_t *) malloc(report_desc_size);
 	if (desc == NULL) {
-		usb_hid_free_report(*report);
+		usb_hid_report_deinit(*report);
 		*report = NULL;
 		return ENOMEM;
@@ -103,5 +103,5 @@
 	    &actual_size);
 	if (rc != EOK) {
-		usb_hid_free_report(*report);
+		usb_hid_report_deinit(*report);
 		*report = NULL;
 		free(desc);
@@ -110,5 +110,5 @@
 	
 	if (actual_size != report_desc_size) {
-		usb_hid_free_report(*report);
+		usb_hid_report_deinit(*report);
 		*report = NULL;
 		free(desc);
Index: uspace/app/usbinfo/hid.c
===================================================================
--- uspace/app/usbinfo/hid.c	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/app/usbinfo/hid.c	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -167,5 +167,5 @@
 
 	free(raw_report);
-	usb_hid_free_report(&report);
+	usb_hid_report_deinit(&report);
 }
 
Index: uspace/drv/bus/usb/ohci/endpoint_list.c
===================================================================
--- uspace/drv/bus/usb/ohci/endpoint_list.c	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/drv/bus/usb/ohci/endpoint_list.c	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -60,5 +60,5 @@
 	    name, instance->list_head, instance->list_head_pa);
 
-	ed_init(instance->list_head, NULL);
+	ed_init(instance->list_head, NULL, NULL);
 	list_initialize(&instance->endpoint_list);
 	fibril_mutex_initialize(&instance->guard);
Index: uspace/drv/bus/usb/ohci/hc.c
===================================================================
--- uspace/drv/bus/usb/ohci/hc.c	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/drv/bus/usb/ohci/hc.c	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -565,5 +565,5 @@
 
 	/*Init HCCA */
-	instance->hcca = malloc32(sizeof(hcca_t));
+	instance->hcca = hcca_get();
 	if (instance->hcca == NULL)
 		return ENOMEM;
Index: uspace/drv/bus/usb/ohci/hw_struct/endpoint_descriptor.c
===================================================================
--- uspace/drv/bus/usb/ohci/hw_struct/endpoint_descriptor.c	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/drv/bus/usb/ohci/hw_struct/endpoint_descriptor.c	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -34,31 +34,59 @@
 #include "endpoint_descriptor.h"
 
-static unsigned direc[3] =
-    { ED_STATUS_D_IN, ED_STATUS_D_OUT, ED_STATUS_D_TRANSFER };
+/** USB direction to OHCI values translation table. */
+static const uint32_t dir[] = {
+	[USB_DIRECTION_IN] = ED_STATUS_D_IN,
+	[USB_DIRECTION_OUT] = ED_STATUS_D_OUT,
+	[USB_DIRECTION_BOTH] = ED_STATUS_D_TD,
+};
 
-void ed_init(ed_t *instance, endpoint_t *ep)
+/**
+ * Initialize ED.
+ *
+ * @param instance ED structure to initialize.
+ * @param ep Driver endpoint to use.
+ * @param td TD to put in the list.
+ *
+ * If @param ep is NULL, dummy ED is initalized with only skip flag set.
+ */
+void ed_init(ed_t *instance, const endpoint_t *ep, const td_t *td)
 {
 	assert(instance);
 	bzero(instance, sizeof(ed_t));
+
 	if (ep == NULL) {
+		/* Mark as dead, used for dummy EDs at the beginning of
+		 * endpoint lists. */
 		instance->status = ED_STATUS_K_FLAG;
 		return;
 	}
-	assert(ep);
+	/* Non-dummy ED must have TD assigned */
+	assert(td);
+
+	/* Status: address, endpoint nr, direction mask and max packet size. */
 	instance->status = 0
 	    | ((ep->address & ED_STATUS_FA_MASK) << ED_STATUS_FA_SHIFT)
 	    | ((ep->endpoint & ED_STATUS_EN_MASK) << ED_STATUS_EN_SHIFT)
-	    | ((direc[ep->direction] & ED_STATUS_D_MASK) << ED_STATUS_D_SHIFT)
+	    | ((dir[ep->direction] & ED_STATUS_D_MASK) << ED_STATUS_D_SHIFT)
 	    | ((ep->max_packet_size & ED_STATUS_MPS_MASK)
 	        << ED_STATUS_MPS_SHIFT);
 
-
+	/* Low speed flag */
 	if (ep->speed == USB_SPEED_LOW)
 		instance->status |= ED_STATUS_S_FLAG;
+
+	/* Isochronous format flag */
 	if (ep->transfer_type == USB_TRANSFER_ISOCHRONOUS)
 		instance->status |= ED_STATUS_F_FLAG;
 
+	/* Set TD to the list */
+	const uintptr_t pa = addr_to_phys(td);
+	instance->td_head = pa & ED_TDHEAD_PTR_MASK;
+	instance->td_tail = pa & ED_TDTAIL_PTR_MASK;
+
+	/* Set toggle bit */
 	if (ep->toggle)
 		instance->td_head |= ED_TDHEAD_TOGGLE_CARRY;
+
 }
 /**
Index: uspace/drv/bus/usb/ohci/hw_struct/endpoint_descriptor.h
===================================================================
--- uspace/drv/bus/usb/ohci/hw_struct/endpoint_descriptor.h	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/drv/bus/usb/ohci/hw_struct/endpoint_descriptor.h	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -45,5 +45,14 @@
 #include "completion_codes.h"
 
+/**
+ * OHCI Endpoint Descriptor representation.
+ *
+ * See OHCI spec. Chapter 4.2, page 16 (pdf page 30) for details */
 typedef struct ed {
+	/**
+	 * Status field.
+	 *
+	 * See table 4-1, p. 17 OHCI spec (pdf page 31).
+	 */
 	volatile uint32_t status;
 #define ED_STATUS_FA_MASK (0x7f)   /* USB device address   */
@@ -51,20 +60,32 @@
 #define ED_STATUS_EN_MASK (0xf)    /* USB endpoint address */
 #define ED_STATUS_EN_SHIFT (7)
-#define ED_STATUS_D_MASK (0x3)     /* direction */
+#define ED_STATUS_D_MASK (0x3)     /* Direction */
 #define ED_STATUS_D_SHIFT (11)
 #define ED_STATUS_D_OUT (0x1)
 #define ED_STATUS_D_IN (0x2)
-#define ED_STATUS_D_TRANSFER (0x3)
+#define ED_STATUS_D_TD (0x3) /* Direction is specified by TD */
 
-#define ED_STATUS_S_FLAG (1 << 13) /* speed flag: 1 = low */
-#define ED_STATUS_K_FLAG (1 << 14) /* skip flag (no not execute this ED) */
-#define ED_STATUS_F_FLAG (1 << 15) /* format: 1 = isochronous*/
-#define ED_STATUS_MPS_MASK (0x3ff) /* max_packet_size*/
+#define ED_STATUS_S_FLAG (1 << 13) /* Speed flag: 1 = low */
+#define ED_STATUS_K_FLAG (1 << 14) /* Skip flag (no not execute this ED) */
+#define ED_STATUS_F_FLAG (1 << 15) /* Format: 1 = isochronous */
+#define ED_STATUS_MPS_MASK (0x3ff) /* Maximum packet size */
 #define ED_STATUS_MPS_SHIFT (16)
 
+	/**
+	 * Pointer to the last TD.
+	 *
+	 * OHCI hw never changes this field and uses it only for a reference.
+	 */
 	volatile uint32_t td_tail;
 #define ED_TDTAIL_PTR_MASK (0xfffffff0)
 #define ED_TDTAIL_PTR_SHIFT (0)
 
+	/**
+	 * Pointer to the first TD.
+	 *
+	 * Driver should not change this field if the ED is active.
+	 * This field is updated by OHCI hw and points to the next TD
+	 * to be executed.
+	 */
 	volatile uint32_t td_head;
 #define ED_TDHEAD_PTR_MASK (0xfffffff0)
@@ -75,4 +96,9 @@
 #define ED_TDHEAD_HALTED_FLAG (0x1)
 
+	/**
+	 * Pointer to the next ED.
+	 *
+	 * Driver should not change this field on active EDs.
+	 */
 	volatile uint32_t next;
 #define ED_NEXT_PTR_MASK (0xfffffff0)
@@ -80,33 +106,62 @@
 } __attribute__((packed)) ed_t;
 
-void ed_init(ed_t *instance, endpoint_t *ep);
+void ed_init(ed_t *instance, const endpoint_t *ep, const td_t *td);
 
-static inline void ed_set_td(ed_t *instance, td_t *td)
+/**
+ * Check for SKIP or HALTED flag being set.
+ * @param instance ED
+ * @return true if either SKIP or HALTED flag is set, false otherwise.
+ */
+static inline bool ed_inactive(const ed_t *instance)
 {
 	assert(instance);
-	uintptr_t pa = addr_to_phys(td);
-	instance->td_head =
-	    ((pa & ED_TDHEAD_PTR_MASK)
-	    | (instance->td_head & ~ED_TDHEAD_PTR_MASK));
+	return (instance->td_head & ED_TDHEAD_HALTED_FLAG)
+	    || (instance->status & ED_STATUS_K_FLAG);
+}
+
+/**
+ * Check whether this ED contains TD to be executed.
+ * @param instance ED
+ * @return true if there are pending TDs, false otherwise.
+ */
+static inline bool ed_transfer_pending(const ed_t *instance)
+{
+	assert(instance);
+	return (instance->td_head & ED_TDHEAD_PTR_MASK)
+	    != (instance->td_tail & ED_TDTAIL_PTR_MASK);
+}
+
+/**
+ * Set the last element of TD list
+ * @param instance ED
+ * @param instance TD to set as the last item.
+ */
+static inline void ed_set_tail_td(ed_t *instance, const td_t *td)
+{
+	assert(instance);
+	const uintptr_t pa = addr_to_phys(td);
 	instance->td_tail = pa & ED_TDTAIL_PTR_MASK;
 }
 
-static inline void ed_set_end_td(ed_t *instance, td_t *td)
-{
-	assert(instance);
-	uintptr_t pa = addr_to_phys(td);
-	instance->td_tail = pa & ED_TDTAIL_PTR_MASK;
-}
-
-static inline void ed_append_ed(ed_t *instance, ed_t *next)
+/**
+ * Set next ED in ED chain.
+ * @param instance ED to modify
+ * @param next ED to append
+ */
+static inline void ed_append_ed(ed_t *instance, const ed_t *next)
 {
 	assert(instance);
 	assert(next);
-	uint32_t pa = addr_to_phys(next);
+	const uint32_t pa = addr_to_phys(next);
 	assert((pa & ED_NEXT_PTR_MASK) << ED_NEXT_PTR_SHIFT == pa);
 	instance->next = pa;
 }
 
-static inline int ed_toggle_get(ed_t *instance)
+/**
+ * Get toggle bit value stored in this ED
+ * @param instance ED
+ * @return Toggle bit value
+ */
+static inline int ed_toggle_get(const ed_t *instance)
 {
 	assert(instance);
@@ -114,12 +169,16 @@
 }
 
-static inline void ed_toggle_set(ed_t *instance, int toggle)
+/**
+ * Set toggle bit value stored in this ED
+ * @param instance ED
+ * @param toggle Toggle bit value
+ */
+static inline void ed_toggle_set(ed_t *instance, bool toggle)
 {
 	assert(instance);
-	assert(toggle == 0 || toggle == 1);
-	if (toggle == 1) {
+	if (toggle) {
 		instance->td_head |= ED_TDHEAD_TOGGLE_CARRY;
 	} else {
-		/* clear halted flag when reseting toggle */
+		/* Clear halted flag when reseting toggle TODO: Why? */
 		instance->td_head &= ~ED_TDHEAD_TOGGLE_CARRY;
 		instance->td_head &= ~ED_TDHEAD_HALTED_FLAG;
Index: uspace/drv/bus/usb/ohci/hw_struct/hcca.h
===================================================================
--- uspace/drv/bus/usb/ohci/hw_struct/hcca.h	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/drv/bus/usb/ohci/hw_struct/hcca.h	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -36,4 +36,5 @@
 
 #include <stdint.h>
+#include <malloc.h>
 
 /** Host controller communication area.
@@ -48,4 +49,9 @@
 } __attribute__((packed, aligned)) hcca_t;
 
+static inline void * hcca_get(void)
+{
+	assert(sizeof(hcca_t) == 256);
+	return memalign(256, sizeof(hcca_t));
+}
 #endif
 /**
Index: uspace/drv/bus/usb/ohci/hw_struct/transfer_descriptor.c
===================================================================
--- uspace/drv/bus/usb/ohci/hw_struct/transfer_descriptor.c	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/drv/bus/usb/ohci/hw_struct/transfer_descriptor.c	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -35,22 +35,42 @@
 #include "transfer_descriptor.h"
 
-static unsigned dp[3] =
-    { TD_STATUS_DP_IN, TD_STATUS_DP_OUT, TD_STATUS_DP_SETUP };
-static unsigned togg[2] = { TD_STATUS_T_0, TD_STATUS_T_1 };
+/** USB direction to OHCI TD values translation table */
+static const uint32_t dir[] = {
+	[USB_DIRECTION_IN] = TD_STATUS_DP_IN,
+	[USB_DIRECTION_OUT] = TD_STATUS_DP_OUT,
+	[USB_DIRECTION_BOTH] = TD_STATUS_DP_SETUP,
+};
 
-void td_init(td_t *instance,
-    usb_direction_t dir, const void *buffer, size_t size, int toggle)
+/**
+ * Initialize OHCI TD.
+ * @param instance TD structure to initialize.
+ * @param next Next TD in ED list.
+ * @param direction Used to determine PID, BOTH means setup PID.
+ * @param buffer Pointer to the first byte of transferred data.
+ * @param size Size of the buffer.
+ * @param toggle Toggle bit value, use 0/1 to set explicitly,
+ *        any other value means that ED toggle will be used.
+ */
+void td_init(td_t *instance, const td_t *next,
+    usb_direction_t direction, const void *buffer, size_t size, int toggle)
 {
 	assert(instance);
 	bzero(instance, sizeof(td_t));
+	/* Set PID and Error code */
 	instance->status = 0
-	    | ((dp[dir] & TD_STATUS_DP_MASK) << TD_STATUS_DP_SHIFT)
+	    | ((dir[direction] & TD_STATUS_DP_MASK) << TD_STATUS_DP_SHIFT)
 	    | ((CC_NOACCESS2 & TD_STATUS_CC_MASK) << TD_STATUS_CC_SHIFT);
+
 	if (toggle == 0 || toggle == 1) {
-		instance->status |= togg[toggle] << TD_STATUS_T_SHIFT;
+		/* Set explicit toggle bit */
+		instance->status |= TD_STATUS_T_USE_TD_FLAG;
+		instance->status |= toggle ? TD_STATUS_T_FLAG : 0;
 	}
+
+	/* Alow less data on input. */
 	if (dir == USB_DIRECTION_IN) {
 		instance->status |= TD_STATUS_ROUND_FLAG;
 	}
+
 	if (buffer != NULL) {
 		assert(size != 0);
@@ -58,4 +78,7 @@
 		instance->be = addr_to_phys(buffer + size - 1);
 	}
+
+	instance->next = addr_to_phys(next) & TD_NEXT_PTR_MASK;
+
 }
 /**
Index: uspace/drv/bus/usb/ohci/hw_struct/transfer_descriptor.h
===================================================================
--- uspace/drv/bus/usb/ohci/hw_struct/transfer_descriptor.h	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/drv/bus/usb/ohci/hw_struct/transfer_descriptor.h	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -37,6 +37,6 @@
 #include <bool.h>
 #include <stdint.h>
+
 #include "../utils/malloc32.h"
-
 #include "completion_codes.h"
 
@@ -46,52 +46,64 @@
 #define OHCI_TD_MAX_TRANSFER (4 * 1024)
 
+/**
+ * Transfer Descriptor representation.
+ *
+ * See OHCI spec chapter 4.3.1 General Transfer Descriptor on page 19
+ * (pdf page 33) for details.
+ */
 typedef struct td {
+	/** Status field. Do not touch on active TDs. */
 	volatile uint32_t status;
 #define TD_STATUS_ROUND_FLAG (1 << 18)
-#define TD_STATUS_DP_MASK (0x3) /* direction/PID */
+#define TD_STATUS_DP_MASK (0x3) /* Direction/PID */
 #define TD_STATUS_DP_SHIFT (19)
 #define TD_STATUS_DP_SETUP (0x0)
 #define TD_STATUS_DP_OUT (0x1)
 #define TD_STATUS_DP_IN (0x2)
-#define TD_STATUS_DI_MASK (0x7) /* delay interrupt, wait DI frames before int */
+#define TD_STATUS_DI_MASK (0x7) /* Delay interrupt, wait n frames before irq */
 #define TD_STATUS_DI_SHIFT (21)
 #define TD_STATUS_DI_NO_INTERRUPT (0x7)
-#define TD_STATUS_T_MASK (0x3)  /* data toggle 1x = use ED toggle carry */
-#define TD_STATUS_T_SHIFT (24)
-#define TD_STATUS_T_0 (0x2)
-#define TD_STATUS_T_1 (0x3)
-#define TD_STATUS_T_ED (0)
-#define TD_STATUS_EC_MASK (0x3) /* error count */
+#define TD_STATUS_T_FLAG (1 << 24) /* Explicit toggle bit value for this TD */
+#define TD_STATUS_T_USE_TD_FLAG (1 << 25) /* 1 = use bit 24 as toggle bit */
+#define TD_STATUS_EC_MASK (0x3) /* Error count */
 #define TD_STATUS_EC_SHIFT (26)
-#define TD_STATUS_CC_MASK (0xf) /* condition code */
+#define TD_STATUS_CC_MASK (0xf) /* Condition code */
 #define TD_STATUS_CC_SHIFT (28)
 
-	volatile uint32_t cbp; /* current buffer ptr, data to be transfered */
+	/**
+	 * Current buffer pointer.
+	 * Phys address of the first byte to be transferred. */
+	volatile uint32_t cbp;
+
+	/** Pointer to the next TD in chain. 16-byte aligned. */
 	volatile uint32_t next;
 #define TD_NEXT_PTR_MASK (0xfffffff0)
 #define TD_NEXT_PTR_SHIFT (0)
 
-	volatile uint32_t be; /* buffer end, address of the last byte */
+	/**
+	 * Buffer end.
+	 * Phys address of the last byte of the transfer.
+	 * @note this does not have to be on the same page as cbp.
+	 */
+	volatile uint32_t be;
 } __attribute__((packed)) td_t;
 
-void td_init(td_t *instance,
+void td_init(td_t *instance, const td_t *next,
     usb_direction_t dir, const void *buffer, size_t size, int toggle);
 
-inline static void td_set_next(td_t *instance, td_t *next)
+/**
+ * Check TD for completion.
+ * @param instance TD structure.
+ * @return true if the TD was accessed and processed by hw, false otherwise.
+ */
+inline static bool td_is_finished(const td_t *instance)
 {
 	assert(instance);
-	instance->next = addr_to_phys(next) & TD_NEXT_PTR_MASK;
-}
-
-inline static bool td_is_finished(td_t *instance)
-{
-	assert(instance);
-	int cc = (instance->status >> TD_STATUS_CC_SHIFT) & TD_STATUS_CC_MASK;
-	/* something went wrong, error code is set */
+	const int cc =
+	    (instance->status >> TD_STATUS_CC_SHIFT) & TD_STATUS_CC_MASK;
+	/* This value is changed on transfer completion,
+	 * either to CC_NOERROR or and error code.
+	 * See OHCI spec 4.3.1.3.5 p. 23 (pdf 37) */
 	if (cc != CC_NOACCESS1 && cc != CC_NOACCESS2) {
-		return true;
-	}
-	/* everything done */
-	if (cc == CC_NOERROR && instance->cbp == 0) {
 		return true;
 	}
@@ -99,16 +111,29 @@
 }
 
-static inline int td_error(td_t *instance)
+/**
+ * Get error code that indicates transfer status.
+ * @param instance TD structure.
+ * @return Error code.
+ */
+static inline int td_error(const td_t *instance)
 {
 	assert(instance);
-	int cc = (instance->status >> TD_STATUS_CC_SHIFT) & TD_STATUS_CC_MASK;
+	const int cc =
+	    (instance->status >> TD_STATUS_CC_SHIFT) & TD_STATUS_CC_MASK;
 	return cc_to_rc(cc);
 }
 
+/**
+ * Get remaining portion of buffer to be read/written
+ * @param instance TD structure
+ * @return size of remaining buffer.
+ */
 static inline size_t td_remain_size(td_t *instance)
 {
 	assert(instance);
+	/* Current buffer pointer is cleared on successful transfer */
 	if (instance->cbp == 0)
 		return 0;
+	/* Buffer end points to the last byte of transfer buffer, so add 1 */
 	return instance->be - instance->cbp + 1;
 }
Index: uspace/drv/bus/usb/ohci/ohci_batch.c
===================================================================
--- uspace/drv/bus/usb/ohci/ohci_batch.c	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/drv/bus/usb/ohci/ohci_batch.c	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -163,13 +163,38 @@
 	    ohci_batch->ed->td_tail, ohci_batch->ed->next);
 
-	size_t i = 0;
-	for (; i < ohci_batch->td_count; ++i) {
+	if (!ed_inactive(ohci_batch->ed) && ed_transfer_pending(ohci_batch->ed))
+		return false;
+
+	/* Now we may be sure that either the ED is inactive because of errors
+	 * or all transfer descriptors completed successfully */
+
+	/* Assume all data got through */
+	ohci_batch->usb_batch->transfered_size =
+	    ohci_batch->usb_batch->buffer_size;
+
+	/* Assume we will leave the last(unused) TD behind */
+	ohci_batch->leave_td = ohci_batch->td_count;
+
+	/* Check all TDs */
+	for (size_t i = 0; i < ohci_batch->td_count; ++i) {
 		assert(ohci_batch->tds[i] != NULL);
 		usb_log_debug("TD %zu: %08x:%08x:%08x:%08x.\n", i,
 		    ohci_batch->tds[i]->status, ohci_batch->tds[i]->cbp,
 		    ohci_batch->tds[i]->next, ohci_batch->tds[i]->be);
-		if (!td_is_finished(ohci_batch->tds[i])) {
-			return false;
-		}
+
+		/* If the TD got all its data through, it will report 0 bytes
+		 * remain, the sole exception is INPUT with data rounding flag
+		 * (short), i.e. every INPUT. Nice thing is that short packets
+		 * will correctly report remaining data, thus making
+		 * this computation correct (short packets need to be produced
+		 * by the last TD)
+		 * NOTE: This also works for CONTROL transfer as
+		 * the first TD will return 0 remain.
+		 * NOTE: Short packets don't break the assumption that
+		 * we leave the very last(unused) TD behind.
+		 */
+		ohci_batch->usb_batch->transfered_size
+		    -= td_remain_size(ohci_batch->tds[i]);
+
 		ohci_batch->usb_batch->error = td_error(ohci_batch->tds[i]);
 		if (ohci_batch->usb_batch->error != EOK) {
@@ -177,30 +202,39 @@
 			    ohci_batch->usb_batch, i,
 			    ohci_batch->tds[i]->status);
-			/* Make sure TD queue is empty (one TD),
-			 * ED should be marked as halted */
-			ohci_batch->ed->td_tail =
-			    (ohci_batch->ed->td_head & ED_TDTAIL_PTR_MASK);
-			++i;
+
+			/* ED should be stopped because of errors */
+			assert((ohci_batch->ed->td_head & ED_TDHEAD_HALTED_FLAG) != 0);
+
+			/* Now we have a problem: we don't know what TD
+			 * the head pointer points to, the retiring rules
+			 * described in specs say it should be the one after
+			 * the failed one so set the tail pointer accordingly.
+			 * It will be the one TD we leave behind.
+			 */
+			ohci_batch->leave_td = i + 1;
+
+			/* Check TD assumption */
+			const uint32_t pa = addr_to_phys(
+			    ohci_batch->tds[ohci_batch->leave_td]);
+			assert((ohci_batch->ed->td_head & ED_TDTAIL_PTR_MASK)
+			    == pa);
+
+			ed_set_tail_td(ohci_batch->ed,
+			    ohci_batch->tds[ohci_batch->leave_td]);
+
+			/* Clear possible ED HALT */
+			ohci_batch->ed->td_head &= ~ED_TDHEAD_HALTED_FLAG;
 			break;
 		}
 	}
-
-	assert(i <= ohci_batch->td_count);
-	ohci_batch->leave_td = i;
-
+	assert(ohci_batch->usb_batch->transfered_size <=
+	    ohci_batch->usb_batch->buffer_size);
+
+	/* Store the remaining TD */
 	ohci_endpoint_t *ohci_ep = ohci_endpoint_get(ohci_batch->usb_batch->ep);
 	assert(ohci_ep);
 	ohci_ep->td = ohci_batch->tds[ohci_batch->leave_td];
-	assert(i > 0);
-	ohci_batch->usb_batch->transfered_size =
-	    ohci_batch->usb_batch->buffer_size;
-	for (--i;i < ohci_batch->td_count; ++i) {
-		ohci_batch->usb_batch->transfered_size
-		    -= td_remain_size(ohci_batch->tds[i]);
-	}
-
-	/* Clear possible ED HALT */
-	ohci_batch->ed->td_head &= ~ED_TDHEAD_HALTED_FLAG;
-	/* just make sure that we are leaving the right TD behind */
+
+	/* Make sure that we are leaving the right TD behind */
 	const uint32_t pa = addr_to_phys(ohci_ep->td);
 	assert(pa == (ohci_batch->ed->td_head & ED_TDHEAD_PTR_MASK));
@@ -217,5 +251,5 @@
 {
 	assert(ohci_batch);
-	ed_set_end_td(ohci_batch->ed, ohci_batch->tds[ohci_batch->td_count]);
+	ed_set_tail_td(ohci_batch->ed, ohci_batch->tds[ohci_batch->td_count]);
 }
 /*----------------------------------------------------------------------------*/
@@ -247,8 +281,8 @@
 	const usb_direction_t status_dir = reverse_dir[dir];
 
-	/* setup stage */
-	td_init(ohci_batch->tds[0], USB_DIRECTION_BOTH, buffer,
-		ohci_batch->usb_batch->setup_size, toggle);
-	td_set_next(ohci_batch->tds[0], ohci_batch->tds[1]);
+	/* Setup stage */
+	td_init(
+	    ohci_batch->tds[0], ohci_batch->tds[1], USB_DIRECTION_BOTH,
+	    buffer, ohci_batch->usb_batch->setup_size, toggle);
 	usb_log_debug("Created CONTROL SETUP TD: %08x:%08x:%08x:%08x.\n",
 	    ohci_batch->tds[0]->status, ohci_batch->tds[0]->cbp,
@@ -256,5 +290,5 @@
 	buffer += ohci_batch->usb_batch->setup_size;
 
-	/* data stage */
+	/* Data stage */
 	size_t td_current = 1;
 	size_t remain_size = ohci_batch->usb_batch->buffer_size;
@@ -265,8 +299,7 @@
 		toggle = 1 - toggle;
 
-		td_init(ohci_batch->tds[td_current], data_dir, buffer,
-		    transfer_size, toggle);
-		td_set_next(ohci_batch->tds[td_current],
-		    ohci_batch->tds[td_current + 1]);
+		td_init(ohci_batch->tds[td_current],
+		    ohci_batch->tds[td_current + 1],
+		    data_dir, buffer, transfer_size, toggle);
 		usb_log_debug("Created CONTROL DATA TD: %08x:%08x:%08x:%08x.\n",
 		    ohci_batch->tds[td_current]->status,
@@ -281,9 +314,8 @@
 	}
 
-	/* status stage */
+	/* Status stage */
 	assert(td_current == ohci_batch->td_count - 1);
-	td_init(ohci_batch->tds[td_current], status_dir, NULL, 0, 1);
-	td_set_next(ohci_batch->tds[td_current],
-	    ohci_batch->tds[td_current + 1]);
+	td_init(ohci_batch->tds[td_current], ohci_batch->tds[td_current + 1],
+	    status_dir, NULL, 0, 1);
 	usb_log_debug("Created CONTROL STATUS TD: %08x:%08x:%08x:%08x.\n",
 	    ohci_batch->tds[td_current]->status,
@@ -323,8 +355,7 @@
 		    ? OHCI_TD_MAX_TRANSFER : remain_size;
 
-		td_init(ohci_batch->tds[td_current], dir, buffer,
-		    transfer_size, -1);
-		td_set_next(ohci_batch->tds[td_current],
-		    ohci_batch->tds[td_current + 1]);
+		td_init(
+		    ohci_batch->tds[td_current], ohci_batch->tds[td_current + 1],
+		    dir, buffer, transfer_size, -1);
 
 		usb_log_debug("Created DATA TD: %08x:%08x:%08x:%08x.\n",
Index: uspace/drv/bus/usb/ohci/ohci_endpoint.c
===================================================================
--- uspace/drv/bus/usb/ohci/ohci_endpoint.c	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/drv/bus/usb/ohci/ohci_endpoint.c	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -102,6 +102,5 @@
 	}
 
-	ed_init(ohci_ep->ed, ep);
-	ed_set_td(ohci_ep->ed, ohci_ep->td);
+	ed_init(ohci_ep->ed, ep, ohci_ep->td);
 	endpoint_set_hc_data(
 	    ep, ohci_ep, ohci_endpoint_fini, ohci_ep_toggle_get, ohci_ep_toggle_set);
Index: uspace/drv/bus/usb/ohci/root_hub.c
===================================================================
--- uspace/drv/bus/usb/ohci/root_hub.c	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/drv/bus/usb/ohci/root_hub.c	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -35,6 +35,9 @@
 #include <errno.h>
 #include <str_error.h>
+#include <fibril_synch.h>
 
 #include <usb/debug.h>
+#include <usb/dev/request.h>
+#include <usb/classes/hub.h>
 
 #include "root_hub.h"
@@ -43,7 +46,4 @@
 #include <usb/dev/driver.h>
 #include "ohci_regs.h"
-
-#include <usb/dev/request.h>
-#include <usb/classes/hub.h>
 
 /**
@@ -108,11 +108,13 @@
 static void create_serialized_hub_descriptor(rh_t *instance);
 static void rh_init_descriptors(rh_t *instance);
-static uint16_t create_interrupt_mask(rh_t *instance);
-static int get_status(rh_t *instance, usb_transfer_batch_t *request);
-static int get_descriptor(rh_t *instance, usb_transfer_batch_t *request);
-static int set_feature(rh_t *instance, usb_transfer_batch_t *request);
-static int clear_feature(rh_t *instance, usb_transfer_batch_t *request);
-static int set_feature_port(rh_t *instance, uint16_t feature, uint16_t port);
-static int clear_feature_port(rh_t *instance, uint16_t feature, uint16_t port);
+static uint16_t create_interrupt_mask(const rh_t *instance);
+static int get_status(const rh_t *instance, usb_transfer_batch_t *request);
+static int get_descriptor(const rh_t *instance, usb_transfer_batch_t *request);
+static int set_feature(const rh_t *instance, usb_transfer_batch_t *request);
+static int clear_feature(const rh_t *instance, usb_transfer_batch_t *request);
+static int set_feature_port(
+    const rh_t *instance, uint16_t feature, uint16_t port);
+static int clear_feature_port(
+    const rh_t *instance, uint16_t feature, uint16_t port);
 static int control_request(rh_t *instance, usb_transfer_batch_t *request);
 static inline void interrupt_request(
@@ -153,9 +155,11 @@
 	instance->unfinished_interrupt_transfer = NULL;
 
-#ifdef OHCI_POWER_SWITCH_no
+#if defined OHCI_POWER_SWITCH_no
 	/* Set port power mode to no power-switching. (always on) */
 	instance->registers->rh_desc_a |= RHDA_NPS_FLAG;
+
 	/* Set to no over-current reporting */
 	instance->registers->rh_desc_a |= RHDA_NOCP_FLAG;
+
 #elif defined OHCI_POWER_SWITCH_ganged
 	/* Set port power mode to no ganged power-switching. */
@@ -163,4 +167,5 @@
 	instance->registers->rh_desc_a &= ~RHDA_PSM_FLAG;
 	instance->registers->rh_status = RHS_CLEAR_GLOBAL_POWER;
+
 	/* Set to global over-current */
 	instance->registers->rh_desc_a &= ~RHDA_NOCP_FLAG;
@@ -174,7 +179,9 @@
 	instance->registers->rh_desc_b &= (RHDB_PCC_MASK << RHDB_PCC_SHIFT);
 	instance->registers->rh_status = RHS_CLEAR_GLOBAL_POWER;
+
 	/* Return control to per port state */
 	instance->registers->rh_desc_b |=
 		((1 << (instance->port_count + 1)) - 1) << RHDB_PCC_SHIFT;
+
 	/* Set per port over-current */
 	instance->registers->rh_desc_a &= ~RHDA_NOCP_FLAG;
@@ -182,4 +189,5 @@
 #endif
 
+	fibril_mutex_initialize(&instance->guard);
 	rh_init_descriptors(instance);
 
@@ -209,13 +217,16 @@
 	case USB_TRANSFER_INTERRUPT:
 		usb_log_debug("Root hub got INTERRUPT packet\n");
+		fibril_mutex_lock(&instance->guard);
+		assert(instance->unfinished_interrupt_transfer == NULL);
 		const uint16_t mask = create_interrupt_mask(instance);
 		if (mask == 0) {
 			usb_log_debug("No changes..\n");
-			assert(instance->unfinished_interrupt_transfer == NULL);
 			instance->unfinished_interrupt_transfer = request;
+			fibril_mutex_unlock(&instance->guard);
 			return;
 		}
 		usb_log_debug("Processing changes...\n");
 		interrupt_request(request, mask, instance->interrupt_mask_size);
+		fibril_mutex_unlock(&instance->guard);
 		break;
 
@@ -237,14 +248,15 @@
 	assert(instance);
 
-	if (!instance->unfinished_interrupt_transfer)
-		return;
-
-	usb_log_debug("Finalizing interrupt transfer\n");
-	const uint16_t mask = create_interrupt_mask(instance);
-	interrupt_request(instance->unfinished_interrupt_transfer,
-	    mask, instance->interrupt_mask_size);
-	usb_transfer_batch_dispose(instance->unfinished_interrupt_transfer);
-
-	instance->unfinished_interrupt_transfer = NULL;
+	fibril_mutex_lock(&instance->guard);
+	if (instance->unfinished_interrupt_transfer) {
+		usb_log_debug("Finalizing interrupt transfer\n");
+		const uint16_t mask = create_interrupt_mask(instance);
+		interrupt_request(instance->unfinished_interrupt_transfer,
+		    mask, instance->interrupt_mask_size);
+		usb_transfer_batch_dispose(
+		    instance->unfinished_interrupt_transfer);
+		instance->unfinished_interrupt_transfer = NULL;
+	}
+	fibril_mutex_unlock(&instance->guard);
 }
 /*----------------------------------------------------------------------------*/
@@ -342,5 +354,5 @@
  * @return Mask of changes.
  */
-uint16_t create_interrupt_mask(rh_t *instance)
+uint16_t create_interrupt_mask(const rh_t *instance)
 {
 	assert(instance);
@@ -372,5 +384,5 @@
  * @return error code
  */
-int get_status(rh_t *instance, usb_transfer_batch_t *request)
+int get_status(const rh_t *instance, usb_transfer_batch_t *request)
 {
 	assert(instance);
@@ -418,5 +430,5 @@
  * @return Error code
  */
-int get_descriptor(rh_t *instance, usb_transfer_batch_t *request)
+int get_descriptor(const rh_t *instance, usb_transfer_batch_t *request)
 {
 	assert(instance);
@@ -496,5 +508,5 @@
  * @return error code
  */
-int set_feature_port(rh_t *instance, uint16_t feature, uint16_t port)
+int set_feature_port(const rh_t *instance, uint16_t feature, uint16_t port)
 {
 	assert(instance);
@@ -535,5 +547,5 @@
  * @return error code
  */
-int clear_feature_port(rh_t *instance, uint16_t feature, uint16_t port)
+int clear_feature_port(const rh_t *instance, uint16_t feature, uint16_t port)
 {
 	assert(instance);
@@ -592,5 +604,5 @@
  * @return error code
  */
-int set_feature(rh_t *instance, usb_transfer_batch_t *request)
+int set_feature(const rh_t *instance, usb_transfer_batch_t *request)
 {
 	assert(instance);
@@ -628,5 +640,5 @@
  * @return error code
  */
-int clear_feature(rh_t *instance, usb_transfer_batch_t *request)
+int clear_feature(const rh_t *instance, usb_transfer_batch_t *request)
 {
 	assert(instance);
@@ -635,5 +647,7 @@
 	const usb_device_request_setup_packet_t *setup_request =
 	    (usb_device_request_setup_packet_t *) request->setup_buffer;
+
 	request->transfered_size = 0;
+
 	switch (setup_request->request_type)
 	{
@@ -647,6 +661,7 @@
 		/*
 		 * Chapter 11.16.2 specifies that only C_HUB_LOCAL_POWER and
-		 * C_HUB_OVER_CURRENT are supported. C_HUB_OVER_CURRENT is represented
-		 * by OHCI RHS_OCIC_FLAG. C_HUB_LOCAL_POWER is not supported
+		 * C_HUB_OVER_CURRENT are supported.
+		 * C_HUB_OVER_CURRENT is represented by OHCI RHS_OCIC_FLAG.
+		 * C_HUB_LOCAL_POWER is not supported
 		 * as root hubs do not support local power status feature.
 		 * (OHCI pg. 127) */
@@ -720,4 +735,5 @@
 		    "additional data\n");
 		return clear_feature(instance, request);
+
 	case USB_DEVREQ_SET_FEATURE:
 		usb_log_debug2("Processing request without "
Index: uspace/drv/bus/usb/ohci/root_hub.h
===================================================================
--- uspace/drv/bus/usb/ohci/root_hub.h	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/drv/bus/usb/ohci/root_hub.h	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -47,4 +47,5 @@
  */
 typedef struct rh {
+	fibril_mutex_t guard;
 	/** pointer to ohci driver registers */
 	ohci_regs_t *registers;
Index: uspace/drv/bus/usb/ohci/utils/malloc32.h
===================================================================
--- uspace/drv/bus/usb/ohci/utils/malloc32.h	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/drv/bus/usb/ohci/utils/malloc32.h	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -41,4 +41,10 @@
 #include <as.h>
 
+/* Generic TDs and EDs require 16byte alignment,
+ * Isochronous TD require 32byte alignment,
+ * buffers do not have to be aligned.
+ */
+#define OHCI_ALIGN 32
+
 /** Get physical address translation
  *
@@ -62,5 +68,5 @@
  */
 static inline void * malloc32(size_t size)
-	{ return memalign(size, size); }
+	{ return memalign(OHCI_ALIGN, size); }
 /*----------------------------------------------------------------------------*/
 /** Physical mallocator simulator
Index: uspace/drv/bus/usb/usbhid/generic/hiddev.c
===================================================================
--- uspace/drv/bus/usb/usbhid/generic/hiddev.c	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/drv/bus/usb/usbhid/generic/hiddev.c	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -48,5 +48,5 @@
 /*----------------------------------------------------------------------------*/
 
-usb_endpoint_description_t usb_hid_generic_poll_endpoint_description = {
+const usb_endpoint_description_t usb_hid_generic_poll_endpoint_description = {
 	.transfer_type = USB_TRANSFER_INTERRUPT,
 	.direction = USB_DIRECTION_IN,
Index: uspace/drv/bus/usb/usbhid/generic/hiddev.h
===================================================================
--- uspace/drv/bus/usb/usbhid/generic/hiddev.h	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/drv/bus/usb/usbhid/generic/hiddev.h	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -41,5 +41,6 @@
 struct usb_hid_dev;
 
-usb_endpoint_description_t usb_hid_generic_poll_endpoint_description;
+extern const usb_endpoint_description_t
+    usb_hid_generic_poll_endpoint_description;
 
 const char *HID_GENERIC_FUN_NAME;
Index: uspace/drv/bus/usb/usbhid/kbd/kbddev.c
===================================================================
--- uspace/drv/bus/usb/usbhid/kbd/kbddev.c	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/drv/bus/usb/usbhid/kbd/kbddev.c	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -88,5 +88,5 @@
 
 /** Keyboard polling endpoint description for boot protocol class. */
-usb_endpoint_description_t usb_hid_kbd_poll_endpoint_description = {
+const usb_endpoint_description_t usb_hid_kbd_poll_endpoint_description = {
 	.transfer_type = USB_TRANSFER_INTERRUPT,
 	.direction = USB_DIRECTION_IN,
@@ -237,33 +237,33 @@
 
 	usb_hid_report_field_t *field = usb_hid_report_get_sibling(
-	    hid_dev->report, NULL, kbd_dev->led_path, 
+	    &hid_dev->report, NULL, kbd_dev->led_path,
 	    USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
 	    USB_HID_REPORT_TYPE_OUTPUT);
 
 	while (field != NULL) {
-		
-		if ((field->usage == USB_HID_LED_NUM_LOCK) 
+
+		if ((field->usage == USB_HID_LED_NUM_LOCK)
 		    && (kbd_dev->mods & KM_NUM_LOCK)){
 			field->value = 1;
 		}
 
-		if ((field->usage == USB_HID_LED_CAPS_LOCK) 
+		if ((field->usage == USB_HID_LED_CAPS_LOCK)
 		    && (kbd_dev->mods & KM_CAPS_LOCK)){
 			field->value = 1;
 		}
 
-		if ((field->usage == USB_HID_LED_SCROLL_LOCK) 
+		if ((field->usage == USB_HID_LED_SCROLL_LOCK)
 		    && (kbd_dev->mods & KM_SCROLL_LOCK)){
 			field->value = 1;
 		}
-		
-		field = usb_hid_report_get_sibling(hid_dev->report, field,
-		    kbd_dev->led_path,  
-	    	USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
-			USB_HID_REPORT_TYPE_OUTPUT);
+
+		field = usb_hid_report_get_sibling(
+		    &hid_dev->report, field, kbd_dev->led_path,
+		USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
+		    USB_HID_REPORT_TYPE_OUTPUT);
 	}
 
 	// TODO: what about the Report ID?
-	int rc = usb_hid_report_output_translate(hid_dev->report, 0,
+	int rc = usb_hid_report_output_translate(&hid_dev->report, 0,
 	    kbd_dev->output_buffer, kbd_dev->output_size);
 
@@ -432,5 +432,4 @@
 static void usb_kbd_process_data(usb_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev)
 {
-	assert(hid_dev->report != NULL);
 	assert(hid_dev != NULL);
 	assert(kbd_dev != NULL);
@@ -444,6 +443,6 @@
 
 	usb_hid_report_field_t *field = usb_hid_report_get_sibling(
-	    hid_dev->report, NULL, path, 
-	    USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 
+	    &hid_dev->report, NULL, path,
+	    USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
 	    USB_HID_REPORT_TYPE_INPUT);
 	unsigned i = 0;
@@ -454,5 +453,5 @@
 		
 		assert(i < kbd_dev->key_count);
-		
+
 		// save the key usage
 		if (field->value != 0) {
@@ -463,9 +462,9 @@
 		}
 		usb_log_debug2("Saved %u. key usage %d\n", i, kbd_dev->keys[i]);
-		
+
 		++i;
-		field = usb_hid_report_get_sibling(hid_dev->report, field, path, 
-		    USB_HID_PATH_COMPARE_END 
-		    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 
+		field = usb_hid_report_get_sibling(
+		    &hid_dev->report, field, path, USB_HID_PATH_COMPARE_END
+		        | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
 		    USB_HID_REPORT_TYPE_INPUT);
 	}
@@ -616,10 +615,10 @@
 
 	kbd_dev->key_count = usb_hid_report_size(
-	    hid_dev->report, 0, USB_HID_REPORT_TYPE_INPUT); 
+	    &hid_dev->report, 0, USB_HID_REPORT_TYPE_INPUT);
 	usb_hid_report_path_free(path);
 
 	usb_log_debug("Size of the input report: %zu\n", kbd_dev->key_count);
 
-	kbd_dev->keys = (int32_t *)calloc(kbd_dev->key_count, sizeof(int32_t));
+	kbd_dev->keys = calloc(kbd_dev->key_count, sizeof(int32_t));
 
 	if (kbd_dev->keys == NULL) {
@@ -643,5 +642,5 @@
 	 */
 	kbd_dev->output_size = 0;
-	kbd_dev->output_buffer = usb_hid_report_output(hid_dev->report, 
+	kbd_dev->output_buffer = usb_hid_report_output(&hid_dev->report,
 	    &kbd_dev->output_size, 0);
 	if (kbd_dev->output_buffer == NULL) {
@@ -657,6 +656,6 @@
 	    kbd_dev->led_path, USB_HIDUT_PAGE_LED, 0);
 
-	kbd_dev->led_output_size = usb_hid_report_size(hid_dev->report, 
-	    0, USB_HID_REPORT_TYPE_OUTPUT);
+	kbd_dev->led_output_size = usb_hid_report_size(
+	    &hid_dev->report, 0, USB_HID_REPORT_TYPE_OUTPUT);
 
 	usb_log_debug("Output report size (in items): %zu\n", 
@@ -826,6 +825,6 @@
 int usb_kbd_set_boot_protocol(usb_hid_dev_t *hid_dev)
 {
-	int rc = usb_hid_parse_report_descriptor(hid_dev->report, 
-	    USB_KBD_BOOT_REPORT_DESCRIPTOR, 
+	int rc = usb_hid_parse_report_descriptor(
+	    &hid_dev->report, USB_KBD_BOOT_REPORT_DESCRIPTOR,
 	    USB_KBD_BOOT_REPORT_DESCRIPTOR_SIZE);
 
@@ -836,5 +835,5 @@
 	}
 
-	rc = usbhid_req_set_protocol(&hid_dev->usb_dev->ctrl_pipe, 
+	rc = usbhid_req_set_protocol(&hid_dev->usb_dev->ctrl_pipe,
 	    hid_dev->usb_dev->interface_no, USB_HID_PROTOCOL_BOOT);
 
Index: uspace/drv/bus/usb/usbhid/kbd/kbddev.h
===================================================================
--- uspace/drv/bus/usb/usbhid/kbd/kbddev.h	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/drv/bus/usb/usbhid/kbd/kbddev.h	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -118,5 +118,5 @@
 /*----------------------------------------------------------------------------*/
 
-usb_endpoint_description_t usb_hid_kbd_poll_endpoint_description;
+extern const usb_endpoint_description_t usb_hid_kbd_poll_endpoint_description;
 
 const char *HID_KBD_FUN_NAME;
Index: uspace/drv/bus/usb/usbhid/main.c
===================================================================
--- uspace/drv/bus/usb/usbhid/main.c	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/drv/bus/usb/usbhid/main.c	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -92,5 +92,5 @@
 	if (rc != EOK) {
 		usb_log_error("Failed to initialize USB/HID device.\n");
-		usb_hid_destroy(hid_dev);
+		usb_hid_deinit(hid_dev);
 		return rc;
 	}
@@ -128,9 +128,8 @@
 		usb_log_error("Failed to start polling fibril for `%s'.\n",
 		    dev->ddf_dev->name);
-		usb_hid_destroy(hid_dev);
+		usb_hid_deinit(hid_dev);
 		return rc;
 	}
 	hid_dev->running = true;
-	dev->driver_data = hid_dev;
 
 	/*
@@ -204,5 +203,5 @@
 
 	assert(!hid_dev->running);
-	usb_hid_destroy(hid_dev);
+	usb_hid_deinit(hid_dev);
 	usb_log_debug2("%s destruction complete.\n", dev->ddf_dev->name);
 	return EOK;
Index: uspace/drv/bus/usb/usbhid/mouse/mousedev.c
===================================================================
--- uspace/drv/bus/usb/usbhid/mouse/mousedev.c	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/drv/bus/usb/usbhid/mouse/mousedev.c	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -59,5 +59,5 @@
 /*----------------------------------------------------------------------------*/
 
-usb_endpoint_description_t usb_hid_mouse_poll_endpoint_description = {
+const usb_endpoint_description_t usb_hid_mouse_poll_endpoint_description = {
 	.transfer_type = USB_TRANSFER_INTERRUPT,
 	.direction = USB_DIRECTION_IN,
@@ -268,12 +268,13 @@
 
 	int shift_x = get_mouse_axis_move_value(hid_dev->report_id,
-	    hid_dev->report, USB_HIDUT_USAGE_GENERIC_DESKTOP_X);
+	    &hid_dev->report, USB_HIDUT_USAGE_GENERIC_DESKTOP_X);
 	int shift_y = get_mouse_axis_move_value(hid_dev->report_id,
-	    hid_dev->report, USB_HIDUT_USAGE_GENERIC_DESKTOP_Y);
+	    &hid_dev->report, USB_HIDUT_USAGE_GENERIC_DESKTOP_Y);
 	int wheel = get_mouse_axis_move_value(hid_dev->report_id,
-	    hid_dev->report, USB_HIDUT_USAGE_GENERIC_DESKTOP_WHEEL);
+	    &hid_dev->report, USB_HIDUT_USAGE_GENERIC_DESKTOP_WHEEL);
 
 	if ((shift_x != 0) || (shift_y != 0)) {
-		async_exch_t *exch = async_exchange_begin(mouse_dev->mouse_sess);
+		async_exch_t *exch =
+		    async_exchange_begin(mouse_dev->mouse_sess);
 		async_req_2_0(exch, MOUSEEV_MOVE_EVENT, shift_x, shift_y);
 		async_exchange_end(exch);
@@ -291,7 +292,6 @@
 
 	usb_hid_report_field_t *field = usb_hid_report_get_sibling(
-	    hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END
-	    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 
-	    USB_HID_REPORT_TYPE_INPUT);
+	    &hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END
+	    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, USB_HID_REPORT_TYPE_INPUT);
 
 	while (field != NULL) {
@@ -314,12 +314,12 @@
 			async_req_2_0(exch, MOUSEEV_BUTTON_EVENT, field->usage, 0);
 			async_exchange_end(exch);
-			
+
 			mouse_dev->buttons[field->usage - field->usage_minimum] =
 			   field->value;
 		}
-		
+
 		field = usb_hid_report_get_sibling(
-		    hid_dev->report, field, path, USB_HID_PATH_COMPARE_END
-		    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 
+		    &hid_dev->report, field, path, USB_HID_PATH_COMPARE_END
+		    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
 		    USB_HID_REPORT_TYPE_INPUT);
 	}
@@ -474,6 +474,6 @@
 	// that the current solution is good enough.
 	/* Adding 1 because we will be accessing buttons[highest]. */
-	mouse_dev->buttons_count = usb_mouse_get_highest_button(hid_dev->report,
-	    hid_dev->report_id) + 1;
+	mouse_dev->buttons_count = 1 + usb_mouse_get_highest_button(
+	    &hid_dev->report, hid_dev->report_id);
 	mouse_dev->buttons = calloc(mouse_dev->buttons_count, sizeof(int32_t));
 
@@ -532,6 +532,6 @@
 int usb_mouse_set_boot_protocol(usb_hid_dev_t *hid_dev)
 {
-	int rc = usb_hid_parse_report_descriptor(hid_dev->report, 
-	    USB_MOUSE_BOOT_REPORT_DESCRIPTOR, 
+	int rc = usb_hid_parse_report_descriptor(
+	    &hid_dev->report, USB_MOUSE_BOOT_REPORT_DESCRIPTOR,
 	    USB_MOUSE_BOOT_REPORT_DESCRIPTOR_SIZE);
 
@@ -542,5 +542,5 @@
 	}
 
-	rc = usbhid_req_set_protocol(&hid_dev->usb_dev->ctrl_pipe, 
+	rc = usbhid_req_set_protocol(&hid_dev->usb_dev->ctrl_pipe,
 	    hid_dev->usb_dev->interface_no, USB_HID_PROTOCOL_BOOT);
 
Index: uspace/drv/bus/usb/usbhid/mouse/mousedev.h
===================================================================
--- uspace/drv/bus/usb/usbhid/mouse/mousedev.h	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/drv/bus/usb/usbhid/mouse/mousedev.h	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -63,5 +63,5 @@
 /*----------------------------------------------------------------------------*/
 
-usb_endpoint_description_t usb_hid_mouse_poll_endpoint_description;
+extern const usb_endpoint_description_t usb_hid_mouse_poll_endpoint_description;
 
 const char *HID_MOUSE_FUN_NAME;
Index: uspace/drv/bus/usb/usbhid/multimedia/multimedia.c
===================================================================
--- uspace/drv/bus/usb/usbhid/multimedia/multimedia.c	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/drv/bus/usb/usbhid/multimedia/multimedia.c	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -161,10 +161,15 @@
 /*----------------------------------------------------------------------------*/
 
-static int usb_multimedia_create_function(usb_hid_dev_t *hid_dev, 
-    usb_multimedia_t *multim_dev)
-{
+int usb_multimedia_init(struct usb_hid_dev *hid_dev, void **data)
+{
+	if (hid_dev == NULL || hid_dev->usb_dev == NULL) {
+		return EINVAL; /*! @todo Other return code? */
+	}
+
+	usb_log_debug(NAME " Initializing HID/multimedia structure...\n");
+
 	/* Create the exposed function. */
-	ddf_fun_t *fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed, 
-	    NAME);
+	ddf_fun_t *fun = ddf_fun_create(
+	    hid_dev->usb_dev->ddf_dev, fun_exposed, NAME);
 	if (fun == NULL) {
 		usb_log_error("Could not create DDF function node.\n");
@@ -173,5 +178,16 @@
 
 	fun->ops = &multimedia_ops;
-	fun->driver_data = multim_dev;   // TODO: maybe change to hid_dev->data
+
+	usb_multimedia_t *multim_dev =
+	    ddf_fun_data_alloc(fun, sizeof(usb_multimedia_t));
+	if (multim_dev == NULL) {
+		ddf_fun_destroy(fun);
+		return ENOMEM;
+	}
+
+	multim_dev->console_sess = NULL;
+	multim_dev->fun = fun;
+
+	//todo Autorepeat?
 
 	int rc = ddf_fun_bind(fun);
@@ -194,40 +210,9 @@
 		return rc;
 	}
-	multim_dev->fun = fun;
-
-	return EOK;
-}
-
-/*----------------------------------------------------------------------------*/
-
-int usb_multimedia_init(struct usb_hid_dev *hid_dev, void **data)
-{
-	if (hid_dev == NULL || hid_dev->usb_dev == NULL) {
-		return EINVAL; /*! @todo Other return code? */
-	}
-
-	usb_log_debug(NAME " Initializing HID/multimedia structure...\n");
-
-	usb_multimedia_t *multim_dev = (usb_multimedia_t *)malloc(
-	    sizeof(usb_multimedia_t));
-	if (multim_dev == NULL) {
-		return ENOMEM;
-	}
-
-	multim_dev->console_sess = NULL;
-
-	/*! @todo Autorepeat */
-
-	// save the KBD device structure into the HID device structure
+
+	/* Save the KBD device structure into the HID device structure. */
 	*data = multim_dev;
 
-	usb_log_debug(NAME " HID/multimedia device structure initialized.\n");
-
-	int rc = usb_multimedia_create_function(hid_dev, multim_dev);
-	if (rc != EOK)
-		return rc;
-
 	usb_log_debug(NAME " HID/multimedia structure initialized.\n");
-
 	return EOK;
 }
@@ -272,6 +257,6 @@
 
 	usb_hid_report_field_t *field = usb_hid_report_get_sibling(
-	    hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END 
-	    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 
+	    &hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END
+	    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
 	    USB_HID_REPORT_TYPE_INPUT);
 
@@ -293,5 +278,5 @@
 
 		field = usb_hid_report_get_sibling(
-		    hid_dev->report, field, path, USB_HID_PATH_COMPARE_END
+		    &hid_dev->report, field, path, USB_HID_PATH_COMPARE_END
 		    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 
 		    USB_HID_REPORT_TYPE_INPUT);
Index: uspace/drv/bus/usb/usbhid/subdrivers.c
===================================================================
--- uspace/drv/bus/usb/usbhid/subdrivers.c	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/drv/bus/usb/usbhid/subdrivers.c	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -42,16 +42,16 @@
 #include "generic/hiddev.h"
 
-static usb_hid_subdriver_usage_t path_kbd[] = {
-	{USB_HIDUT_PAGE_GENERIC_DESKTOP, 
-	 USB_HIDUT_USAGE_GENERIC_DESKTOP_KEYBOARD}, 
+static const usb_hid_subdriver_usage_t path_kbd[] = {
+	{USB_HIDUT_PAGE_GENERIC_DESKTOP,
+	 USB_HIDUT_USAGE_GENERIC_DESKTOP_KEYBOARD},
 	{0, 0}
 };
 
-static usb_hid_subdriver_usage_t path_mouse[] = {
+static const usb_hid_subdriver_usage_t path_mouse[] = {
 	{USB_HIDUT_PAGE_GENERIC_DESKTOP, USB_HIDUT_USAGE_GENERIC_DESKTOP_MOUSE},
 	{0, 0}
 };
 
-static usb_hid_subdriver_usage_t multim_key_path[] = {
+static const usb_hid_subdriver_usage_t multim_key_path[] = {
 	{USB_HIDUT_PAGE_CONSUMER, USB_HIDUT_USAGE_CONSUMER_CONSUMER_CONTROL},
 	{0, 0}
@@ -71,5 +71,4 @@
 			.poll_end = NULL
 		},
-		
 	},
 	{
@@ -102,4 +101,7 @@
 };
 
+const int USB_HID_MAX_SUBDRIVERS =
+    sizeof(usb_hid_subdrivers) / sizeof(usb_hid_subdrivers[0]);
+
 /**
  * @}
Index: uspace/drv/bus/usb/usbhid/subdrivers.h
===================================================================
--- uspace/drv/bus/usb/usbhid/subdrivers.h	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/drv/bus/usb/usbhid/subdrivers.h	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -78,5 +78,5 @@
 
 	/** Subdriver for controlling this device. */
-	usb_hid_subdriver_t subdriver;
+	const usb_hid_subdriver_t subdriver;
 } usb_hid_subdriver_mapping_t;
 
@@ -84,4 +84,5 @@
 
 extern const usb_hid_subdriver_mapping_t usb_hid_subdrivers[];
+extern const int USB_HID_MAX_SUBDRIVERS;
 
 /*----------------------------------------------------------------------------*/
Index: uspace/drv/bus/usb/usbhid/usbhid.c
===================================================================
--- uspace/drv/bus/usb/usbhid/usbhid.c	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/drv/bus/usb/usbhid/usbhid.c	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -54,5 +54,5 @@
 
 /* Array of endpoints expected on the device, NULL terminated. */
-usb_endpoint_description_t *usb_hid_endpoints[] = {
+const usb_endpoint_description_t *usb_hid_endpoints[] = {
 	&usb_hid_kbd_poll_endpoint_description,
 	&usb_hid_mouse_poll_endpoint_description,
@@ -61,35 +61,18 @@
 };
 
-static const int USB_HID_MAX_SUBDRIVERS = 10;
-
 /*----------------------------------------------------------------------------*/
 
 static int usb_hid_set_boot_kbd_subdriver(usb_hid_dev_t *hid_dev)
 {
-	assert(hid_dev != NULL && hid_dev->subdriver_count == 0);
-
-	hid_dev->subdrivers = (usb_hid_subdriver_t *)malloc(
-	    sizeof(usb_hid_subdriver_t));
+	assert(hid_dev != NULL);
+	assert(hid_dev->subdriver_count == 0);
+
+	hid_dev->subdrivers = malloc(sizeof(usb_hid_subdriver_t));
 	if (hid_dev->subdrivers == NULL) {
 		return ENOMEM;
 	}
-
-	assert(hid_dev->subdriver_count >= 0);
-
-	// set the init callback
-	hid_dev->subdrivers[hid_dev->subdriver_count].init = usb_kbd_init;
-
-	// set the polling callback
-	hid_dev->subdrivers[hid_dev->subdriver_count].poll = 
-	    usb_kbd_polling_callback;
-
-	// set the polling ended callback
-	hid_dev->subdrivers[hid_dev->subdriver_count].poll_end = NULL;
-
-	// set the deinit callback
-	hid_dev->subdrivers[hid_dev->subdriver_count].deinit = usb_kbd_deinit;
-
-	// set subdriver count
-	++hid_dev->subdriver_count;
+	hid_dev->subdriver_count = 1;
+	// TODO 0 should be keyboard, but find a better way
+	hid_dev->subdrivers[0] = usb_hid_subdrivers[0].subdriver;
 
 	return EOK;
@@ -100,29 +83,14 @@
 static int usb_hid_set_boot_mouse_subdriver(usb_hid_dev_t *hid_dev)
 {
-	assert(hid_dev != NULL && hid_dev->subdriver_count == 0);
-
-	hid_dev->subdrivers = (usb_hid_subdriver_t *)malloc(
-	    sizeof(usb_hid_subdriver_t));
+	assert(hid_dev != NULL);
+	assert(hid_dev->subdriver_count == 0);
+
+	hid_dev->subdrivers = malloc(sizeof(usb_hid_subdriver_t));
 	if (hid_dev->subdrivers == NULL) {
 		return ENOMEM;
 	}
-
-	assert(hid_dev->subdriver_count >= 0);
-
-	// set the init callback
-	hid_dev->subdrivers[hid_dev->subdriver_count].init = usb_mouse_init;
-
-	// set the polling callback
-	hid_dev->subdrivers[hid_dev->subdriver_count].poll = 
-	    usb_mouse_polling_callback;
-
-	// set the polling ended callback
-	hid_dev->subdrivers[hid_dev->subdriver_count].poll_end = NULL;
-
-	// set the deinit callback
-	hid_dev->subdrivers[hid_dev->subdriver_count].deinit = usb_mouse_deinit;
-
-	// set subdriver count
-	++hid_dev->subdriver_count;
+	hid_dev->subdriver_count = 1;
+	// TODO 2 should be mouse, but find a better way
+	hid_dev->subdrivers[2] = usb_hid_subdrivers[0].subdriver;
 
 	return EOK;
@@ -135,29 +103,15 @@
 	assert(hid_dev != NULL && hid_dev->subdriver_count == 0);
 
-	hid_dev->subdrivers = (usb_hid_subdriver_t *)malloc(
-	    sizeof(usb_hid_subdriver_t));
+	hid_dev->subdrivers = malloc(sizeof(usb_hid_subdriver_t));
 	if (hid_dev->subdrivers == NULL) {
 		return ENOMEM;
 	}
-
-	assert(hid_dev->subdriver_count >= 0);
-
-	// set the init callback
-	hid_dev->subdrivers[hid_dev->subdriver_count].init =
-	    usb_generic_hid_init;
-
-	// set the polling callback
-	hid_dev->subdrivers[hid_dev->subdriver_count].poll = 
-	    usb_generic_hid_polling_callback;
-
-	// set the polling ended callback
-	hid_dev->subdrivers[hid_dev->subdriver_count].poll_end = NULL;
-
-	// set the deinit callback
-	hid_dev->subdrivers[hid_dev->subdriver_count].deinit =
-	    usb_generic_hid_deinit;
-
-	// set subdriver count
-	++hid_dev->subdriver_count;
+	hid_dev->subdriver_count = 1;
+
+	/* Set generic hid subdriver routines */
+	hid_dev->subdrivers[0].init = usb_generic_hid_init;
+	hid_dev->subdrivers[0].poll = usb_generic_hid_polling_callback;
+	hid_dev->subdrivers[0].poll_end = NULL;
+	hid_dev->subdrivers[0].deinit = usb_generic_hid_deinit;
 
 	return EOK;
@@ -166,5 +120,5 @@
 /*----------------------------------------------------------------------------*/
 
-static bool usb_hid_ids_match(usb_hid_dev_t *hid_dev, 
+static bool usb_hid_ids_match(const usb_hid_dev_t *hid_dev,
     const usb_hid_subdriver_mapping_t *mapping)
 {
@@ -172,5 +126,5 @@
 	assert(hid_dev->usb_dev != NULL);
 
-	return (hid_dev->usb_dev->descriptors.device.vendor_id 
+	return (hid_dev->usb_dev->descriptors.device.vendor_id
 	    == mapping->vendor_id
 	    && hid_dev->usb_dev->descriptors.device.product_id 
@@ -180,5 +134,5 @@
 /*----------------------------------------------------------------------------*/
 
-static bool usb_hid_path_matches(usb_hid_dev_t *hid_dev, 
+static bool usb_hid_path_matches(usb_hid_dev_t *hid_dev,
     const usb_hid_subdriver_mapping_t *mapping)
 {
@@ -192,8 +146,8 @@
 	}
 	int i = 0;
-	while (mapping->usage_path[i].usage != 0 
+	while (mapping->usage_path[i].usage != 0
 	    || mapping->usage_path[i].usage_page != 0) {
-		if (usb_hid_report_path_append_item(usage_path, 
-		    mapping->usage_path[i].usage_page, 
+		if (usb_hid_report_path_append_item(usage_path,
+		    mapping->usage_path[i].usage_page,
 		    mapping->usage_path[i].usage) != EOK) {
 			usb_log_debug("Failed to append to usage path.\n");
@@ -204,6 +158,4 @@
 	}
 
-	assert(hid_dev->report != NULL);
-
 	usb_log_debug("Compare flags: %d\n", mapping->compare);
 
@@ -213,5 +165,5 @@
 	do {
 		usb_log_debug("Trying report id %u\n", report_id);
-		
+
 		if (report_id != 0) {
 			usb_hid_report_path_set_report_id(usage_path,
@@ -220,8 +172,7 @@
 
 		usb_hid_report_field_t *field = usb_hid_report_get_sibling(
-		    hid_dev->report,
-		    NULL, usage_path, mapping->compare, 
+		    &hid_dev->report, NULL, usage_path, mapping->compare,
 		    USB_HID_REPORT_TYPE_INPUT);
-		
+
 		usb_log_debug("Field: %p\n", field);
 
@@ -230,8 +181,7 @@
 			break;
 		}
-		
+
 		report_id = usb_hid_get_next_report_id(
-		    hid_dev->report, report_id,
-		    USB_HID_REPORT_TYPE_INPUT);
+		    &hid_dev->report, report_id, USB_HID_REPORT_TYPE_INPUT);
 	} while (!matches && report_id != 0);
 
@@ -243,5 +193,5 @@
 /*----------------------------------------------------------------------------*/
 
-static int usb_hid_save_subdrivers(usb_hid_dev_t *hid_dev, 
+static int usb_hid_save_subdrivers(usb_hid_dev_t *hid_dev,
     const usb_hid_subdriver_t **subdrivers, int count)
 {
@@ -254,8 +204,6 @@
 	}
 
-	// add one generic HID subdriver per device
-
-	hid_dev->subdrivers = (usb_hid_subdriver_t *)malloc((count + 1) * 
-	    sizeof(usb_hid_subdriver_t));
+	/* +1 for generic hid subdriver */
+	hid_dev->subdrivers = calloc((count + 1), sizeof(usb_hid_subdriver_t));
 	if (hid_dev->subdrivers == NULL) {
 		return ENOMEM;
@@ -269,4 +217,5 @@
 	}
 
+	/* Add one generic HID subdriver per device */
 	hid_dev->subdrivers[count].init = usb_generic_hid_init;
 	hid_dev->subdrivers[count].poll = usb_generic_hid_polling_callback;
@@ -307,8 +256,8 @@
 			return EINVAL;
 		}
-		
+
 		ids_matched = false;
 		matched = false;
-		
+
 		if (mapping->vendor_id >= 0) {
 			assert(mapping->product_id >= 0);
@@ -321,5 +270,5 @@
 			}
 		}
-		
+
 		if (mapping->usage_path != NULL) {
 			usb_log_debug("Comparing device against usage path.\n");
@@ -332,14 +281,16 @@
 			matched = ids_matched;
 		}
-		
+
 		if (matched) {
 			usb_log_debug("Subdriver matched.\n");
 			subdrivers[count++] = &mapping->subdriver;
 		}
-		
+
 		mapping = &usb_hid_subdrivers[++i];
 	}
 
-	// we have all subdrivers determined, save them into the hid device
+	/* We have all subdrivers determined, save them into the hid device */
+	// TODO Dowe really need this complicated stuff if there is
+	// max_subdrivers limitation?
 	return usb_hid_save_subdrivers(hid_dev, subdrivers, count);
 }
@@ -347,9 +298,8 @@
 /*----------------------------------------------------------------------------*/
 
-static int usb_hid_check_pipes(usb_hid_dev_t *hid_dev, usb_device_t *dev)
-{
-	assert(hid_dev != NULL && dev != NULL);
-
-	int rc = EOK;
+static int usb_hid_check_pipes(usb_hid_dev_t *hid_dev, const usb_device_t *dev)
+{
+	assert(hid_dev);
+	assert(dev);
 
 	if (dev->pipes[USB_HID_KBD_POLL_EP_NO].present) {
@@ -368,8 +318,8 @@
 		usb_log_error("None of supported endpoints found - probably"
 		    " not a supported device.\n");
-		rc = ENOTSUP;
-	}
-
-	return rc;
+		return ENOTSUP;
+	}
+
+	return EOK;
 }
 
@@ -378,19 +328,18 @@
 static int usb_hid_init_report(usb_hid_dev_t *hid_dev)
 {
-	assert(hid_dev != NULL && hid_dev->report != NULL);
+	assert(hid_dev != NULL);
 
 	uint8_t report_id = 0;
-	size_t size;
-
 	size_t max_size = 0;
 
 	do {
 		usb_log_debug("Getting size of the report.\n");
-		size = usb_hid_report_byte_size(hid_dev->report, report_id, 
-		    USB_HID_REPORT_TYPE_INPUT);
+		const size_t size =
+		    usb_hid_report_byte_size(&hid_dev->report, report_id,
+		        USB_HID_REPORT_TYPE_INPUT);
 		usb_log_debug("Report ID: %u, size: %zu\n", report_id, size);
 		max_size = (size > max_size) ? size : max_size;
 		usb_log_debug("Getting next report ID\n");
-		report_id = usb_hid_get_next_report_id(hid_dev->report, 
+		report_id = usb_hid_get_next_report_id(&hid_dev->report,
 		    report_id, USB_HID_REPORT_TYPE_INPUT);
 	} while (report_id != 0);
@@ -398,12 +347,11 @@
 	usb_log_debug("Max size of input report: %zu\n", max_size);
 
-	hid_dev->max_input_report_size = max_size;
 	assert(hid_dev->input_report == NULL);
 
-	hid_dev->input_report = malloc(max_size);
+	hid_dev->input_report = calloc(1, max_size);
 	if (hid_dev->input_report == NULL) {
 		return ENOMEM;
 	}
-	memset(hid_dev->input_report, 0, max_size);
+	hid_dev->max_input_report_size = max_size;
 
 	return EOK;
@@ -430,11 +378,5 @@
 	}
 
-	hid_dev->report = (usb_hid_report_t *)(malloc(sizeof(
-	    usb_hid_report_t)));
-	if (hid_dev->report == NULL) {
-		usb_log_error("No memory!\n");
-		return ENOMEM;
-	}
-	usb_hid_report_init(hid_dev->report);
+	usb_hid_report_init(&hid_dev->report);
 
 	/* The USB device should already be initialized, save it in structure */
@@ -446,8 +388,8 @@
 		return rc;
 	}
-		
+
 	/* Get the report descriptor and parse it. */
-	rc = usb_hid_process_report_descriptor(hid_dev->usb_dev, 
-	    hid_dev->report, &hid_dev->report_desc, &hid_dev->report_desc_size);
+	rc = usb_hid_process_report_descriptor(hid_dev->usb_dev,
+	    &hid_dev->report, &hid_dev->report_desc, &hid_dev->report_desc_size);
 
 	bool fallback = false;
@@ -488,7 +430,7 @@
 			break;
 		default:
-			assert(hid_dev->poll_pipe_index 
+			assert(hid_dev->poll_pipe_index
 			    == USB_HID_GENERIC_POLL_EP_NO);
-			
+
 			usb_log_info("Falling back to generic HID driver.\n");
 			rc = usb_hid_set_generic_hid_subdriver(hid_dev);
@@ -499,13 +441,12 @@
 		usb_log_error("No subdriver for handling this device could be"
 		    " initialized: %s.\n", str_error(rc));
-		usb_log_debug("Subdriver count: %d\n", 
+		usb_log_debug("Subdriver count: %d\n",
 		    hid_dev->subdriver_count);
-		
 	} else {
 		bool ok = false;
-		
-		usb_log_debug("Subdriver count: %d\n", 
+
+		usb_log_debug("Subdriver count: %d\n",
 		    hid_dev->subdriver_count);
-		
+
 		for (i = 0; i < hid_dev->subdriver_count; ++i) {
 			if (hid_dev->subdrivers[i].init != NULL) {
@@ -524,5 +465,5 @@
 			}
 		}
-		
+
 		rc = (ok) ? EOK : -1;	// what error to report
 	}
@@ -538,5 +479,4 @@
 	}
 
-
 	return rc;
 }
@@ -544,17 +484,15 @@
 /*----------------------------------------------------------------------------*/
 
-bool usb_hid_polling_callback(usb_device_t *dev, uint8_t *buffer, 
+bool usb_hid_polling_callback(usb_device_t *dev, uint8_t *buffer,
     size_t buffer_size, void *arg)
 {
-	int i;
-
 	if (dev == NULL || arg == NULL || buffer == NULL) {
 		usb_log_error("Missing arguments to polling callback.\n");
 		return false;
 	}
-
-	usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)arg;
+	usb_hid_dev_t *hid_dev = arg;
 
 	assert(hid_dev->input_report != NULL);
+
 	usb_log_debug("New data [%zu/%zu]: %s\n", buffer_size,
 	    hid_dev->max_input_report_size,
@@ -568,22 +506,18 @@
 	}
 
-	// parse the input report
-
-	int rc = usb_hid_parse_report(hid_dev->report, buffer, buffer_size, 
-	    &hid_dev->report_id);
-
+	/* Parse the input report */
+	const int rc = usb_hid_parse_report(
+	    &hid_dev->report, buffer, buffer_size, &hid_dev->report_id);
 	if (rc != EOK) {
 		usb_log_warning("Error in usb_hid_parse_report():"
 		    "%s\n", str_error(rc));
-	}	
+	}
 
 	bool cont = false;
-
-	// continue if at least one of the subdrivers want to continue
-	for (i = 0; i < hid_dev->subdriver_count; ++i) {
-		if (hid_dev->subdrivers[i].poll != NULL
-		    && hid_dev->subdrivers[i].poll(hid_dev, 
-		        hid_dev->subdrivers[i].data)) {
-			cont = true;
+	/* Continue if at least one of the subdrivers want to continue */
+	for (int i = 0; i < hid_dev->subdriver_count; ++i) {
+		if (hid_dev->subdrivers[i].poll != NULL) {
+			cont = cont || hid_dev->subdrivers[i].poll(
+			    hid_dev, hid_dev->subdrivers[i].data);
 		}
 	}
@@ -594,19 +528,15 @@
 /*----------------------------------------------------------------------------*/
 
-void usb_hid_polling_ended_callback(usb_device_t *dev, bool reason, 
-     void *arg)
-{
-	int i; 
-
-	if (dev == NULL || arg == NULL) {
-		return;
-	}
-
-	usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)arg;
-
-	for (i = 0; i < hid_dev->subdriver_count; ++i) {
+void usb_hid_polling_ended_callback(usb_device_t *dev, bool reason, void *arg)
+{
+	assert(dev);
+	assert(arg);
+
+	usb_hid_dev_t *hid_dev = arg;
+
+	for (int i = 0; i < hid_dev->subdriver_count; ++i) {
 		if (hid_dev->subdrivers[i].poll_end != NULL) {
-			hid_dev->subdrivers[i].poll_end(hid_dev,
-			    hid_dev->subdrivers[i].data, reason);
+			hid_dev->subdrivers[i].poll_end(
+			    hid_dev, hid_dev->subdrivers[i].data, reason);
 		}
 	}
@@ -624,5 +554,5 @@
 /*----------------------------------------------------------------------------*/
 
-int usb_hid_report_number(usb_hid_dev_t *hid_dev)
+int usb_hid_report_number(const usb_hid_dev_t *hid_dev)
 {
 	return hid_dev->report_nr;
@@ -631,19 +561,14 @@
 /*----------------------------------------------------------------------------*/
 
-void usb_hid_destroy(usb_hid_dev_t *hid_dev)
-{
-	int i;
-
-	if (hid_dev == NULL) {
-		return;
-	}
+void usb_hid_deinit(usb_hid_dev_t *hid_dev)
+{
+	assert(hid_dev);
+	assert(hid_dev->subdrivers != NULL || hid_dev->subdriver_count == 0);
+
 
 	usb_log_debug("Subdrivers: %p, subdriver count: %d\n", 
 	    hid_dev->subdrivers, hid_dev->subdriver_count);
 
-	assert(hid_dev->subdrivers != NULL 
-	    || hid_dev->subdriver_count == 0);
-
-	for (i = 0; i < hid_dev->subdriver_count; ++i) {
+	for (int i = 0; i < hid_dev->subdriver_count; ++i) {
 		if (hid_dev->subdrivers[i].deinit != NULL) {
 			hid_dev->subdrivers[i].deinit(hid_dev,
@@ -657,7 +582,5 @@
 
 	/* Destroy the parser */
-	if (hid_dev->report != NULL) {
-		usb_hid_free_report(hid_dev->report);
-	}
+	usb_hid_report_deinit(&hid_dev->report);
 
 }
Index: uspace/drv/bus/usb/usbhid/usbhid.h
===================================================================
--- uspace/drv/bus/usb/usbhid/usbhid.h	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/drv/bus/usb/usbhid/usbhid.h	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -119,5 +119,5 @@
 
 	/** HID Report parser. */
-	usb_hid_report_t *report;
+	usb_hid_report_t report;
 
 	uint8_t report_id;
@@ -141,5 +141,5 @@
 };
 
-extern usb_endpoint_description_t *usb_hid_endpoints[];
+extern const usb_endpoint_description_t *usb_hid_endpoints[];
 
 /*----------------------------------------------------------------------------*/
@@ -147,15 +147,14 @@
 int usb_hid_init(usb_hid_dev_t *hid_dev, usb_device_t *dev);
 
-bool usb_hid_polling_callback(usb_device_t *dev, uint8_t *buffer, 
-    size_t buffer_size, void *arg);
+void usb_hid_deinit(usb_hid_dev_t *hid_dev);
 
-void usb_hid_polling_ended_callback(usb_device_t *dev, bool reason, 
-     void *arg);
+bool usb_hid_polling_callback(usb_device_t *dev,
+    uint8_t *buffer, size_t buffer_size, void *arg);
+
+void usb_hid_polling_ended_callback(usb_device_t *dev, bool reason, void *arg);
 
 void usb_hid_new_report(usb_hid_dev_t *hid_dev);
 
-int usb_hid_report_number(usb_hid_dev_t *hid_dev);
-
-void usb_hid_destroy(usb_hid_dev_t *hid_dev);
+int usb_hid_report_number(const usb_hid_dev_t *hid_dev);
 
 #endif /* USB_HID_USBHID_H_ */
Index: uspace/drv/bus/usb/usbhub/main.c
===================================================================
--- uspace/drv/bus/usb/usbhub/main.c	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/drv/bus/usb/usbhub/main.c	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -67,5 +67,5 @@
 
 /** Hub endpoints, excluding control endpoint. */
-static usb_endpoint_description_t *usb_hub_endpoints[] = {
+static const usb_endpoint_description_t *usb_hub_endpoints[] = {
 	&hub_status_change_endpoint_description,
 	NULL,
Index: uspace/drv/bus/usb/usbmast/main.c
===================================================================
--- uspace/drv/bus/usb/usbmast/main.c	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/drv/bus/usb/usbmast/main.c	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -72,5 +72,5 @@
 };
 
-usb_endpoint_description_t *mast_endpoints[] = {
+static const usb_endpoint_description_t *mast_endpoints[] = {
 	&bulk_in_ep,
 	&bulk_out_ep,
Index: uspace/drv/bus/usb/usbmouse/init.c
===================================================================
--- uspace/drv/bus/usb/usbmouse/init.c	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/drv/bus/usb/usbmouse/init.c	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -44,5 +44,5 @@
 
 /** Mouse polling endpoint description for boot protocol subclass. */
-usb_endpoint_description_t poll_endpoint_description = {
+const usb_endpoint_description_t poll_endpoint_description = {
 	.transfer_type = USB_TRANSFER_INTERRUPT,
 	.direction = USB_DIRECTION_IN,
Index: uspace/drv/bus/usb/usbmouse/main.c
===================================================================
--- uspace/drv/bus/usb/usbmouse/main.c	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/drv/bus/usb/usbmouse/main.c	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -83,5 +83,5 @@
 };
 
-static usb_endpoint_description_t *endpoints[] = {
+static const usb_endpoint_description_t *endpoints[] = {
 	&poll_endpoint_description,
 	NULL
Index: uspace/drv/bus/usb/usbmouse/mouse.c
===================================================================
--- uspace/drv/bus/usb/usbmouse/mouse.c	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/drv/bus/usb/usbmouse/mouse.c	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -124,5 +124,5 @@
 	mouse->console_sess = NULL;
 	
-	usb_device_destroy(dev);
+	usb_device_deinit(dev);
 }
 
Index: uspace/drv/bus/usb/usbmouse/mouse.h
===================================================================
--- uspace/drv/bus/usb/usbmouse/mouse.h	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/drv/bus/usb/usbmouse/mouse.h	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -61,5 +61,5 @@
 } usb_mouse_t;
 
-extern usb_endpoint_description_t poll_endpoint_description;
+extern const usb_endpoint_description_t poll_endpoint_description;
 
 extern int usb_mouse_create(usb_device_t *);
Index: uspace/lib/usbdev/include/usb/dev/driver.h
===================================================================
--- uspace/lib/usbdev/include/usb/dev/driver.h	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/lib/usbdev/include/usb/dev/driver.h	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -156,5 +156,5 @@
 \endcode
 	 */
-	usb_endpoint_description_t **endpoints;
+	const usb_endpoint_description_t **endpoints;
 	/** Driver ops. */
 	const usb_driver_ops_t *ops;
@@ -164,13 +164,14 @@
 
 int usb_device_select_interface(usb_device_t *, uint8_t,
-    usb_endpoint_description_t **);
+    const usb_endpoint_description_t **);
 
 int usb_device_retrieve_descriptors(usb_pipe_t *, usb_device_descriptors_t *);
 int usb_device_create_pipes(const ddf_dev_t *, usb_device_connection_t *,
-    usb_endpoint_description_t **, const uint8_t *, size_t, int, int,
+    const usb_endpoint_description_t **, const uint8_t *, size_t, int, int,
     usb_endpoint_mapping_t **, size_t *);
 int usb_device_destroy_pipes(const ddf_dev_t *, usb_endpoint_mapping_t *, size_t);
-int usb_device_create(ddf_dev_t *, usb_endpoint_description_t **, usb_device_t **, const char **);
-void usb_device_destroy(usb_device_t *);
+int usb_device_create(ddf_dev_t *, const usb_endpoint_description_t **,
+    usb_device_t **, const char **);
+void usb_device_deinit(usb_device_t *);
 void * usb_device_data_alloc(usb_device_t *, size_t);
 
Index: uspace/lib/usbdev/src/devdrv.c
===================================================================
--- uspace/lib/usbdev/src/devdrv.c	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/lib/usbdev/src/devdrv.c	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -81,5 +81,5 @@
  * @return Number of pipes (excluding default control pipe).
  */
-static size_t count_other_pipes(usb_endpoint_description_t **endpoints)
+static size_t count_other_pipes(const usb_endpoint_description_t **endpoints)
 {
 	size_t count = 0;
@@ -101,5 +101,5 @@
  * @return Error code.
  */
-static int initialize_other_pipes(usb_endpoint_description_t **endpoints,
+static int initialize_other_pipes(const usb_endpoint_description_t **endpoints,
     usb_device_t *dev, int alternate_setting)
 {
@@ -154,5 +154,5 @@
 	rc = driver->ops->device_add(dev);
 	if (rc != EOK)
-		usb_device_destroy(dev);
+		usb_device_deinit(dev);
 	return rc;
 }
@@ -191,5 +191,5 @@
 	const int ret = driver->ops->device_gone(usb_dev);
 	if (ret == EOK)
-		usb_device_destroy(usb_dev);
+		usb_device_deinit(usb_dev);
 
 	return ret;
@@ -238,5 +238,5 @@
  */
 int usb_device_select_interface(usb_device_t *dev, uint8_t alternate_setting,
-    usb_endpoint_description_t **endpoints)
+    const usb_endpoint_description_t **endpoints)
 {
 	if (dev->interface_no < 0) {
@@ -321,5 +321,5 @@
  */
 int usb_device_create_pipes(const ddf_dev_t *dev, usb_device_connection_t *wire,
-    usb_endpoint_description_t **endpoints,
+    const usb_endpoint_description_t **endpoints,
     const uint8_t *config_descr, size_t config_descr_size,
     int interface_no, int interface_setting,
@@ -526,5 +526,5 @@
  */
 int usb_device_create(ddf_dev_t *ddf_dev,
-    usb_endpoint_description_t **endpoints,
+    const usb_endpoint_description_t **endpoints,
     usb_device_t **dev_ptr, const char **errstr_ptr)
 {
@@ -590,7 +590,9 @@
 /** Destroy instance of a USB device.
  *
- * @param dev Device to be destroyed.
- */
-void usb_device_destroy(usb_device_t *dev)
+ * @param dev Device to be de-initialized.
+ *
+ * Does not free/destroy supplied pointer.
+ */
+void usb_device_deinit(usb_device_t *dev)
 {
 	if (dev == NULL) {
Index: uspace/lib/usbhid/include/usb/hid/hiddescriptor.h
===================================================================
--- uspace/lib/usbhid/include/usb/hid/hiddescriptor.h	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/lib/usbhid/include/usb/hid/hiddescriptor.h	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -42,12 +42,12 @@
 #include <usb/hid/hidtypes.h>
 
-int usb_hid_parse_report_descriptor(usb_hid_report_t *report, 
+int usb_hid_parse_report_descriptor(usb_hid_report_t *report,
 		const uint8_t *data, size_t size);
-
-void usb_hid_free_report(usb_hid_report_t *report);
 
 void usb_hid_descriptor_print(usb_hid_report_t *report);
 
 int usb_hid_report_init(usb_hid_report_t *report);
+
+void usb_hid_report_deinit(usb_hid_report_t *report);
 
 int usb_hid_report_append_fields(usb_hid_report_t *report,
Index: uspace/lib/usbhid/src/hiddescriptor.c
===================================================================
--- uspace/lib/usbhid/src/hiddescriptor.c	(revision 25696fead2f82e3c4923516a5d7d80ffe0dd3e7a)
+++ uspace/lib/usbhid/src/hiddescriptor.c	(revision 22ceff3a80ac18ff36c3836ced4e7fe4470aca56)
@@ -1016,5 +1016,5 @@
  * @return void
  */
-void usb_hid_free_report(usb_hid_report_t *report)
+void usb_hid_report_deinit(usb_hid_report_t *report)
 {
 	if(report == NULL){
