// globals
BOOLEAN is_polling_set = FALSE;
-#if defined(DYNAMIC_FDS)
-HANDLE fd_update = INVALID_HANDLE_VALUE; // event to notify poll of fd update
-HANDLE new_fd[MAX_FDS]; // overlapped event handles for fds created since last poll
-unsigned nb_new_fds = 0; // nb new fds created since last poll
-usbi_mutex_t new_fd_mutex; // mutex required for the above
-#endif
LONG pipe_number = 0;
static volatile LONG compat_spinlock = 0;
_poll_fd[i].thread_id = 0;
InitializeCriticalSection(&_poll_fd[i].mutex);
}
-#if defined(DYNAMIC_FDS)
- // We need to create an update event so that poll is warned when there
- // are new/deleted fds during a timeout wait operation
- fd_update = CreateEvent(NULL, TRUE, FALSE, NULL);
- if (fd_update == NULL) {
- usbi_err(NULL, "unable to create update event");
- }
- usbi_mutex_init(&new_fd_mutex, NULL);
- nb_new_fds = 0;
-#endif
is_polling_set = TRUE;
}
compat_spinlock = 0;
}
}
poll_fd[i] = INVALID_WINFD;
-#if defined(DYNAMIC_FDS)
- usbi_mutex_destroy(&new_fd_mutex);
- CloseHandle(fd_update);
- fd_update = INVALID_HANDLE_VALUE;
-#endif
LeaveCriticalSection(&_poll_fd[i].mutex);
DeleteCriticalSection(&_poll_fd[i].mutex);
}
wfd.overlapped = overlapped;
memcpy(&poll_fd[i], &wfd, sizeof(struct winfd));
LeaveCriticalSection(&_poll_fd[i].mutex);
-#if defined(DYNAMIC_FDS)
- usbi_mutex_lock(&new_fd_mutex);
- new_fd[nb_new_fds++] = overlapped->hEvent;
- usbi_mutex_unlock(&new_fd_mutex);
- // Notify poll that fds have been updated
- SetEvent(fd_update);
-#endif
return wfd;
}
}
DWORD nb_handles_to_wait_on = 0;
DWORD ret;
-#if defined(DYNAMIC_FDS)
- DWORD nb_extra_handles = 0;
- unsigned j;
-
- // To address the possibility of missing new fds between the time the new
- // pollable fd set is assembled, and the ResetEvent() call below, an
- // additional new_fd[] HANDLE table is used for any new fd that was created
- // since the last call to poll (see below)
- ResetEvent(fd_update);
-
- // At this stage, any new fd creation will be detected through the fd_update
- // event notification, and any previous creation that we may have missed
- // will be picked up through the existing new_fd[] table.
-#endif
-
CHECK_INIT_POLLING;
triggered = 0;
} else {
handles_to_wait_on[nb_handles_to_wait_on] = poll_fd[_index].overlapped->hEvent;
handle_to_index[nb_handles_to_wait_on] = i;
-#if defined(DYNAMIC_FDS)
- // If this fd from the poll set is also part of the new_fd event handle table, remove it
- usbi_mutex_lock(&new_fd_mutex);
- for (j=0; j<nb_new_fds; j++) {
- if (handles_to_wait_on[nb_handles_to_wait_on] == new_fd[j]) {
- new_fd[j] = INVALID_HANDLE_VALUE;
- break;
- }
- }
- usbi_mutex_unlock(&new_fd_mutex);
-#endif
nb_handles_to_wait_on++;
}
LeaveCriticalSection(&_poll_fd[_index].mutex);
}
-#if defined(DYNAMIC_FDS)
- // At this stage, new_fd[] should only contain events from fds that
- // have been added since the last call to poll, but are not (yet) part
- // of the pollable fd set. Typically, these would be from fds that have
- // been created between the construction of the fd set and the calling
- // of poll.
- // Event if we won't be able to return usable poll data on these events,
- // make sure we monitor them to return an EINTR code
- usbi_mutex_lock(&new_fd_mutex); // We could probably do without
- for (i=0; i<nb_new_fds; i++) {
- if (new_fd[i] != INVALID_HANDLE_VALUE) {
- handles_to_wait_on[nb_handles_to_wait_on++] = new_fd[i];
- nb_extra_handles++;
- }
- }
- usbi_mutex_unlock(&new_fd_mutex);
- poll_dbg("dynamic_fds: added %d extra handles", nb_extra_handles);
-#endif
// If nothing was triggered, wait on all fds that require it
if ((timeout != 0) && (triggered == 0) && (nb_handles_to_wait_on != 0)) {
-#if defined(DYNAMIC_FDS)
- // Register for fd update notifications
- handles_to_wait_on[nb_handles_to_wait_on++] = fd_update;
- nb_extra_handles++;
-#endif
if (timeout < 0) {
poll_dbg("starting infinite wait for %d handles...", (int)nb_handles_to_wait_on);
} else {
FALSE, (timeout<0)?INFINITE:(DWORD)timeout);
object_index = ret-WAIT_OBJECT_0;
if ((object_index >= 0) && ((DWORD)object_index < nb_handles_to_wait_on)) {
-#if defined(DYNAMIC_FDS)
- if ((DWORD)object_index >= (nb_handles_to_wait_on-nb_extra_handles)) {
- // Detected fd update => flag a poll interruption
- if ((DWORD)object_index == (nb_handles_to_wait_on-1))
- poll_dbg(" dynamic_fds: fd_update event");
- else
- poll_dbg(" dynamic_fds: new fd I/O event");
- errno = EINTR;
- triggered = -1;
- goto poll_exit;
- }
-#endif
poll_dbg(" completed after wait");
i = handle_to_index[object_index];
_index = _fd_to_index_and_lock(fds[i].fd);
if (handle_to_index != NULL) {
free(handle_to_index);
}
-#if defined(DYNAMIC_FDS)
- usbi_mutex_lock(&new_fd_mutex);
- nb_new_fds = 0;
- usbi_mutex_unlock(&new_fd_mutex);
-#endif
return triggered;
}
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-// COMPILATION OPTIONS:
-// - Should libusbx automatically claim (and release) the interfaces it requires?
-#define AUTO_CLAIM
-// - Forces instant overlapped completion on timeouts: can prevents extensive
-// wait in poll, after a timeout, but might affect subsequent API calls.
-// ***USE AT YOUR OWN RISKS***
-//#define FORCE_INSTANT_TIMEOUTS
-
#include <config.h>
#include <windows.h>
#include <setupapi.h>
enum windows_version windows_version = WINDOWS_UNSUPPORTED;
// Concurrency
static int concurrent_usage = -1;
-#if defined(AUTO_CLAIM)
usbi_mutex_t autoclaim_lock;
-#endif
// Timer thread
// NB: index 0 is for monotonic and 1 is for the thread exit event
HANDLE timer_thread = NULL;
/*
* auto-claiming and auto-release helper functions
*/
-#if defined(AUTO_CLAIM)
static int auto_claim(struct libusb_transfer *transfer, int *interface_number, int api_type)
{
struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
}
usbi_mutex_unlock(&autoclaim_lock);
}
-#endif
-
/*
* init: libusbx backend init function
goto init_exit;
}
-#if defined(AUTO_CLAIM)
// We need a lock for proper auto-release
usbi_mutex_init(&autoclaim_lock, NULL);
-#endif
// Initialize pollable file descriptors
init_polling();
struct windows_transfer_priv *transfer_priv = (struct windows_transfer_priv*)usbi_transfer_get_os_priv(itransfer);
usbi_free_fd(transfer_priv->pollable_fd.fd);
-#if defined(AUTO_CLAIM)
// When auto claim is in use, attempt to release the auto-claimed interface
auto_release(itransfer);
-#endif
}
static int submit_bulk_transfer(struct usbi_transfer *itransfer)
usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd,
(short)(IS_XFERIN(transfer) ? POLLIN : POLLOUT));
-#if !defined(DYNAMIC_FDS)
- usbi_fd_notification(ctx);
-#endif
return LIBUSB_SUCCESS;
}
usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd,
(short)(IS_XFERIN(transfer) ? POLLIN : POLLOUT));
-#if !defined(DYNAMIC_FDS)
- usbi_fd_notification(ctx);
-#endif
return LIBUSB_SUCCESS;
}
}
usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, POLLIN);
-#if !defined(DYNAMIC_FDS)
- usbi_fd_notification(ctx);
-#endif
return LIBUSB_SUCCESS;
static int windows_cancel_transfer(struct usbi_transfer *itransfer)
{
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
-#if defined(FORCE_INSTANT_TIMEOUTS)
- struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
- // Forces instant overlapped completion on timeouts - use at your own risks
- if (itransfer->flags & USBI_TRANSFER_TIMED_OUT) {
- transfer_priv->pollable_fd.overlapped->Internal &= ~STATUS_PENDING;
- }
-#endif
switch (transfer->type) {
case LIBUSB_TRANSFER_TYPE_CONTROL:
return windows_abort_control(itransfer);
// It is a requirement for multiple interface devices using WinUSB that you
// must first claim the first interface before you claim any other
if ((winusb_handle == 0) || (winusb_handle == INVALID_HANDLE_VALUE)) {
-#if defined(AUTO_CLAIM)
file_handle = handle_priv->interface_handle[0].dev_handle;
if (WinUsb_Initialize(file_handle, &winusb_handle)) {
handle_priv->interface_handle[0].api_handle = winusb_handle;
usbi_warn(ctx, "failed to auto-claim interface 0 (required to claim %d with WinUSB)", iface);
return LIBUSB_ERROR_ACCESS;
}
-#else
- usbi_warn(ctx, "you must claim interface 0 before you can claim %d with WinUSB", iface);
- return LIBUSB_ERROR_ACCESS;
-#endif
}
if (!WinUsb_GetAssociatedInterface(winusb_handle, (UCHAR)(iface-1),
&handle_priv->interface_handle[iface].api_handle)) {
current_interface = winusb_get_valid_interface(transfer->dev_handle);
if (current_interface < 0) {
-#if defined(AUTO_CLAIM)
if (auto_claim(transfer, ¤t_interface, USB_API_WINUSB) != LIBUSB_SUCCESS) {
return LIBUSB_ERROR_NOT_FOUND;
}
-#else
- usbi_warn(ctx, "no interface available for control transfer");
- return LIBUSB_ERROR_NOT_FOUND;
-#endif
}
usbi_dbg("will use interface %d", current_interface);