Skip to content

Instantly share code, notes, and snippets.

@Flafla2
Created April 9, 2015 01:08
Show Gist options
  • Save Flafla2/d261a156ea2e3e3c1e5c to your computer and use it in GitHub Desktop.
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
// 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