]> git.sesse.net Git - nageru/blobdiff - patches/libusb-add-support-for-persistent-device-memory.diff
Add some useful (pending) upstream patches that have not gone in yet.
[nageru] / patches / libusb-add-support-for-persistent-device-memory.diff
diff --git a/patches/libusb-add-support-for-persistent-device-memory.diff b/patches/libusb-add-support-for-persistent-device-memory.diff
new file mode 100644 (file)
index 0000000..1642493
--- /dev/null
@@ -0,0 +1,212 @@
+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