Index: uspace/drv/ohci/iface.c
===================================================================
--- uspace/drv/ohci/iface.c	(revision 92d6868acefb75faf04356ff5afea6f519df39c9)
+++ uspace/drv/ohci/iface.c	(revision 8e8b84febc9e520c05c14694bb2a261c13671b97)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2011 Vojtech Horky
+ * Copyright (c) 2011 Vojtech Horky, Jan Vesely
  * All rights reserved.
  *
@@ -30,5 +30,5 @@
  */
 /** @file
- * USB-HC interface implementation.
+ * @brief OHCI driver hc interface implementation
  */
 #include <ddf/driver.h>
@@ -36,19 +36,60 @@
 
 #include <usb/debug.h>
+#include <usb/host/endpoint.h>
 
 #include "iface.h"
 #include "hc.h"
 
-#define UNSUPPORTED(methodname) \
-	usb_log_warning("Unsupported interface method `%s()' in %s:%d.\n", \
-	    methodname, __FILE__, __LINE__)
-
-/** Reserve default address.
- *
- * This function may block the caller.
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] speed Speed of the device for which the default address is
- *	reserved.
+static inline int setup_batch(
+    ddf_fun_t *fun, usb_target_t target, usb_direction_t direction,
+    void *data, size_t size, void * setup_data, size_t setup_size,
+    usbhc_iface_transfer_in_callback_t in,
+    usbhc_iface_transfer_out_callback_t out, void *arg, const char* name,
+    hc_t **hc, usb_transfer_batch_t **batch)
+{
+	assert(hc);
+	assert(batch);
+	assert(fun);
+	*hc = fun_to_hc(fun);
+	assert(*hc);
+
+	size_t res_bw;
+	endpoint_t *ep = usb_endpoint_manager_get_ep(&(*hc)->ep_manager,
+	    target.address, target.endpoint, direction, &res_bw);
+	if (ep == NULL) {
+		usb_log_error("Endpoint(%d:%d) not registered for %s.\n",
+		    target.address, target.endpoint, name);
+		return ENOENT;
+	}
+
+	const size_t bw = bandwidth_count_usb11(
+	    ep->speed, ep->transfer_type, size, ep->max_packet_size);
+	if (res_bw < bw) {
+		usb_log_error("Endpoint(%d:%d) %s needs %zu bw "
+		    "but only %zu is reserved.\n",
+		    name, target.address, target.endpoint, bw, res_bw);
+		return ENOSPC;
+	}
+	usb_log_debug("%s %d:%d %zu(%zu).\n",
+	    name, target.address, target.endpoint, size, ep->max_packet_size);
+
+	assert(ep->speed ==
+	    usb_device_keeper_get_speed(&(*hc)->manager, target.address));
+//	assert(ep->max_packet_size == max_packet_size);
+//	assert(ep->transfer_type == USB_TRANSFER_CONTROL);
+
+	*batch =
+	    batch_get(fun, ep, data, size, setup_data, setup_size,
+		in, out, arg);
+	if (!batch)
+		return ENOMEM;
+	return EOK;
+}
+
+
+/** Reserve default address interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] speed Speed to associate with the new default address.
  * @return Error code.
  */
@@ -61,9 +102,28 @@
 	usb_device_keeper_reserve_default_address(&hc->manager, speed);
 	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-/** Release default address.
- *
- * @param[in] fun Device function the action was invoked on.
+#if 0
+	endpoint_t *ep = malloc(sizeof(endpoint_t));
+	if (ep == NULL)
+		return ENOMEM;
+	const size_t max_packet_size = speed == USB_SPEED_LOW ? 8 : 64;
+	endpoint_init(ep, USB_TRANSFER_CONTROL, speed, max_packet_size);
+	int ret;
+try_retgister:
+	ret = usb_endpoint_manager_register_ep(&hc->ep_manager,
+	    USB_ADDRESS_DEFAULT, 0, USB_DIRECTION_BOTH, ep, endpoint_destroy, 0);
+	if (ret == EEXISTS) {
+		async_usleep(1000);
+		goto try_retgister;
+	}
+	if (ret != EOK) {
+		endpoint_destroy(ep);
+	}
+	return ret;
+#endif
+}
+/*----------------------------------------------------------------------------*/
+/** Release default address interface function
+ *
+ * @param[in] fun DDF function that was called.
  * @return Error code.
  */
@@ -74,13 +134,15 @@
 	assert(hc);
 	usb_log_debug("Default address release.\n");
+//	return usb_endpoint_manager_unregister_ep(&hc->ep_manager,
+//	    USB_ADDRESS_DEFAULT, 0, USB_DIRECTION_BOTH);
 	usb_device_keeper_release_default_address(&hc->manager);
 	return EOK;
 }
 /*----------------------------------------------------------------------------*/
-/** Found free USB address.
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] speed Speed of the device that will get this address.
- * @param[out] address Non-null pointer where to store the free address.
+/** Request address interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] speed Speed to associate with the new default address.
+ * @param[out] address Place to write a new address.
  * @return Error code.
  */
@@ -101,13 +163,13 @@
 }
 /*----------------------------------------------------------------------------*/
-/** Bind USB address with device devman handle.
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] address USB address of the device.
- * @param[in] handle Devman handle of the device.
+/** Bind address interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] address Address of the device
+ * @param[in] handle Devman handle of the device driver.
  * @return Error code.
  */
 static int bind_address(
-    ddf_fun_t *fun, usb_address_t address, devman_handle_t handle)
+  ddf_fun_t *fun, usb_address_t address, devman_handle_t handle)
 {
 	assert(fun);
@@ -119,7 +181,7 @@
 }
 /*----------------------------------------------------------------------------*/
-/** Release previously requested address.
- *
- * @param[in] fun Device function the action was invoked on.
+/** Release address interface function
+ *
+ * @param[in] fun DDF function that was called.
  * @param[in] address USB address to be released.
  * @return Error code.
@@ -135,15 +197,4 @@
 }
 /*----------------------------------------------------------------------------*/
-/** Register endpoint for bandwidth reservation.
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] address USB address of the device.
- * @param[in] endpoint Endpoint number.
- * @param[in] transfer_type USB transfer type.
- * @param[in] direction Endpoint data direction.
- * @param[in] max_packet_size Max packet size of the endpoint.
- * @param[in] interval Polling interval.
- * @return Error code.
- */
 static int register_endpoint(
     ddf_fun_t *fun, usb_address_t address, usb_endpoint_t endpoint,
@@ -151,32 +202,41 @@
     size_t max_packet_size, unsigned int interval)
 {
-	assert(fun);
-	hc_t *hc = fun_to_hc(fun);
-	assert(hc);
-	if (address == hc->rh.address)
-		return EOK;
+	hc_t *hc = fun_to_hc(fun);
+	assert(hc);
 	const usb_speed_t speed =
-		usb_device_keeper_get_speed(&hc->manager, address);
-	const size_t size = max_packet_size;
+	    usb_device_keeper_get_speed(&hc->manager, address);
+	const size_t size =
+	    (transfer_type == USB_TRANSFER_INTERRUPT
+	    || transfer_type == USB_TRANSFER_ISOCHRONOUS) ?
+	    max_packet_size : 0;
+	int ret;
+
+	endpoint_t *ep = malloc(sizeof(endpoint_t));
+	if (ep == NULL)
+		return ENOMEM;
+	ret = endpoint_init(ep, address, endpoint, direction,
+	    transfer_type, speed, max_packet_size);
+	if (ret != EOK) {
+		free(ep);
+		return ret;
+	}
+
 	usb_log_debug("Register endpoint %d:%d %s %s(%d) %zu(%zu) %u.\n",
 	    address, endpoint, usb_str_transfer_type(transfer_type),
 	    usb_str_speed(speed), direction, size, max_packet_size, interval);
-	// TODO use real endpoint here!
-	return usb_endpoint_manager_register_ep(&hc->ep_manager,NULL, 0);
-}
-/*----------------------------------------------------------------------------*/
-/** Unregister endpoint (free some bandwidth reservation).
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] address USB address of the device.
- * @param[in] endpoint Endpoint number.
- * @param[in] direction Endpoint data direction.
- * @return Error code.
- */
+
+	ret = usb_endpoint_manager_register_ep(&hc->ep_manager, ep, size);
+	if (ret != EOK) {
+		endpoint_destroy(ep);
+	} else {
+		usb_device_keeper_add_ep(&hc->manager, address, ep);
+	}
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
 static int unregister_endpoint(
     ddf_fun_t *fun, usb_address_t address,
     usb_endpoint_t endpoint, usb_direction_t direction)
 {
-	assert(fun);
 	hc_t *hc = fun_to_hc(fun);
 	assert(hc);
@@ -187,19 +247,13 @@
 }
 /*----------------------------------------------------------------------------*/
-/** Schedule interrupt out transfer.
- *
- * The callback is supposed to be called once the transfer (on the wire) is
- * complete regardless of the outcome.
- * However, the callback could be called only when this function returns
- * with success status (i.e. returns EOK).
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] target Target pipe (address and endpoint number) specification.
- * @param[in] max_packet_size Max packet size for the transfer.
- * @param[in] data Data to be sent (in USB endianess, allocated and deallocated
- *	by the caller).
- * @param[in] size Size of the @p data buffer in bytes.
- * @param[in] callback Callback to be issued once the transfer is complete.
- * @param[in] arg Pass-through argument to the callback.
+/** Interrupt out transaction interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] target USB device to write to.
+ * @param[in] max_packet_size maximum size of data packet the device accepts
+ * @param[in] data Source of data.
+ * @param[in] size Size of data source.
+ * @param[in] callback Function to call on transaction completion
+ * @param[in] arg Additional for callback function.
  * @return Error code.
  */
@@ -208,41 +262,27 @@
     size_t size, usbhc_iface_transfer_out_callback_t callback, void *arg)
 {
-	assert(fun);
-	hc_t *hc = fun_to_hc(fun);
-	assert(hc);
-	usb_speed_t speed =
-	    usb_device_keeper_get_speed(&hc->manager, target.address);
-
-	usb_log_debug("Interrupt OUT %d:%d %zu(%zu).\n",
-	    target.address, target.endpoint, size, max_packet_size);
-
-	usb_transfer_batch_t *batch =
-	    batch_get(fun, target, USB_TRANSFER_INTERRUPT, max_packet_size,
-	        speed, data, size, NULL, 0, NULL, callback, arg, &hc->manager);
-	if (!batch)
-		return ENOMEM;
+	usb_transfer_batch_t *batch = NULL;
+	hc_t *hc = NULL;
+	int ret = setup_batch(fun, target, USB_DIRECTION_OUT, data, size,
+	    NULL, 0, NULL, callback, arg, "Interrupt OUT", &hc, &batch);
+	if (ret != EOK)
+		return ret;
 	batch_interrupt_out(batch);
-	const int ret = hc_schedule(hc, batch);
-	if (ret != EOK) {
-		batch_dispose(batch);
-	}
-	return ret;
-}
-/*----------------------------------------------------------------------------*/
-/** Schedule interrupt in transfer.
- *
- * The callback is supposed to be called once the transfer (on the wire) is
- * complete regardless of the outcome.
- * However, the callback could be called only when this function returns
- * with success status (i.e. returns EOK).
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] target Target pipe (address and endpoint number) specification.
- * @param[in] max_packet_size Max packet size for the transfer.
- * @param[in] data Buffer where to store the data (in USB endianess,
- *	allocated and deallocated by the caller).
- * @param[in] size Size of the @p data buffer in bytes.
- * @param[in] callback Callback to be issued once the transfer is complete.
- * @param[in] arg Pass-through argument to the callback.
+	ret = hc_schedule(hc, batch);
+	if (ret != EOK) {
+		batch_dispose(batch);
+	}
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+/** Interrupt in transaction interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] target USB device to write to.
+ * @param[in] max_packet_size maximum size of data packet the device accepts
+ * @param[out] data Data destination.
+ * @param[in] size Size of data source.
+ * @param[in] callback Function to call on transaction completion
+ * @param[in] arg Additional for callback function.
  * @return Error code.
  */
@@ -251,40 +291,27 @@
     size_t size, usbhc_iface_transfer_in_callback_t callback, void *arg)
 {
-	assert(fun);
-	hc_t *hc = fun_to_hc(fun);
-	assert(hc);
-	usb_speed_t speed =
-	    usb_device_keeper_get_speed(&hc->manager, target.address);
-	usb_log_debug("Interrupt IN %d:%d %zu(%zu).\n",
-	    target.address, target.endpoint, size, max_packet_size);
-
-	usb_transfer_batch_t *batch =
-	    batch_get(fun, target, USB_TRANSFER_INTERRUPT, max_packet_size,
-	        speed, data, size, NULL, 0, callback, NULL, arg, &hc->manager);
-	if (!batch)
-		return ENOMEM;
+	usb_transfer_batch_t *batch = NULL;
+	hc_t *hc = NULL;
+	int ret = setup_batch(fun, target, USB_DIRECTION_IN, data, size,
+	    NULL, 0, callback, NULL, arg, "Interrupt IN", &hc, &batch);
+	if (ret != EOK)
+		return ret;
 	batch_interrupt_in(batch);
-	const int ret = hc_schedule(hc, batch);
-	if (ret != EOK) {
-		batch_dispose(batch);
-	}
-	return ret;
-}
-/*----------------------------------------------------------------------------*/
-/** Schedule bulk out transfer.
- *
- * The callback is supposed to be called once the transfer (on the wire) is
- * complete regardless of the outcome.
- * However, the callback could be called only when this function returns
- * with success status (i.e. returns EOK).
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] target Target pipe (address and endpoint number) specification.
- * @param[in] max_packet_size Max packet size for the transfer.
- * @param[in] data Data to be sent (in USB endianess, allocated and deallocated
- *	by the caller).
- * @param[in] size Size of the @p data buffer in bytes.
- * @param[in] callback Callback to be issued once the transfer is complete.
- * @param[in] arg Pass-through argument to the callback.
+	ret = hc_schedule(hc, batch);
+	if (ret != EOK) {
+		batch_dispose(batch);
+	}
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+/** Bulk out transaction interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] target USB device to write to.
+ * @param[in] max_packet_size maximum size of data packet the device accepts
+ * @param[in] data Source of data.
+ * @param[in] size Size of data source.
+ * @param[in] callback Function to call on transaction completion
+ * @param[in] arg Additional for callback function.
  * @return Error code.
  */
@@ -293,41 +320,27 @@
     size_t size, usbhc_iface_transfer_out_callback_t callback, void *arg)
 {
-	assert(fun);
-	hc_t *hc = fun_to_hc(fun);
-	assert(hc);
-	usb_speed_t speed =
-	    usb_device_keeper_get_speed(&hc->manager, target.address);
-
-	usb_log_debug("Bulk OUT %d:%d %zu(%zu).\n",
-	    target.address, target.endpoint, size, max_packet_size);
-
-	usb_transfer_batch_t *batch =
-	    batch_get(fun, target, USB_TRANSFER_BULK, max_packet_size, speed,
-	        data, size, NULL, 0, NULL, callback, arg, &hc->manager);
-	if (!batch)
-		return ENOMEM;
+	usb_transfer_batch_t *batch = NULL;
+	hc_t *hc = NULL;
+	int ret = setup_batch(fun, target, USB_DIRECTION_OUT, data, size,
+	    NULL, 0, NULL, callback, arg, "Bulk OUT", &hc, &batch);
+	if (ret != EOK)
+		return ret;
 	batch_bulk_out(batch);
-	const int ret = hc_schedule(hc, batch);
-	if (ret != EOK) {
-		batch_dispose(batch);
-	}
-	return ret;
-}
-/*----------------------------------------------------------------------------*/
-/** Schedule bulk in transfer.
- *
- * The callback is supposed to be called once the transfer (on the wire) is
- * complete regardless of the outcome.
- * However, the callback could be called only when this function returns
- * with success status (i.e. returns EOK).
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] target Target pipe (address and endpoint number) specification.
- * @param[in] max_packet_size Max packet size for the transfer.
- * @param[in] data Buffer where to store the data (in USB endianess,
- *	allocated and deallocated by the caller).
- * @param[in] size Size of the @p data buffer in bytes.
- * @param[in] callback Callback to be issued once the transfer is complete.
- * @param[in] arg Pass-through argument to the callback.
+	ret = hc_schedule(hc, batch);
+	if (ret != EOK) {
+		batch_dispose(batch);
+	}
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+/** Bulk in transaction interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] target USB device to write to.
+ * @param[in] max_packet_size maximum size of data packet the device accepts
+ * @param[out] data Data destination.
+ * @param[in] size Size of data source.
+ * @param[in] callback Function to call on transaction completion
+ * @param[in] arg Additional for callback function.
  * @return Error code.
  */
@@ -336,43 +349,29 @@
     size_t size, usbhc_iface_transfer_in_callback_t callback, void *arg)
 {
-	assert(fun);
-	hc_t *hc = fun_to_hc(fun);
-	assert(hc);
-	usb_speed_t speed =
-	    usb_device_keeper_get_speed(&hc->manager, target.address);
-	usb_log_debug("Bulk IN %d:%d %zu(%zu).\n",
-	    target.address, target.endpoint, size, max_packet_size);
-
-	usb_transfer_batch_t *batch =
-	    batch_get(fun, target, USB_TRANSFER_BULK, max_packet_size, speed,
-	        data, size, NULL, 0, callback, NULL, arg, &hc->manager);
-	if (!batch)
-		return ENOMEM;
+	usb_transfer_batch_t *batch = NULL;
+	hc_t *hc = NULL;
+	int ret = setup_batch(fun, target, USB_DIRECTION_IN, data, size,
+	    NULL, 0, callback, NULL, arg, "Bulk IN", &hc, &batch);
+	if (ret != EOK)
+		return ret;
 	batch_bulk_in(batch);
-	const int ret = hc_schedule(hc, batch);
-	if (ret != EOK) {
-		batch_dispose(batch);
-	}
-	return ret;
-}
-/*----------------------------------------------------------------------------*/
-/** Schedule control write transfer.
- *
- * The callback is supposed to be called once the transfer (on the wire) is
- * complete regardless of the outcome.
- * However, the callback could be called only when this function returns
- * with success status (i.e. returns EOK).
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] target Target pipe (address and endpoint number) specification.
- * @param[in] max_packet_size Max packet size for the transfer.
- * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated
- *	and deallocated by the caller).
- * @param[in] setup_packet_size Size of @p setup_packet buffer in bytes.
- * @param[in] data_buffer Data buffer (in USB endianess, allocated and
- *	deallocated by the caller).
- * @param[in] data_buffer_size Size of @p data_buffer buffer in bytes.
- * @param[in] callback Callback to be issued once the transfer is complete.
- * @param[in] arg Pass-through argument to the callback.
+	ret = hc_schedule(hc, batch);
+	if (ret != EOK) {
+		batch_dispose(batch);
+	}
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+/** Control write transaction interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] target USB device to write to.
+ * @param[in] max_packet_size maximum size of data packet the device accepts.
+ * @param[in] setup_data Data to send with SETUP transfer.
+ * @param[in] setup_size Size of data to send with SETUP transfer (always 8B).
+ * @param[in] data Source of data.
+ * @param[in] size Size of data source.
+ * @param[in] callback Function to call on transaction completion.
+ * @param[in] arg Additional for callback function.
  * @return Error code.
  */
@@ -382,48 +381,31 @@
     usbhc_iface_transfer_out_callback_t callback, void *arg)
 {
-	assert(fun);
-	hc_t *hc = fun_to_hc(fun);
-	assert(hc);
-	usb_speed_t speed =
-	    usb_device_keeper_get_speed(&hc->manager, target.address);
-	usb_log_debug("Control WRITE (%d) %d:%d %zu(%zu).\n",
-	    speed, target.address, target.endpoint, size, max_packet_size);
-
-	if (setup_size != 8)
-		return EINVAL;
-
-	usb_transfer_batch_t *batch =
-	    batch_get(fun, target, USB_TRANSFER_CONTROL, max_packet_size,
-	        speed, data, size, setup_data, setup_size, NULL, callback, arg,
-		&hc->manager);
-	if (!batch)
-		return ENOMEM;
+	usb_transfer_batch_t *batch = NULL;
+	hc_t *hc = NULL;
+	int ret = setup_batch(fun, target, USB_DIRECTION_BOTH, data, size,
+	    setup_data, setup_size, NULL, callback, arg, "Control WRITE",
+	    &hc, &batch);
+	if (ret != EOK)
+		return ret;
 	usb_device_keeper_reset_if_need(&hc->manager, target, setup_data);
 	batch_control_write(batch);
-	const int ret = hc_schedule(hc, batch);
-	if (ret != EOK) {
-		batch_dispose(batch);
-	}
-	return ret;
-}
-/*----------------------------------------------------------------------------*/
-/** Schedule control read transfer.
- *
- * The callback is supposed to be called once the transfer (on the wire) is
- * complete regardless of the outcome.
- * However, the callback could be called only when this function returns
- * with success status (i.e. returns EOK).
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] target Target pipe (address and endpoint number) specification.
- * @param[in] max_packet_size Max packet size for the transfer.
- * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated
- *	and deallocated by the caller).
- * @param[in] setup_packet_size Size of @p setup_packet buffer in bytes.
- * @param[in] data_buffer Buffer where to store the data (in USB endianess,
- *	allocated and deallocated by the caller).
- * @param[in] data_buffer_size Size of @p data_buffer buffer in bytes.
- * @param[in] callback Callback to be issued once the transfer is complete.
- * @param[in] arg Pass-through argument to the callback.
+	ret = hc_schedule(hc, batch);
+	if (ret != EOK) {
+		batch_dispose(batch);
+	}
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+/** Control read transaction interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] target USB device to write to.
+ * @param[in] max_packet_size maximum size of data packet the device accepts.
+ * @param[in] setup_data Data to send with SETUP packet.
+ * @param[in] setup_size Size of data to send with SETUP packet (should be 8B).
+ * @param[out] data Source of data.
+ * @param[in] size Size of data source.
+ * @param[in] callback Function to call on transaction completion.
+ * @param[in] arg Additional for callback function.
  * @return Error code.
  */
@@ -433,27 +415,19 @@
     usbhc_iface_transfer_in_callback_t callback, void *arg)
 {
-	assert(fun);
-	hc_t *hc = fun_to_hc(fun);
-	assert(hc);
-	usb_speed_t speed =
-	    usb_device_keeper_get_speed(&hc->manager, target.address);
-
-	usb_log_debug("Control READ(%d) %d:%d %zu(%zu).\n",
-	    speed, target.address, target.endpoint, size, max_packet_size);
-	usb_transfer_batch_t *batch =
-	    batch_get(fun, target, USB_TRANSFER_CONTROL, max_packet_size,
-	        speed, data, size, setup_data, setup_size, callback, NULL, arg,
-		&hc->manager);
-	if (!batch)
-		return ENOMEM;
+	usb_transfer_batch_t *batch = NULL;
+	hc_t *hc = NULL;
+	int ret = setup_batch(fun, target, USB_DIRECTION_BOTH, data, size,
+	    setup_data, setup_size, callback, NULL, arg, "Control READ",
+	    &hc, &batch);
+	if (ret != EOK)
+		return ret;
 	batch_control_read(batch);
-	const int ret = hc_schedule(hc, batch);
-	if (ret != EOK) {
-		batch_dispose(batch);
-	}
-	return ret;
-}
-/*----------------------------------------------------------------------------*/
-/** Host controller interface implementation for OHCI. */
+	ret = hc_schedule(hc, batch);
+	if (ret != EOK) {
+		batch_dispose(batch);
+	}
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
 usbhc_iface_t hc_iface = {
 	.reserve_default_address = reserve_default_address,
@@ -475,5 +449,4 @@
 	.control_read = control_read,
 };
-
 /**
  * @}
