Index: uspace/drv/bus/usb/ehci/ehci_batch.c
===================================================================
--- uspace/drv/bus/usb/ehci/ehci_batch.c	(revision b60944bca829148fb902a29e4e88cbbecd57922f)
+++ uspace/drv/bus/usb/ehci/ehci_batch.c	(revision 35c37fc2ef57407c4bf38bf0ac3d777777e3ccd1)
@@ -42,5 +42,4 @@
 #include <usb/usb.h>
 #include <usb/debug.h>
-#include <usb/host/utils/malloc32.h>
 
 #include "ehci_batch.h"
@@ -62,11 +61,5 @@
 {
 	assert(ehci_batch);
-	if (ehci_batch->tds) {
-		for (size_t i = 0; i < ehci_batch->td_count; ++i) {
-			free32(ehci_batch->tds[i]);
-		}
-		free(ehci_batch->tds);
-	}
-	free32(ehci_batch->device_buffer);
+	dma_buffer_free(&ehci_batch->dma_buffer);
 	free(ehci_batch);
 	usb_log_debug2("Batch(%p): disposed", ehci_batch);
@@ -112,49 +105,37 @@
 	const size_t size = ehci_batch->base.buffer_size;
 
-	/* Mix setup stage and data together, we have enough space */
-        if (size + setup_size > 0) {
-		/* Use one buffer for setup and data stage */
-		ehci_batch->device_buffer = malloc32(size + setup_size);
-		if (!ehci_batch->device_buffer) {
+	/* Add TD left over by the previous transfer */
+	ehci_batch->qh = ehci_endpoint_get(ehci_batch->base.ep)->qh;
+
+	/* Determine number of TDs needed */
+	ehci_batch->td_count = (size + EHCI_TD_MAX_TRANSFER - 1)
+		/ EHCI_TD_MAX_TRANSFER;
+
+	/* Control transfer need Setup and Status stage */
+	if (ehci_batch->base.ep->transfer_type == USB_TRANSFER_CONTROL) {
+		ehci_batch->td_count += 2;
+	}
+
+	const size_t tds_size = ehci_batch->td_count * sizeof(td_t);
+
+	/* Mix setup stage, data and TDs together, we have enough space */
+	if (size + setup_size + tds_size > 0) {
+		if (dma_buffer_alloc(&ehci_batch->dma_buffer, tds_size + setup_size + size)) {
 			usb_log_error("Batch %p: Failed to allocate device "
 			    "buffer", ehci_batch);
 			return ENOMEM;
 		}
+		/* Clean TDs */
+		ehci_batch->tds = ehci_batch->dma_buffer.virt;
+		memset(ehci_batch->tds, 0, tds_size);
 		/* Copy setup data */
-                memcpy(ehci_batch->device_buffer, ehci_batch->base.setup.buffer,
-		    setup_size);
+		ehci_batch->setup_buffer = ehci_batch->dma_buffer.virt + tds_size;
+                memcpy(ehci_batch->setup_buffer, ehci_batch->base.setup.buffer, setup_size);
 		/* Copy generic data */
+		ehci_batch->data_buffer = ehci_batch->setup_buffer + setup_size;
 		if (ehci_batch->base.dir != USB_DIRECTION_IN)
-			memcpy(ehci_batch->device_buffer + setup_size,
-			    ehci_batch->base.buffer, ehci_batch->base.buffer_size);
-        }
-
-	/* Add TD left over by the previous transfer */
-	ehci_batch->qh = ehci_endpoint_get(ehci_batch->base.ep)->qh;
-
-	/* Determine number of TDs needed */
-	ehci_batch->td_count = (size + EHCI_TD_MAX_TRANSFER - 1)
-		/ EHCI_TD_MAX_TRANSFER;
-
-	/* Control transfer need Setup and Status stage */
-	if (ehci_batch->base.ep->transfer_type == USB_TRANSFER_CONTROL) {
-		ehci_batch->td_count += 2;
-	}
-
-	ehci_batch->tds = calloc(ehci_batch->td_count, sizeof(td_t*));
-	if (!ehci_batch->tds) {
-		usb_log_error("Batch %p: Failed to allocate EHCI transfer "
-		    "descriptors.", ehci_batch);
-		return ENOMEM;
-	}
-
-	for (unsigned i = 0; i < ehci_batch->td_count; ++i) {
-		ehci_batch->tds[i] = malloc32(sizeof(td_t));
-		if (!ehci_batch->tds[i]) {
-			usb_log_error("Batch %p: Failed to allocate TD %d.",
-			    ehci_batch, i);
-			return ENOMEM;
-		}
-		memset(ehci_batch->tds[i], 0, sizeof(td_t));
+			memcpy(ehci_batch->data_buffer,
+			    ehci_batch->base.buffer,
+			    ehci_batch->base.buffer_size);
 	}
 
@@ -203,11 +184,10 @@
 	/* Check all TDs */
 	for (size_t i = 0; i < ehci_batch->td_count; ++i) {
-		assert(ehci_batch->tds[i] != NULL);
 		usb_log_debug("Batch %p: TD %zu: %08x:%08x:%08x.",
 		    ehci_batch, i,
-		    ehci_batch->tds[i]->status, ehci_batch->tds[i]->next,
-		    ehci_batch->tds[i]->alternate);
-
-		ehci_batch->base.error = td_error(ehci_batch->tds[i]);
+		    ehci_batch->tds[i].status, ehci_batch->tds[i].next,
+		    ehci_batch->tds[i].alternate);
+
+		ehci_batch->base.error = td_error(&ehci_batch->tds[i]);
 		if (ehci_batch->base.error == EOK) {
 			/* If the TD got all its data through, it will report
@@ -224,9 +204,9 @@
 			 */
 			ehci_batch->base.transfered_size
-			    -= td_remain_size(ehci_batch->tds[i]);
+			    -= td_remain_size(&ehci_batch->tds[i]);
 		} else {
 			usb_log_debug("Batch %p found error TD(%zu):%08x (%d).",
 			    ehci_batch, i,
-			    ehci_batch->tds[i]->status,
+			    ehci_batch->tds[i].status,
 			    ehci_batch->base.error);
 			/* Clear possible ED HALT */
@@ -238,11 +218,7 @@
 	assert(ehci_batch->base.transfered_size <= ehci_batch->base.buffer_size);
 
-	const size_t setup_size = (ehci_batch->base.ep->transfer_type == USB_TRANSFER_CONTROL)
-		? USB_SETUP_PACKET_SIZE
-		: 0;
-
 	if (ehci_batch->base.dir == USB_DIRECTION_IN)
 		memcpy(ehci_batch->base.buffer,
-		    ehci_batch->device_buffer + setup_size,
+		    ehci_batch->data_buffer,
 		    ehci_batch->base.transfered_size);
 
@@ -263,5 +239,5 @@
 {
 	assert(ehci_batch);
-	qh_set_next_td(ehci_batch->qh, ehci_batch->tds[0]);
+	qh_set_next_td(ehci_batch->qh, dma_buffer_phys(&ehci_batch->dma_buffer, &ehci_batch->tds[0]));
 }
 
@@ -281,7 +257,7 @@
 	assert(dir == USB_DIRECTION_IN || dir == USB_DIRECTION_OUT);
 
-	usb_log_debug2("Batch %p: Control QH(%"PRIxn"): "
+	usb_log_debug2("Batch %p: Control QH(%p): "
 	    "%08x:%08x:%08x:%08x:%08x:%08x", ehci_batch,
-	    addr_to_phys(ehci_batch->qh),
+	    ehci_batch->qh,
 	    ehci_batch->qh->ep_char, ehci_batch->qh->ep_cap,
 	    ehci_batch->qh->status, ehci_batch->qh->current,
@@ -293,35 +269,35 @@
 
 	int toggle = 0;
-	const char* buffer = ehci_batch->device_buffer;
 	const usb_direction_t data_dir = dir;
 	const usb_direction_t status_dir = reverse_dir[dir];
 
 	/* Setup stage */
-	td_init(ehci_batch->tds[0], ehci_batch->tds[1], USB_DIRECTION_BOTH,
-	    buffer, USB_SETUP_PACKET_SIZE, toggle, false);
+	td_init(&ehci_batch->tds[0],
+	    dma_buffer_phys(&ehci_batch->dma_buffer, &ehci_batch->tds[1]),
+	    dma_buffer_phys(&ehci_batch->dma_buffer, ehci_batch->setup_buffer),
+	    USB_DIRECTION_BOTH, USB_SETUP_PACKET_SIZE, toggle, false);
 	usb_log_debug2("Batch %p: Created CONTROL SETUP TD(%"PRIxn"): "
 	    "%08x:%08x:%08x", ehci_batch,
-	    addr_to_phys(ehci_batch->tds[0]),
-	    ehci_batch->tds[0]->status, ehci_batch->tds[0]->next,
-	    ehci_batch->tds[0]->alternate);
-	buffer += USB_SETUP_PACKET_SIZE;
+	    dma_buffer_phys(&ehci_batch->dma_buffer, &ehci_batch->tds[0]),
+	    ehci_batch->tds[0].status, ehci_batch->tds[0].next,
+	    ehci_batch->tds[0].alternate);
 
 	/* Data stage */
-	size_t td_current = 1;
+	unsigned td_current = 1;
 	size_t remain_size = ehci_batch->base.buffer_size;
+	uintptr_t buffer = dma_buffer_phys(&ehci_batch->dma_buffer, ehci_batch->data_buffer);
 	while (remain_size > 0) {
-		const size_t transfer_size =
-		    min(remain_size, EHCI_TD_MAX_TRANSFER);
+		const size_t transfer_size = min(remain_size, EHCI_TD_MAX_TRANSFER);
 		toggle = 1 - toggle;
 
-		td_init(ehci_batch->tds[td_current],
-		    ehci_batch->tds[td_current + 1], data_dir, buffer,
-		    transfer_size, toggle, false);
+		td_init(&ehci_batch->tds[td_current],
+		    dma_buffer_phys(&ehci_batch->dma_buffer, &ehci_batch->tds[td_current + 1]),
+		    buffer, data_dir, transfer_size, toggle, false);
 		usb_log_debug2("Batch %p: Created CONTROL DATA TD(%"PRIxn"): "
 		    "%08x:%08x:%08x", ehci_batch,
-		    addr_to_phys(ehci_batch->tds[td_current]),
-		    ehci_batch->tds[td_current]->status,
-		    ehci_batch->tds[td_current]->next,
-		    ehci_batch->tds[td_current]->alternate);
+		    dma_buffer_phys(&ehci_batch->dma_buffer, &ehci_batch->tds[td_current]),
+		    ehci_batch->tds[td_current].status,
+		    ehci_batch->tds[td_current].next,
+		    ehci_batch->tds[td_current].alternate);
 
 		buffer += transfer_size;
@@ -333,11 +309,11 @@
 	/* Status stage */
 	assert(td_current == ehci_batch->td_count - 1);
-	td_init(ehci_batch->tds[td_current], NULL, status_dir, NULL, 0, 1, true);
-	usb_log_debug2("Batch %p: Created CONTROL STATUS TD(%"PRIxn"): "
-	    "%08x:%08x:%08x", ehci_batch,
-	    addr_to_phys(ehci_batch->tds[td_current]),
-	    ehci_batch->tds[td_current]->status,
-	    ehci_batch->tds[td_current]->next,
-	    ehci_batch->tds[td_current]->alternate);
+	td_init(&ehci_batch->tds[td_current], 0, 0, status_dir, 0, 1, true);
+	usb_log_debug2("Batch %p: Created CONTROL STATUS TD %d(%"PRIxn"): "
+	    "%08x:%08x:%08x", ehci_batch, td_current,
+	    dma_buffer_phys(&ehci_batch->dma_buffer, &ehci_batch->tds[td_current]),
+	    ehci_batch->tds[td_current].status,
+	    ehci_batch->tds[td_current].next,
+	    ehci_batch->tds[td_current].alternate);
 }
 
@@ -354,7 +330,7 @@
 	assert(ehci_batch);
 
-	usb_log_debug2("Batch %p: Data QH(%"PRIxn"): "
+	usb_log_debug2("Batch %p: Data QH(%p): "
 	    "%08x:%08x:%08x:%08x:%08x:%08x", ehci_batch,
-	    addr_to_phys(ehci_batch->qh),
+	    ehci_batch->qh,
 	    ehci_batch->qh->ep_char, ehci_batch->qh->ep_cap,
 	    ehci_batch->qh->status, ehci_batch->qh->current,
@@ -363,5 +339,5 @@
 	size_t td_current = 0;
 	size_t remain_size = ehci_batch->base.buffer_size;
-	char *buffer = ehci_batch->device_buffer;
+	uintptr_t buffer = dma_buffer_phys(&ehci_batch->dma_buffer, ehci_batch->data_buffer);
 	while (remain_size > 0) {
 		const size_t transfer_size = remain_size > EHCI_TD_MAX_TRANSFER
@@ -369,15 +345,14 @@
 
 		const bool last = (remain_size == transfer_size);
-		td_init(
-		    ehci_batch->tds[td_current],
-		    last ? NULL : ehci_batch->tds[td_current + 1],
-		    ehci_batch->base.dir, buffer, transfer_size, -1, last);
+		td_init(&ehci_batch->tds[td_current],
+		    last ? 0 : dma_buffer_phys(&ehci_batch->dma_buffer, &ehci_batch->tds[td_current + 1]),
+		    buffer, ehci_batch->base.dir, transfer_size, -1, last);
 
 		usb_log_debug2("Batch %p: DATA TD(%"PRIxn": %08x:%08x:%08x",
 		    ehci_batch,
-		    addr_to_phys(ehci_batch->tds[td_current]),
-		    ehci_batch->tds[td_current]->status,
-		    ehci_batch->tds[td_current]->next,
-		    ehci_batch->tds[td_current]->alternate);
+		    dma_buffer_phys(&ehci_batch->dma_buffer, &ehci_batch->tds[td_current]),
+		    ehci_batch->tds[td_current].status,
+		    ehci_batch->tds[td_current].next,
+		    ehci_batch->tds[td_current].alternate);
 
 		buffer += transfer_size;
Index: uspace/drv/bus/usb/ehci/ehci_batch.h
===================================================================
--- uspace/drv/bus/usb/ehci/ehci_batch.h	(revision b60944bca829148fb902a29e4e88cbbecd57922f)
+++ uspace/drv/bus/usb/ehci/ehci_batch.h	(revision 35c37fc2ef57407c4bf38bf0ac3d777777e3ccd1)
@@ -39,4 +39,5 @@
 #include <stdbool.h>
 #include <usb/host/usb_transfer_batch.h>
+#include <usb/host/dma_buffer.h>
 
 #include "hw_struct/queue_head.h"
@@ -46,14 +47,17 @@
 typedef struct ehci_transfer_batch {
 	usb_transfer_batch_t base;
+	/** Number of TDs used by the transfer */
+	size_t td_count;
 	/** Link */
 	link_t link;
 	/** Endpoint descriptor of the target endpoint. */
 	qh_t *qh;
-	/** List of TDs needed for the transfer */
-	td_t **tds;
-	/** Number of TDs used by the transfer */
-	size_t td_count;
 	/** Data buffer, must be accessible by the EHCI hw. */
-	char *device_buffer;
+	dma_buffer_t dma_buffer;
+	/** List of TDs needed for the transfer - backed by dma_buffer */
+	td_t *tds;
+	/** Data buffers - backed by dma_buffer */
+	void *setup_buffer;
+	void *data_buffer;
 	/** Generic USB transfer structure */
 	usb_transfer_batch_t *usb_batch;
Index: uspace/drv/bus/usb/ehci/ehci_bus.c
===================================================================
--- uspace/drv/bus/usb/ehci/ehci_bus.c	(revision b60944bca829148fb902a29e4e88cbbecd57922f)
+++ uspace/drv/bus/usb/ehci/ehci_bus.c	(revision 35c37fc2ef57407c4bf38bf0ac3d777777e3ccd1)
@@ -36,5 +36,4 @@
 #include <assert.h>
 #include <stdlib.h>
-#include <usb/host/utils/malloc32.h>
 #include <usb/host/bandwidth.h>
 #include <usb/debug.h>
@@ -90,10 +89,9 @@
 
 	// TODO: extract USB2 information from desc
+	
+	if (dma_buffer_alloc(&ehci_ep->dma_buffer, sizeof(qh_t)))
+		return NULL;
 
-	ehci_ep->qh = malloc32(sizeof(qh_t));
-	if (ehci_ep->qh == NULL) {
-		free(ehci_ep);
-		return NULL;
-	}
+	ehci_ep->qh = ehci_ep->dma_buffer.virt;
 
 	link_initialize(&ehci_ep->link);
@@ -111,5 +109,5 @@
 	ehci_endpoint_t *instance = ehci_endpoint_get(ep);
 
-	free32(instance->qh);
+	dma_buffer_free(&instance->dma_buffer);
 	free(instance);
 }
Index: uspace/drv/bus/usb/ehci/ehci_bus.h
===================================================================
--- uspace/drv/bus/usb/ehci/ehci_bus.h	(revision b60944bca829148fb902a29e4e88cbbecd57922f)
+++ uspace/drv/bus/usb/ehci/ehci_bus.h	(revision 35c37fc2ef57407c4bf38bf0ac3d777777e3ccd1)
@@ -40,4 +40,5 @@
 #include <usb/host/usb2_bus.h>
 #include <usb/host/endpoint.h>
+#include <usb/host/dma_buffer.h>
 
 #include "hw_struct/queue_head.h"
@@ -48,6 +49,8 @@
 	endpoint_t base;
 
-	/** EHCI endpoint descriptor */
+	/** EHCI endpoint descriptor, backed by dma_buffer */
 	qh_t *qh;
+	
+	dma_buffer_t dma_buffer;
 	/** Linked list used by driver software */
 	link_t link;
Index: uspace/drv/bus/usb/ehci/endpoint_list.c
===================================================================
--- uspace/drv/bus/usb/ehci/endpoint_list.c	(revision b60944bca829148fb902a29e4e88cbbecd57922f)
+++ uspace/drv/bus/usb/ehci/endpoint_list.c	(revision 35c37fc2ef57407c4bf38bf0ac3d777777e3ccd1)
@@ -54,10 +54,10 @@
 	assert(instance);
 	instance->name = name;
-	instance->list_head = malloc32(sizeof(qh_t));
-	if (!instance->list_head) {
+	if (dma_buffer_alloc(&instance->dma_buffer, sizeof(qh_t))) {
 		usb_log_error("EPL(%p-%s): Failed to allocate list head.",
 		    instance, name);
 		return ENOMEM;
 	}
+	instance->list_head = instance->dma_buffer.virt;
 	qh_init(instance->list_head, NULL);
 
Index: uspace/drv/bus/usb/ehci/endpoint_list.h
===================================================================
--- uspace/drv/bus/usb/ehci/endpoint_list.h	(revision b60944bca829148fb902a29e4e88cbbecd57922f)
+++ uspace/drv/bus/usb/ehci/endpoint_list.h	(revision 35c37fc2ef57407c4bf38bf0ac3d777777e3ccd1)
@@ -38,5 +38,4 @@
 #include <assert.h>
 #include <fibril_synch.h>
-#include <usb/host/utils/malloc32.h>
 
 #include "ehci_bus.h"
@@ -49,4 +48,5 @@
 	/** EHCI hw structure at the beginning of the queue */
 	qh_t *list_head;
+	dma_buffer_t dma_buffer;
 	/** Assigned name, provides nicer debug output */
 	const char *name;
@@ -64,5 +64,5 @@
 {
 	assert(instance);
-	free32(instance->list_head);
+	dma_buffer_free(&instance->dma_buffer);
 	instance->list_head = NULL;
 }
Index: uspace/drv/bus/usb/ehci/hc.c
===================================================================
--- uspace/drv/bus/usb/ehci/hc.c	(revision b60944bca829148fb902a29e4e88cbbecd57922f)
+++ uspace/drv/bus/usb/ehci/hc.c	(revision 35c37fc2ef57407c4bf38bf0ac3d777777e3ccd1)
@@ -45,5 +45,4 @@
 #include <usb/debug.h>
 #include <usb/usb.h>
-#include <usb/host/utils/malloc32.h>
 
 #include "ehci_batch.h"
@@ -198,14 +197,11 @@
  * @param[in] instance Host controller structure to use.
  */
-int hc_gone(hc_device_t *instance)
-{
-	assert(instance);
-	return EOK;
-	//TODO: stop the hw
-#if 0
-	endpoint_list_fini(&instance->async_list);
-	endpoint_list_fini(&instance->int_list);
-	return_page(instance->periodic_list_base);
-#endif
+int hc_gone(hc_device_t *hcd)
+{
+	hc_t *hc = hcd_to_hc(hcd);
+	endpoint_list_fini(&hc->async_list);
+	endpoint_list_fini(&hc->int_list);
+	dma_buffer_free(&hc->dma_buffer);
+	return EOK;
 };
 
@@ -406,7 +402,7 @@
 
 	/* Enable periodic list */
-	assert(instance->periodic_list_base);
+	assert(instance->periodic_list);
 	uintptr_t phys_base =
-	    addr_to_phys((void*)instance->periodic_list_base);
+	    addr_to_phys((void*)instance->periodic_list);
 	assert((phys_base & USB_PERIODIC_LIST_BASE_MASK) == phys_base);
 	EHCI_WR(instance->registers->periodiclistbase, phys_base);
@@ -477,6 +473,5 @@
 
 	/* Take 1024 periodic list heads, we ignore low mem options */
-	instance->periodic_list_base = get_page();
-	if (!instance->periodic_list_base) {
+	if (dma_buffer_alloc(&instance->dma_buffer, PAGE_SIZE)) {
 		usb_log_error("HC(%p): Failed to get ISO schedule page.",
 		    instance);
@@ -485,11 +480,11 @@
 		return ENOMEM;
 	}
+	instance->periodic_list = instance->dma_buffer.virt;
 
 	usb_log_debug2("HC(%p): Initializing Periodic list.", instance);
-	for (unsigned i = 0;
-	    i < PAGE_SIZE/sizeof(instance->periodic_list_base[0]); ++i)
+	for (unsigned i = 0; i < PAGE_SIZE/sizeof(link_pointer_t); ++i)
 	{
 		/* Disable everything for now */
-		instance->periodic_list_base[i] =
+		instance->periodic_list[i] =
 		    LINK_POINTER_QH(addr_to_phys(instance->int_list.list_head));
 	}
Index: uspace/drv/bus/usb/ehci/hc.h
===================================================================
--- uspace/drv/bus/usb/ehci/hc.h	(revision b60944bca829148fb902a29e4e88cbbecd57922f)
+++ uspace/drv/bus/usb/ehci/hc.h	(revision 35c37fc2ef57407c4bf38bf0ac3d777777e3ccd1)
@@ -63,6 +63,8 @@
 	ehci_regs_t *registers;
 
-	/** Iso transfer list */
-	link_pointer_t *periodic_list_base;
+	/** Iso transfer list, backed by dma_buffer */
+	link_pointer_t *periodic_list;
+
+	dma_buffer_t dma_buffer;
 
 	/** CONTROL and BULK schedules */
Index: uspace/drv/bus/usb/ehci/hw_struct/queue_head.h
===================================================================
--- uspace/drv/bus/usb/ehci/hw_struct/queue_head.h	(revision b60944bca829148fb902a29e4e88cbbecd57922f)
+++ uspace/drv/bus/usb/ehci/hw_struct/queue_head.h	(revision 35c37fc2ef57407c4bf38bf0ac3d777777e3ccd1)
@@ -193,9 +193,9 @@
 }
 
-static inline void qh_set_next_td(qh_t *qh, td_t *td)
+static inline void qh_set_next_td(qh_t *qh, uintptr_t td)
 {
 	assert(qh);
 	assert(td);
-	EHCI_MEM32_WR(qh->next, LINK_POINTER_TD(addr_to_phys(td)));
+	EHCI_MEM32_WR(qh->next, LINK_POINTER_TD(td));
 }
 
Index: uspace/drv/bus/usb/ehci/hw_struct/transfer_descriptor.c
===================================================================
--- uspace/drv/bus/usb/ehci/hw_struct/transfer_descriptor.c	(revision b60944bca829148fb902a29e4e88cbbecd57922f)
+++ uspace/drv/bus/usb/ehci/hw_struct/transfer_descriptor.c	(revision 35c37fc2ef57407c4bf38bf0ac3d777777e3ccd1)
@@ -39,5 +39,4 @@
 
 #include <usb/usb.h>
-#include <usb/host/utils/malloc32.h>
 
 #include "mem_access.h"
@@ -70,8 +69,10 @@
 };
 
+#include <usb/debug.h>
+
 /**
  * Initialize EHCI TD.
  * @param instance TD structure to initialize.
- * @param next Next TD in ED list.
+ * @param next_phys Next TD in ED list.
  * @param direction Used to determine PID, BOTH means setup PID.
  * @param buffer Pointer to the first byte of transferred data.
@@ -80,7 +81,6 @@
  *        any other value means that ED toggle will be used.
  */
-void td_init(td_t *instance, const td_t *next,
-    usb_direction_t direction, const void *buffer, size_t size, int toggle,
-    bool ioc)
+void td_init(td_t *instance, uintptr_t next_phys, uintptr_t buffer,
+    usb_direction_t direction, size_t size, int toggle, bool ioc)
 {
 	assert(instance);
@@ -98,22 +98,19 @@
 	}
 
-	if (buffer != NULL) {
+	if (buffer != 0) {
 		assert(size != 0);
 		for (unsigned i = 0; (i < ARRAY_SIZE(instance->buffer_pointer))
 		    && size; ++i) {
-			const uintptr_t page =
-			    (addr_to_phys(buffer) & TD_BUFFER_POINTER_MASK);
-			const size_t offset =
-			    ((uintptr_t)buffer & TD_BUFFER_POINTER_OFFSET_MASK);
+			const uintptr_t offset = buffer & TD_BUFFER_POINTER_OFFSET_MASK;
 			assert(offset == 0 || i == 0);
-			size -= min((4096 - offset), size);
-			buffer += min((4096 - offset), size);
-			EHCI_MEM32_WR(instance->buffer_pointer[i],
-			    page | offset);
+			const size_t this_size = min(size, 4096 - offset);
+			EHCI_MEM32_WR(instance->buffer_pointer[i], buffer);
+			size -= this_size;
+			buffer += this_size;
 		}
 	}
 
-	EHCI_MEM32_WR(instance->next, next ?
-	    LINK_POINTER_TD(addr_to_phys(next)) : LINK_POINTER_TERM);
+	EHCI_MEM32_WR(instance->next, next_phys ?
+	    LINK_POINTER_TD(next_phys) : LINK_POINTER_TERM);
 
 	EHCI_MEM32_WR(instance->alternate, LINK_POINTER_TERM);
Index: uspace/drv/bus/usb/ehci/hw_struct/transfer_descriptor.h
===================================================================
--- uspace/drv/bus/usb/ehci/hw_struct/transfer_descriptor.h	(revision b60944bca829148fb902a29e4e88cbbecd57922f)
+++ uspace/drv/bus/usb/ehci/hw_struct/transfer_descriptor.h	(revision 35c37fc2ef57407c4bf38bf0ac3d777777e3ccd1)
@@ -37,4 +37,5 @@
 #include <stddef.h>
 #include <stdint.h>
+#include <macros.h>
 #include "link_pointer.h"
 #include "mem_access.h"
@@ -75,5 +76,11 @@
 	/* 64 bit struct only */
 	volatile uint32_t extended_bp[5];
-} td_t;
+
+	/* TDs must be 32-byte aligned */
+	PADD32 [3];
+
+} __attribute__((packed)) td_t;
+
+static_assert(sizeof(td_t) % 32 == 0);
 
 static inline bool td_active(const td_t *td)
@@ -92,5 +99,5 @@
 int td_error(const td_t *td);
 
-void td_init(td_t *td, const td_t *next, usb_direction_t dir, const void * buf,
+void td_init(td_t *td, uintptr_t next_phys, uintptr_t buf, usb_direction_t dir,
     size_t buf_size, int toggle, bool ioc);
 
