Created
April 9, 2015 01:08
-
-
Save Flafla2/d261a156ea2e3e3c1e5c to your computer and use it in GitHub Desktop.
A modified version of hid.c for windows, edited to fix a regression in hid_write on the MS bluetooth stack
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// hid.c, edited to fix a regression in hid_write on the MS bluetooth stack | |
// For brevity irrelevant code has been omitted. | |
// Additions are marked with !!ADDED!! | |
// There are no modifications except for hid_write() | |
// ... | |
#ifndef HIDAPI_USE_DDK | |
/* Since we're not building with the DDK, and the HID header | |
files aren't part of the SDK, we have to define all this | |
stuff here. In lookup_functions(), the function pointers | |
defined below are set. */ | |
typedef struct _HIDD_ATTRIBUTES{ | |
ULONG Size; | |
USHORT VendorID; | |
USHORT ProductID; | |
USHORT VersionNumber; | |
} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES; | |
typedef USHORT USAGE; | |
typedef struct _HIDP_CAPS { | |
USAGE Usage; | |
USAGE UsagePage; | |
USHORT InputReportByteLength; | |
USHORT OutputReportByteLength; | |
USHORT FeatureReportByteLength; | |
USHORT Reserved[17]; | |
USHORT fields_not_used_by_hidapi[10]; | |
} HIDP_CAPS, *PHIDP_CAPS; | |
typedef void* PHIDP_PREPARSED_DATA; | |
#define HIDP_STATUS_SUCCESS 0x110000 | |
typedef BOOLEAN (__stdcall *HidD_GetAttributes_)(HANDLE device, PHIDD_ATTRIBUTES attrib); | |
typedef BOOLEAN (__stdcall *HidD_GetSerialNumberString_)(HANDLE device, PVOID buffer, ULONG buffer_len); | |
typedef BOOLEAN (__stdcall *HidD_GetManufacturerString_)(HANDLE handle, PVOID buffer, ULONG buffer_len); | |
typedef BOOLEAN (__stdcall *HidD_GetProductString_)(HANDLE handle, PVOID buffer, ULONG buffer_len); | |
typedef BOOLEAN (__stdcall *HidD_SetFeature_)(HANDLE handle, PVOID data, ULONG length); | |
typedef BOOLEAN (__stdcall *HidD_GetFeature_)(HANDLE handle, PVOID data, ULONG length); | |
typedef BOOLEAN (__stdcall *HidD_GetIndexedString_)(HANDLE handle, ULONG string_index, PVOID buffer, ULONG buffer_len); | |
typedef BOOLEAN (__stdcall *HidD_GetPreparsedData_)(HANDLE handle, PHIDP_PREPARSED_DATA *preparsed_data); | |
typedef BOOLEAN (__stdcall *HidD_FreePreparsedData_)(PHIDP_PREPARSED_DATA preparsed_data); | |
typedef NTSTATUS (__stdcall *HidP_GetCaps_)(PHIDP_PREPARSED_DATA preparsed_data, HIDP_CAPS *caps); | |
typedef BOOLEAN (__stdcall *HidD_SetNumInputBuffers_)(HANDLE handle, ULONG number_buffers); | |
typedef BOOLEAN(__stdcall *HidD_SetOutputReport_)(HANDLE handle, PVOID ReportBuffer, ULONG length); // !!ADDED!! | |
static HidD_GetAttributes_ HidD_GetAttributes; | |
static HidD_GetSerialNumberString_ HidD_GetSerialNumberString; | |
static HidD_GetManufacturerString_ HidD_GetManufacturerString; | |
static HidD_GetProductString_ HidD_GetProductString; | |
static HidD_SetFeature_ HidD_SetFeature; | |
static HidD_GetFeature_ HidD_GetFeature; | |
static HidD_GetIndexedString_ HidD_GetIndexedString; | |
static HidD_GetPreparsedData_ HidD_GetPreparsedData; | |
static HidD_FreePreparsedData_ HidD_FreePreparsedData; | |
static HidP_GetCaps_ HidP_GetCaps; | |
static HidD_SetNumInputBuffers_ HidD_SetNumInputBuffers; | |
static HidD_SetOutputReport_ HidD_SetOutputReport; // !!ADDED!! | |
static HMODULE lib_handle = NULL; | |
static BOOLEAN initialized = FALSE; | |
#endif /* HIDAPI_USE_DDK */ | |
// ... | |
// hid_read and hid_write behave differently between the MS and BS stacks | |
#define STACK_UNKNOWN 0 // !!ADDED!! | |
#define STACK_BLUESOLEIL 1 // !!ADDED!! | |
#define STACK_MICROSOFT 2 // !!ADDED!! | |
int stack = STACK_UNKNOWN; // !!ADDED!! | |
// ... | |
#ifndef HIDAPI_USE_DDK | |
static int lookup_functions() | |
{ | |
lib_handle = LoadLibraryA("hid.dll"); | |
if (lib_handle) { | |
#define RESOLVE(x) x = (x##_)GetProcAddress(lib_handle, #x); if (!x) return -1; | |
RESOLVE(HidD_GetAttributes); | |
RESOLVE(HidD_GetSerialNumberString); | |
RESOLVE(HidD_GetManufacturerString); | |
RESOLVE(HidD_GetProductString); | |
RESOLVE(HidD_SetFeature); | |
RESOLVE(HidD_GetFeature); | |
RESOLVE(HidD_GetIndexedString); | |
RESOLVE(HidD_GetPreparsedData); | |
RESOLVE(HidD_FreePreparsedData); | |
RESOLVE(HidP_GetCaps); | |
RESOLVE(HidD_SetNumInputBuffers); | |
RESOLVE(HidD_SetOutputReport); // !!ADDED!! | |
#undef RESOLVE | |
} | |
else | |
return -1; | |
return 0; | |
} | |
#endif | |
// ... | |
int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length) // !!HEAVILY EDITED!! | |
{ | |
DWORD bytes_written; | |
BOOL res; | |
OVERLAPPED ol; | |
unsigned char *buf; | |
memset(&ol, 0, sizeof(ol)); | |
switch (stack) { | |
case STACK_UNKNOWN: | |
stack = STACK_MICROSOFT; | |
int iores = hid_write(dev, data, length); | |
if (iores >= 0) | |
return iores; | |
stack = STACK_BLUESOLEIL; | |
iores = hid_write(dev, data, length); | |
if (iores >= 0) | |
return iores; | |
return -1; | |
break; | |
case STACK_BLUESOLEIL: | |
/* Make sure the right number of bytes are passed to WriteFile. Windows | |
expects the number of bytes which are in the _longest_ report (plus | |
one for the report number) bytes even if the data is a report | |
which is shorter than that. Windows gives us this value in | |
caps.OutputReportByteLength. If a user passes in fewer bytes than this, | |
create a temporary buffer which is the proper size. */ | |
if (length >= dev->output_report_length) { | |
/* The user passed the right number of bytes. Use the buffer as-is. */ | |
buf = (unsigned char *)data; | |
} | |
else { | |
/* Create a temporary buffer and copy the user's data | |
into it, padding the rest with zeros. */ | |
buf = (unsigned char *)malloc(dev->output_report_length); | |
memcpy(buf, data, length); | |
memset(buf + length, 0, dev->output_report_length - length); | |
length = dev->output_report_length; | |
} | |
ResetEvent(dev->ol.hEvent); | |
res = WriteFile(dev->device_handle, buf, length, NULL, &ol); | |
if (!res) { | |
if (GetLastError() != ERROR_IO_PENDING) { | |
/* WriteFile() failed. Return error. */ | |
register_error(dev, "WriteFile"); | |
bytes_written = -1; | |
goto end_of_function; | |
} | |
} | |
/* Wait here until the write is done. This makes | |
hid_write() synchronous. */ | |
res = GetOverlappedResult(dev->device_handle, &ol, &bytes_written, TRUE/*wait*/); | |
if (!res) { | |
/* The Write operation failed. */ | |
register_error(dev, "WriteFile"); | |
bytes_written = -1; | |
goto end_of_function; | |
} | |
break; | |
case STACK_MICROSOFT: | |
buf = (unsigned char *)data; | |
res = HidD_SetOutputReport(dev->device_handle, buf, length); | |
return res ? length : -1; | |
break; | |
} | |
end_of_function: | |
if (buf != data) | |
free(buf); | |
return bytes_written; | |
} | |
// ... |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment