Index: uspace/lib/usb/src/hcdhubd.c
===================================================================
--- uspace/lib/usb/src/hcdhubd.c	(revision 4b4c797d23deaa3f0f365f40c3d0d3960c0218c7)
+++ uspace/lib/usb/src/hcdhubd.c	(revision 4b4c797d23deaa3f0f365f40c3d0d3960c0218c7)
@@ -0,0 +1,349 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libusb usb
+ * @{
+ */
+/** @file
+ * @brief HC driver and hub driver (implementation).
+ */
+#include <usb/hcdhubd.h>
+#include <usb_iface.h>
+#include <driver.h>
+#include <bool.h>
+#include <errno.h>
+
+/** List of handled host controllers. */
+static LIST_INITIALIZE(hc_list);
+
+/** Our HC driver. */
+static usb_hc_driver_t *hc_driver = NULL;
+
+static usb_iface_t usb_interface = {
+	.interrupt_out = NULL,
+	.interrupt_in = NULL
+};
+
+static device_ops_t usb_device_ops = {
+	.interfaces[USB_DEV_IFACE] = &usb_interface
+};
+
+/** Callback when new device is detected and must be handled by this driver.
+ *
+ * @param dev New device.
+ * @return Error code.
+ */
+static int add_device(device_t *dev)
+{
+	/*
+	 * FIXME: use some magic to determine whether hub or another HC
+	 * was connected.
+	 */
+	bool is_hc = true;
+
+	if (is_hc) {
+		/*
+		 * We are the HC itself.
+		 */
+		usb_hc_device_t *hc_dev = malloc(sizeof(usb_hc_device_t));
+		list_initialize(&hc_dev->link);
+		hc_dev->transfer_ops = NULL;
+
+		hc_dev->generic = dev;
+		dev->ops = &usb_device_ops;
+		hc_dev->generic->driver_data = hc_dev;
+
+		int rc = hc_driver->add_hc(hc_dev);
+		if (rc != EOK) {
+			free(hc_dev);
+			return rc;
+		}
+
+		/*
+		 * FIXME: The following line causes devman to hang.
+		 * Will investigate later why.
+		 */
+		// add_device_to_class(dev, "usbhc");
+
+		list_append(&hc_dev->link, &hc_list);
+
+		return EOK;
+	} else {
+		/*
+		 * We are some (probably deeply nested) hub.
+		 * Thus, assign our own operations and explore already
+		 * connected devices.
+		 */
+		return ENOTSUP;
+	}
+}
+
+/** Check changes on all known hubs.
+ */
+static void check_hub_changes(void)
+{
+	/*
+	 * Iterate through all HCs.
+	 */
+	link_t *link_hc;
+	for (link_hc = hc_list.next;
+	    link_hc != &hc_list;
+	    link_hc = link_hc->next) {
+		usb_hc_device_t *hc = list_get_instance(link_hc,
+		    usb_hc_device_t, link);
+		/*
+		 * Iterate through all their hubs.
+		 */
+		link_t *link_hub;
+		for (link_hub = hc->hubs.next;
+		    link_hub != &hc->hubs;
+		    link_hub = link_hub->next) {
+			usb_hcd_hub_info_t *hub = list_get_instance(link_hub,
+			    usb_hcd_hub_info_t, link);
+
+			/*
+			 * Check status change pipe of this hub.
+			 */
+			usb_target_t target = {
+				.address = hub->device->address,
+				.endpoint = 1
+			};
+
+			// FIXME: count properly
+			size_t byte_length = (hub->port_count / 8) + 1;
+
+			void *change_bitmap = malloc(byte_length);
+			size_t actual_size;
+			usb_handle_t handle;
+
+			/*
+			 * Send the request.
+			 * FIXME: check returned value for possible errors
+			 */
+			usb_hc_async_interrupt_in(hc, target,
+			    change_bitmap, byte_length, &actual_size,
+			    &handle);
+
+			usb_hc_async_wait_for(handle);
+
+			/*
+			 * TODO: handle the changes.
+			 */
+		}
+	}
+}
+
+/** Operations for combined HC and HUB driver. */
+static driver_ops_t hc_driver_generic_ops = {
+	.add_device = add_device
+};
+
+/** Combined HC and HUB driver. */
+static driver_t hc_driver_generic = {
+	.driver_ops = &hc_driver_generic_ops
+};
+
+/** Main USB host controller driver routine.
+ *
+ * @see driver_main
+ *
+ * @param hc Host controller driver.
+ * @return Error code.
+ */
+int usb_hcd_main(usb_hc_driver_t *hc)
+{
+	hc_driver = hc;
+	hc_driver_generic.name = hc->name;
+
+	/*
+	 * Launch here fibril that will periodically check all
+	 * attached hubs for status change.
+	 * WARN: This call will effectively do nothing.
+	 */
+	check_hub_changes();
+
+	/*
+	 * Run the device driver framework.
+	 */
+	return driver_main(&hc_driver_generic);
+}
+
+/** Add a root hub for given host controller.
+ * This function shall be called only once for each host controller driven
+ * by this driver.
+ * It takes care of creating child device - hub - that will be driven by
+ * this task.
+ *
+ * @param dev Host controller device.
+ * @return Error code.
+ */
+int usb_hcd_add_root_hub(usb_hc_device_t *dev)
+{
+	int rc;
+
+	/*
+	 * For testing/debugging purposes only.
+	 * Try to send some data to default USB address.
+	 */
+	usb_target_t target = {0, 0};
+	usb_handle_t handle = 0;
+	char *data = (char *) "Hello, World!";
+
+
+	(void)usb_hc_async_interrupt_out(dev, target, data, str_length(data), &handle);
+	(void)usb_hc_async_wait_for(handle);
+
+	/*
+	 * Announce presence of child device.
+	 */
+	device_t *hub = NULL;
+	match_id_t *match_id = NULL;
+
+	hub = create_device();
+	if (hub == NULL) {
+		rc = ENOMEM;
+		goto failure;
+	}
+	hub->name = "usbhub";
+
+	match_id = create_match_id();
+	if (match_id == NULL) {
+		rc = ENOMEM;
+		goto failure;
+	}
+
+	char *id;
+	rc = asprintf(&id, "usb&hc=%s&hub", dev->generic->name);
+	if (rc <= 0) {
+		rc = ENOMEM;
+		goto failure;
+	}
+
+	match_id->id = id;
+	match_id->score = 30;
+
+	add_match_id(&hub->match_ids, match_id);
+
+	rc = child_device_register(hub, dev->generic);
+	if (rc != EOK) {
+		goto failure;
+	}
+
+	printf("%s: registered root hub\n", dev->generic->name);
+	return EOK;
+
+failure:
+	if (hub != NULL) {
+		hub->name = NULL;
+		delete_device(hub);
+	}
+	delete_match_id(match_id);
+
+	return rc;
+}
+
+/** Issue interrupt OUT transfer to HC driven by current task.
+ *
+ * @param hc Host controller to handle the transfer.
+ * @param target Target device address.
+ * @param buffer Data buffer.
+ * @param size Buffer size.
+ * @param handle Transfer handle.
+ * @return Error code.
+ */
+int usb_hc_async_interrupt_out(usb_hc_device_t *hc, usb_target_t target,
+    void *buffer, size_t size,
+    usb_handle_t *handle)
+{
+	if ((hc->transfer_ops == NULL)
+	    || (hc->transfer_ops->transfer_out == NULL)) {
+		return ENOTSUP;
+	}
+
+	/*
+	 * For debugging purposes only.
+	 * We need to find appropriate device in list of managed device
+	 * and pass it to the transfer callback function.
+	 */
+	usb_hcd_attached_device_info_t dev = {
+		.address = target.address,
+		.endpoint_count = 0,
+		.endpoints = NULL,
+	};
+	usb_hc_endpoint_info_t endpoint = {
+		.endpoint = target.endpoint,
+		.transfer_type = USB_TRANSFER_INTERRUPT,
+		.direction = USB_DIRECTION_OUT,
+		.data_toggle = 0
+	};
+
+	hc->transfer_ops->transfer_out(hc, &dev, &endpoint, buffer, size, NULL, NULL);
+
+	*handle = NULL;
+
+	return EOK;
+}
+
+
+/** Issue interrupt IN transfer to HC driven by current task.
+ *
+ * @warning The @p buffer and @p actual_size parameters shall not be
+ * touched until this transfer is waited for by usb_hc_async_wait_for().
+ *
+ * @param hc Host controller to handle the transfer.
+ * @param target Target device address.
+ * @param buffer Data buffer.
+ * @param size Buffer size.
+ * @param actual_size Size of actually transferred data.
+ * @param handle Transfer handle.
+ * @return Error code.
+ */
+int usb_hc_async_interrupt_in(usb_hc_device_t *hc, usb_target_t target,
+    void *buffer, size_t size, size_t *actual_size,
+    usb_handle_t *handle)
+{
+	/*
+	 * TODO: verify that given endpoint is of interrupt type and
+	 * call hc->transfer_ops->transfer_in()
+	 */
+	return ENOTSUP;
+}
+
+/** Wait for transfer to complete.
+ *
+ * @param handle Transfer handle.
+ * @return Error code.
+ */
+int usb_hc_async_wait_for(usb_handle_t handle)
+{
+	return ENOTSUP;
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/usb.c
===================================================================
--- uspace/lib/usb/src/usb.c	(revision 4b4c797d23deaa3f0f365f40c3d0d3960c0218c7)
+++ uspace/lib/usb/src/usb.c	(revision 4b4c797d23deaa3f0f365f40c3d0d3960c0218c7)
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libusb usb
+ * @{
+ */
+/** @file
+ * @brief Base USB types.
+ */
+#include <usb/usb.h>
+#include <errno.h>
+
+
+/** String representation for USB transfer type. */
+const char * usb_str_transfer_type(usb_transfer_type_t t)
+{
+	switch (t) {
+		case USB_TRANSFER_ISOCHRONOUS:
+			return "isochronous";
+		case USB_TRANSFER_INTERRUPT:
+			return "interrupt";
+		case USB_TRANSFER_CONTROL:
+			return "control";
+		case USB_TRANSFER_BULK:
+			return "bulk";
+		default:
+			return "unknown";
+	}
+}
+
+/** String representation of USB transaction outcome. */
+const char * usb_str_transaction_outcome(usb_transaction_outcome_t o)
+{
+	switch (o) {
+		case USB_OUTCOME_OK:
+			return "ok";
+		case USB_OUTCOME_CRCERROR:
+			return "CRC error";
+		case USB_OUTCOME_BABBLE:
+			return "babble";
+		default:
+			return "unknown";
+	}
+}
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/usbdrv.c
===================================================================
--- uspace/lib/usb/src/usbdrv.c	(revision 4b4c797d23deaa3f0f365f40c3d0d3960c0218c7)
+++ uspace/lib/usb/src/usbdrv.c	(revision 4b4c797d23deaa3f0f365f40c3d0d3960c0218c7)
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libusb usb
+ * @{
+ */
+/** @file
+ * @brief USB driver (implementation).
+ */
+#include <usb/usbdrv.h>
+#include <usb_iface.h>
+#include <errno.h>
+
+/** Information about pending transaction on HC. */
+typedef struct {
+	/** Phone to host controller driver. */
+	int phone;
+	/** Data buffer. */
+	void *buffer;
+	/** Buffer size. */
+	size_t size;
+	/** Storage for actual number of bytes transferred. */
+	size_t *size_transferred;
+	/** Initial call replay data. */
+	ipc_call_t reply;
+	/** Initial call identifier. */
+	aid_t request;
+} transfer_info_t;
+
+/** Connect to host controller the device is physically attached to.
+ *
+ * @param handle Device handle.
+ * @param flags Connection flags (blocking connection).
+ * @return Phone to corresponding HC or error code.
+ */
+int usb_drv_hc_connect(device_t *dev, unsigned int flags)
+{
+	/*
+	 * Call parent hub to obtain device handle of respective HC.
+	 */
+	return ENOTSUP;
+}
+
+/** Tell USB address assigned to given device.
+ *
+ * @param phone Phone to my HC.
+ * @param dev Device in question.
+ * @return USB address or error code.
+ */
+usb_address_t usb_drv_get_my_address(int phone, device_t *dev)
+{
+	return ENOTSUP;
+}
+
+/** Send data to HCD.
+ *
+ * @param phone Phone to HC.
+ * @param method Method used for calling.
+ * @param target Targeted device.
+ * @param buffer Data buffer (NULL to skip data transfer phase).
+ * @param size Buffer size (must be zero when @p buffer is NULL).
+ * @param handle Storage for transaction handle (cannot be NULL).
+ * @return Error status.
+ * @retval EINVAL Invalid parameter.
+ * @retval ENOMEM Not enough memory to complete the operation.
+ */
+static int async_send_buffer(int phone, int method,
+    usb_target_t target,
+    void *buffer, size_t size,
+    usb_handle_t *handle)
+{
+	if (phone < 0) {
+		return EINVAL;
+	}
+
+	if ((buffer == NULL) && (size > 0)) {
+		return EINVAL;
+	}
+
+	if (handle == NULL) {
+		return EINVAL;
+	}
+
+	transfer_info_t *transfer
+	    = (transfer_info_t *) malloc(sizeof(transfer_info_t));
+	if (transfer == NULL) {
+		return ENOMEM;
+	}
+
+	transfer->size_transferred = NULL;
+	transfer->buffer = NULL;
+	transfer->size = 0;
+	transfer->phone = phone;
+
+	int rc;
+
+	transfer->request = async_send_4(phone,
+	    DEV_IFACE_ID(USB_DEV_IFACE),
+	    method,
+	    target.address, target.endpoint,
+	    size,
+	    &transfer->reply);
+
+	if (size > 0) {
+		rc = async_data_write_start(phone, buffer, size);
+		if (rc != EOK) {
+			async_wait_for(transfer->request, NULL);
+			return rc;
+		}
+	}
+
+	*handle = (usb_handle_t) transfer;
+
+	return EOK;
+}
+
+/** Prepare data retrieval.
+ *
+ * @param phone Opened phone to HCD.
+ * @param method Method used for calling.
+ * @param target Targeted device.
+ * @param buffer Buffer where to store retrieved data
+ * 	(NULL to skip data transfer phase).
+ * @param size Buffer size (must be zero when @p buffer is NULL).
+ * @param actual_size Storage where actual number of bytes transferred will
+ * 	be stored.
+ * @param handle Storage for transaction handle (cannot be NULL).
+ * @return Error status.
+ * @retval EINVAL Invalid parameter.
+ * @retval ENOMEM Not enough memory to complete the operation.
+ */
+static int async_recv_buffer(int phone, int method,
+    usb_target_t target,
+    void *buffer, size_t size, size_t *actual_size,
+    usb_handle_t *handle)
+{
+	if (phone < 0) {
+		return EINVAL;
+	}
+
+	if ((buffer == NULL) && (size > 0)) {
+		return EINVAL;
+	}
+
+	if (handle == NULL) {
+		return EINVAL;
+	}
+
+	transfer_info_t *transfer
+	    = (transfer_info_t *) malloc(sizeof(transfer_info_t));
+	if (transfer == NULL) {
+		return ENOMEM;
+	}
+
+	transfer->size_transferred = actual_size;
+	transfer->buffer = buffer;
+	transfer->size = size;
+	transfer->phone = phone;
+
+	transfer->request = async_send_4(phone,
+	    DEV_IFACE_ID(USB_DEV_IFACE),
+	    method,
+	    target.address, target.endpoint,
+	    size,
+	    &transfer->reply);
+
+	*handle = (usb_handle_t) transfer;
+
+	return EOK;
+}
+
+/** Read buffer from HCD.
+ *
+ * @param phone Opened phone to HCD.
+ * @param hash Buffer hash (obtained after completing IN transaction).
+ * @param buffer Buffer where to store data data.
+ * @param size Buffer size.
+ * @param actual_size Storage where actual number of bytes transferred will
+ * 	be stored.
+ * @return Error status.
+ */
+static int read_buffer_in(int phone, ipcarg_t hash,
+    void *buffer, size_t size, size_t *actual_size)
+{
+	ipc_call_t answer_data;
+	ipcarg_t answer_rc;
+	aid_t req;
+	int rc;
+
+	req = async_send_2(phone,
+	    DEV_IFACE_ID(USB_DEV_IFACE),
+	    IPC_M_USB_GET_BUFFER,
+	    hash,
+	    &answer_data);
+
+	rc = async_data_read_start(phone, buffer, size);
+	if (rc != EOK) {
+		async_wait_for(req, NULL);
+		return EINVAL;
+	}
+
+	async_wait_for(req, &answer_rc);
+	rc = (int)answer_rc;
+
+	if (rc != EOK) {
+		return rc;
+	}
+
+	*actual_size = IPC_GET_ARG1(answer_data);
+
+	return EOK;
+}
+
+/** Blocks caller until given USB transaction is finished.
+ * After the transaction is finished, the user can access all output data
+ * given to initial call function.
+ *
+ * @param handle Transaction handle.
+ * @return Error status.
+ * @retval EOK No error.
+ * @retval EBADMEM Invalid handle.
+ * @retval ENOENT Data buffer associated with transaction does not exist.
+ */
+int usb_drv_async_wait_for(usb_handle_t handle)
+{
+	if (handle == 0) {
+		return EBADMEM;
+	}
+
+	int rc = EOK;
+
+	transfer_info_t *transfer = (transfer_info_t *) handle;
+
+	ipcarg_t answer_rc;
+	async_wait_for(transfer->request, &answer_rc);
+
+	if (answer_rc != EOK) {
+		rc = (int) answer_rc;
+		goto leave;
+	}
+
+	/*
+	 * If the buffer is not NULL, we must accept some data.
+	 */
+	if ((transfer->buffer != NULL) && (transfer->size > 0)) {
+		/*
+		 * The buffer hash identifies the data on the server
+		 * side.
+		 * We will use it when actually reading-in the data.
+		 */
+		ipcarg_t buffer_hash = IPC_GET_ARG1(transfer->reply);
+		if (buffer_hash == 0) {
+			rc = ENOENT;
+			goto leave;
+		}
+
+		size_t actual_size;
+		rc = read_buffer_in(transfer->phone, buffer_hash,
+		    transfer->buffer, transfer->size, &actual_size);
+
+		if (rc != EOK) {
+			goto leave;
+		}
+
+		if (transfer->size_transferred) {
+			*(transfer->size_transferred) = actual_size;
+		}
+	}
+
+leave:
+	free(transfer);
+
+	return rc;
+}
+
+/** Send interrupt data to device. */
+int usb_drv_async_interrupt_out(int phone, usb_target_t target,
+    void *buffer, size_t size,
+    usb_handle_t *handle)
+{
+	return async_send_buffer(phone,
+	    IPC_M_USB_INTERRUPT_OUT,
+	    target,
+	    buffer, size,
+	    handle);
+}
+
+/** Request interrupt data from device. */
+int usb_drv_async_interrupt_in(int phone, usb_target_t target,
+    void *buffer, size_t size, size_t *actual_size,
+    usb_handle_t *handle)
+{
+	return async_recv_buffer(phone,
+	    IPC_M_USB_INTERRUPT_IN,
+	    target,
+	    buffer, size, actual_size,
+	    handle);
+}
+
+/**
+ * @}
+ */
