Index: uspace/lib/drv/include/usbhc_iface.h
===================================================================
--- uspace/lib/drv/include/usbhc_iface.h	(revision 5c69377fed97da1526d8fb7b301c4eaa6f5bf92a)
+++ uspace/lib/drv/include/usbhc_iface.h	(revision cc63815c45bec69f85b3455ff1f4c5dcc15c228c)
@@ -103,4 +103,7 @@
 } usb_target_t;
 
+// FIXME: DMA buffers shall be part of libdrv anyway.
+typedef unsigned dma_policy_t;
+
 typedef struct usb_pipe_desc {
 	/** Endpoint number. */
Index: uspace/lib/usb/include/usb/dma_buffer.h
===================================================================
--- uspace/lib/usb/include/usb/dma_buffer.h	(revision 5c69377fed97da1526d8fb7b301c4eaa6f5bf92a)
+++ uspace/lib/usb/include/usb/dma_buffer.h	(revision cc63815c45bec69f85b3455ff1f4c5dcc15c228c)
@@ -32,9 +32,17 @@
  * @brief USB host controller library: DMA buffer helpers
  *
- * Simplifies usage of bounce buffers
+ * Simplifies handling of buffers accessible to hardware. Defines properties of
+ * such buffer, which can be communicated through IPC to allow higher layers to
+ * allocate a buffer that is ready to be passed to HW right away (after being
+ * shared through IPC).
  *
- * Currently the minimum size allocated is a page, which is wasteful. Could be
- * extended to support memory pools, which will enable smaller units of
- * allocation.
+ * Note that although allocated memory is always page-aligned, the buffer itself
+ * may be only a part of it, justifying the existence of page-alignment and
+ * page-crossing flags.
+ *
+ * Also, currently the buffers that are allocated are always contiguous and
+ * page-aligned, regardless of whether the policy requires it. We blindly
+ * believe this fact in dma_buffer_phys, which will yield wrong results if the
+ * buffer is not contiguous.
  */
 #ifndef LIB_USB_DMA_BUFFER
@@ -43,12 +51,14 @@
 #include <stdint.h>
 #include <stdlib.h>
+#include <usbhc_iface.h>
 #include <errno.h>
 
-typedef const struct dma_policy {
-	unsigned flags;
+#define DMA_POLICY_4GiB		(1<<0)	/**< Must use only 32-bit addresses */
+#define DMA_POLICY_PAGE_ALIGNED	(1<<1)	/**< The first pointer must be page-aligned */
+#define DMA_POLICY_CONTIGUOUS	(1<<2)	/**< Pages must follow each other physically */
+#define DMA_POLICY_NOT_CROSSING	(1<<3)	/**< Buffer must not cross page boundary. (Implies buffer is no larger than page).  */
 
-#define DMA_POLICY_F_4GiB	(1<<0)	/**< Must use only 32-bit addresses */
-#define DMA_POLICY_F_CONTIGUOUS	(1<<1)	/**< Pages must follow each other physically */
-} dma_policy_t;
+#define DMA_POLICY_STRICT	(-1U)
+#define DMA_POLICY_DEFAULT	DMA_POLICY_STRICT
 
 typedef struct dma_buffer {
@@ -57,10 +67,13 @@
 } dma_buffer_t;
 
-extern int dma_buffer_alloc(dma_buffer_t *db, size_t size);
-extern int dma_buffer_alloc_policy(dma_buffer_t *, size_t, dma_policy_t *);
+extern errno_t dma_buffer_alloc(dma_buffer_t *db, size_t size);
+extern errno_t dma_buffer_alloc_policy(dma_buffer_t *, size_t, dma_policy_t);
 extern void dma_buffer_free(dma_buffer_t *);
 extern uintptr_t dma_buffer_phys(const dma_buffer_t *, void *);
 
-extern bool dma_buffer_check_policy(const void *, size_t, dma_policy_t *);
+extern bool dma_buffer_check_policy(const void *, size_t, const dma_policy_t);
+
+extern errno_t dma_buffer_lock(dma_buffer_t *, void *, size_t);
+extern void dma_buffer_unlock(dma_buffer_t *, size_t);
 
 static inline int dma_buffer_is_set(dma_buffer_t *db)
Index: uspace/lib/usb/src/dma_buffer.c
===================================================================
--- uspace/lib/usb/src/dma_buffer.c	(revision 5c69377fed97da1526d8fb7b301c4eaa6f5bf92a)
+++ uspace/lib/usb/src/dma_buffer.c	(revision cc63815c45bec69f85b3455ff1f4c5dcc15c228c)
@@ -39,21 +39,21 @@
 #include "usb/dma_buffer.h"
 
-const dma_policy_t dma_policy_default = {
-	.flags = DMA_POLICY_F_4GiB | DMA_POLICY_F_CONTIGUOUS,
-};
-
-/**
- * The routine of allocating a DMA buffer. Inlined to force optimization for the
- * default policy.
- *
- * FIXME: We ignore the non-presence of contiguous flag, for now.
- */
-static inline int dma_buffer_alloc_internal(dma_buffer_t *db,
-    size_t size, const dma_policy_t *policy)
+/**
+ * Allocate a DMA buffer.
+ *
+ * XXX: Currently cannot make much use of missing constraints, as it always
+ * allocates page-aligned contiguous buffer. We rely on it in dma_buffer_phys.
+ *
+ * @param[in] db dma_buffer_t structure to fill
+ * @param[in] size Size of the required memory space
+ * @param[in] policy dma_policy_t flags to guide the allocation
+ * @return Error code.
+ */
+errno_t dma_buffer_alloc_policy(dma_buffer_t *db, size_t size, dma_policy_t policy)
 {
 	assert(db);
 
 	const size_t real_size = ALIGN_UP(size, PAGE_SIZE);
-	const bool need_4gib = !!(policy->flags & DMA_POLICY_F_4GiB);
+	const bool need_4gib = !!(policy & DMA_POLICY_4GiB);
 
 	const uintptr_t flags = need_4gib ? DMAMEM_4GiB : 0;
@@ -67,4 +67,9 @@
 
 	if (ret == EOK) {
+		/* Access the pages to force mapping */
+		volatile char *buf = address;
+		for (size_t i = 0; i < size; i += PAGE_SIZE)
+			buf[i] = 0xff;
+
 		db->virt = address;
 		db->phys = phys;
@@ -73,17 +78,4 @@
 }
 
-/**
- * Allocate a DMA buffer.
- *
- * @param[in] db dma_buffer_t structure to fill
- * @param[in] size Size of the required memory space
- * @param[in] policy dma_policy_t structure to guide
- * @return Error code.
- */
-int dma_buffer_alloc_policy(dma_buffer_t *db, size_t size,
-    const dma_policy_t *policy)
-{
-	return dma_buffer_alloc_internal(db, size, policy);
-}
 
 /**
@@ -94,7 +86,7 @@
  * @return Error code.
  */
-int dma_buffer_alloc(dma_buffer_t *db, size_t size)
-{
-	return dma_buffer_alloc_internal(db, size, &dma_policy_default);
+errno_t dma_buffer_alloc(dma_buffer_t *db, size_t size)
+{
+	return dma_buffer_alloc_policy(db, size, DMA_POLICY_DEFAULT);
 }
 
@@ -128,15 +120,25 @@
  * Check whether a memory area is compatible with a policy.
  *
- * Useful to skip copying, if the buffer is already ready to be given to
- * hardware.
- */
-bool dma_buffer_check_policy(const void *buffer, size_t size, dma_policy_t *policy)
-{
-	/* Buffer must be always page aligned */
-	if (((uintptr_t) buffer) % PAGE_SIZE)
+ * Useful to skip copying when the buffer is already ready to be given to
+ * hardware as is.
+ *
+ * Note that the "as_get_physical_mapping" fails when the page is not mapped
+ * yet, and that the caller is responsible for forcing the mapping.
+ */
+bool dma_buffer_check_policy(const void *buffer, size_t size, const dma_policy_t policy)
+{
+	uintptr_t addr = (uintptr_t) buffer;
+
+	const bool check_4gib       = !!(policy & DMA_POLICY_4GiB);
+	const bool check_crossing   = !!(policy & DMA_POLICY_NOT_CROSSING);
+	const bool check_alignment  = !!(policy & DMA_POLICY_PAGE_ALIGNED);
+	const bool check_contiguous = !!(policy & DMA_POLICY_CONTIGUOUS);
+
+	/* Check the two conditions that are easy */
+	if (check_crossing && (addr + size - 1) / PAGE_SIZE != addr / PAGE_SIZE)
 		goto violated;
 
-	const bool check_4gib = !!(policy->flags & DMA_POLICY_F_4GiB);
-	const bool check_contiguous = !!(policy->flags & DMA_POLICY_F_CONTIGUOUS);
+	if (check_alignment && ((uintptr_t) buffer) % PAGE_SIZE)
+		goto violated;
 
 	/*
@@ -145,5 +147,5 @@
 	 */
 	if (check_contiguous || check_4gib) {
-		const void * virt = buffer;
+		const void *virt = buffer;
 		uintptr_t phys;
 
@@ -156,5 +158,5 @@
 			goto violated;
 
-		while (size <= PAGE_SIZE) {
+		while (size >= PAGE_SIZE) {
 			/* Move to the next page */
 			virt += PAGE_SIZE;
@@ -182,4 +184,29 @@
 
 /**
+ * Lock an arbitrary buffer for DMA operations, creating a DMA buffer.
+ *
+ * FIXME: To handle page-unaligned buffers, we need to calculate the base
+ *        address and lock the whole first page. But as the operation is not yet
+ *        implemented in the kernel, it doesn't matter.
+ */
+errno_t dma_buffer_lock(dma_buffer_t *db, void *virt, size_t size)
+{
+	db->virt = virt;
+	return dmamem_map(db->virt, size, 0, 0, &db->phys);
+}
+
+/**
+ * Unlock a buffer for DMA operations.
+ */
+void dma_buffer_unlock(dma_buffer_t *db, size_t size)
+{
+	if (db->virt) {
+		dmamem_unmap(db->virt, size);
+		db->virt = NULL;
+		db->phys = 0;
+	}
+}
+
+/**
  * @}
  */
