Index: uspace/lib/drv/generic/remote_usbhc.c
===================================================================
--- uspace/lib/drv/generic/remote_usbhc.c	(revision af16ebece2cb3bc7592cffdd6e1a6da6698dc8db)
+++ uspace/lib/drv/generic/remote_usbhc.c	(revision 239eea4167f0ebbd6c42050e2c252fd03a7f3c08)
@@ -51,6 +51,5 @@
 	IPC_M_USB_REGISTER_ENDPOINT,
 	IPC_M_USB_UNREGISTER_ENDPOINT,
-	IPC_M_USB_READ,
-	IPC_M_USB_WRITE,
+	IPC_M_USB_TRANSFER,
 } usbhc_iface_funcs_t;
 
@@ -183,7 +182,6 @@
  * temporarily shared with the HC.
  */
-errno_t usbhc_transfer(async_exch_t *exch, usb_endpoint_t endpoint,
-    usb_direction_t dir, uint64_t setup, void *area, size_t size,
-    size_t *transferred)
+errno_t usbhc_transfer(async_exch_t *exch,
+    const usbhc_iface_transfer_request_t *req, size_t *transferred)
 {
 	if (transferred)
@@ -193,25 +191,24 @@
 		return EBADMEM;
 
-	if (size == 0 && setup == 0)
-		return EOK;
-
-	sysarg_t method = (dir == USB_DIRECTION_IN)
-		? IPC_M_USB_READ : IPC_M_USB_WRITE;
-
 	ipc_call_t call;
 
-
-	aid_t opening_request = async_send_5(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
-	    method, endpoint, size, (setup & UINT32_MAX), (setup >> 32), &call);
+	aid_t opening_request = async_send_1(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USB_TRANSFER, &call);
 
 	if (opening_request == 0)
 		return ENOMEM;
 
-	/* Send the data if any. */
-	if (size > 0) {
-		unsigned flags = (dir == USB_DIRECTION_IN)
+	const errno_t ret = async_data_write_start(exch, req, sizeof(*req));
+	if (ret != EOK) {
+		async_forget(opening_request);
+		return ret;
+	}
+
+	/* Share the data, if any. */
+	if (req->size > 0) {
+		unsigned flags = (req->dir == USB_DIRECTION_IN)
 			? AS_AREA_WRITE : AS_AREA_READ;
 
-		const errno_t ret = async_share_out_start(exch, area, flags);
+		const errno_t ret = async_share_out_start(exch, req->base, flags);
 		if (ret != EOK) {
 			async_forget(opening_request);
@@ -244,6 +241,5 @@
 	[IPC_M_USB_REGISTER_ENDPOINT] = remote_usbhc_register_endpoint,
 	[IPC_M_USB_UNREGISTER_ENDPOINT] = remote_usbhc_unregister_endpoint,
-	[IPC_M_USB_READ] = remote_usbhc_transfer,
-	[IPC_M_USB_WRITE] = remote_usbhc_transfer,
+	[IPC_M_USB_TRANSFER] = remote_usbhc_transfer,
 };
 
@@ -257,5 +253,5 @@
 typedef struct {
 	ipc_callid_t caller;
-	void *buffer;
+	usbhc_iface_transfer_request_t request;
 } async_transaction_t;
 
@@ -378,6 +374,6 @@
 		return;
 	}
-	if (trans->buffer != NULL) {
-		as_area_destroy(trans->buffer);
+	if (trans->request.base != NULL) {
+		as_area_destroy(trans->request.base);
 	}
 
@@ -387,11 +383,8 @@
 static async_transaction_t *async_transaction_create(ipc_callid_t caller)
 {
-	async_transaction_t *trans = malloc(sizeof(async_transaction_t));
-	if (trans == NULL) {
-		return NULL;
-	}
-
-	trans->caller = caller;
-	trans->buffer = NULL;
+	async_transaction_t *trans = calloc(1, sizeof(async_transaction_t));
+
+	if (trans != NULL)
+		trans->caller = caller;
 
 	return trans;
@@ -406,9 +399,13 @@
 }
 
-static errno_t receive_memory_buffer(async_transaction_t *trans,
-	size_t required_size, unsigned required_flags)
+static errno_t receive_memory_buffer(async_transaction_t *trans)
 {
 	assert(trans);
-	assert(required_size > 0);
+	assert(trans->request.size > 0);
+
+	const size_t required_size = trans->request.offset + trans->request.size;
+	const unsigned required_flags =
+		(trans->request.dir == USB_DIRECTION_IN)
+		? AS_AREA_WRITE : AS_AREA_READ;
 
 	errno_t err;
@@ -425,5 +422,5 @@
 	}
 
-	if ((err = async_share_out_finalize(data_callid, &trans->buffer)))
+	if ((err = async_share_out_finalize(data_callid, &trans->request.base)))
 		return err;
 
@@ -435,9 +432,9 @@
 	if (flags & AS_AREA_READ) {
 		char foo = 0;
-		volatile const char *buf = trans->buffer;
+		volatile const char *buf = trans->request.base + trans->request.offset;
 		for (size_t i = 0; i < size; i += PAGE_SIZE)
 			foo += buf[i];
 	} else {
-		volatile char *buf = trans->buffer;
+		volatile char *buf = trans->request.base + trans->request.offset;
 		for (size_t i = 0; i < size; i += PAGE_SIZE)
 			buf[i] = 0xff;
@@ -460,13 +457,4 @@
 	}
 
-	const sysarg_t method = IPC_GET_ARG1(*call);
-	const usb_direction_t dir =
-		method == IPC_M_USB_READ ? USB_DIRECTION_IN : USB_DIRECTION_OUT;
-
-	const usb_endpoint_t ep = IPC_GET_ARG2(*call);
-	const size_t size = IPC_GET_ARG3(*call);
-	const uint64_t setup = ((uint64_t)IPC_GET_ARG4(*call)) |
-	    (((uint64_t)IPC_GET_ARG5(*call)) << 32);
-
 	async_transaction_t *trans = async_transaction_create(callid);
 	if (trans == NULL) {
@@ -475,30 +463,36 @@
 	}
 
-	if (size > 0) {
-		const unsigned required_flags = (dir == USB_DIRECTION_IN)
-			? AS_AREA_WRITE : AS_AREA_READ;
-
-		const errno_t rc = receive_memory_buffer(trans, size, required_flags);
-		if (rc != EOK) {
-			async_transaction_destroy(trans);
-			async_answer_0(callid, rc);
-			return;
-		}
-	}
-
-	const usb_target_t target = {{
-		/* .address is initialized by write itself */
-		.endpoint = ep,
-		/* streams are not given by the API call yet */
-		.stream = 0,
-	}};
-
-	const errno_t rc = usbhc_iface->transfer(fun, target, dir, setup,
-	    trans->buffer, size, &transfer_finished, trans);
-
-	if (rc != EOK) {
-		async_answer_0(callid, rc);
-		async_transaction_destroy(trans);
-	}
+	errno_t err = EPARTY;
+
+	ipc_callid_t data_callid;
+	size_t len;
+	if (!async_data_write_receive(&data_callid, &len)
+	    || len != sizeof(trans->request)) {
+		async_answer_0(data_callid, EINVAL);
+		goto err;
+	}
+
+	if ((err = async_data_write_finalize(data_callid,
+			    &trans->request, sizeof(trans->request))))
+		goto err;
+
+	if (trans->request.size > 0) {
+		if ((err = receive_memory_buffer(trans)))
+			goto err;
+	} else {
+		/* The value was valid on the other side, for us, its garbage. */
+		trans->request.base = NULL;
+	}
+
+	if ((err = usbhc_iface->transfer(fun, &trans->request,
+	    &transfer_finished, trans)))
+		goto err;
+
+	/* The call will be answered asynchronously by the callback. */
+	return;
+
+err:
+	async_answer_0(callid, err);
+	async_transaction_destroy(trans);
 }
 
Index: uspace/lib/drv/include/usbhc_iface.h
===================================================================
--- uspace/lib/drv/include/usbhc_iface.h	(revision af16ebece2cb3bc7592cffdd6e1a6da6698dc8db)
+++ uspace/lib/drv/include/usbhc_iface.h	(revision 239eea4167f0ebbd6c42050e2c252fd03a7f3c08)
@@ -126,4 +126,22 @@
 } usb_pipe_desc_t;
 
+typedef struct usb_pipe_transfer_request {
+	usb_direction_t dir;
+	usb_endpoint_t endpoint;
+	usb_stream_t stream;
+
+	uint64_t setup;			/**< Valid iff the transfer is of control type */
+
+	/**
+	 * Base address of the buffer to share. Must be at least offset + size
+	 * large. Is patched after being transmitted over IPC, so the pointer is
+	 * still valid.
+	 */
+	void *base;			
+	size_t offset;			/**< Offset to the buffer */
+	size_t size;			/**< Requested size. */
+	dma_policy_t buffer_policy;	/**< Properties of the buffer. */
+} usbhc_iface_transfer_request_t;
+
 /** This structure follows standard endpoint descriptor + superspeed companion
  * descriptor, and exists to avoid dependency of libdrv on libusb. Keep the
@@ -157,6 +175,5 @@
 extern errno_t usbhc_unregister_endpoint(async_exch_t *, const usb_pipe_desc_t *);
 
-extern errno_t usbhc_transfer(async_exch_t *, usb_endpoint_t, usb_direction_t,
-    uint64_t, void *, size_t, size_t *);
+extern errno_t usbhc_transfer(async_exch_t *, const usbhc_iface_transfer_request_t *, size_t *);
 
 /** Callback for outgoing transfer */
@@ -173,7 +190,6 @@
 	errno_t (*unregister_endpoint)(ddf_fun_t *, const usb_pipe_desc_t *);
 
-	errno_t (*transfer)(ddf_fun_t *, usb_target_t,
-		usb_direction_t, uint64_t, char *, size_t,
-		usbhc_iface_transfer_callback_t, void *);
+	errno_t (*transfer)(ddf_fun_t *, const usbhc_iface_transfer_request_t *,
+	    usbhc_iface_transfer_callback_t, void *);
 } usbhc_iface_t;
 
Index: uspace/lib/usb/include/usb/usb.h
===================================================================
--- uspace/lib/usb/include/usb/usb.h	(revision af16ebece2cb3bc7592cffdd6e1a6da6698dc8db)
+++ uspace/lib/usb/include/usb/usb.h	(revision 239eea4167f0ebbd6c42050e2c252fd03a7f3c08)
@@ -132,5 +132,5 @@
  * @return True, if values are wihtin limits, false otherwise.
  */
-static inline bool usb_target_is_valid(usb_target_t *target)
+static inline bool usb_target_is_valid(const usb_target_t *target)
 {
 	return usb_address_is_valid(target->address) &&
Index: uspace/lib/usbdev/src/pipes.c
===================================================================
--- uspace/lib/usbdev/src/pipes.c	(revision af16ebece2cb3bc7592cffdd6e1a6da6698dc8db)
+++ uspace/lib/usbdev/src/pipes.c	(revision 239eea4167f0ebbd6c42050e2c252fd03a7f3c08)
@@ -39,5 +39,7 @@
 
 #include <assert.h>
+#include <bitops.h>
 #include <async.h>
+#include <as.h>
 #include <errno.h>
 #include <mem.h>
@@ -61,11 +63,14 @@
 }
 
+/* Helper structure to avoid passing loads of arguments through */
 typedef struct {
 	usb_pipe_t *pipe;
 	usb_direction_t dir;
-	bool is_control;
-	uint64_t setup;
+	bool is_control;	// Only for checking purposes
 	void *buffer;
 	size_t buffer_size;
+
+	usbhc_iface_transfer_request_t req;
+
 	size_t transferred_size;
 } transfer_t;
@@ -80,6 +85,13 @@
 		return ENOMEM;
 
-	const errno_t rc = usbhc_transfer(exch, t->pipe->desc.endpoint_no,
-	    t->dir, t->setup, t->buffer, t->buffer_size, &t->transferred_size);
+	t->req.dir = t->dir;
+	t->req.endpoint = t->pipe->desc.endpoint_no;
+
+	/* We support only aligned buffers for now. */
+	t->req.base = t->buffer;
+	t->req.offset = 0;
+	t->req.size = t->buffer_size;
+
+	const errno_t rc = usbhc_transfer(exch, &t->req, &t->transferred_size);
 
 	async_exchange_end(exch);
@@ -143,5 +155,5 @@
 		return EINVAL;
 	
-	memcpy(&t->setup, setup, 8);
+	memcpy(&t->req.setup, setup, 8);
 	return EOK;
 }
Index: uspace/lib/usbhost/src/ddf_helpers.c
===================================================================
--- uspace/lib/usbhost/src/ddf_helpers.c	(revision af16ebece2cb3bc7592cffdd6e1a6da6698dc8db)
+++ uspace/lib/usbhost/src/ddf_helpers.c	(revision 239eea4167f0ebbd6c42050e2c252fd03a7f3c08)
@@ -271,6 +271,5 @@
  * @return Error code.
  */
-static errno_t transfer(ddf_fun_t *fun, usb_target_t target,
-    usb_direction_t dir, uint64_t setup_data, char *data, size_t size,
+static errno_t transfer(ddf_fun_t *fun, const usbhc_iface_transfer_request_t *req,
     usbhc_iface_transfer_callback_t callback, void *arg)
 {
@@ -279,10 +278,14 @@
 	assert(dev);
 
-	target.address = dev->address;
+	const usb_target_t target = {{
+		.address = dev->address,
+		.endpoint = req->endpoint,
+		.stream = req->stream,
+	}};
 
 	if (!usb_target_is_valid(&target))
 		return EINVAL;
 
-	if (size > 0 && data == NULL)
+	if (req->size > 0 && req->base == NULL)
 		return EBADMEM;
 
@@ -290,8 +293,10 @@
 		return EBADMEM;
 
-	const char *name = (dir == USB_DIRECTION_IN) ? "READ" : "WRITE";
-
-	return bus_device_send_batch(dev, target, dir,
-	    (char *) data, size, setup_data,
+	const char *name = (req->dir == USB_DIRECTION_IN) ? "READ" : "WRITE";
+
+	char *buffer = req->base + req->offset;
+
+	return bus_device_send_batch(dev, target, req->dir,
+	    buffer, req->size, req->setup,
 	    callback, arg, name);
 }
