Index: uspace/drv/bus/usb/uhci/batch.c
===================================================================
--- uspace/drv/bus/usb/uhci/batch.c	(revision 3afb7580ffb5859d718216a15a79100e3ab8aa0a)
+++ uspace/drv/bus/usb/uhci/batch.c	(revision 1a025171dce783accd2bf90e64bd6ee89ca65990)
@@ -93,5 +93,5 @@
  * @param[in] uhci_batch Instance to destroy.
  */
-void uhci_transfer_batch_dispose(void *uhci_batch)
+static void uhci_transfer_batch_dispose(void *uhci_batch)
 {
 	uhci_transfer_batch_t *instance = uhci_batch;
@@ -119,5 +119,5 @@
  * Initializes parameters needed for the transfer and callback.
  */
-void * uhci_transfer_batch_create(usb_transfer_batch_t *batch)
+int batch_init_private(usb_transfer_batch_t *batch)
 {
 #define CHECK_NULL_DISPOSE_RETURN(ptr, message...) \
@@ -127,5 +127,5 @@
 			uhci_transfer_batch_dispose(uhci_data); \
 		} \
-		return NULL; \
+		return ENOMEM; \
 	} else (void)0
 
@@ -164,4 +164,5 @@
 	/* Set generic data buffer pointer */
 	batch->data_buffer = setup + batch->setup_size;
+	batch->private_data_dtor = uhci_transfer_batch_dispose;
 	batch->private_data = uhci_data;
 	usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT
@@ -171,7 +172,6 @@
 	batch_setup[batch->ep->transfer_type][batch->ep->direction](batch);
 
-	return uhci_data;
-}
-/*----------------------------------------------------------------------------*/
+	return EOK;
+}
 /*----------------------------------------------------------------------------*/
 /** Check batch TDs for activity.
Index: uspace/drv/bus/usb/uhci/batch.h
===================================================================
--- uspace/drv/bus/usb/uhci/batch.h	(revision 3afb7580ffb5859d718216a15a79100e3ab8aa0a)
+++ uspace/drv/bus/usb/uhci/batch.h	(revision 1a025171dce783accd2bf90e64bd6ee89ca65990)
@@ -39,10 +39,7 @@
 #include "hw_struct/queue_head.h"
 
-void * uhci_transfer_batch_create(usb_transfer_batch_t *batch);
-void uhci_transfer_batch_dispose(void *uhci_batch);
-
-bool batch_is_complete(usb_transfer_batch_t *instance);
-
-qh_t * batch_qh(usb_transfer_batch_t *instance);
+int batch_init_private(usb_transfer_batch_t *batch);
+bool batch_is_complete(usb_transfer_batch_t *batch);
+qh_t * batch_qh(usb_transfer_batch_t *batch);
 #endif
 /**
Index: uspace/drv/bus/usb/uhci/hc.c
===================================================================
--- uspace/drv/bus/usb/uhci/hc.c	(revision 3afb7580ffb5859d718216a15a79100e3ab8aa0a)
+++ uspace/drv/bus/usb/uhci/hc.c	(revision 1a025171dce783accd2bf90e64bd6ee89ca65990)
@@ -198,6 +198,6 @@
 	instance->generic.private_data = instance;
 	instance->generic.schedule = hc_schedule;
-	instance->generic.batch_private_ctor = uhci_transfer_batch_create;
-	instance->generic.batch_private_dtor = uhci_transfer_batch_dispose;
+	instance->generic.batch_init_hook = batch_init_private;
+	instance->generic.ep_add_hook = NULL;
 #undef CHECK_RET_DEST_FUN_RETURN
 
Index: uspace/lib/usbhost/include/usb/host/hcd.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/hcd.h	(revision 3afb7580ffb5859d718216a15a79100e3ab8aa0a)
+++ uspace/lib/usbhost/include/usb/host/hcd.h	(revision 1a025171dce783accd2bf90e64bd6ee89ca65990)
@@ -50,6 +50,6 @@
 
 	int (*schedule)(hcd_t *, usb_transfer_batch_t *);
-	void * (*batch_private_ctor)(usb_transfer_batch_t *);
-	void (*batch_private_dtor)(void *);
+	int (*batch_init_hook)(usb_transfer_batch_t *);
+	int (*ep_add_hook)(endpoint_t *);
 };
 /*----------------------------------------------------------------------------*/
Index: uspace/lib/usbhost/include/usb/host/usb_endpoint_manager.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/usb_endpoint_manager.h	(revision 3afb7580ffb5859d718216a15a79100e3ab8aa0a)
+++ uspace/lib/usbhost/include/usb/host/usb_endpoint_manager.h	(revision 1a025171dce783accd2bf90e64bd6ee89ca65990)
@@ -77,4 +77,5 @@
     usb_endpoint_manager_t *instance, usb_target_t target, const uint8_t *data);
 
+/** Wrapper combining allocation and insertion */
 static inline int usb_endpoint_manager_add_ep(usb_endpoint_manager_t *instance,
     usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction,
Index: uspace/lib/usbhost/src/iface.c
===================================================================
--- uspace/lib/usbhost/src/iface.c	(revision 3afb7580ffb5859d718216a15a79100e3ab8aa0a)
+++ uspace/lib/usbhost/src/iface.c	(revision 1a025171dce783accd2bf90e64bd6ee89ca65990)
@@ -78,12 +78,12 @@
 	}
 
+	/* No private data and no private data_dtor, these should be set by
+	 * batch_init_hook*/
 	usb_transfer_batch_init(batch, ep, data, NULL, size, setup_data,
-	    setup_size, in, out, arg, fun, NULL, hcd->batch_private_dtor);
-	if (hcd->batch_private_ctor) {
-		batch->private_data = hcd->batch_private_ctor(batch);
-		if (!batch->private_data) {
-			ret = ENOMEM;
+	    setup_size, in, out, arg, fun, NULL, NULL);
+	if (hcd->batch_init_hook) {
+		ret = hcd->batch_init_hook(batch);
+		if (ret != EOK)
 			goto out;
-		}
 	} else {
 		usb_log_warning("Missing batch_private_data constructor!\n");
@@ -199,6 +199,22 @@
 	    max_packet_size, interval);
 
-	return usb_endpoint_manager_add_ep(&hcd->ep_manager, address, endpoint,
-	    direction, transfer_type, speed, max_packet_size, size);
+	endpoint_t *ep = endpoint_get(
+	    address, endpoint, direction, transfer_type, speed, max_packet_size);
+	if (!ep)
+		return ENOMEM;
+	int ret = EOK;
+	if (hcd->ep_add_hook) {
+		ret = hcd->ep_add_hook(ep);
+	}
+	if (ret != EOK) {
+		endpoint_destroy(ep);
+		return ret;
+	}
+
+	ret = usb_endpoint_manager_register_ep(&hcd->ep_manager, ep, size);
+	if (ret != EOK) {
+		endpoint_destroy(ep);
+	}
+	return ret;
 }
 /*----------------------------------------------------------------------------*/
