--- /dev/null
+From 66c3edf744415f117c3be95ae83f0bab6e128830 Mon Sep 17 00:00:00 2001\r
+From: "Steinar H. Gunderson" <sesse@google.com>\r
+Date: Wed, 9 Dec 2015 10:03:15 +0100\r
+Subject: [PATCH] Add support for persistent device memory.\r
+\r
+Add a function to allocate memory belonging to a specific device,\r
+so that the operating system can DMA straight into it for zerocopy,\r
+and also avoid some clearing. Also, this allows up-front memory\r
+allocation in the kernel at program startup; memory allocation is\r
+otherwise done per-transfer, which can fail in a system where memory has become\r
+fragmented over time).\r
+\r
+This mirrors new functionality going into Linux' USB stack (recently\r
+reviewed and acked upstream); only Linux is supported as a backend\r
+currently.\r
+---\r
+ libusb/core.c | 29 +++++++++++++++++++++++++++++\r
+ libusb/libusb-1.0.def | 4 ++++\r
+ libusb/libusb.h | 30 +++++++++++++++++++++++++++++-\r
+ libusb/libusbi.h | 10 ++++++++++\r
+ libusb/os/linux_usbfs.c | 30 ++++++++++++++++++++++++++++++\r
+ 5 files changed, 102 insertions(+), 1 deletion(-)\r
+\r
+diff --git a/libusb/core.c b/libusb/core.c\r
+index 9c617fb..3eba85a 100644\r
+--- a/libusb/core.c\r
++++ b/libusb/core.c\r
+@@ -351,6 +351,8 @@ if (cfg != desired)\r
+ * - libusb_control_transfer_get_setup()\r
+ * - libusb_cpu_to_le16()\r
+ * - libusb_detach_kernel_driver()\r
++ * - libusb_dev_mem_alloc()\r
++ * - libusb_dev_mem_free()\r
+ * - libusb_error_name()\r
+ * - libusb_event_handler_active()\r
+ * - libusb_event_handling_ok()\r
+@@ -1805,6 +1807,33 @@ int API_EXPORTED libusb_free_streams(libusb_device_handle *dev,\r
+ return LIBUSB_ERROR_NOT_SUPPORTED;\r
+ }\r
+ \r
++API_EXPORTED unsigned char *libusb_dev_mem_alloc(libusb_device_handle *dev,\r
++ int length)\r
++{\r
++ if (!dev->dev->attached)\r
++ return NULL;\r
++\r
++ if (usbi_backend->dev_mem_alloc)\r
++ return usbi_backend->dev_mem_alloc(dev, length);\r
++ else\r
++ return NULL;\r
++}\r
++\r
++/* Note: No current backends actually use the "dev" parameter; it is only there\r
++ * for any future, less lenient OSes.\r
++ */\r
++int API_EXPORTED libusb_dev_mem_free(libusb_device_handle *dev,\r
++ unsigned char *buffer, int len)\r
++{\r
++ if (!dev->dev->attached)\r
++ return LIBUSB_ERROR_NO_DEVICE;\r
++\r
++ if (usbi_backend->dev_mem_free)\r
++ return usbi_backend->dev_mem_free(dev, buffer, len);\r
++ else\r
++ return LIBUSB_ERROR_NOT_SUPPORTED;\r
++}\r
++\r
+ /** \ingroup dev\r
+ * Determine if a kernel driver is active on an interface. If a kernel driver\r
+ * is active, you cannot claim the interface, and libusb will be unable to\r
+diff --git a/libusb/libusb-1.0.def b/libusb/libusb-1.0.def\r
+index 538ad49..e040f4b 100644\r
+--- a/libusb/libusb-1.0.def\r
++++ b/libusb/libusb-1.0.def\r
+@@ -20,6 +20,10 @@ EXPORTS\r
+ libusb_control_transfer@32 = libusb_control_transfer\r
+ libusb_detach_kernel_driver\r
+ libusb_detach_kernel_driver@8 = libusb_detach_kernel_driver\r
++ libusb_dev_mem_alloc\r
++ libusb_dev_mem_alloc@8 = libusb_dev_mem_alloc\r
++ libusb_dev_mem_free\r
++ libusb_dev_mem_free@12 = libusb_dev_mem_free\r
+ libusb_error_name\r
+ libusb_error_name@4 = libusb_error_name\r
+ libusb_event_handler_active\r
+diff --git a/libusb/libusb.h b/libusb/libusb.h\r
+index 513945f..5a84f5b 100644\r
+--- a/libusb/libusb.h\r
++++ b/libusb/libusb.h\r
+@@ -141,7 +141,7 @@ typedef unsigned __int32 uint32_t;\r
+ * Internally, LIBUSB_API_VERSION is defined as follows:\r
+ * (libusb major << 24) | (libusb minor << 16) | (16 bit incremental)\r
+ */\r
+-#define LIBUSB_API_VERSION 0x01000104\r
++#define LIBUSB_API_VERSION 0x01000105\r
+ \r
+ /* The following is kept for compatibility, but will be deprecated in the future */\r
+ #define LIBUSBX_API_VERSION LIBUSB_API_VERSION\r
+@@ -1749,6 +1749,34 @@ int LIBUSB_CALL libusb_interrupt_transfer(libusb_device_handle *dev_handle,\r
+ unsigned char endpoint, unsigned char *data, int length,\r
+ int *actual_length, unsigned int timeout);\r
+ \r
++/** \ingroup asyncio\r
++ * Attempts to allocate a block of persistent DMA memory suitable for transfers\r
++ * against the given device. If successful, will return a block of memory\r
++ * that is suitable for use as "buffer" in \ref libusb_transfer against this\r
++ * device. Using this memory instead of regular memory means that the host\r
++ * controller can use DMA directly into the buffer to increase performance, and\r
++ * also that transfers can no longer fail due to kernel memory fragmentation.\r
++ *\r
++ * Note that this means you should not modify this memory (or even data on\r
++ * the same cache lines) when a transfer is in progress, although it is legal\r
++ * to have several transfers going on within the same memory block.\r
++ *\r
++ * Will return NULL on failure. Many systems do not support such zerocopy\r
++ * and will always return NULL. Memory allocated with this function must be\r
++ * freed with \ref libusb_dev_mem_free.\r
++ *\r
++ * Since version 1.0.21, \ref LIBUSB_API_VERSION >= 0x01000105\r
++ *\r
++ * \param dev a device handle\r
++ * \param length size of desired data buffer\r
++ * \returns a pointer to the newly allocated memory, or NULL on failure\r
++ */\r
++unsigned char *LIBUSB_CALL libusb_dev_mem_alloc(libusb_device_handle *dev,\r
++ int length);\r
++\r
++int LIBUSB_CALL libusb_dev_mem_free(libusb_device_handle *dev,\r
++ unsigned char *buffer, int length);\r
++\r
+ /** \ingroup desc\r
+ * Retrieve a descriptor from the default control pipe.\r
+ * This is a convenience function which formulates the appropriate control\r
+diff --git a/libusb/libusbi.h b/libusb/libusbi.h\r
+index f1afd99..66bdf46 100644\r
+--- a/libusb/libusbi.h\r
++++ b/libusb/libusbi.h\r
+@@ -913,6 +913,16 @@ struct usbi_os_backend {\r
+ int (*free_streams)(struct libusb_device_handle *handle,\r
+ unsigned char *endpoints, int num_endpoints);\r
+ \r
++ /* Allocate persistent DMA memory for the given device, suitable for\r
++ * zerocopy. May return NULL on failure. Optional to implement.\r
++ */\r
++ unsigned char *(*dev_mem_alloc)(struct libusb_device_handle *handle,\r
++ size_t len);\r
++\r
++ /* Free memory allocated by dev_mem_alloc. */\r
++ int (*dev_mem_free)(struct libusb_device_handle *handle,\r
++ unsigned char *buffer, size_t len);\r
++\r
+ /* Determine if a kernel driver is active on an interface. Optional.\r
+ *\r
+ * The presence of a kernel driver on an interface indicates that any\r
+diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c\r
+index a63852f..a167084 100644\r
+--- a/libusb/os/linux_usbfs.c\r
++++ b/libusb/os/linux_usbfs.c\r
+@@ -33,6 +33,7 @@\r
+ #include <stdlib.h>\r
+ #include <string.h>\r
+ #include <sys/ioctl.h>\r
++#include <sys/mman.h>\r
+ #include <sys/stat.h>\r
+ #include <sys/types.h>\r
+ #include <sys/utsname.h>\r
+@@ -1561,6 +1562,32 @@ static int op_free_streams(struct libusb_device_handle *handle,\r
+ endpoints, num_endpoints);\r
+ }\r
+ \r
++static unsigned char *op_dev_mem_alloc(struct libusb_device_handle *handle,\r
++ size_t len)\r
++{\r
++ struct linux_device_handle_priv *hpriv = _device_handle_priv(handle);\r
++ unsigned char *buffer = (unsigned char *)mmap(NULL, len,\r
++ PROT_READ | PROT_WRITE, MAP_SHARED, hpriv->fd, 0);\r
++ if (buffer == MAP_FAILED) {\r
++ usbi_err(HANDLE_CTX(handle), "alloc dev mem failed errno %d",\r
++ errno);\r
++ return NULL;\r
++ }\r
++ return buffer;\r
++}\r
++\r
++static int op_dev_mem_free(struct libusb_device_handle *handle,\r
++ unsigned char *buffer, size_t len)\r
++{\r
++ if (munmap(buffer, len) != 0) {\r
++ usbi_err(HANDLE_CTX(handle), "free dev mem failed errno %d",\r
++ errno);\r
++ return LIBUSB_ERROR_OTHER;\r
++ } else {\r
++ return LIBUSB_SUCCESS;\r
++ }\r
++}\r
++\r
+ static int op_kernel_driver_active(struct libusb_device_handle *handle,\r
+ int interface)\r
+ {\r
+@@ -2682,6 +2709,9 @@ const struct usbi_os_backend linux_usbfs_backend = {\r
+ .alloc_streams = op_alloc_streams,\r
+ .free_streams = op_free_streams,\r
+ \r
++ .dev_mem_alloc = op_dev_mem_alloc,\r
++ .dev_mem_free = op_dev_mem_free,\r
++\r
+ .kernel_driver_active = op_kernel_driver_active,\r
+ .detach_kernel_driver = op_detach_kernel_driver,\r
+ .attach_kernel_driver = op_attach_kernel_driver,\r
+-- \r
+2.6.4\r
+\r