diff options
author | Pete Batard <pbatard@gmail.com> | 2010-03-15 17:24:05 +0000 |
---|---|---|
committer | Pete Batard <pbatard@gmail.com> | 2010-03-15 17:24:05 +0000 |
commit | 5859a25c16345366831d40d79de7fb72ebda4485 (patch) | |
tree | 4e7ab9488314091b9975bf2748f49423cd6ec535 /libusb/os | |
parent | 9194f49c8495aae1ba864f1f864e8d1ecb530c50 (diff) | |
download | libusb-a170.tar.gz |
merge r205-207a170
Diffstat (limited to 'libusb/os')
-rw-r--r-- | libusb/os/poll_windows.c | 38 | ||||
-rw-r--r-- | libusb/os/poll_windows.h | 8 | ||||
-rw-r--r-- | libusb/os/windows_usb.c | 29 |
3 files changed, 55 insertions, 20 deletions
diff --git a/libusb/os/poll_windows.c b/libusb/os/poll_windows.c index 3bbe615..0d8d487 100644 --- a/libusb/os/poll_windows.c +++ b/libusb/os/poll_windows.c @@ -117,13 +117,15 @@ static inline int _open_osfhandle(intptr_t osfhandle, int flags) #define CHECK_INIT_POLLING do {if(!is_polling_set) init_polling();} while(0) // public fd data -const struct winfd INVALID_WINFD = {-1, NULL, NULL, RW_NONE, FALSE}; +const struct winfd INVALID_WINFD = {-1, NULL, NULL, RW_NONE}; struct winfd poll_fd[MAX_FDS]; // internal fd data struct { CRITICAL_SECTION mutex; // lock for fds BYTE marker; // 1st byte of a usbi_read operation gets stored here - + // Additional variables for XP CancelIoEx partial emulation + HANDLE original_handle; + DWORD thread_id; } _poll_fd[MAX_FDS]; // globals @@ -146,11 +148,19 @@ __inline BOOL cancel_io(int index) if ((index < 0) || (index >= MAX_FDS)) { return FALSE; } + + if ( (poll_fd[index].fd < 0) || (poll_fd[index].handle == INVALID_HANDLE_VALUE) + || (poll_fd[index].handle == 0) || (poll_fd[index].overlapped == NULL) ) { + return TRUE; + } if (pCancelIoEx != NULL) { return (*pCancelIoEx)(poll_fd[index].handle, poll_fd[index].overlapped); - } else { + } + if (_poll_fd[index].thread_id == GetCurrentThreadId()) { return CancelIo(poll_fd[index].handle); } + usbi_warn(NULL, "Unable to cancel I/O that was started from another thread"); + return FALSE; } // Init @@ -169,6 +179,8 @@ void init_polling(void) for (i=0; i<MAX_FDS; i++) { poll_fd[i] = INVALID_WINFD; _poll_fd[i].marker = 0; + _poll_fd[i].original_handle = INVALID_HANDLE_VALUE; + _poll_fd[i].thread_id = 0; InitializeCriticalSection(&_poll_fd[i].mutex); } #if defined(DYNAMIC_FDS) @@ -385,7 +397,6 @@ int usbi_pipe(int filedes[2]) poll_fd[i].handle = handle[j]; poll_fd[i].overlapped = (j==0)?overlapped0:overlapped1; poll_fd[i].rw = RW_READ+j; - poll_fd[i].completed_synchronously = FALSE; j++; if (j==1) { // Start a 1 byte nonblocking read operation @@ -471,7 +482,19 @@ struct winfd usbi_create_fd(HANDLE handle, int access_mode) continue; } wfd.fd = fd; - wfd.handle = handle; + // Attempt to emulate some of the CancelIoEx behaviour on platforms + // that don't have it + if (pCancelIoEx == NULL) { + _poll_fd[i].thread_id = GetCurrentThreadId(); + _poll_fd[i].original_handle = handle; + if (!DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(), + &wfd.handle, 0, TRUE, DUPLICATE_SAME_ACCESS)) { + usbi_warn(NULL, "could not duplicate handle for CancelIo - using orignal one"); + wfd.handle = handle; + } + } else { + wfd.handle = handle; + } wfd.overlapped = overlapped; memcpy(&poll_fd[i], &wfd, sizeof(struct winfd)); LeaveCriticalSection(&_poll_fd[i].mutex); @@ -500,6 +523,9 @@ void _free_index(int index) _close(poll_fd[index].fd); } free_overlapped(poll_fd[index].overlapped); + CloseHandle(_poll_fd[index].original_handle); + _poll_fd[index].original_handle = INVALID_HANDLE_VALUE; + _poll_fd[index].thread_id = 0; poll_fd[index] = INVALID_WINFD; } @@ -691,7 +717,7 @@ int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout) // The following macro only works if overlapped I/O was reported pending if ( (HasOverlappedIoCompleted(poll_fd[index].overlapped)) - || (poll_fd[index].completed_synchronously) ) { + || (HasOverlappedIoCompletedSync(poll_fd[index].overlapped)) ) { poll_dbg(" completed"); // checks above should ensure this works: fds[i].revents = fds[i].events; diff --git a/libusb/os/poll_windows.h b/libusb/os/poll_windows.h index 0da805b..97259e9 100644 --- a/libusb/os/poll_windows.h +++ b/libusb/os/poll_windows.h @@ -39,6 +39,13 @@ #endif #endif +// Handle synchronous completion through the overlapped structure +#if !defined(STATUS_REPARSE) // reuse the REPARSE status code +#define STATUS_REPARSE ((LONG)0x00000104L) +#endif +#define STATUS_COMPLETED_SYNCHRONOUSLY STATUS_REPARSE +#define HasOverlappedIoCompletedSync(lpOverlapped) (((DWORD)(lpOverlapped)->Internal) == STATUS_COMPLETED_SYNCHRONOUSLY) + enum windows_version { WINDOWS_UNSUPPORTED, WINDOWS_XP, @@ -77,7 +84,6 @@ struct winfd { HANDLE handle; // what we need to attach overlapped to the I/O op, so we can poll it OVERLAPPED* overlapped; // what will report our I/O status enum rw_type rw; // I/O transfer direction: read *XOR* write (NOT BOTH) - BOOLEAN completed_synchronously;// flag for async transfers that completed during request }; extern const struct winfd INVALID_WINFD; diff --git a/libusb/os/windows_usb.c b/libusb/os/windows_usb.c index fe7961e..a81673a 100644 --- a/libusb/os/windows_usb.c +++ b/libusb/os/windows_usb.c @@ -1933,10 +1933,10 @@ static int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds, if (found) { // Handle async requests that completed synchronously first - if (transfer_priv->pollable_fd.completed_synchronously) { + if (HasOverlappedIoCompletedSync(transfer_priv->pollable_fd.overlapped)) { io_result = NO_ERROR; io_size = (DWORD)transfer_priv->pollable_fd.overlapped->InternalHigh; - // Regular saync overlapped + // Regular async overlapped } else if (GetOverlappedResult(transfer_priv->pollable_fd.handle, transfer_priv->pollable_fd.overlapped, &io_size, false)) { io_result = NO_ERROR; @@ -2555,6 +2555,7 @@ static int winusb_submit_control_transfer(struct usbi_transfer *itransfer) winusb_handle = handle_priv->interface_handle[current_interface].api_handle; wfd = usbi_create_fd(winusb_handle, _O_RDONLY); + // Always use the handle returned from usbi_create_fd (wfd.handle) if (wfd.fd < 0) { return LIBUSB_ERROR_NO_MEM; } @@ -2566,7 +2567,7 @@ static int winusb_submit_control_transfer(struct usbi_transfer *itransfer) return LIBUSB_ERROR_IO; } } else { - wfd.completed_synchronously = true; + wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; wfd.overlapped->InternalHigh = (DWORD)size; } @@ -2631,16 +2632,17 @@ static int winusb_submit_bulk_transfer(struct usbi_transfer *itransfer) direction_in = transfer->endpoint & LIBUSB_ENDPOINT_IN; wfd = usbi_create_fd(winusb_handle, direction_in?_O_RDONLY:_O_WRONLY); + // Always use the handle returned from usbi_create_fd (wfd.handle) if (wfd.fd < 0) { return LIBUSB_ERROR_NO_MEM; } if (direction_in) { usbi_dbg("reading %d bytes", transfer->length); - ret = WinUsb_ReadPipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, wfd.overlapped); + ret = WinUsb_ReadPipe(wfd.handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, wfd.overlapped); } else { usbi_dbg("writing %d bytes", transfer->length); - ret = WinUsb_WritePipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, wfd.overlapped); + ret = WinUsb_WritePipe(wfd.handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, wfd.overlapped); } if (!ret) { if(GetLastError() != ERROR_IO_PENDING) { @@ -2649,7 +2651,7 @@ static int winusb_submit_bulk_transfer(struct usbi_transfer *itransfer) return LIBUSB_ERROR_IO; } } else { - wfd.completed_synchronously = true; + wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; wfd.overlapped->InternalHigh = (DWORD)transfer->length; } @@ -3593,7 +3595,7 @@ static int hid_submit_control_transfer(struct usbi_transfer *itransfer) usbi_dbg("will use interface %d", current_interface); hid_handle = handle_priv->interface_handle[current_interface].api_handle; - + // Always use the handle returned from usbi_create_fd (wfd.handle) wfd = usbi_create_fd(hid_handle, _O_RDONLY); if (wfd.fd < 0) { return LIBUSB_ERROR_NO_MEM; @@ -3603,7 +3605,7 @@ static int hid_submit_control_transfer(struct usbi_transfer *itransfer) case LIBUSB_REQUEST_TYPE_STANDARD: switch(setup->request) { case LIBUSB_REQUEST_GET_DESCRIPTOR: - r = _hid_get_descriptor(priv->hid, hid_handle, LIBUSB_REQ_RECIPIENT(setup->request_type), + r = _hid_get_descriptor(priv->hid, wfd.handle, LIBUSB_REQ_RECIPIENT(setup->request_type), (setup->value >> 8) & 0xFF, setup->value & 0xFF, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, &size); break; case LIBUSB_REQUEST_GET_CONFIGURATION: @@ -3638,7 +3640,7 @@ static int hid_submit_control_transfer(struct usbi_transfer *itransfer) } break; case LIBUSB_REQUEST_TYPE_CLASS: - r =_hid_class_request(priv->hid, hid_handle, setup->request_type, setup->request, setup->value, + r =_hid_class_request(priv->hid, wfd.handle, setup->request_type, setup->request, setup->value, setup->index, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, transfer_priv, &size, wfd.overlapped); break; @@ -3649,7 +3651,7 @@ static int hid_submit_control_transfer(struct usbi_transfer *itransfer) if (r == LIBUSB_COMPLETED) { // Force request to be completed synchronously. Transferred size has been set by previous call - wfd.completed_synchronously = true; + wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; // http://msdn.microsoft.com/en-us/library/ms684342%28VS.85%29.aspx // set InternalHigh to the number of bytes transferred wfd.overlapped->InternalHigh = (DWORD)size; @@ -3697,6 +3699,7 @@ static int hid_submit_bulk_transfer(struct usbi_transfer *itransfer) { direction_in = transfer->endpoint & LIBUSB_ENDPOINT_IN; wfd = usbi_create_fd(hid_handle, direction_in?_O_RDONLY:_O_WRONLY); + // Always use the handle returned from usbi_create_fd (wfd.handle) if (wfd.fd < 0) { return LIBUSB_ERROR_NO_MEM; } @@ -3709,13 +3712,13 @@ static int hid_submit_bulk_transfer(struct usbi_transfer *itransfer) { if (direction_in) { transfer_priv->hid_buffer[0] = priv->hid->input_report_id; usbi_dbg("reading %d bytes (report ID: 0x%02X)", transfer->length+1, transfer_priv->hid_buffer[0]); - ret = ReadFile(hid_handle, transfer_priv->hid_buffer, transfer->length+1, &size, wfd.overlapped); + ret = ReadFile(wfd.handle, transfer_priv->hid_buffer, transfer->length+1, &size, wfd.overlapped); } else { transfer_priv->hid_buffer[0] = priv->hid->output_report_id; memcpy(transfer_priv->hid_buffer+1, transfer->buffer, transfer->length); usbi_dbg("writing %d bytes (report ID: 0x%02X)", transfer->length+1, transfer_priv->hid_buffer[0]); transfer_priv->hid_buffer[0] = 0; - ret = WriteFile(hid_handle, transfer_priv->hid_buffer, transfer->length+1, &size, wfd.overlapped); + ret = WriteFile(wfd.handle, transfer_priv->hid_buffer, transfer->length+1, &size, wfd.overlapped); } if (!ret) { if (GetLastError() != ERROR_IO_PENDING) { @@ -3738,7 +3741,7 @@ static int hid_submit_bulk_transfer(struct usbi_transfer *itransfer) { usbi_err(ctx, "OVERFLOW!"); r = LIBUSB_ERROR_OVERFLOW; } - wfd.completed_synchronously = true; + wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; wfd.overlapped->InternalHigh = size; } |