Index: uspace/lib/drv/generic/remote_usb.c
===================================================================
--- uspace/lib/drv/generic/remote_usb.c	(revision 1298a8fa81d80adef31cde419d130f1eac1b6422)
+++ uspace/lib/drv/generic/remote_usb.c	(revision 64e1fb2eca59f3163d32012107ab8b46a0fe2428)
@@ -74,4 +74,6 @@
 	IPC_M_USB_REGISTER_ENDPOINT,
 	IPC_M_USB_UNREGISTER_ENDPOINT,
+	IPC_M_USB_READ,
+	IPC_M_USB_WRITE,
 } usb_iface_funcs_t;
 
@@ -223,4 +225,88 @@
 }
 
+int usb_read(async_exch_t *exch, usb_endpoint_t endpoint, uint64_t setup,
+    void *data, size_t size, size_t *rec_size)
+{
+	if (!exch)
+		return EBADMEM;
+
+	if (size == 0 && setup == 0)
+		return EOK;
+
+	/* Make call identifying target USB device and type of transfer. */
+	aid_t opening_request = async_send_4(exch,
+	    DEV_IFACE_ID(USB_DEV_IFACE), IPC_M_USB_READ, endpoint,
+	    (setup & UINT32_MAX), (setup >> 32), NULL);
+
+	if (opening_request == 0) {
+		return ENOMEM;
+	}
+
+	/* Retrieve the data. */
+	ipc_call_t data_request_call;
+	aid_t data_request =
+	    async_data_read(exch, data, size, &data_request_call);
+
+	if (data_request == 0) {
+		// FIXME: How to let the other side know that we want to abort?
+		async_forget(opening_request);
+		return ENOMEM;
+	}
+
+	/* Wait for the answer. */
+	sysarg_t data_request_rc;
+	sysarg_t opening_request_rc;
+	async_wait_for(data_request, &data_request_rc);
+	async_wait_for(opening_request, &opening_request_rc);
+
+	if (data_request_rc != EOK) {
+		/* Prefer the return code of the opening request. */
+		if (opening_request_rc != EOK) {
+			return (int) opening_request_rc;
+		} else {
+			return (int) data_request_rc;
+		}
+	}
+	if (opening_request_rc != EOK) {
+		return (int) opening_request_rc;
+	}
+
+	*rec_size = IPC_GET_ARG2(data_request_call);
+	return EOK;
+}
+
+int usb_write(async_exch_t *exch, usb_endpoint_t endpoint, uint64_t setup,
+    const void *data, size_t size)
+{
+	if (!exch)
+		return EBADMEM;
+
+	if (size == 0 && setup == 0)
+		return EOK;
+
+	aid_t opening_request = async_send_5(exch,
+	    DEV_IFACE_ID(USB_DEV_IFACE), IPC_M_USB_WRITE, endpoint, size,
+	    (setup & UINT32_MAX), (setup >> 32), NULL);
+
+	if (opening_request == 0) {
+		return ENOMEM;
+	}
+
+	/* Send the data if any. */
+	if (size > 0) {
+		const int ret = async_data_write_start(exch, data, size);
+		if (ret != EOK) {
+			async_forget(opening_request);
+			return ret;
+		}
+	}
+
+	/* Wait for the answer. */
+	sysarg_t opening_request_rc;
+	async_wait_for(opening_request, &opening_request_rc);
+
+	return (int) opening_request_rc;
+}
+
 static void remote_usb_get_my_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
 static void remote_usb_get_my_interface(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
@@ -234,4 +320,7 @@
 static void remote_usb_register_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
 static void remote_usb_unregister_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usb_read(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call);
+
+static void remote_usb_write(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call);
 
 /** Remote USB interface operations. */
@@ -247,4 +336,6 @@
 	[IPC_M_USB_REGISTER_ENDPOINT] = remote_usb_register_endpoint,
 	[IPC_M_USB_UNREGISTER_ENDPOINT] = remote_usb_unregister_endpoint,
+	[IPC_M_USB_READ] = remote_usb_read,
+	[IPC_M_USB_WRITE] = remote_usb_write,
 };
 
@@ -445,4 +536,163 @@
 	async_answer_0(callid, rc);
 }
+
+typedef struct {
+	ipc_callid_t caller;
+	ipc_callid_t data_caller;
+	void *buffer;
+} async_transaction_t;
+
+static void async_transaction_destroy(async_transaction_t *trans)
+{
+	if (trans == NULL) {
+		return;
+	}
+	if (trans->buffer != NULL) {
+		free(trans->buffer);
+	}
+
+	free(trans);
+}
+
+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->data_caller = 0;
+	trans->buffer = NULL;
+
+	return trans;
+}
+
+static void callback_out(int outcome, void *arg)
+{
+	async_transaction_t *trans = arg;
+
+	async_answer_0(trans->caller, outcome);
+
+	async_transaction_destroy(trans);
+}
+
+static void callback_in(int outcome, size_t actual_size, void *arg)
+{
+	async_transaction_t *trans = (async_transaction_t *)arg;
+
+	if (outcome != EOK) {
+		async_answer_0(trans->caller, outcome);
+		if (trans->data_caller) {
+			async_answer_0(trans->data_caller, EINTR);
+		}
+		async_transaction_destroy(trans);
+		return;
+	}
+
+	if (trans->data_caller) {
+		async_data_read_finalize(trans->data_caller,
+		    trans->buffer, actual_size);
+	}
+
+	async_answer_0(trans->caller, EOK);
+
+	async_transaction_destroy(trans);
+}
+
+void remote_usb_read(
+    ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
+{
+	assert(fun);
+	assert(iface);
+	assert(call);
+
+	const usb_iface_t *usb_iface = iface;
+
+	if (!usb_iface->read) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	const usb_endpoint_t ep = DEV_IPC_GET_ARG1(*call);
+	const uint64_t setup =
+	    ((uint64_t)DEV_IPC_GET_ARG2(*call)) |
+	    (((uint64_t)DEV_IPC_GET_ARG3(*call)) << 32);
+
+	async_transaction_t *trans = async_transaction_create(callid);
+	if (trans == NULL) {
+		async_answer_0(callid, ENOMEM);
+		return;
+	}
+
+	size_t size = 0;
+	if (!async_data_read_receive(&trans->data_caller, &size)) {
+		async_answer_0(callid, EPARTY);
+		return;
+	}
+
+	trans->buffer = malloc(size);
+	if (trans->buffer == NULL) {
+		async_answer_0(trans->data_caller, ENOMEM);
+		async_answer_0(callid, ENOMEM);
+		async_transaction_destroy(trans);
+	}
+
+	const int rc = usb_iface->read(
+	    fun, ep, setup, trans->buffer, size, callback_in, trans);
+
+	if (rc != EOK) {
+		async_answer_0(trans->data_caller, rc);
+		async_answer_0(callid, rc);
+		async_transaction_destroy(trans);
+	}
+}
+
+void remote_usb_write(
+    ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
+{
+	assert(fun);
+	assert(iface);
+	assert(call);
+
+	const usb_iface_t *usb_iface = iface;
+
+	if (!usb_iface->write) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	const usb_endpoint_t ep = DEV_IPC_GET_ARG1(*call);
+	const size_t data_buffer_len = DEV_IPC_GET_ARG2(*call);
+	const uint64_t setup =
+	    ((uint64_t)DEV_IPC_GET_ARG3(*call)) |
+	    (((uint64_t)DEV_IPC_GET_ARG4(*call)) << 32);
+
+	async_transaction_t *trans = async_transaction_create(callid);
+	if (trans == NULL) {
+		async_answer_0(callid, ENOMEM);
+		return;
+	}
+
+	size_t size = 0;
+	if (data_buffer_len > 0) {
+		const int rc = async_data_write_accept(&trans->buffer, false,
+		    1, data_buffer_len, 0, &size);
+
+		if (rc != EOK) {
+			async_answer_0(callid, rc);
+			async_transaction_destroy(trans);
+			return;
+		}
+	}
+
+	const int rc = usb_iface->write(
+	    fun, ep, setup, trans->buffer, size, callback_out, trans);
+
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		async_transaction_destroy(trans);
+	}
+}
 /**
  * @}
Index: uspace/lib/drv/include/usb_iface.h
===================================================================
--- uspace/lib/drv/include/usb_iface.h	(revision 1298a8fa81d80adef31cde419d130f1eac1b6422)
+++ uspace/lib/drv/include/usb_iface.h	(revision 64e1fb2eca59f3163d32012107ab8b46a0fe2428)
@@ -66,4 +66,12 @@
     usb_direction_t, size_t, unsigned);
 int usb_unregister_endpoint(async_exch_t *, usb_endpoint_t, usb_direction_t);
+int usb_read(async_exch_t *, usb_endpoint_t, uint64_t, void *, size_t, size_t *);
+int usb_write(async_exch_t *, usb_endpoint_t, uint64_t, const void *, size_t);
+
+/** Callback for outgoing transfer. */
+typedef void (*usbhc_iface_transfer_out_callback_t)(int, void *);
+
+/** Callback for incoming transfer. */
+typedef void (*usbhc_iface_transfer_in_callback_t)(int, size_t, void *);
 
 /** USB device communication interface. */
@@ -83,4 +91,8 @@
 	int (*unregister_endpoint)(ddf_fun_t *, usb_endpoint_t,
 	    usb_direction_t);
+	int (*read)(ddf_fun_t *, usb_endpoint_t, uint64_t, uint8_t *, size_t,
+	    usbhc_iface_transfer_in_callback_t, void *);
+	int (*write)(ddf_fun_t *, usb_endpoint_t, uint64_t, const uint8_t *,
+	    size_t, usbhc_iface_transfer_out_callback_t, void *);
 } usb_iface_t;
 
