Add libusb and libuvc
[rtmpclient.git] / app / src / main / jni / libusb-1.0.22 / libusb / os / poll_windows.c
diff --git a/app/src/main/jni/libusb-1.0.22/libusb/os/poll_windows.c b/app/src/main/jni/libusb-1.0.22/libusb/os/poll_windows.c
new file mode 100644 (file)
index 0000000..4d28333
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+ * poll_windows: poll compatibility wrapper for Windows
+ * Copyright © 2017 Chris Dickens <christopher.a.dickens@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+/*
+ * poll() and pipe() Windows compatibility layer for libusb 1.0
+ *
+ * The way this layer works is by using OVERLAPPED with async I/O transfers, as
+ * OVERLAPPED have an associated event which is flagged for I/O completion.
+ *
+ * For USB pollable async I/O, you would typically:
+ * - obtain a Windows HANDLE to a file or device that has been opened in
+ *   OVERLAPPED mode
+ * - call usbi_create_fd with this handle to obtain a custom fd.
+ * - leave the core functions call the poll routine and flag POLLIN/POLLOUT
+ *
+ * The pipe pollable synchronous I/O works using the overlapped event associated
+ * with a fake pipe. The read/write functions are only meant to be used in that
+ * context.
+ */
+#include <config.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "libusbi.h"
+#include "windows_common.h"
+
+// public fd data
+const struct winfd INVALID_WINFD = { -1, NULL };
+
+// private data
+struct file_descriptor {
+       enum fd_type { FD_TYPE_PIPE, FD_TYPE_TRANSFER } type;
+       OVERLAPPED overlapped;
+};
+
+static usbi_mutex_static_t fd_table_lock = USBI_MUTEX_INITIALIZER;
+static struct file_descriptor *fd_table[MAX_FDS];
+
+static struct file_descriptor *create_fd(enum fd_type type)
+{
+       struct file_descriptor *fd = calloc(1, sizeof(*fd));
+       if (fd == NULL)
+               return NULL;
+       fd->overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+       if (fd->overlapped.hEvent == NULL) {
+               free(fd);
+               return NULL;
+       }
+       fd->type = type;
+       return fd;
+}
+
+static void free_fd(struct file_descriptor *fd)
+{
+       CloseHandle(fd->overlapped.hEvent);
+       free(fd);
+}
+
+/*
+ * Create both an fd and an OVERLAPPED, so that it can be used with our
+ * polling function
+ * The handle MUST support overlapped transfers (usually requires CreateFile
+ * with FILE_FLAG_OVERLAPPED)
+ * Return a pollable file descriptor struct, or INVALID_WINFD on error
+ *
+ * Note that the fd returned by this function is a per-transfer fd, rather
+ * than a per-session fd and cannot be used for anything else but our
+ * custom functions.
+ * if you plan to do R/W on the same handle, you MUST create 2 fds: one for
+ * read and one for write. Using a single R/W fd is unsupported and will
+ * produce unexpected results
+ */
+struct winfd usbi_create_fd(void)
+{
+       struct file_descriptor *fd;
+       struct winfd wfd;
+
+       fd = create_fd(FD_TYPE_TRANSFER);
+       if (fd == NULL)
+               return INVALID_WINFD;
+
+       usbi_mutex_static_lock(&fd_table_lock);
+       for (wfd.fd = 0; wfd.fd < MAX_FDS; wfd.fd++) {
+               if (fd_table[wfd.fd] != NULL)
+                       continue;
+               fd_table[wfd.fd] = fd;
+               break;
+       }
+       usbi_mutex_static_unlock(&fd_table_lock);
+
+       if (wfd.fd == MAX_FDS) {
+               free_fd(fd);
+               return INVALID_WINFD;
+       }
+
+       wfd.overlapped = &fd->overlapped;
+
+       return wfd;
+}
+
+static int check_pollfds(struct pollfd *fds, unsigned int nfds,
+       HANDLE *wait_handles, DWORD *nb_wait_handles)
+{
+       struct file_descriptor *fd;
+       unsigned int n;
+       int nready = 0;
+
+       usbi_mutex_static_lock(&fd_table_lock);
+
+       for (n = 0; n < nfds; ++n) {
+               fds[n].revents = 0;
+
+               // Keep it simple - only allow either POLLIN *or* POLLOUT
+               assert((fds[n].events == POLLIN) || (fds[n].events == POLLOUT));
+               if ((fds[n].events != POLLIN) && (fds[n].events != POLLOUT)) {
+                       fds[n].revents = POLLNVAL;
+                       nready++;
+                       continue;
+               }
+
+               if ((fds[n].fd >= 0) && (fds[n].fd < MAX_FDS))
+                       fd = fd_table[fds[n].fd];
+               else
+                       fd = NULL;
+
+               assert(fd != NULL);
+               if (fd == NULL) {
+                       fds[n].revents = POLLNVAL;
+                       nready++;
+                       continue;
+               }
+
+               if (HasOverlappedIoCompleted(&fd->overlapped)
+                               && (WaitForSingleObject(fd->overlapped.hEvent, 0) == WAIT_OBJECT_0)) {
+                       fds[n].revents = fds[n].events;
+                       nready++;
+               } else if (wait_handles != NULL) {
+                       if (*nb_wait_handles == MAXIMUM_WAIT_OBJECTS) {
+                               usbi_warn(NULL, "too many HANDLEs to wait on");
+                               continue;
+                       }
+                       wait_handles[*nb_wait_handles] = fd->overlapped.hEvent;
+                       (*nb_wait_handles)++;
+               }
+       }
+
+       usbi_mutex_static_unlock(&fd_table_lock);
+
+       return nready;
+}
+/*
+ * POSIX poll equivalent, using Windows OVERLAPPED
+ * Currently, this function only accepts one of POLLIN or POLLOUT per fd
+ * (but you can create multiple fds from the same handle for read and write)
+ */
+int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout)
+{
+       HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
+       DWORD nb_wait_handles = 0;
+       DWORD ret;
+       int nready;
+
+       nready = check_pollfds(fds, nfds, wait_handles, &nb_wait_handles);
+
+       // If nothing was triggered, wait on all fds that require it
+       if ((nready == 0) && (nb_wait_handles != 0) && (timeout != 0)) {
+               ret = WaitForMultipleObjects(nb_wait_handles, wait_handles,
+                       FALSE, (timeout < 0) ? INFINITE : (DWORD)timeout);
+               if (ret < (WAIT_OBJECT_0 + nb_wait_handles)) {
+                       nready = check_pollfds(fds, nfds, NULL, NULL);
+               } else if (ret != WAIT_TIMEOUT) {
+                       if (ret == WAIT_FAILED)
+                               usbi_err(NULL, "WaitForMultipleObjects failed: %u", (unsigned int)GetLastError());
+                       nready = -1;
+               }
+       }
+
+       return nready;
+}
+
+/*
+ * close a fake file descriptor
+ */
+int usbi_close(int _fd)
+{
+       struct file_descriptor *fd;
+
+       if (_fd < 0 || _fd >= MAX_FDS)
+               goto err_badfd;
+
+       usbi_mutex_static_lock(&fd_table_lock);
+       fd = fd_table[_fd];
+       fd_table[_fd] = NULL;
+       usbi_mutex_static_unlock(&fd_table_lock);
+
+       if (fd == NULL)
+               goto err_badfd;
+
+       if (fd->type == FD_TYPE_PIPE) {
+               // InternalHigh is our reference count
+               fd->overlapped.InternalHigh--;
+               if (fd->overlapped.InternalHigh == 0)
+                       free_fd(fd);
+       } else {
+               free_fd(fd);
+       }
+
+       return 0;
+
+err_badfd:
+       errno = EBADF;
+       return -1;
+}
+
+/*
+* Create a fake pipe.
+* As libusb only uses pipes for signaling, all we need from a pipe is an
+* event. To that extent, we create a single wfd and overlapped as a means
+* to access that event.
+*/
+int usbi_pipe(int filedes[2])
+{
+       struct file_descriptor *fd;
+       int r_fd = -1, w_fd = -1;
+       int i;
+
+       fd = create_fd(FD_TYPE_PIPE);
+       if (fd == NULL) {
+               errno = ENOMEM;
+               return -1;
+       }
+
+       // Use InternalHigh as a reference count
+       fd->overlapped.Internal = STATUS_PENDING;
+       fd->overlapped.InternalHigh = 2;
+
+       usbi_mutex_static_lock(&fd_table_lock);
+       do {
+               for (i = 0; i < MAX_FDS; i++) {
+                       if (fd_table[i] != NULL)
+                               continue;
+                       if (r_fd == -1) {
+                               r_fd = i;
+                       } else if (w_fd == -1) {
+                               w_fd = i;
+                               break;
+                       }
+               }
+
+               if (i == MAX_FDS)
+                       break;
+
+               fd_table[r_fd] = fd;
+               fd_table[w_fd] = fd;
+
+       } while (0);
+       usbi_mutex_static_unlock(&fd_table_lock);
+
+       if (i == MAX_FDS) {
+               free_fd(fd);
+               errno = EMFILE;
+               return -1;
+       }
+
+       filedes[0] = r_fd;
+       filedes[1] = w_fd;
+
+       return 0;
+}
+
+/*
+ * synchronous write for fake "pipe" signaling
+ */
+ssize_t usbi_write(int fd, const void *buf, size_t count)
+{
+       int error = EBADF;
+
+       UNUSED(buf);
+
+       if (fd < 0 || fd >= MAX_FDS)
+               goto err_out;
+
+       if (count != sizeof(unsigned char)) {
+               usbi_err(NULL, "this function should only used for signaling");
+               error = EINVAL;
+               goto err_out;
+       }
+
+       usbi_mutex_static_lock(&fd_table_lock);
+       if ((fd_table[fd] != NULL) && (fd_table[fd]->type == FD_TYPE_PIPE)) {
+               assert(fd_table[fd]->overlapped.Internal == STATUS_PENDING);
+               assert(fd_table[fd]->overlapped.InternalHigh == 2);
+               fd_table[fd]->overlapped.Internal = STATUS_WAIT_0;
+               SetEvent(fd_table[fd]->overlapped.hEvent);
+               error = 0;
+       }
+       usbi_mutex_static_unlock(&fd_table_lock);
+
+       if (error)
+               goto err_out;
+
+       return sizeof(unsigned char);
+
+err_out:
+       errno = error;
+       return -1;
+}
+
+/*
+ * synchronous read for fake "pipe" signaling
+ */
+ssize_t usbi_read(int fd, void *buf, size_t count)
+{
+       int error = EBADF;
+
+       UNUSED(buf);
+
+       if (fd < 0 || fd >= MAX_FDS)
+               goto err_out;
+
+       if (count != sizeof(unsigned char)) {
+               usbi_err(NULL, "this function should only used for signaling");
+               error = EINVAL;
+               goto err_out;
+       }
+
+       usbi_mutex_static_lock(&fd_table_lock);
+       if ((fd_table[fd] != NULL) && (fd_table[fd]->type == FD_TYPE_PIPE)) {
+               assert(fd_table[fd]->overlapped.Internal == STATUS_WAIT_0);
+               assert(fd_table[fd]->overlapped.InternalHigh == 2);
+               fd_table[fd]->overlapped.Internal = STATUS_PENDING;
+               ResetEvent(fd_table[fd]->overlapped.hEvent);
+               error = 0;
+       }
+       usbi_mutex_static_unlock(&fd_table_lock);
+
+       if (error)
+               goto err_out;
+
+       return sizeof(unsigned char);
+
+err_out:
+       errno = error;
+       return -1;
+}