core: Remove use of gettimeofday()
[platform/upstream/libusb.git] / libusb / libusbi.h
index 5548b80..9fd634f 100644 (file)
 extern "C" {
 #endif
 
-#define DEVICE_DESC_LENGTH             18
+#define DEVICE_DESC_LENGTH     18
 
 #define USB_MAXENDPOINTS       32
 #define USB_MAXINTERFACES      32
 #define USB_MAXCONFIG          8
 
 /* Backend specific capabilities */
-#define USBI_CAP_HAS_HID_ACCESS                                        0x00010000
+#define USBI_CAP_HAS_HID_ACCESS                        0x00010000
 #define USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER 0x00020000
-#define USBI_CAP_HAS_POLLABLE_DEVICE_FD                0x00040000
 
 /* Maximum number of bytes in a log line */
 #define USBI_MAX_LOG_LEN       1024
@@ -69,10 +68,10 @@ extern "C" {
 #define USBI_LOG_LINE_END      "\n"
 
 /* The following is used to silence warnings for unused variables */
-#define UNUSED(var)                    do { (void)(var); } while(0)
+#define UNUSED(var)            do { (void)(var); } while(0)
 
 #if !defined(ARRAYSIZE)
-#define ARRAYSIZE(array) (sizeof(array)/sizeof(array[0]))
+#define ARRAYSIZE(array) (sizeof(array) / sizeof(array[0]))
 #endif
 
 struct list_head {
@@ -87,6 +86,9 @@ struct list_head {
 #define list_entry(ptr, type, member) \
        ((type *)((uintptr_t)(ptr) - (uintptr_t)offsetof(type, member)))
 
+#define list_first_entry(ptr, type, member) \
+       list_entry((ptr)->next, type, member)
+
 /* Get each entry from a list
  *  pos - A structure pointer has a "member" element
  *  head - list head
@@ -94,14 +96,14 @@ struct list_head {
  *  type - the type of the first parameter
  */
 #define list_for_each_entry(pos, head, member, type)                   \
-       for (pos = list_entry((head)->next, type, member);                      \
-                &pos->member != (head);                                                                \
+       for (pos = list_entry((head)->next, type, member);              \
+                &pos->member != (head);                                \
                 pos = list_entry(pos->member.next, type, member))
 
-#define list_for_each_entry_safe(pos, n, head, member, type)   \
-       for (pos = list_entry((head)->next, type, member),                      \
-                n = list_entry(pos->member.next, type, member);                \
-                &pos->member != (head);                                                                \
+#define list_for_each_entry_safe(pos, n, head, member, type)           \
+       for (pos = list_entry((head)->next, type, member),              \
+                n = list_entry(pos->member.next, type, member);        \
+                &pos->member != (head);                                \
                 pos = n, n = list_entry(n->member.next, type, member))
 
 #define list_empty(entry) ((entry)->next == (entry))
@@ -145,9 +147,9 @@ static inline void *usbi_reallocf(void *ptr, size_t size)
        return ret;
 }
 
-#define container_of(ptr, type, member) ({                      \
-        const typeof( ((type *)0)->member ) *mptr = (ptr);    \
-        (type *)( (char *)mptr - offsetof(type,member) );})
+#define container_of(ptr, type, member) ({                     \
+       const typeof( ((type *)0)->member ) *mptr = (ptr);      \
+       (type *)( (char *)mptr - offsetof(type,member) );})
 
 #ifndef MIN
 #define MIN(a, b)      ((a) < (b) ? (a) : (b))
@@ -158,13 +160,19 @@ static inline void *usbi_reallocf(void *ptr, size_t size)
 
 #define TIMESPEC_IS_SET(ts) ((ts)->tv_sec != 0 || (ts)->tv_nsec != 0)
 
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
+#define TIMEVAL_TV_SEC_TYPE    long
+#else
+#define TIMEVAL_TV_SEC_TYPE    time_t
+#endif
+
 /* Some platforms don't have this define */
 #ifndef TIMESPEC_TO_TIMEVAL
-#define TIMESPEC_TO_TIMEVAL(tv, ts)                                     \
-        do {                                                            \
-                (tv)->tv_sec = (ts)->tv_sec;                            \
-                (tv)->tv_usec = (ts)->tv_nsec / 1000;                   \
-        } while (0)
+#define TIMESPEC_TO_TIMEVAL(tv, ts)                                    \
+       do {                                                            \
+               (tv)->tv_sec = (TIMEVAL_TV_SEC_TYPE) (ts)->tv_sec;      \
+               (tv)->tv_usec = (ts)->tv_nsec / 1000;                   \
+       } while (0)
 #endif
 
 void usbi_log(struct libusb_context *ctx, enum libusb_log_level level,
@@ -190,49 +198,54 @@ void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level,
 #else /* !defined(_MSC_VER) || _MSC_VER >= 1400 */
 
 #ifdef ENABLE_LOGGING
-#define LOG_BODY(ctxt, level) \
-{                             \
-       va_list args;             \
-       va_start (args, format);  \
-       usbi_log_v(ctxt, level, "", format, args); \
-       va_end(args);             \
+#define LOG_BODY(ctxt, level)                          \
+{                                                      \
+       va_list args;                                   \
+       va_start(args, format);                         \
+       usbi_log_v(ctxt, level, "", format, args);      \
+       va_end(args);                                   \
 }
 #else
-#define LOG_BODY(ctxt, level) do { (void)(ctxt); } while(0)
+#define LOG_BODY(ctxt, level)                          \
+{                                                      \
+       (void)(ctxt);                                   \
+}
 #endif
 
-static inline void usbi_info(struct libusb_context *ctx, const char *format,
-       ...)
-       LOG_BODY(ctx,LIBUSB_LOG_LEVEL_INFO)
-static inline void usbi_warn(struct libusb_context *ctx, const char *format,
-       ...)
-       LOG_BODY(ctx,LIBUSB_LOG_LEVEL_WARNING)
-static inline void usbi_err( struct libusb_context *ctx, const char *format,
-       ...)
-       LOG_BODY(ctx,LIBUSB_LOG_LEVEL_ERROR)
+static inline void usbi_info(struct libusb_context *ctx, const char *format, ...)
+       LOG_BODY(ctx, LIBUSB_LOG_LEVEL_INFO)
+static inline void usbi_warn(struct libusb_context *ctx, const char *format, ...)
+       LOG_BODY(ctx, LIBUSB_LOG_LEVEL_WARNING)
+static inline void usbi_err(struct libusb_context *ctx, const char *format, ...)
+       LOG_BODY(ctx, LIBUSB_LOG_LEVEL_ERROR)
 
 static inline void usbi_dbg(const char *format, ...)
-       LOG_BODY(NULL,LIBUSB_LOG_LEVEL_DEBUG)
+       LOG_BODY(NULL, LIBUSB_LOG_LEVEL_DEBUG)
 
 #endif /* !defined(_MSC_VER) || _MSC_VER >= 1400 */
 
-#define USBI_GET_CONTEXT(ctx) if (!(ctx)) (ctx) = usbi_default_context
-#define DEVICE_CTX(dev) ((dev)->ctx)
-#define HANDLE_CTX(handle) (DEVICE_CTX((handle)->dev))
-#define TRANSFER_CTX(transfer) (HANDLE_CTX((transfer)->dev_handle))
+#define USBI_GET_CONTEXT(ctx)                          \
+       do {                                            \
+               if (!(ctx))                             \
+                       (ctx) = usbi_default_context;   \
+       } while(0)
+
+#define DEVICE_CTX(dev)                ((dev)->ctx)
+#define HANDLE_CTX(handle)     (DEVICE_CTX((handle)->dev))
+#define TRANSFER_CTX(transfer) (HANDLE_CTX((transfer)->dev_handle))
 #define ITRANSFER_CTX(transfer) \
        (TRANSFER_CTX(USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer)))
 
-#define IS_EPIN(ep) (0 != ((ep) & LIBUSB_ENDPOINT_IN))
-#define IS_EPOUT(ep) (!IS_EPIN(ep))
-#define IS_XFERIN(xfer) (0 != ((xfer)->endpoint & LIBUSB_ENDPOINT_IN))
-#define IS_XFEROUT(xfer) (!IS_XFERIN(xfer))
+#define IS_EPIN(ep)            (0 != ((ep) & LIBUSB_ENDPOINT_IN))
+#define IS_EPOUT(ep)           (!IS_EPIN(ep))
+#define IS_XFERIN(xfer)                (0 != ((xfer)->endpoint & LIBUSB_ENDPOINT_IN))
+#define IS_XFEROUT(xfer)       (!IS_XFERIN(xfer))
 
 /* Internal abstraction for thread synchronization */
 #if defined(THREADS_POSIX)
 #include "os/threads_posix.h"
 #elif defined(OS_WINDOWS) || defined(OS_WINCE)
-#include <os/threads_windows.h>
+#include "os/threads_windows.h"
 #endif
 
 extern struct libusb_context *usbi_default_context;
@@ -244,9 +257,8 @@ struct libusb_context {
        int debug;
        int debug_fixed;
 
-       /* internal control pipe, used for interrupting event handling when
-        * an internal event occurs. */
-       int ctrl_pipe[2];
+       /* internal event pipe, used for signalling occurrence of an internal event. */
+       int event_pipe[2];
 
        struct list_head usb_devs;
        usbi_mutex_t usb_devs_lock;
@@ -259,24 +271,16 @@ struct libusb_context {
        /* A list of registered hotplug callbacks */
        struct list_head hotplug_cbs;
        usbi_mutex_t hotplug_cbs_lock;
-       int hotplug_pipe[2];
 
        /* this is a list of in-flight transfer handles, sorted by timeout
         * expiration. URBs to timeout the soonest are placed at the beginning of
         * the list, URBs that will time out later are placed after, and urbs with
         * infinite timeout are always placed at the very end. */
        struct list_head flying_transfers;
+       /* Note paths taking both this and usbi_transfer->lock must always
+        * take this lock first */
        usbi_mutex_t flying_transfers_lock;
 
-       /* list and count of poll fds and an array of poll fd structures that is
-        * (re)allocated as necessary prior to polling, and a flag to indicate
-        * when the list of poll fds has changed since the last poll. */
-       struct list_head ipollfds;
-       struct pollfd *pollfds;
-       POLL_NFDS_TYPE pollfds_cnt;
-       unsigned int pollfds_modified;
-       usbi_mutex_t pollfds_lock;
-
        /* user callbacks for pollfd changes */
        libusb_pollfd_added_cb fd_added_cb;
        libusb_pollfd_removed_cb fd_removed_cb;
@@ -288,17 +292,37 @@ struct libusb_context {
        /* used to see if there is an active thread doing event handling */
        int event_handler_active;
 
+       /* A thread-local storage key to track which thread is performing event
+        * handling */
+       usbi_tls_key_t event_handling_key;
+
+       /* used to wait for event completion in threads other than the one that is
+        * event handling */
+       usbi_mutex_t event_waiters_lock;
+       usbi_cond_t event_waiters_cond;
+
        /* A lock to protect internal context event data. */
        usbi_mutex_t event_data_lock;
 
+       /* A bitmask of flags that are set to indicate specific events that need to
+        * be handled. Protected by event_data_lock. */
+       unsigned int event_flags;
+
        /* A counter that is set when we want to interrupt and prevent event handling,
         * in order to safely close a device. Protected by event_data_lock. */
        unsigned int device_close;
 
-       /* used to wait for event completion in threads other than the one that is
-        * event handling */
-       usbi_mutex_t event_waiters_lock;
-       usbi_cond_t event_waiters_cond;
+       /* list and count of poll fds and an array of poll fd structures that is
+        * (re)allocated as necessary prior to polling. Protected by event_data_lock. */
+       struct list_head ipollfds;
+       struct pollfd *pollfds;
+       POLL_NFDS_TYPE pollfds_cnt;
+
+       /* A list of pending hotplug messages. Protected by event_data_lock. */
+       struct list_head hotplug_msgs;
+
+       /* A list of pending completed transfers. Protected by event_data_lock. */
+       struct list_head completed_transfers;
 
 #ifdef USBI_TIMERFD_AVAILABLE
        /* used for timeout handling, if supported by OS.
@@ -309,6 +333,29 @@ struct libusb_context {
        struct list_head list;
 };
 
+enum usbi_event_flags {
+       /* The list of pollfds has been modified */
+       USBI_EVENT_POLLFDS_MODIFIED = 1 << 0,
+
+       /* The user has interrupted the event handler */
+       USBI_EVENT_USER_INTERRUPT = 1 << 1,
+};
+
+/* Macros for managing event handling state */
+#define usbi_handling_events(ctx) \
+       (usbi_tls_key_get((ctx)->event_handling_key) != NULL)
+
+#define usbi_start_event_handling(ctx) \
+       usbi_tls_key_set((ctx)->event_handling_key, ctx)
+
+#define usbi_end_event_handling(ctx) \
+       usbi_tls_key_set((ctx)->event_handling_key, NULL)
+
+/* Update the following macro if new event sources are added */
+#define usbi_pending_events(ctx) \
+       ((ctx)->event_flags || (ctx)->device_close \
+        || !list_empty(&(ctx)->hotplug_msgs) || !list_empty(&(ctx)->completed_transfers))
+
 #ifdef USBI_TIMERFD_AVAILABLE
 #define usbi_using_timerfd(ctx) ((ctx)->timerfd >= 0)
 #else
@@ -342,7 +389,11 @@ struct libusb_device {
 #else
        [0] /* non-standard, but usually working code */
 #endif
+#if defined(OS_SUNOS)
+       __attribute__ ((aligned (8)));
+#else
        ;
+#endif
 };
 
 struct libusb_device_handle {
@@ -359,12 +410,16 @@ struct libusb_device_handle {
 #else
        [0] /* non-standard, but usually working code */
 #endif
+#if defined(OS_SUNOS)
+       __attribute__ ((aligned (8)));
+#else
        ;
+#endif
 };
 
 enum {
-  USBI_CLOCK_MONOTONIC,
-  USBI_CLOCK_REALTIME
+       USBI_CLOCK_MONOTONIC,
+       USBI_CLOCK_REALTIME
 };
 
 /* in-memory transfer layout:
@@ -383,10 +438,12 @@ enum {
 struct usbi_transfer {
        int num_iso_packets;
        struct list_head list;
+       struct list_head completed_list;
        struct timeval timeout;
        int transferred;
        uint32_t stream_id;
-       uint8_t flags;
+       uint8_t state_flags;   /* Protected by usbi_transfer->lock */
+       uint8_t timeout_flags; /* Protected by the flying_stransfers_lock */
 
        /* this lock is held during libusb_submit_transfer() and
         * libusb_cancel_transfer() (allowing the OS backend to prevent duplicate
@@ -394,32 +451,39 @@ struct usbi_transfer {
         * should also take this lock in the handle_events path, to prevent the user
         * cancelling the transfer from another thread while you are processing
         * its completion (presumably there would be races within your OS backend
-        * if this were possible). */
+        * if this were possible).
+        * Note paths taking both this and the flying_transfers_lock must
+        * always take the flying_transfers_lock first */
        usbi_mutex_t lock;
 };
 
-enum usbi_transfer_flags {
-       /* The transfer has timed out */
-       USBI_TRANSFER_TIMED_OUT = 1 << 0,
-
-       /* Set by backend submit_transfer() if the OS handles timeout */
-       USBI_TRANSFER_OS_HANDLES_TIMEOUT = 1 << 1,
+enum usbi_transfer_state_flags {
+       /* Transfer successfully submitted by backend */
+       USBI_TRANSFER_IN_FLIGHT = 1 << 0,
 
        /* Cancellation was requested via libusb_cancel_transfer() */
-       USBI_TRANSFER_CANCELLING = 1 << 2,
+       USBI_TRANSFER_CANCELLING = 1 << 1,
 
        /* Operation on the transfer failed because the device disappeared */
-       USBI_TRANSFER_DEVICE_DISAPPEARED = 1 << 3,
+       USBI_TRANSFER_DEVICE_DISAPPEARED = 1 << 2,
+};
+
+enum usbi_transfer_timeout_flags {
+       /* Set by backend submit_transfer() if the OS handles timeout */
+       USBI_TRANSFER_OS_HANDLES_TIMEOUT = 1 << 0,
 
-       /* Set by backend submit_transfer() if the fds in use have been updated */
-       USBI_TRANSFER_UPDATED_FDS = 1 << 4,
+       /* The transfer timeout has been handled */
+       USBI_TRANSFER_TIMEOUT_HANDLED = 1 << 1,
+
+       /* The transfer timeout was successfully processed */
+       USBI_TRANSFER_TIMED_OUT = 1 << 2,
 };
 
-#define USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer) \
-       ((struct libusb_transfer *)(((unsigned char *)(transfer)) \
+#define USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer)                     \
+       ((struct libusb_transfer *)(((unsigned char *)(transfer))       \
                + sizeof(struct usbi_transfer)))
-#define LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer) \
-       ((struct usbi_transfer *)(((unsigned char *)(transfer)) \
+#define LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer)                     \
+       ((struct usbi_transfer *)(((unsigned char *)(transfer))         \
                - sizeof(struct usbi_transfer)))
 
 static inline void *usbi_transfer_get_os_priv(struct usbi_transfer *transfer)
@@ -434,8 +498,8 @@ static inline void *usbi_transfer_get_os_priv(struct usbi_transfer *transfer)
 
 /* All standard descriptors have these 2 fields in common */
 struct usb_descriptor_header {
-       uint8_t  bLength;
-       uint8_t  bDescriptorType;
+       uint8_t bLength;
+       uint8_t bDescriptorType;
 };
 
 /* shared data and functions */
@@ -448,11 +512,12 @@ struct libusb_device *usbi_alloc_device(struct libusb_context *ctx,
 struct libusb_device *usbi_get_device_by_session_id(struct libusb_context *ctx,
        unsigned long session_id);
 int usbi_sanitize_device(struct libusb_device *dev);
-void usbi_handle_disconnect(struct libusb_device_handle *handle);
+void usbi_handle_disconnect(struct libusb_device_handle *dev_handle);
 
 int usbi_handle_transfer_completion(struct usbi_transfer *itransfer,
        enum libusb_transfer_status status);
 int usbi_handle_transfer_cancellation(struct usbi_transfer *transfer);
+void usbi_signal_transfer_completion(struct usbi_transfer *transfer);
 
 int usbi_parse_descriptor(const unsigned char *source, const char *descriptor,
        void *dest, int host_endian);
@@ -463,8 +528,12 @@ int usbi_get_config_index_by_value(struct libusb_device *dev,
 void usbi_connect_device (struct libusb_device *dev);
 void usbi_disconnect_device (struct libusb_device *dev);
 
+int usbi_signal_event(struct libusb_context *ctx);
+int usbi_clear_event(struct libusb_context *ctx);
+
 /* Internal abstraction for poll (needs struct usbi_transfer on Windows) */
-#if defined(OS_LINUX) || defined(OS_DARWIN) || defined(OS_OPENBSD) || defined(OS_NETBSD) || defined(OS_HAIKU)
+#if defined(OS_LINUX) || defined(OS_DARWIN) || defined(OS_OPENBSD) || defined(OS_NETBSD) ||\
+       defined(OS_HAIKU) || defined(OS_SUNOS)
 #include <unistd.h>
 #include "os/poll_posix.h"
 #elif defined(OS_WINDOWS) || defined(OS_WINCE)
@@ -474,14 +543,6 @@ void usbi_disconnect_device (struct libusb_device *dev);
 #if (defined(OS_WINDOWS) || defined(OS_WINCE)) && !defined(__GNUC__)
 #define snprintf _snprintf
 #define vsnprintf _vsnprintf
-int usbi_gettimeofday(struct timeval *tp, void *tzp);
-#define LIBUSB_GETTIMEOFDAY_WIN32
-#define HAVE_USBI_GETTIMEOFDAY
-#else
-#ifdef HAVE_GETTIMEOFDAY
-#define usbi_gettimeofday(tv, tz) gettimeofday((tv), (tz))
-#define HAVE_USBI_GETTIMEOFDAY
-#endif
 #endif
 
 struct usbi_pollfd {
@@ -493,7 +554,6 @@ struct usbi_pollfd {
 
 int usbi_add_pollfd(struct libusb_context *ctx, int fd, short events);
 void usbi_remove_pollfd(struct libusb_context *ctx, int fd);
-void usbi_fd_notification(struct libusb_context *ctx);
 
 /* device discovery */
 
@@ -642,7 +702,7 @@ struct usbi_os_backend {
         * Do not worry about freeing the handle on failed open, the upper layers
         * do this for you.
         */
-       int (*open)(struct libusb_device_handle *handle);
+       int (*open)(struct libusb_device_handle *dev_handle);
 
        /* Close a device such that the handle cannot be used again. Your backend
         * should destroy any resources that were allocated in the open path.
@@ -652,7 +712,7 @@ struct usbi_os_backend {
         *
         * This function is called when the user closes a device handle.
         */
-       void (*close)(struct libusb_device_handle *handle);
+       void (*close)(struct libusb_device_handle *dev_handle);
 
        /* Retrieve the device descriptor from a device.
         *
@@ -759,7 +819,7 @@ struct usbi_os_backend {
         *   blocking
         * - another LIBUSB_ERROR code on other failure.
         */
-       int (*get_configuration)(struct libusb_device_handle *handle, int *config);
+       int (*get_configuration)(struct libusb_device_handle *dev_handle, int *config);
 
        /* Set the active configuration for a device.
         *
@@ -776,7 +836,7 @@ struct usbi_os_backend {
         *   was opened
         * - another LIBUSB_ERROR code on other failure.
         */
-       int (*set_configuration)(struct libusb_device_handle *handle, int config);
+       int (*set_configuration)(struct libusb_device_handle *dev_handle, int config);
 
        /* Claim an interface. When claimed, the application can then perform
         * I/O to an interface's endpoints.
@@ -784,7 +844,7 @@ struct usbi_os_backend {
         * This function should not generate any bus I/O and should not block.
         * Interface claiming is a logical operation that simply ensures that
         * no other drivers/applications are using the interface, and after
-        * claiming, no other drivers/applicatiosn can use the interface because
+        * claiming, no other drivers/applications can use the interface because
         * we now "own" it.
         *
         * Return:
@@ -795,7 +855,7 @@ struct usbi_os_backend {
         *   was opened
         * - another LIBUSB_ERROR code on other failure
         */
-       int (*claim_interface)(struct libusb_device_handle *handle, int interface_number);
+       int (*claim_interface)(struct libusb_device_handle *dev_handle, int interface_number);
 
        /* Release a previously claimed interface.
         *
@@ -812,7 +872,7 @@ struct usbi_os_backend {
         *   was opened
         * - another LIBUSB_ERROR code on other failure
         */
-       int (*release_interface)(struct libusb_device_handle *handle, int interface_number);
+       int (*release_interface)(struct libusb_device_handle *dev_handle, int interface_number);
 
        /* Set the alternate setting for an interface.
         *
@@ -828,7 +888,7 @@ struct usbi_os_backend {
         *   was opened
         * - another LIBUSB_ERROR code on other failure
         */
-       int (*set_interface_altsetting)(struct libusb_device_handle *handle,
+       int (*set_interface_altsetting)(struct libusb_device_handle *dev_handle,
                int interface_number, int altsetting);
 
        /* Clear a halt/stall condition on an endpoint.
@@ -842,12 +902,12 @@ struct usbi_os_backend {
         *   was opened
         * - another LIBUSB_ERROR code on other failure
         */
-       int (*clear_halt)(struct libusb_device_handle *handle,
+       int (*clear_halt)(struct libusb_device_handle *dev_handle,
                unsigned char endpoint);
 
        /* Perform a USB port reset to reinitialize a device.
         *
-        * If possible, the handle should still be usable after the reset
+        * If possible, the device handle should still be usable after the reset
         * completes, assuming that the device descriptors did not change during
         * reset and all previous interface state can be restored.
         *
@@ -861,16 +921,26 @@ struct usbi_os_backend {
         *   has been disconnected since it was opened
         * - another LIBUSB_ERROR code on other failure
         */
-       int (*reset_device)(struct libusb_device_handle *handle);
+       int (*reset_device)(struct libusb_device_handle *dev_handle);
 
        /* Alloc num_streams usb3 bulk streams on the passed in endpoints */
-       int (*alloc_streams)(struct libusb_device_handle *handle,
+       int (*alloc_streams)(struct libusb_device_handle *dev_handle,
                uint32_t num_streams, unsigned char *endpoints, int num_endpoints);
 
        /* Free usb3 bulk streams allocated with alloc_streams */
-       int (*free_streams)(struct libusb_device_handle *handle,
+       int (*free_streams)(struct libusb_device_handle *dev_handle,
                unsigned char *endpoints, int num_endpoints);
 
+       /* Allocate persistent DMA memory for the given device, suitable for
+        * zerocopy. May return NULL on failure. Optional to implement.
+        */
+       unsigned char *(*dev_mem_alloc)(struct libusb_device_handle *handle,
+               size_t len);
+
+       /* Free memory allocated by dev_mem_alloc. */
+       int (*dev_mem_free)(struct libusb_device_handle *handle,
+               unsigned char *buffer, size_t len);
+
        /* Determine if a kernel driver is active on an interface. Optional.
         *
         * The presence of a kernel driver on an interface indicates that any
@@ -883,7 +953,7 @@ struct usbi_os_backend {
         *   was opened
         * - another LIBUSB_ERROR code on other failure
         */
-       int (*kernel_driver_active)(struct libusb_device_handle *handle,
+       int (*kernel_driver_active)(struct libusb_device_handle *dev_handle,
                int interface_number);
 
        /* Detach a kernel driver from an interface. Optional.
@@ -899,7 +969,7 @@ struct usbi_os_backend {
         *   was opened
         * - another LIBUSB_ERROR code on other failure
         */
-       int (*detach_kernel_driver)(struct libusb_device_handle *handle,
+       int (*detach_kernel_driver)(struct libusb_device_handle *dev_handle,
                int interface_number);
 
        /* Attach a kernel driver to an interface. Optional.
@@ -916,7 +986,7 @@ struct usbi_os_backend {
         *   preventing reattachment
         * - another LIBUSB_ERROR code on other failure
         */
-       int (*attach_kernel_driver)(struct libusb_device_handle *handle,
+       int (*attach_kernel_driver)(struct libusb_device_handle *dev_handle,
                int interface_number);
 
        /* Destroy a device. Optional.
@@ -962,8 +1032,14 @@ struct usbi_os_backend {
         */
        void (*clear_transfer_priv)(struct usbi_transfer *itransfer);
 
-       /* Handle any pending events. This involves monitoring any active
-        * transfers and processing their completion or cancellation.
+       /* Handle any pending events on file descriptors. Optional.
+        *
+        * Provide this function when file descriptors directly indicate device
+        * or transfer activity. If your backend does not have such file descriptors,
+        * implement the handle_transfer_completion function below.
+        *
+        * This involves monitoring any active transfers and processing their
+        * completion or cancellation.
         *
         * The function is passed an array of pollfd structures (size nfds)
         * as a result of the poll() system call. The num_ready parameter
@@ -991,6 +1067,31 @@ struct usbi_os_backend {
        int (*handle_events)(struct libusb_context *ctx,
                struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready);
 
+       /* Handle transfer completion. Optional.
+        *
+        * Provide this function when there are no file descriptors available
+        * that directly indicate device or transfer activity. If your backend does
+        * have such file descriptors, implement the handle_events function above.
+        *
+        * Your backend must tell the library when a transfer has completed by
+        * calling usbi_signal_transfer_completion(). You should store any private
+        * information about the transfer and its completion status in the transfer's
+        * private backend data.
+        *
+        * During event handling, this function will be called on each transfer for
+        * which usbi_signal_transfer_completion() was called.
+        *
+        * For any cancelled transfers, call usbi_handle_transfer_cancellation().
+        * For completed transfers, call usbi_handle_transfer_completion().
+        * For control/bulk/interrupt transfers, populate the "transferred"
+        * element of the appropriate usbi_transfer structure before calling the
+        * above functions. For isochronous transfers, populate the status and
+        * transferred fields of the iso packet descriptors of the transfer.
+        *
+        * Return 0 on success, or a LIBUSB_ERROR code on failure.
+        */
+       int (*handle_transfer_completion)(struct usbi_transfer *itransfer);
+
        /* Get time from specified clock. At least two clocks must be implemented
           by the backend: USBI_CLOCK_REALTIME, and USBI_CLOCK_MONOTONIC.
 
@@ -1021,12 +1122,6 @@ struct usbi_os_backend {
         * usbi_transfer_get_os_priv() on the appropriate usbi_transfer instance.
         */
        size_t transfer_priv_size;
-
-       /* Mumber of additional bytes for os_priv for each iso packet.
-        * Can your backend use this? */
-       /* FIXME: linux can't use this any more. if other OS's cannot either,
-        * then remove this */
-       size_t add_iso_packet_size;
 };
 
 extern const struct usbi_os_backend * const usbi_backend;
@@ -1036,8 +1131,10 @@ extern const struct usbi_os_backend darwin_backend;
 extern const struct usbi_os_backend openbsd_backend;
 extern const struct usbi_os_backend netbsd_backend;
 extern const struct usbi_os_backend windows_backend;
+extern const struct usbi_os_backend usbdk_backend;
 extern const struct usbi_os_backend wince_backend;
 extern const struct usbi_os_backend haiku_usb_raw_backend;
+extern const struct usbi_os_backend sunos_backend;
 
 extern struct list_head active_contexts_list;
 extern usbi_mutex_static_t active_contexts_lock;