Index: uspace/drv/bus/usb/xhci/bus.c
===================================================================
--- uspace/drv/bus/usb/xhci/bus.c	(revision 20eaa82bcd1e1ed452c2148cd68afde550e29457)
+++ uspace/drv/bus/usb/xhci/bus.c	(revision 2770b669432a0a3478940311f193e80df63b07b8)
@@ -79,5 +79,5 @@
 
 	/* Assign an address to the device */
-	if ((err = xhci_rh_address_device(&hc->rh, dev))) {
+	if ((err = xhci_rh_address_device(&hc->rh, dev, bus))) {
 		usb_log_error("Failed to setup address of the new device: %s", str_error(err));
 		return err;
Index: uspace/drv/bus/usb/xhci/endpoint.h
===================================================================
--- uspace/drv/bus/usb/xhci/endpoint.h	(revision 20eaa82bcd1e1ed452c2148cd68afde550e29457)
+++ uspace/drv/bus/usb/xhci/endpoint.h	(revision 2770b669432a0a3478940311f193e80df63b07b8)
@@ -66,13 +66,22 @@
 	endpoint_t base;	/**< Inheritance. Keep this first. */
 
+	/** Parent device. */
 	xhci_device_t *device;
 } xhci_endpoint_t;
 
 typedef struct xhci_device {
+	/** Unique USB address assigned to the device. */
 	usb_address_t address;
 
+	/** Slot ID assigned to the device by xHC. */
 	uint32_t slot_id;
 
+	/** Associated device in libusbhost. */
+	device_t *device;
+
+	/** All endpoints of the device. Inactive ones are NULL */
 	xhci_endpoint_t *endpoints[XHCI_DEVICE_MAX_ENDPOINTS];
+
+	/** Number of non-NULL endpoints. Reference count of sorts. */
 	uint8_t active_endpoint_count;
 } xhci_device_t;
Index: uspace/drv/bus/usb/xhci/hc.c
===================================================================
--- uspace/drv/bus/usb/xhci/hc.c	(revision 20eaa82bcd1e1ed452c2148cd68afde550e29457)
+++ uspace/drv/bus/usb/xhci/hc.c	(revision 2770b669432a0a3478940311f193e80df63b07b8)
@@ -213,6 +213,9 @@
 		goto err_scratch;
 
+	if ((err = xhci_init_transfers(hc)))
+		goto err_cmd;
+
 	if ((err = xhci_rh_init(&hc->rh, hc)))
-		goto err_cmd;
+		goto err_transfers;
 
 	if ((err = xhci_bus_init(&hc->bus)))
@@ -224,4 +227,6 @@
 err_rh:
 	xhci_rh_fini(&hc->rh);
+err_transfers:
+	xhci_fini_transfers(hc);
 err_cmd:
 	xhci_fini_commands(hc);
@@ -472,10 +477,12 @@
 	case USB_TRANSFER_ISOCHRONOUS:
 		/* TODO: Implement me. */
-		break;
+		usb_log_error("Isochronous transfers are not yet implemented!");
+		return ENOTSUP;
 	case USB_TRANSFER_BULK:
 		return xhci_schedule_bulk_transfer(hc, batch);
 	case USB_TRANSFER_INTERRUPT:
 		/* TODO: Implement me. */
-		break;
+		usb_log_error("Interrupt transfers are not yet implemented!");
+		return ENOTSUP;
 	}
 
@@ -617,4 +624,5 @@
 	xhci_event_ring_fini(&hc->event_ring);
 	hc_dcbaa_fini(hc);
+	xhci_fini_transfers(hc);
 	xhci_fini_commands(hc);
 	xhci_rh_fini(&hc->rh);
Index: uspace/drv/bus/usb/xhci/rh.c
===================================================================
--- uspace/drv/bus/usb/xhci/rh.c	(revision 20eaa82bcd1e1ed452c2148cd68afde550e29457)
+++ uspace/drv/bus/usb/xhci/rh.c	(revision 2770b669432a0a3478940311f193e80df63b07b8)
@@ -36,8 +36,10 @@
 #include <errno.h>
 #include <str_error.h>
+#include <usb/request.h>
 #include <usb/debug.h>
 #include <usb/host/utils/malloc32.h>
 #include <usb/host/bus.h>
 #include <usb/host/ddf_helpers.h>
+#include <usb/host/hcd.h>
 
 #include "debug.h"
@@ -74,5 +76,5 @@
 // TODO: This currently assumes the device is attached to rh directly.
 //       Also, we should consider moving a lot of functionailty to xhci bus
-int xhci_rh_address_device(xhci_rh_t *rh, device_t *dev)
+int xhci_rh_address_device(xhci_rh_t *rh, device_t *dev, xhci_bus_t *bus)
 {
 	int err;
@@ -160,10 +162,29 @@
 	usb_log_debug2("Obtained USB address: %d.\n", dev->address);
 
-	// TODO: Ask libusbhost to create a control endpoint for EP0.
-
-	// TODO: Save all data structures in the corresponding xhci_device_t.
-
-	return EOK;
-
+	// Ask libusbhost to create a control endpoint for EP0.
+	bus_t *bus_base = &bus->base;
+	usb_target_t ep0_target = { .address = dev->address, .endpoint = 0 };
+	usb_direction_t ep0_direction = USB_DIRECTION_BOTH;
+
+	// TODO: Should this call be unified with other calls to `bus_add_ep()`?
+	err = bus_add_ep(bus_base, dev, ep0_target.endpoint, ep0_direction,
+	    USB_TRANSFER_CONTROL, CTRL_PIPE_MIN_PACKET_SIZE, CTRL_PIPE_MIN_PACKET_SIZE, 1);
+
+	if (err != EOK)
+		goto err_add_ep;
+
+	// Save all data structures in the corresponding xhci_device_t.
+	endpoint_t *ep0_base = bus_find_endpoint(bus_base, ep0_target, ep0_direction);
+	xhci_endpoint_t *ep0 = xhci_endpoint_get(ep0_base);
+	xhci_device_t *xhci_dev = ep0->device;
+
+	xhci_dev->device = dev;
+	xhci_dev->slot_id = slot_id;
+
+	// TODO: Save anything else?
+
+	return EOK;
+
+err_add_ep:
 err_dctx:
 	if (dctx) {
Index: uspace/drv/bus/usb/xhci/rh.h
===================================================================
--- uspace/drv/bus/usb/xhci/rh.h	(revision 20eaa82bcd1e1ed452c2148cd68afde550e29457)
+++ uspace/drv/bus/usb/xhci/rh.h	(revision 2770b669432a0a3478940311f193e80df63b07b8)
@@ -54,4 +54,5 @@
 
 typedef struct hcd_roothub hcd_roothub_t;
+typedef struct xhci_bus xhci_bus_t;
 
 /* XHCI root hub instance */
@@ -84,5 +85,5 @@
 void xhci_rh_handle_port_change(xhci_rh_t *);
 
-int xhci_rh_address_device(xhci_rh_t *rh, device_t *dev);
+int xhci_rh_address_device(xhci_rh_t *rh, device_t *dev, xhci_bus_t *bus);
 
 #endif
Index: uspace/drv/bus/usb/xhci/transfers.c
===================================================================
--- uspace/drv/bus/usb/xhci/transfers.c	(revision 20eaa82bcd1e1ed452c2148cd68afde550e29457)
+++ uspace/drv/bus/usb/xhci/transfers.c	(revision 2770b669432a0a3478940311f193e80df63b07b8)
@@ -145,5 +145,5 @@
 	transfer->batch = batch;
 	link_initialize(&transfer->link);
-	transfer->hc_buffer = malloc32(batch->buffer_size);
+	transfer->hc_buffer = batch->buffer_size > 0 ? malloc32(batch->buffer_size) : NULL;
 
 	return transfer;
@@ -152,5 +152,9 @@
 void xhci_transfer_fini(xhci_transfer_t* transfer) {
 	if (transfer) {
-		free32(transfer->hc_buffer);
+		if (transfer->batch->buffer_size > 0)
+			free32(transfer->hc_buffer);
+
+		usb_transfer_batch_destroy(transfer->batch);
+
 		free(transfer);
 	}
@@ -179,5 +183,9 @@
 	/* For the TRB formats, see xHCI specification 6.4.1.2 */
 	xhci_transfer_t *transfer = xhci_transfer_alloc(batch);
-	memcpy(transfer->hc_buffer, batch->buffer, batch->buffer_size);
+
+	if (!transfer->direction) {
+		// Sending stuff from host to device, we need to copy the actual data.
+		memcpy(transfer->hc_buffer, batch->buffer, batch->buffer_size);
+	}
 
 	xhci_trb_t trb_setup;
@@ -318,4 +326,6 @@
 	batch->transfered_size = batch->buffer_size - TRB_TRANSFER_LENGTH(*trb);
 	if (transfer->direction) {
+		memcpy(batch->buffer, transfer->hc_buffer, batch->buffer_size);
+
 		/* Device-to-host, IN */
 		if (batch->callback_in)
