-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 (scheduled\r
-for inclusion in mainline around 4.6); only Linux is supported as a\r
-backend 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