2013-09-30 18:36:54 +13:00
|
|
|
/*
|
2014-12-27 15:39:17 +01:00
|
|
|
* Windows CE backend for libusb 1.0
|
2013-09-30 18:36:54 +13:00
|
|
|
* Copyright © 2011-2013 RealVNC Ltd.
|
|
|
|
* Large portions taken from Windows backend, which is
|
|
|
|
* Copyright © 2009-2010 Pete Batard <pbatard@gmail.com>
|
|
|
|
* With contributions from Michael Plante, Orin Eman et al.
|
|
|
|
* Parts of this code adapted from libusb-win32-v1 by Stephan Meyer
|
|
|
|
* Major code testing contribution by Xiaofan Chen
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
2016-08-25 18:27:40 -07:00
|
|
|
#include <config.h>
|
2013-09-30 18:36:54 +13:00
|
|
|
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <inttypes.h>
|
|
|
|
|
2016-08-25 18:27:40 -07:00
|
|
|
#include "libusbi.h"
|
2013-09-30 18:36:54 +13:00
|
|
|
#include "wince_usb.h"
|
|
|
|
|
|
|
|
// Global variables
|
2019-05-01 11:47:48 +02:00
|
|
|
int errno = 0;
|
2016-11-20 14:07:07 +01:00
|
|
|
static uint64_t hires_frequency, hires_ticks_to_ps;
|
|
|
|
static HANDLE driver_handle = INVALID_HANDLE_VALUE;
|
2013-09-30 18:36:54 +13:00
|
|
|
static int concurrent_usage = -1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Converts a windows error to human readable string
|
|
|
|
* uses retval as errorcode, or, if 0, use GetLastError()
|
|
|
|
*/
|
|
|
|
#if defined(ENABLE_LOGGING)
|
2019-05-01 11:47:48 +02:00
|
|
|
static const char *windows_error_str(DWORD error_code)
|
2013-09-30 18:36:54 +13:00
|
|
|
{
|
|
|
|
static TCHAR wErr_string[ERR_BUFFER_SIZE];
|
|
|
|
static char err_string[ERR_BUFFER_SIZE];
|
|
|
|
|
|
|
|
DWORD size;
|
2019-05-01 11:47:48 +02:00
|
|
|
int len;
|
2013-09-30 18:36:54 +13:00
|
|
|
|
2019-05-01 11:47:48 +02:00
|
|
|
if (error_code == 0)
|
|
|
|
error_code = GetLastError();
|
2016-08-25 18:27:40 -07:00
|
|
|
|
2019-05-01 11:47:48 +02:00
|
|
|
len = sprintf(err_string, "[%u] ", (unsigned int)error_code);
|
2016-08-25 18:27:40 -07:00
|
|
|
|
2019-05-01 11:47:48 +02:00
|
|
|
size = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
|
|
NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
|
|
wErr_string, ERR_BUFFER_SIZE, NULL);
|
2013-09-30 18:36:54 +13:00
|
|
|
if (size == 0) {
|
2019-05-01 11:47:48 +02:00
|
|
|
DWORD format_error = GetLastError();
|
2013-09-30 18:36:54 +13:00
|
|
|
if (format_error)
|
2019-05-01 11:47:48 +02:00
|
|
|
snprintf(err_string, ERR_BUFFER_SIZE,
|
|
|
|
"Windows error code %u (FormatMessage error code %u)",
|
2016-11-20 14:07:07 +01:00
|
|
|
(unsigned int)error_code, (unsigned int)format_error);
|
2013-09-30 18:36:54 +13:00
|
|
|
else
|
2019-05-01 11:47:48 +02:00
|
|
|
snprintf(err_string, ERR_BUFFER_SIZE, "Unknown error code %u", (unsigned int)error_code);
|
2013-09-30 18:36:54 +13:00
|
|
|
} else {
|
2019-05-01 11:47:48 +02:00
|
|
|
// Remove CR/LF terminators, if present
|
|
|
|
size_t pos = size - 2;
|
|
|
|
if (wErr_string[pos] == 0x0D)
|
|
|
|
wErr_string[pos] = 0;
|
2016-11-20 14:07:07 +01:00
|
|
|
|
2019-05-01 11:47:48 +02:00
|
|
|
if (!WideCharToMultiByte(CP_ACP, 0, wErr_string, -1, &err_string[len], ERR_BUFFER_SIZE - len, NULL, NULL))
|
|
|
|
strcpy(err_string, "Unable to convert error string");
|
|
|
|
}
|
2016-11-20 14:07:07 +01:00
|
|
|
|
2013-09-30 18:36:54 +13:00
|
|
|
return err_string;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static struct wince_device_priv *_device_priv(struct libusb_device *dev)
|
|
|
|
{
|
2016-11-20 14:07:07 +01:00
|
|
|
return (struct wince_device_priv *)dev->os_priv;
|
2013-09-30 18:36:54 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
// ceusbkwrapper to libusb error code mapping
|
2016-11-20 14:07:07 +01:00
|
|
|
static int translate_driver_error(DWORD error)
|
2013-09-30 18:36:54 +13:00
|
|
|
{
|
|
|
|
switch (error) {
|
2016-11-20 14:07:07 +01:00
|
|
|
case ERROR_INVALID_PARAMETER:
|
|
|
|
return LIBUSB_ERROR_INVALID_PARAM;
|
|
|
|
case ERROR_CALL_NOT_IMPLEMENTED:
|
|
|
|
case ERROR_NOT_SUPPORTED:
|
|
|
|
return LIBUSB_ERROR_NOT_SUPPORTED;
|
|
|
|
case ERROR_NOT_ENOUGH_MEMORY:
|
|
|
|
return LIBUSB_ERROR_NO_MEM;
|
|
|
|
case ERROR_INVALID_HANDLE:
|
|
|
|
return LIBUSB_ERROR_NO_DEVICE;
|
|
|
|
case ERROR_BUSY:
|
|
|
|
return LIBUSB_ERROR_BUSY;
|
|
|
|
|
|
|
|
// Error codes that are either unexpected, or have
|
|
|
|
// no suitable LIBUSB_ERROR equivalent.
|
|
|
|
case ERROR_CANCELLED:
|
|
|
|
case ERROR_INTERNAL_ERROR:
|
|
|
|
default:
|
|
|
|
return LIBUSB_ERROR_OTHER;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-01 11:47:48 +02:00
|
|
|
static BOOL init_dllimports(void)
|
2016-11-20 14:07:07 +01:00
|
|
|
{
|
|
|
|
DLL_GET_HANDLE(ceusbkwrapper);
|
|
|
|
DLL_LOAD_FUNC(ceusbkwrapper, UkwOpenDriver, TRUE);
|
|
|
|
DLL_LOAD_FUNC(ceusbkwrapper, UkwGetDeviceList, TRUE);
|
|
|
|
DLL_LOAD_FUNC(ceusbkwrapper, UkwReleaseDeviceList, TRUE);
|
|
|
|
DLL_LOAD_FUNC(ceusbkwrapper, UkwGetDeviceAddress, TRUE);
|
|
|
|
DLL_LOAD_FUNC(ceusbkwrapper, UkwGetDeviceDescriptor, TRUE);
|
|
|
|
DLL_LOAD_FUNC(ceusbkwrapper, UkwGetConfigDescriptor, TRUE);
|
|
|
|
DLL_LOAD_FUNC(ceusbkwrapper, UkwCloseDriver, TRUE);
|
|
|
|
DLL_LOAD_FUNC(ceusbkwrapper, UkwCancelTransfer, TRUE);
|
|
|
|
DLL_LOAD_FUNC(ceusbkwrapper, UkwIssueControlTransfer, TRUE);
|
|
|
|
DLL_LOAD_FUNC(ceusbkwrapper, UkwClaimInterface, TRUE);
|
|
|
|
DLL_LOAD_FUNC(ceusbkwrapper, UkwReleaseInterface, TRUE);
|
|
|
|
DLL_LOAD_FUNC(ceusbkwrapper, UkwSetInterfaceAlternateSetting, TRUE);
|
|
|
|
DLL_LOAD_FUNC(ceusbkwrapper, UkwClearHaltHost, TRUE);
|
|
|
|
DLL_LOAD_FUNC(ceusbkwrapper, UkwClearHaltDevice, TRUE);
|
|
|
|
DLL_LOAD_FUNC(ceusbkwrapper, UkwGetConfig, TRUE);
|
|
|
|
DLL_LOAD_FUNC(ceusbkwrapper, UkwSetConfig, TRUE);
|
|
|
|
DLL_LOAD_FUNC(ceusbkwrapper, UkwResetDevice, TRUE);
|
|
|
|
DLL_LOAD_FUNC(ceusbkwrapper, UkwKernelDriverActive, TRUE);
|
|
|
|
DLL_LOAD_FUNC(ceusbkwrapper, UkwAttachKernelDriver, TRUE);
|
|
|
|
DLL_LOAD_FUNC(ceusbkwrapper, UkwDetachKernelDriver, TRUE);
|
|
|
|
DLL_LOAD_FUNC(ceusbkwrapper, UkwIssueBulkTransfer, TRUE);
|
|
|
|
DLL_LOAD_FUNC(ceusbkwrapper, UkwIsPipeHalted, TRUE);
|
2013-09-30 18:36:54 +13:00
|
|
|
|
2019-05-01 11:47:48 +02:00
|
|
|
return TRUE;
|
2013-09-30 18:36:54 +13:00
|
|
|
}
|
|
|
|
|
2016-11-20 14:07:07 +01:00
|
|
|
static void exit_dllimports(void)
|
|
|
|
{
|
|
|
|
DLL_FREE_HANDLE(ceusbkwrapper);
|
|
|
|
}
|
|
|
|
|
2016-08-25 18:27:40 -07:00
|
|
|
static int init_device(
|
|
|
|
struct libusb_device *dev, UKW_DEVICE drv_dev,
|
|
|
|
unsigned char bus_addr, unsigned char dev_addr)
|
2013-09-30 18:36:54 +13:00
|
|
|
{
|
|
|
|
struct wince_device_priv *priv = _device_priv(dev);
|
|
|
|
int r = LIBUSB_SUCCESS;
|
|
|
|
|
|
|
|
dev->bus_number = bus_addr;
|
|
|
|
dev->device_address = dev_addr;
|
|
|
|
priv->dev = drv_dev;
|
|
|
|
|
2016-11-20 14:07:07 +01:00
|
|
|
if (!UkwGetDeviceDescriptor(priv->dev, &(priv->desc)))
|
2013-09-30 18:36:54 +13:00
|
|
|
r = translate_driver_error(GetLastError());
|
2016-11-20 14:07:07 +01:00
|
|
|
|
2013-09-30 18:36:54 +13:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Internal API functions
|
|
|
|
static int wince_init(struct libusb_context *ctx)
|
|
|
|
{
|
2016-08-25 18:27:40 -07:00
|
|
|
int r = LIBUSB_ERROR_OTHER;
|
2013-09-30 18:36:54 +13:00
|
|
|
HANDLE semaphore;
|
2016-08-25 18:27:40 -07:00
|
|
|
LARGE_INTEGER li_frequency;
|
2016-11-20 14:07:07 +01:00
|
|
|
TCHAR sem_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0'
|
2013-09-30 18:36:54 +13:00
|
|
|
|
2016-11-20 14:07:07 +01:00
|
|
|
_stprintf(sem_name, _T("libusb_init%08X"), (unsigned int)(GetCurrentProcessId() & 0xFFFFFFFF));
|
2013-09-30 18:36:54 +13:00
|
|
|
semaphore = CreateSemaphore(NULL, 1, 1, sem_name);
|
|
|
|
if (semaphore == NULL) {
|
|
|
|
usbi_err(ctx, "could not create semaphore: %s", windows_error_str(0));
|
|
|
|
return LIBUSB_ERROR_NO_MEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
// A successful wait brings our semaphore count to 0 (unsignaled)
|
|
|
|
// => any concurent wait stalls until the semaphore's release
|
|
|
|
if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) {
|
|
|
|
usbi_err(ctx, "failure to access semaphore: %s", windows_error_str(0));
|
|
|
|
CloseHandle(semaphore);
|
|
|
|
return LIBUSB_ERROR_NO_MEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
// NB: concurrent usage supposes that init calls are equally balanced with
|
|
|
|
// exit calls. If init is called more than exit, we will not exit properly
|
|
|
|
if ( ++concurrent_usage == 0 ) { // First init?
|
|
|
|
// Load DLL imports
|
2019-05-01 11:47:48 +02:00
|
|
|
if (!init_dllimports()) {
|
2013-09-30 18:36:54 +13:00
|
|
|
usbi_err(ctx, "could not resolve DLL functions");
|
|
|
|
r = LIBUSB_ERROR_NOT_SUPPORTED;
|
|
|
|
goto init_exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
// try to open a handle to the driver
|
|
|
|
driver_handle = UkwOpenDriver();
|
|
|
|
if (driver_handle == INVALID_HANDLE_VALUE) {
|
|
|
|
usbi_err(ctx, "could not connect to driver");
|
|
|
|
r = LIBUSB_ERROR_NOT_SUPPORTED;
|
|
|
|
goto init_exit;
|
|
|
|
}
|
|
|
|
|
2016-08-25 18:27:40 -07:00
|
|
|
// find out if we have access to a monotonic (hires) timer
|
|
|
|
if (QueryPerformanceFrequency(&li_frequency)) {
|
|
|
|
hires_frequency = li_frequency.QuadPart;
|
|
|
|
// The hires frequency can go as high as 4 GHz, so we'll use a conversion
|
|
|
|
// to picoseconds to compute the tv_nsecs part in clock_gettime
|
|
|
|
hires_ticks_to_ps = UINT64_C(1000000000000) / hires_frequency;
|
|
|
|
usbi_dbg("hires timer available (Frequency: %"PRIu64" Hz)", hires_frequency);
|
|
|
|
} else {
|
|
|
|
usbi_dbg("no hires timer available on this platform");
|
|
|
|
hires_frequency = 0;
|
|
|
|
hires_ticks_to_ps = UINT64_C(0);
|
2014-12-27 15:39:17 +01:00
|
|
|
}
|
2013-09-30 18:36:54 +13:00
|
|
|
}
|
|
|
|
// At this stage, either we went through full init successfully, or didn't need to
|
|
|
|
r = LIBUSB_SUCCESS;
|
|
|
|
|
|
|
|
init_exit: // Holds semaphore here.
|
|
|
|
if (!concurrent_usage && r != LIBUSB_SUCCESS) { // First init failed?
|
2016-11-20 14:07:07 +01:00
|
|
|
exit_dllimports();
|
|
|
|
|
2013-09-30 18:36:54 +13:00
|
|
|
if (driver_handle != INVALID_HANDLE_VALUE) {
|
|
|
|
UkwCloseDriver(driver_handle);
|
|
|
|
driver_handle = INVALID_HANDLE_VALUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (r != LIBUSB_SUCCESS)
|
|
|
|
--concurrent_usage; // Not expected to call libusb_exit if we failed.
|
|
|
|
|
|
|
|
ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1
|
|
|
|
CloseHandle(semaphore);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2019-05-01 11:47:48 +02:00
|
|
|
static void wince_exit(struct libusb_context *ctx)
|
2013-09-30 18:36:54 +13:00
|
|
|
{
|
|
|
|
HANDLE semaphore;
|
2016-11-20 14:07:07 +01:00
|
|
|
TCHAR sem_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0'
|
2019-05-01 11:47:48 +02:00
|
|
|
UNUSED(ctx);
|
2013-09-30 18:36:54 +13:00
|
|
|
|
2016-11-20 14:07:07 +01:00
|
|
|
_stprintf(sem_name, _T("libusb_init%08X"), (unsigned int)(GetCurrentProcessId() & 0xFFFFFFFF));
|
2013-09-30 18:36:54 +13:00
|
|
|
semaphore = CreateSemaphore(NULL, 1, 1, sem_name);
|
2016-11-20 14:07:07 +01:00
|
|
|
if (semaphore == NULL)
|
2013-09-30 18:36:54 +13:00
|
|
|
return;
|
|
|
|
|
|
|
|
// A successful wait brings our semaphore count to 0 (unsignaled)
|
|
|
|
// => any concurent wait stalls until the semaphore release
|
|
|
|
if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) {
|
|
|
|
CloseHandle(semaphore);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only works if exits and inits are balanced exactly
|
|
|
|
if (--concurrent_usage < 0) { // Last exit
|
2016-11-20 14:07:07 +01:00
|
|
|
exit_dllimports();
|
2013-09-30 18:36:54 +13:00
|
|
|
|
|
|
|
if (driver_handle != INVALID_HANDLE_VALUE) {
|
|
|
|
UkwCloseDriver(driver_handle);
|
|
|
|
driver_handle = INVALID_HANDLE_VALUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1
|
|
|
|
CloseHandle(semaphore);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int wince_get_device_list(
|
|
|
|
struct libusb_context *ctx,
|
|
|
|
struct discovered_devs **discdevs)
|
|
|
|
{
|
|
|
|
UKW_DEVICE devices[MAX_DEVICE_COUNT];
|
2016-11-20 14:07:07 +01:00
|
|
|
struct discovered_devs *new_devices = *discdevs;
|
2013-09-30 18:36:54 +13:00
|
|
|
DWORD count = 0, i;
|
|
|
|
struct libusb_device *dev = NULL;
|
|
|
|
unsigned char bus_addr, dev_addr;
|
|
|
|
unsigned long session_id;
|
|
|
|
BOOL success;
|
|
|
|
DWORD release_list_offset = 0;
|
|
|
|
int r = LIBUSB_SUCCESS;
|
|
|
|
|
|
|
|
success = UkwGetDeviceList(driver_handle, devices, MAX_DEVICE_COUNT, &count);
|
|
|
|
if (!success) {
|
|
|
|
int libusbErr = translate_driver_error(GetLastError());
|
|
|
|
usbi_err(ctx, "could not get devices: %s", windows_error_str(0));
|
|
|
|
return libusbErr;
|
|
|
|
}
|
2016-11-20 14:07:07 +01:00
|
|
|
|
|
|
|
for (i = 0; i < count; ++i) {
|
2013-09-30 18:36:54 +13:00
|
|
|
release_list_offset = i;
|
|
|
|
success = UkwGetDeviceAddress(devices[i], &bus_addr, &dev_addr, &session_id);
|
|
|
|
if (!success) {
|
|
|
|
r = translate_driver_error(GetLastError());
|
2016-11-20 14:07:07 +01:00
|
|
|
usbi_err(ctx, "could not get device address for %u: %s", (unsigned int)i, windows_error_str(0));
|
2013-09-30 18:36:54 +13:00
|
|
|
goto err_out;
|
|
|
|
}
|
2016-11-20 14:07:07 +01:00
|
|
|
|
2013-09-30 18:36:54 +13:00
|
|
|
dev = usbi_get_device_by_session_id(ctx, session_id);
|
|
|
|
if (dev) {
|
2016-11-20 14:07:07 +01:00
|
|
|
usbi_dbg("using existing device for %u/%u (session %lu)",
|
2013-09-30 18:36:54 +13:00
|
|
|
bus_addr, dev_addr, session_id);
|
2016-08-25 18:27:40 -07:00
|
|
|
// Release just this element in the device list (as we already hold a
|
2013-09-30 18:36:54 +13:00
|
|
|
// reference to it).
|
|
|
|
UkwReleaseDeviceList(driver_handle, &devices[i], 1);
|
|
|
|
release_list_offset++;
|
|
|
|
} else {
|
2016-11-20 14:07:07 +01:00
|
|
|
usbi_dbg("allocating new device for %u/%u (session %lu)",
|
2013-09-30 18:36:54 +13:00
|
|
|
bus_addr, dev_addr, session_id);
|
|
|
|
dev = usbi_alloc_device(ctx, session_id);
|
|
|
|
if (!dev) {
|
|
|
|
r = LIBUSB_ERROR_NO_MEM;
|
|
|
|
goto err_out;
|
|
|
|
}
|
2016-11-20 14:07:07 +01:00
|
|
|
|
2013-09-30 18:36:54 +13:00
|
|
|
r = init_device(dev, devices[i], bus_addr, dev_addr);
|
|
|
|
if (r < 0)
|
|
|
|
goto err_out;
|
2016-11-20 14:07:07 +01:00
|
|
|
|
2013-09-30 18:36:54 +13:00
|
|
|
r = usbi_sanitize_device(dev);
|
|
|
|
if (r < 0)
|
|
|
|
goto err_out;
|
|
|
|
}
|
2016-11-20 14:07:07 +01:00
|
|
|
|
2013-09-30 18:36:54 +13:00
|
|
|
new_devices = discovered_devs_append(new_devices, dev);
|
2019-05-01 11:47:48 +02:00
|
|
|
if (!new_devices) {
|
2013-09-30 18:36:54 +13:00
|
|
|
r = LIBUSB_ERROR_NO_MEM;
|
|
|
|
goto err_out;
|
|
|
|
}
|
2016-11-20 14:07:07 +01:00
|
|
|
|
2019-05-01 11:47:48 +02:00
|
|
|
libusb_unref_device(dev);
|
2013-09-30 18:36:54 +13:00
|
|
|
}
|
2016-11-20 14:07:07 +01:00
|
|
|
|
2013-09-30 18:36:54 +13:00
|
|
|
*discdevs = new_devices;
|
|
|
|
return r;
|
|
|
|
err_out:
|
|
|
|
*discdevs = new_devices;
|
2019-05-01 11:47:48 +02:00
|
|
|
libusb_unref_device(dev);
|
2013-09-30 18:36:54 +13:00
|
|
|
// Release the remainder of the unprocessed device list.
|
2016-08-25 18:27:40 -07:00
|
|
|
// The devices added to new_devices already will still be passed up to libusb,
|
2013-09-30 18:36:54 +13:00
|
|
|
// which can dispose of them at its leisure.
|
|
|
|
UkwReleaseDeviceList(driver_handle, &devices[release_list_offset], count - release_list_offset);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int wince_open(struct libusb_device_handle *handle)
|
|
|
|
{
|
|
|
|
// Nothing to do to open devices as a handle to it has
|
|
|
|
// been retrieved by wince_get_device_list
|
|
|
|
return LIBUSB_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void wince_close(struct libusb_device_handle *handle)
|
|
|
|
{
|
|
|
|
// Nothing to do as wince_open does nothing.
|
|
|
|
}
|
|
|
|
|
|
|
|
static int wince_get_device_descriptor(
|
2016-08-25 18:27:40 -07:00
|
|
|
struct libusb_device *device,
|
|
|
|
unsigned char *buffer, int *host_endian)
|
2013-09-30 18:36:54 +13:00
|
|
|
{
|
|
|
|
struct wince_device_priv *priv = _device_priv(device);
|
|
|
|
|
|
|
|
*host_endian = 1;
|
|
|
|
memcpy(buffer, &priv->desc, DEVICE_DESC_LENGTH);
|
|
|
|
return LIBUSB_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int wince_get_active_config_descriptor(
|
|
|
|
struct libusb_device *device,
|
|
|
|
unsigned char *buffer, size_t len, int *host_endian)
|
|
|
|
{
|
|
|
|
struct wince_device_priv *priv = _device_priv(device);
|
|
|
|
DWORD actualSize = len;
|
2016-11-20 14:07:07 +01:00
|
|
|
|
2013-09-30 18:36:54 +13:00
|
|
|
*host_endian = 0;
|
2016-11-20 14:07:07 +01:00
|
|
|
if (!UkwGetConfigDescriptor(priv->dev, UKW_ACTIVE_CONFIGURATION, buffer, len, &actualSize))
|
2013-09-30 18:36:54 +13:00
|
|
|
return translate_driver_error(GetLastError());
|
2016-11-20 14:07:07 +01:00
|
|
|
|
2013-09-30 18:36:54 +13:00
|
|
|
return actualSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int wince_get_config_descriptor(
|
|
|
|
struct libusb_device *device,
|
|
|
|
uint8_t config_index,
|
|
|
|
unsigned char *buffer, size_t len, int *host_endian)
|
|
|
|
{
|
|
|
|
struct wince_device_priv *priv = _device_priv(device);
|
|
|
|
DWORD actualSize = len;
|
2016-11-20 14:07:07 +01:00
|
|
|
|
2013-09-30 18:36:54 +13:00
|
|
|
*host_endian = 0;
|
2016-11-20 14:07:07 +01:00
|
|
|
if (!UkwGetConfigDescriptor(priv->dev, config_index, buffer, len, &actualSize))
|
2013-09-30 18:36:54 +13:00
|
|
|
return translate_driver_error(GetLastError());
|
2016-11-20 14:07:07 +01:00
|
|
|
|
2013-09-30 18:36:54 +13:00
|
|
|
return actualSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int wince_get_configuration(
|
2016-08-25 18:27:40 -07:00
|
|
|
struct libusb_device_handle *handle,
|
|
|
|
int *config)
|
2013-09-30 18:36:54 +13:00
|
|
|
{
|
|
|
|
struct wince_device_priv *priv = _device_priv(handle->dev);
|
|
|
|
UCHAR cv = 0;
|
2016-11-20 14:07:07 +01:00
|
|
|
|
|
|
|
if (!UkwGetConfig(priv->dev, &cv))
|
2013-09-30 18:36:54 +13:00
|
|
|
return translate_driver_error(GetLastError());
|
2016-11-20 14:07:07 +01:00
|
|
|
|
2013-09-30 18:36:54 +13:00
|
|
|
(*config) = cv;
|
|
|
|
return LIBUSB_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int wince_set_configuration(
|
|
|
|
struct libusb_device_handle *handle,
|
|
|
|
int config)
|
|
|
|
{
|
|
|
|
struct wince_device_priv *priv = _device_priv(handle->dev);
|
|
|
|
// Setting configuration 0 places the device in Address state.
|
|
|
|
// This should correspond to the "unconfigured state" required by
|
|
|
|
// libusb when the specified configuration is -1.
|
|
|
|
UCHAR cv = (config < 0) ? 0 : config;
|
2016-11-20 14:07:07 +01:00
|
|
|
if (!UkwSetConfig(priv->dev, cv))
|
2013-09-30 18:36:54 +13:00
|
|
|
return translate_driver_error(GetLastError());
|
2016-11-20 14:07:07 +01:00
|
|
|
|
2013-09-30 18:36:54 +13:00
|
|
|
return LIBUSB_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int wince_claim_interface(
|
|
|
|
struct libusb_device_handle *handle,
|
|
|
|
int interface_number)
|
|
|
|
{
|
|
|
|
struct wince_device_priv *priv = _device_priv(handle->dev);
|
2016-11-20 14:07:07 +01:00
|
|
|
|
|
|
|
if (!UkwClaimInterface(priv->dev, interface_number))
|
2013-09-30 18:36:54 +13:00
|
|
|
return translate_driver_error(GetLastError());
|
2016-11-20 14:07:07 +01:00
|
|
|
|
2013-09-30 18:36:54 +13:00
|
|
|
return LIBUSB_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int wince_release_interface(
|
|
|
|
struct libusb_device_handle *handle,
|
|
|
|
int interface_number)
|
|
|
|
{
|
|
|
|
struct wince_device_priv *priv = _device_priv(handle->dev);
|
2016-11-20 14:07:07 +01:00
|
|
|
|
|
|
|
if (!UkwSetInterfaceAlternateSetting(priv->dev, interface_number, 0))
|
2013-09-30 18:36:54 +13:00
|
|
|
return translate_driver_error(GetLastError());
|
2016-11-20 14:07:07 +01:00
|
|
|
|
|
|
|
if (!UkwReleaseInterface(priv->dev, interface_number))
|
2013-09-30 18:36:54 +13:00
|
|
|
return translate_driver_error(GetLastError());
|
2016-11-20 14:07:07 +01:00
|
|
|
|
2013-09-30 18:36:54 +13:00
|
|
|
return LIBUSB_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int wince_set_interface_altsetting(
|
|
|
|
struct libusb_device_handle *handle,
|
|
|
|
int interface_number, int altsetting)
|
|
|
|
{
|
|
|
|
struct wince_device_priv *priv = _device_priv(handle->dev);
|
2016-11-20 14:07:07 +01:00
|
|
|
|
|
|
|
if (!UkwSetInterfaceAlternateSetting(priv->dev, interface_number, altsetting))
|
2013-09-30 18:36:54 +13:00
|
|
|
return translate_driver_error(GetLastError());
|
2016-11-20 14:07:07 +01:00
|
|
|
|
2013-09-30 18:36:54 +13:00
|
|
|
return LIBUSB_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int wince_clear_halt(
|
|
|
|
struct libusb_device_handle *handle,
|
|
|
|
unsigned char endpoint)
|
|
|
|
{
|
|
|
|
struct wince_device_priv *priv = _device_priv(handle->dev);
|
2016-11-20 14:07:07 +01:00
|
|
|
|
|
|
|
if (!UkwClearHaltHost(priv->dev, endpoint))
|
2013-09-30 18:36:54 +13:00
|
|
|
return translate_driver_error(GetLastError());
|
2016-11-20 14:07:07 +01:00
|
|
|
|
|
|
|
if (!UkwClearHaltDevice(priv->dev, endpoint))
|
2013-09-30 18:36:54 +13:00
|
|
|
return translate_driver_error(GetLastError());
|
2016-11-20 14:07:07 +01:00
|
|
|
|
2013-09-30 18:36:54 +13:00
|
|
|
return LIBUSB_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int wince_reset_device(
|
|
|
|
struct libusb_device_handle *handle)
|
|
|
|
{
|
|
|
|
struct wince_device_priv *priv = _device_priv(handle->dev);
|
2016-11-20 14:07:07 +01:00
|
|
|
|
|
|
|
if (!UkwResetDevice(priv->dev))
|
2013-09-30 18:36:54 +13:00
|
|
|
return translate_driver_error(GetLastError());
|
2016-11-20 14:07:07 +01:00
|
|
|
|
2013-09-30 18:36:54 +13:00
|
|
|
return LIBUSB_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int wince_kernel_driver_active(
|
|
|
|
struct libusb_device_handle *handle,
|
|
|
|
int interface_number)
|
|
|
|
{
|
|
|
|
struct wince_device_priv *priv = _device_priv(handle->dev);
|
|
|
|
BOOL result = FALSE;
|
2016-11-20 14:07:07 +01:00
|
|
|
|
|
|
|
if (!UkwKernelDriverActive(priv->dev, interface_number, &result))
|
2013-09-30 18:36:54 +13:00
|
|
|
return translate_driver_error(GetLastError());
|
2016-11-20 14:07:07 +01:00
|
|
|
|
2013-09-30 18:36:54 +13:00
|
|
|
return result ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int wince_detach_kernel_driver(
|
|
|
|
struct libusb_device_handle *handle,
|
|
|
|
int interface_number)
|
|
|
|
{
|
|
|
|
struct wince_device_priv *priv = _device_priv(handle->dev);
|
2016-11-20 14:07:07 +01:00
|
|
|
|
|
|
|
if (!UkwDetachKernelDriver(priv->dev, interface_number))
|
2013-09-30 18:36:54 +13:00
|
|
|
return translate_driver_error(GetLastError());
|
2016-11-20 14:07:07 +01:00
|
|
|
|
2013-09-30 18:36:54 +13:00
|
|
|
return LIBUSB_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int wince_attach_kernel_driver(
|
|
|
|
struct libusb_device_handle *handle,
|
|
|
|
int interface_number)
|
|
|
|
{
|
|
|
|
struct wince_device_priv *priv = _device_priv(handle->dev);
|
2016-11-20 14:07:07 +01:00
|
|
|
|
|
|
|
if (!UkwAttachKernelDriver(priv->dev, interface_number))
|
2013-09-30 18:36:54 +13:00
|
|
|
return translate_driver_error(GetLastError());
|
2016-11-20 14:07:07 +01:00
|
|
|
|
2013-09-30 18:36:54 +13:00
|
|
|
return LIBUSB_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2016-08-25 18:27:40 -07:00
|
|
|
static void wince_destroy_device(struct libusb_device *dev)
|
2013-09-30 18:36:54 +13:00
|
|
|
{
|
|
|
|
struct wince_device_priv *priv = _device_priv(dev);
|
2016-11-20 14:07:07 +01:00
|
|
|
|
2013-09-30 18:36:54 +13:00
|
|
|
UkwReleaseDeviceList(driver_handle, &priv->dev, 1);
|
|
|
|
}
|
|
|
|
|
2016-08-25 18:27:40 -07:00
|
|
|
static void wince_clear_transfer_priv(struct usbi_transfer *itransfer)
|
2013-09-30 18:36:54 +13:00
|
|
|
{
|
2016-11-20 14:07:07 +01:00
|
|
|
struct wince_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
|
|
|
|
|
2019-05-01 11:47:48 +02:00
|
|
|
usbi_close(transfer_priv->pollable_fd.fd);
|
|
|
|
transfer_priv->pollable_fd = INVALID_WINFD;
|
2013-09-30 18:36:54 +13:00
|
|
|
}
|
|
|
|
|
2016-08-25 18:27:40 -07:00
|
|
|
static int wince_cancel_transfer(struct usbi_transfer *itransfer)
|
2013-09-30 18:36:54 +13:00
|
|
|
{
|
|
|
|
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
|
|
struct wince_device_priv *priv = _device_priv(transfer->dev_handle->dev);
|
2016-11-20 14:07:07 +01:00
|
|
|
struct wince_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
|
2016-08-25 18:27:40 -07:00
|
|
|
|
2016-11-20 14:07:07 +01:00
|
|
|
if (!UkwCancelTransfer(priv->dev, transfer_priv->pollable_fd.overlapped, UKW_TF_NO_WAIT))
|
2013-09-30 18:36:54 +13:00
|
|
|
return translate_driver_error(GetLastError());
|
2016-11-20 14:07:07 +01:00
|
|
|
|
2013-09-30 18:36:54 +13:00
|
|
|
return LIBUSB_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int wince_submit_control_or_bulk_transfer(struct usbi_transfer *itransfer)
|
|
|
|
{
|
|
|
|
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
|
|
struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
|
2016-11-20 14:07:07 +01:00
|
|
|
struct wince_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
|
2013-09-30 18:36:54 +13:00
|
|
|
struct wince_device_priv *priv = _device_priv(transfer->dev_handle->dev);
|
|
|
|
BOOL direction_in, ret;
|
|
|
|
struct winfd wfd;
|
|
|
|
DWORD flags;
|
|
|
|
PUKW_CONTROL_HEADER setup = NULL;
|
|
|
|
const BOOL control_transfer = transfer->type == LIBUSB_TRANSFER_TYPE_CONTROL;
|
2019-05-01 11:47:48 +02:00
|
|
|
int r;
|
2013-09-30 18:36:54 +13:00
|
|
|
|
|
|
|
if (control_transfer) {
|
|
|
|
setup = (PUKW_CONTROL_HEADER) transfer->buffer;
|
|
|
|
direction_in = setup->bmRequestType & LIBUSB_ENDPOINT_IN;
|
|
|
|
} else {
|
|
|
|
direction_in = transfer->endpoint & LIBUSB_ENDPOINT_IN;
|
|
|
|
}
|
|
|
|
flags = direction_in ? UKW_TF_IN_TRANSFER : UKW_TF_OUT_TRANSFER;
|
|
|
|
flags |= UKW_TF_SHORT_TRANSFER_OK;
|
|
|
|
|
2019-05-01 11:47:48 +02:00
|
|
|
wfd = usbi_create_fd();
|
|
|
|
if (wfd.fd < 0)
|
2013-09-30 18:36:54 +13:00
|
|
|
return LIBUSB_ERROR_NO_MEM;
|
|
|
|
|
2019-05-01 11:47:48 +02:00
|
|
|
r = usbi_add_pollfd(ctx, wfd.fd, direction_in ? POLLIN : POLLOUT);
|
|
|
|
if (r) {
|
|
|
|
usbi_close(wfd.fd);
|
|
|
|
return r;
|
2013-09-30 18:36:54 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
transfer_priv->pollable_fd = wfd;
|
2019-05-01 11:47:48 +02:00
|
|
|
|
2013-09-30 18:36:54 +13:00
|
|
|
if (control_transfer) {
|
|
|
|
// Split out control setup header and data buffer
|
|
|
|
DWORD bufLen = transfer->length - sizeof(UKW_CONTROL_HEADER);
|
|
|
|
PVOID buf = (PVOID) &transfer->buffer[sizeof(UKW_CONTROL_HEADER)];
|
|
|
|
|
|
|
|
ret = UkwIssueControlTransfer(priv->dev, flags, setup, buf, bufLen, &transfer->actual_length, wfd.overlapped);
|
|
|
|
} else {
|
2016-08-25 18:27:40 -07:00
|
|
|
ret = UkwIssueBulkTransfer(priv->dev, flags, transfer->endpoint, transfer->buffer,
|
2013-09-30 18:36:54 +13:00
|
|
|
transfer->length, &transfer->actual_length, wfd.overlapped);
|
|
|
|
}
|
2016-11-20 14:07:07 +01:00
|
|
|
|
2013-09-30 18:36:54 +13:00
|
|
|
if (!ret) {
|
|
|
|
int libusbErr = translate_driver_error(GetLastError());
|
2016-11-20 14:07:07 +01:00
|
|
|
usbi_err(ctx, "UkwIssue%sTransfer failed: error %u",
|
|
|
|
control_transfer ? "Control" : "Bulk", (unsigned int)GetLastError());
|
2019-05-01 11:47:48 +02:00
|
|
|
usbi_remove_pollfd(ctx, wfd.fd);
|
|
|
|
usbi_close(wfd.fd);
|
|
|
|
transfer_priv->pollable_fd = INVALID_WINFD;
|
2013-09-30 18:36:54 +13:00
|
|
|
return libusbErr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-05-01 11:47:48 +02:00
|
|
|
return LIBUSB_SUCCESS;
|
2013-09-30 18:36:54 +13:00
|
|
|
}
|
|
|
|
|
2016-08-25 18:27:40 -07:00
|
|
|
static int wince_submit_transfer(struct usbi_transfer *itransfer)
|
2013-09-30 18:36:54 +13:00
|
|
|
{
|
|
|
|
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
|
|
|
|
|
|
switch (transfer->type) {
|
|
|
|
case LIBUSB_TRANSFER_TYPE_CONTROL:
|
|
|
|
case LIBUSB_TRANSFER_TYPE_BULK:
|
|
|
|
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
|
|
|
|
return wince_submit_control_or_bulk_transfer(itransfer);
|
|
|
|
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
|
2014-12-27 15:39:17 +01:00
|
|
|
case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
|
|
|
|
return LIBUSB_ERROR_NOT_SUPPORTED;
|
2013-09-30 18:36:54 +13:00
|
|
|
default:
|
|
|
|
usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
|
|
|
|
return LIBUSB_ERROR_INVALID_PARAM;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-25 18:27:40 -07:00
|
|
|
static void wince_transfer_callback(
|
|
|
|
struct usbi_transfer *itransfer,
|
|
|
|
uint32_t io_result, uint32_t io_size)
|
2013-09-30 18:36:54 +13:00
|
|
|
{
|
|
|
|
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
|
|
struct wince_transfer_priv *transfer_priv = (struct wince_transfer_priv*)usbi_transfer_get_os_priv(itransfer);
|
|
|
|
struct wince_device_priv *priv = _device_priv(transfer->dev_handle->dev);
|
|
|
|
int status;
|
|
|
|
|
2016-11-20 14:07:07 +01:00
|
|
|
usbi_dbg("handling I/O completion with errcode %u", io_result);
|
2013-09-30 18:36:54 +13:00
|
|
|
|
2016-08-25 18:27:40 -07:00
|
|
|
if (io_result == ERROR_NOT_SUPPORTED &&
|
2013-09-30 18:36:54 +13:00
|
|
|
transfer->type != LIBUSB_TRANSFER_TYPE_CONTROL) {
|
2016-08-25 18:27:40 -07:00
|
|
|
/* For functional stalls, the WinCE USB layer (and therefore the USB Kernel Wrapper
|
|
|
|
* Driver) will report USB_ERROR_STALL/ERROR_NOT_SUPPORTED in situations where the
|
2013-09-30 18:36:54 +13:00
|
|
|
* endpoint isn't actually stalled.
|
|
|
|
*
|
|
|
|
* One example of this is that some devices will occasionally fail to reply to an IN
|
|
|
|
* token. The WinCE USB layer carries on with the transaction until it is completed
|
|
|
|
* (or cancelled) but then completes it with USB_ERROR_STALL.
|
|
|
|
*
|
|
|
|
* This code therefore needs to confirm that there really is a stall error, by both
|
|
|
|
* checking the pipe status and requesting the endpoint status from the device.
|
|
|
|
*/
|
|
|
|
BOOL halted = FALSE;
|
|
|
|
usbi_dbg("checking I/O completion with errcode ERROR_NOT_SUPPORTED is really a stall");
|
|
|
|
if (UkwIsPipeHalted(priv->dev, transfer->endpoint, &halted)) {
|
|
|
|
/* Pipe status retrieved, so now request endpoint status by sending a GET_STATUS
|
2016-08-25 18:27:40 -07:00
|
|
|
* control request to the device. This is done synchronously, which is a bit
|
2013-09-30 18:36:54 +13:00
|
|
|
* naughty, but this is a special corner case.
|
|
|
|
*/
|
|
|
|
WORD wStatus = 0;
|
|
|
|
DWORD written = 0;
|
|
|
|
UKW_CONTROL_HEADER ctrlHeader;
|
|
|
|
ctrlHeader.bmRequestType = LIBUSB_REQUEST_TYPE_STANDARD |
|
|
|
|
LIBUSB_ENDPOINT_IN | LIBUSB_RECIPIENT_ENDPOINT;
|
|
|
|
ctrlHeader.bRequest = LIBUSB_REQUEST_GET_STATUS;
|
|
|
|
ctrlHeader.wValue = 0;
|
|
|
|
ctrlHeader.wIndex = transfer->endpoint;
|
|
|
|
ctrlHeader.wLength = sizeof(wStatus);
|
|
|
|
if (UkwIssueControlTransfer(priv->dev,
|
|
|
|
UKW_TF_IN_TRANSFER | UKW_TF_SEND_TO_ENDPOINT,
|
|
|
|
&ctrlHeader, &wStatus, sizeof(wStatus), &written, NULL)) {
|
|
|
|
if (written == sizeof(wStatus) &&
|
|
|
|
(wStatus & STATUS_HALT_FLAG) == 0) {
|
|
|
|
if (!halted || UkwClearHaltHost(priv->dev, transfer->endpoint)) {
|
|
|
|
usbi_dbg("Endpoint doesn't appear to be stalled, overriding error with success");
|
|
|
|
io_result = ERROR_SUCCESS;
|
|
|
|
} else {
|
|
|
|
usbi_dbg("Endpoint doesn't appear to be stalled, but the host is halted, changing error");
|
|
|
|
io_result = ERROR_IO_DEVICE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(io_result) {
|
|
|
|
case ERROR_SUCCESS:
|
|
|
|
itransfer->transferred += io_size;
|
|
|
|
status = LIBUSB_TRANSFER_COMPLETED;
|
|
|
|
break;
|
|
|
|
case ERROR_CANCELLED:
|
|
|
|
usbi_dbg("detected transfer cancel");
|
|
|
|
status = LIBUSB_TRANSFER_CANCELLED;
|
|
|
|
break;
|
|
|
|
case ERROR_NOT_SUPPORTED:
|
|
|
|
case ERROR_GEN_FAILURE:
|
|
|
|
usbi_dbg("detected endpoint stall");
|
|
|
|
status = LIBUSB_TRANSFER_STALL;
|
|
|
|
break;
|
|
|
|
case ERROR_SEM_TIMEOUT:
|
|
|
|
usbi_dbg("detected semaphore timeout");
|
|
|
|
status = LIBUSB_TRANSFER_TIMED_OUT;
|
|
|
|
break;
|
|
|
|
case ERROR_OPERATION_ABORTED:
|
2016-11-20 14:07:07 +01:00
|
|
|
usbi_dbg("detected operation aborted");
|
|
|
|
status = LIBUSB_TRANSFER_CANCELLED;
|
2013-09-30 18:36:54 +13:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
usbi_err(ITRANSFER_CTX(itransfer), "detected I/O error: %s", windows_error_str(io_result));
|
|
|
|
status = LIBUSB_TRANSFER_ERROR;
|
|
|
|
break;
|
|
|
|
}
|
2016-11-20 14:07:07 +01:00
|
|
|
|
2013-09-30 18:36:54 +13:00
|
|
|
wince_clear_transfer_priv(itransfer);
|
2016-11-20 14:07:07 +01:00
|
|
|
if (status == LIBUSB_TRANSFER_CANCELLED)
|
2013-09-30 18:36:54 +13:00
|
|
|
usbi_handle_transfer_cancellation(itransfer);
|
2016-11-20 14:07:07 +01:00
|
|
|
else
|
2013-09-30 18:36:54 +13:00
|
|
|
usbi_handle_transfer_completion(itransfer, (enum libusb_transfer_status)status);
|
|
|
|
}
|
|
|
|
|
2016-08-25 18:27:40 -07:00
|
|
|
static void wince_handle_callback(
|
|
|
|
struct usbi_transfer *itransfer,
|
|
|
|
uint32_t io_result, uint32_t io_size)
|
2013-09-30 18:36:54 +13:00
|
|
|
{
|
|
|
|
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
|
|
|
|
|
|
switch (transfer->type) {
|
|
|
|
case LIBUSB_TRANSFER_TYPE_CONTROL:
|
|
|
|
case LIBUSB_TRANSFER_TYPE_BULK:
|
|
|
|
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
|
|
|
|
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
|
|
|
|
wince_transfer_callback (itransfer, io_result, io_size);
|
|
|
|
break;
|
2014-12-27 15:39:17 +01:00
|
|
|
case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
|
2016-08-25 18:27:40 -07:00
|
|
|
break;
|
2013-09-30 18:36:54 +13:00
|
|
|
default:
|
|
|
|
usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int wince_handle_events(
|
|
|
|
struct libusb_context *ctx,
|
|
|
|
struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready)
|
|
|
|
{
|
|
|
|
struct wince_transfer_priv* transfer_priv = NULL;
|
|
|
|
POLL_NFDS_TYPE i = 0;
|
|
|
|
BOOL found = FALSE;
|
2019-05-01 11:47:48 +02:00
|
|
|
struct usbi_transfer *itransfer;
|
2013-09-30 18:36:54 +13:00
|
|
|
DWORD io_size, io_result;
|
2016-11-20 14:07:07 +01:00
|
|
|
int r = LIBUSB_SUCCESS;
|
2013-09-30 18:36:54 +13:00
|
|
|
|
|
|
|
usbi_mutex_lock(&ctx->open_devs_lock);
|
|
|
|
for (i = 0; i < nfds && num_ready > 0; i++) {
|
|
|
|
|
|
|
|
usbi_dbg("checking fd %d with revents = %04x", fds[i].fd, fds[i].revents);
|
|
|
|
|
2016-11-20 14:07:07 +01:00
|
|
|
if (!fds[i].revents)
|
2013-09-30 18:36:54 +13:00
|
|
|
continue;
|
|
|
|
|
|
|
|
num_ready--;
|
|
|
|
|
|
|
|
// Because a Windows OVERLAPPED is used for poll emulation,
|
|
|
|
// a pollable fd is created and stored with each transfer
|
|
|
|
usbi_mutex_lock(&ctx->flying_transfers_lock);
|
2019-05-01 11:47:48 +02:00
|
|
|
list_for_each_entry(itransfer, &ctx->flying_transfers, list, struct usbi_transfer) {
|
|
|
|
transfer_priv = usbi_transfer_get_os_priv(itransfer);
|
2013-09-30 18:36:54 +13:00
|
|
|
if (transfer_priv->pollable_fd.fd == fds[i].fd) {
|
|
|
|
found = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
usbi_mutex_unlock(&ctx->flying_transfers_lock);
|
|
|
|
|
|
|
|
if (found && HasOverlappedIoCompleted(transfer_priv->pollable_fd.overlapped)) {
|
|
|
|
io_result = (DWORD)transfer_priv->pollable_fd.overlapped->Internal;
|
|
|
|
io_size = (DWORD)transfer_priv->pollable_fd.overlapped->InternalHigh;
|
|
|
|
usbi_remove_pollfd(ctx, transfer_priv->pollable_fd.fd);
|
|
|
|
// let handle_callback free the event using the transfer wfd
|
|
|
|
// If you don't use the transfer wfd, you run a risk of trying to free a
|
|
|
|
// newly allocated wfd that took the place of the one from the transfer.
|
2019-05-01 11:47:48 +02:00
|
|
|
wince_handle_callback(itransfer, io_result, io_size);
|
2013-09-30 18:36:54 +13:00
|
|
|
} else if (found) {
|
2016-11-20 14:07:07 +01:00
|
|
|
usbi_err(ctx, "matching transfer for fd %d has not completed", fds[i]);
|
|
|
|
r = LIBUSB_ERROR_OTHER;
|
|
|
|
break;
|
2013-09-30 18:36:54 +13:00
|
|
|
} else {
|
2016-11-20 14:07:07 +01:00
|
|
|
usbi_err(ctx, "could not find a matching transfer for fd %d", fds[i]);
|
|
|
|
r = LIBUSB_ERROR_NOT_FOUND;
|
|
|
|
break;
|
2013-09-30 18:36:54 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
usbi_mutex_unlock(&ctx->open_devs_lock);
|
2016-11-20 14:07:07 +01:00
|
|
|
|
|
|
|
return r;
|
2013-09-30 18:36:54 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Monotonic and real time functions
|
|
|
|
*/
|
|
|
|
static int wince_clock_gettime(int clk_id, struct timespec *tp)
|
|
|
|
{
|
2016-08-25 18:27:40 -07:00
|
|
|
LARGE_INTEGER hires_counter;
|
2013-09-30 18:36:54 +13:00
|
|
|
ULARGE_INTEGER rtime;
|
2016-08-25 18:27:40 -07:00
|
|
|
FILETIME filetime;
|
2013-09-30 18:36:54 +13:00
|
|
|
SYSTEMTIME st;
|
2016-11-20 14:07:07 +01:00
|
|
|
|
2013-09-30 18:36:54 +13:00
|
|
|
switch(clk_id) {
|
|
|
|
case USBI_CLOCK_MONOTONIC:
|
2016-08-25 18:27:40 -07:00
|
|
|
if (hires_frequency != 0 && QueryPerformanceCounter(&hires_counter)) {
|
|
|
|
tp->tv_sec = (long)(hires_counter.QuadPart / hires_frequency);
|
|
|
|
tp->tv_nsec = (long)(((hires_counter.QuadPart % hires_frequency) / 1000) * hires_ticks_to_ps);
|
|
|
|
return LIBUSB_SUCCESS;
|
2013-09-30 18:36:54 +13:00
|
|
|
}
|
2016-08-25 18:27:40 -07:00
|
|
|
// Fall through and return real-time if monotonic read failed or was not detected @ init
|
2013-09-30 18:36:54 +13:00
|
|
|
case USBI_CLOCK_REALTIME:
|
|
|
|
// We follow http://msdn.microsoft.com/en-us/library/ms724928%28VS.85%29.aspx
|
2019-05-01 11:47:48 +02:00
|
|
|
// with a predef epoch time to have an epoch that starts at 1970.01.01 00:00
|
2013-09-30 18:36:54 +13:00
|
|
|
// Note however that our resolution is bounded by the Windows system time
|
|
|
|
// functions and is at best of the order of 1 ms (or, usually, worse)
|
|
|
|
GetSystemTime(&st);
|
|
|
|
SystemTimeToFileTime(&st, &filetime);
|
|
|
|
rtime.LowPart = filetime.dwLowDateTime;
|
|
|
|
rtime.HighPart = filetime.dwHighDateTime;
|
2019-05-01 11:47:48 +02:00
|
|
|
rtime.QuadPart -= EPOCH_TIME;
|
2013-09-30 18:36:54 +13:00
|
|
|
tp->tv_sec = (long)(rtime.QuadPart / 10000000);
|
|
|
|
tp->tv_nsec = (long)((rtime.QuadPart % 10000000)*100);
|
|
|
|
return LIBUSB_SUCCESS;
|
|
|
|
default:
|
|
|
|
return LIBUSB_ERROR_INVALID_PARAM;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-01 11:47:48 +02:00
|
|
|
const struct usbi_os_backend usbi_backend = {
|
2016-08-25 18:27:40 -07:00
|
|
|
"Windows CE",
|
|
|
|
0,
|
|
|
|
wince_init,
|
|
|
|
wince_exit,
|
2019-05-01 11:47:48 +02:00
|
|
|
NULL, /* set_option() */
|
2013-09-30 18:36:54 +13:00
|
|
|
|
2016-08-25 18:27:40 -07:00
|
|
|
wince_get_device_list,
|
2013-09-30 18:36:54 +13:00
|
|
|
NULL, /* hotplug_poll */
|
2016-08-25 18:27:40 -07:00
|
|
|
wince_open,
|
|
|
|
wince_close,
|
2013-09-30 18:36:54 +13:00
|
|
|
|
2016-08-25 18:27:40 -07:00
|
|
|
wince_get_device_descriptor,
|
|
|
|
wince_get_active_config_descriptor,
|
|
|
|
wince_get_config_descriptor,
|
2013-09-30 18:36:54 +13:00
|
|
|
NULL, /* get_config_descriptor_by_value() */
|
|
|
|
|
2016-08-25 18:27:40 -07:00
|
|
|
wince_get_configuration,
|
|
|
|
wince_set_configuration,
|
|
|
|
wince_claim_interface,
|
|
|
|
wince_release_interface,
|
2013-09-30 18:36:54 +13:00
|
|
|
|
2016-08-25 18:27:40 -07:00
|
|
|
wince_set_interface_altsetting,
|
|
|
|
wince_clear_halt,
|
|
|
|
wince_reset_device,
|
2013-09-30 18:36:54 +13:00
|
|
|
|
2014-12-27 15:39:17 +01:00
|
|
|
NULL, /* alloc_streams */
|
|
|
|
NULL, /* free_streams */
|
|
|
|
|
2016-11-20 14:07:07 +01:00
|
|
|
NULL, /* dev_mem_alloc() */
|
|
|
|
NULL, /* dev_mem_free() */
|
|
|
|
|
2016-08-25 18:27:40 -07:00
|
|
|
wince_kernel_driver_active,
|
|
|
|
wince_detach_kernel_driver,
|
|
|
|
wince_attach_kernel_driver,
|
2013-09-30 18:36:54 +13:00
|
|
|
|
2016-08-25 18:27:40 -07:00
|
|
|
wince_destroy_device,
|
2013-09-30 18:36:54 +13:00
|
|
|
|
2016-08-25 18:27:40 -07:00
|
|
|
wince_submit_transfer,
|
|
|
|
wince_cancel_transfer,
|
|
|
|
wince_clear_transfer_priv,
|
2013-09-30 18:36:54 +13:00
|
|
|
|
2016-08-25 18:27:40 -07:00
|
|
|
wince_handle_events,
|
|
|
|
NULL, /* handle_transfer_completion() */
|
2013-09-30 18:36:54 +13:00
|
|
|
|
2016-08-25 18:27:40 -07:00
|
|
|
wince_clock_gettime,
|
2019-05-01 11:47:48 +02:00
|
|
|
0,
|
2016-08-25 18:27:40 -07:00
|
|
|
sizeof(struct wince_device_priv),
|
2016-11-20 14:07:07 +01:00
|
|
|
0,
|
2016-08-25 18:27:40 -07:00
|
|
|
sizeof(struct wince_transfer_priv),
|
2013-09-30 18:36:54 +13:00
|
|
|
};
|