Skip to content

Commit

Permalink
Change IOWrite to only use WriteFile
Browse files Browse the repository at this point in the history
See https://msdn.microsoft.com/en-us/library/windows/hardware/ff543402(v=vs.85).aspx. It is recommended to use WriteFile over HidD_SetOutputReport.
Therefore stack distinction is not needed anymore.
Wait for completion was added even if the written bytes are not requested. Otherwise a new Write Request, while another is still pending, may interfere.
  • Loading branch information
jloehr committed Nov 9, 2015
1 parent 2ebdaca commit c244c6f
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 108 deletions.
146 changes: 48 additions & 98 deletions Source/Core/Core/HW/WiimoteReal/IOWin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,10 +207,9 @@ class WiimoteWindows final : public Wiimote
HANDLE m_dev_handle; // HID handle
OVERLAPPED m_hid_overlap_read; // Overlap handles
OVERLAPPED m_hid_overlap_write;
enum win_bt_stack_t m_stack; // Type of Bluetooth stack to use
};

int _IOWrite(HANDLE &dev_handle, OVERLAPPED &hid_overlap_write, enum win_bt_stack_t &stack, const u8* buf, size_t len, DWORD* written);
int _IOWrite(HANDLE &dev_handle, OVERLAPPED &hid_overlap_write, const u8* buf, size_t len, DWORD* written);
int _IORead(HANDLE &dev_handle, OVERLAPPED &hid_overlap_read, u8* buf, int index);

template <typename T>
Expand Down Expand Up @@ -320,13 +319,12 @@ int CheckDeviceType_Write(HANDLE &dev_handle, const u8* buf, size_t size, int at
{
OVERLAPPED hid_overlap_write = OVERLAPPED();
hid_overlap_write.hEvent = CreateEvent(nullptr, true, false, nullptr);
enum win_bt_stack_t stack = MSBT_STACK_UNKNOWN;

DWORD written = 0;

for (; attempts>0; --attempts)
{
if (_IOWrite(dev_handle, hid_overlap_write, stack, buf, size, &written))
if (_IOWrite(dev_handle, hid_overlap_write, buf, size, &written))
break;
}

Expand Down Expand Up @@ -602,7 +600,6 @@ void WiimoteWindows::DisconnectInternal()
WiimoteWindows::WiimoteWindows(const std::basic_string<TCHAR>& path) : m_devicepath(path)
{
m_dev_handle = nullptr;
m_stack = MSBT_STACK_UNKNOWN;

m_hid_overlap_read = OVERLAPPED();
m_hid_overlap_read.hEvent = CreateEvent(nullptr, true, false, nullptr);
Expand Down Expand Up @@ -637,15 +634,15 @@ int _IORead(HANDLE &dev_handle, OVERLAPPED &hid_overlap_read, u8* buf, int index
ResetEvent(hid_overlap_read.hEvent);
if (!ReadFile(dev_handle, buf + 1, MAX_PAYLOAD - 1, &bytes, &hid_overlap_read))
{
auto const read_err = GetLastError();
DWORD const read_err = GetLastError();

if (ERROR_IO_PENDING == read_err)
{
if (!GetOverlappedResult(dev_handle, &hid_overlap_read, &bytes, TRUE))
{
auto const overlapped_err = GetLastError();
DWORD const overlapped_err = GetLastError();

//In case it was aborted by someone else
// In case it was aborted by someone else
if (ERROR_OPERATION_ABORTED == overlapped_err)
{
return -1;
Expand All @@ -654,10 +651,10 @@ int _IORead(HANDLE &dev_handle, OVERLAPPED &hid_overlap_read, u8* buf, int index
WARN_LOG(WIIMOTE, "GetOverlappedResult error %d on Wiimote %i.", overlapped_err, index + 1);
return 0;
}
//If IOWakeup sets the event so GetOverlappedResult returns prematurely, but the request is still pending
// If IOWakeup sets the event so GetOverlappedResult returns prematurely, but the request is still pending
else if (hid_overlap_read.Internal == STATUS_PENDING)
{
//Don't forget to cancel it.
// Don't forget to cancel it.
CancelIo(dev_handle);
return -1;
}
Expand Down Expand Up @@ -687,110 +684,63 @@ int WiimoteWindows::IORead(u8* buf)
}


int _IOWrite(HANDLE &dev_handle, OVERLAPPED &hid_overlap_write, enum win_bt_stack_t &stack, const u8* buf, size_t len, DWORD* written)
int _IOWrite(HANDLE &dev_handle, OVERLAPPED &hid_overlap_write, const u8* buf, size_t len, DWORD* written)
{
switch (stack)
if (len <= 1)
{
case MSBT_STACK_UNKNOWN:
{
// Try to auto-detect the stack type
stack = MSBT_STACK_BLUESOLEIL;
if (_IOWrite(dev_handle, hid_overlap_write, stack, buf, len, written))
return 1;

stack = MSBT_STACK_MS;
if (_IOWrite(dev_handle, hid_overlap_write, stack, buf, len, written))
return 1;

stack = MSBT_STACK_UNKNOWN;
break;
}
case MSBT_STACK_MS:
{
auto result = pHidD_SetOutputReport(dev_handle, const_cast<u8*>(buf) + 1, (ULONG)(len - 1));
//FlushFileBuffers(dev_handle);
WARN_LOG(WIIMOTE, "Tried to send less than 1 Byte to Wiimote");
return 0;
}

if (!result)
{
auto err = GetLastError();
if (err == 121)
{
// Semaphore timeout
NOTICE_LOG(WIIMOTE, "WiimoteIOWrite[MSBT_STACK_MS]: Unable to send data to the Wiimote");
}
else if (err != 0x1F) // Some third-party adapters (DolphinBar) use this
// error code to signal the absence of a Wiimote
// linked to the HID device.
{
WARN_LOG(WIIMOTE, "IOWrite[MSBT_STACK_MS]: ERROR: %08x", err);
}
}
DWORD bytes_written = 0;

if (written)
*written = (result ? (DWORD)len : 0);
ResetEvent(hid_overlap_write.hEvent);
BOOL result = WriteFile(dev_handle, buf + 1, (DWORD)(len - 1), &bytes_written, &hid_overlap_write);

return result;
}
case MSBT_STACK_BLUESOLEIL:
if (!result)
{
DWORD const err = GetLastError();
if (err != ERROR_IO_PENDING)
{
u8 big_buf[MAX_PAYLOAD];
if (len < MAX_PAYLOAD)
{
std::copy(buf, buf + len, big_buf);
std::fill(big_buf + len, big_buf + MAX_PAYLOAD, 0);
buf = big_buf;
}

ResetEvent(hid_overlap_write.hEvent);
DWORD bytes = 0;
auto result = WriteFile(dev_handle, buf + 1, (DWORD)len - 1, &bytes, &hid_overlap_write);

if (!result)
{
auto const err = GetLastError();
if (ERROR_IO_PENDING != err)
{
CancelIo(dev_handle);
return 0;
}
}
WARN_LOG(WIIMOTE, "_IOWrite: Error on WriteFile: %08x", err);
CancelIo(dev_handle);
return 0;
}
}

if (written)
{
*written = 0;
}
if (written)
{
*written = 0;
}

//Wait for completion
auto const wait_result = WaitForSingleObject(hid_overlap_write.hEvent, WIIMOTE_DEFAULT_TIMEOUT);
if (WAIT_TIMEOUT == wait_result)
{
WARN_LOG(WIIMOTE, "_IOWrite: A timeout occurred on writing to Wiimote.");
CancelIo(dev_handle);
return 1;
}
else if (WAIT_FAILED == wait_result)
{
WARN_LOG(WIIMOTE, "_IOWrite: A wait error occurred on writing to Wiimote.");
CancelIo(dev_handle);
return 1;
}
// Wait for completion
DWORD wait_result = WaitForSingleObject(hid_overlap_write.hEvent, WIIMOTE_DEFAULT_TIMEOUT);

if (written)
{
if (!GetOverlappedResult(dev_handle, &hid_overlap_write, written, TRUE))
*written = 0;
}
if (WAIT_TIMEOUT == wait_result)
{
WARN_LOG(WIIMOTE, "_IOWrite: A timeout occurred on writing to Wiimote.");
CancelIo(dev_handle);
return 1;
}
else if (WAIT_FAILED == wait_result)
{
WARN_LOG(WIIMOTE, "_IOWrite: A wait error occurred on writing to Wiimote.");
CancelIo(dev_handle);
return 1;
}

return 1;
}
if (written)
{
if (!GetOverlappedResult(dev_handle, &hid_overlap_write, written, TRUE))
*written = 0;
}

return 0;
return 1;
}

int WiimoteWindows::IOWrite(const u8* buf, size_t len)
{
return _IOWrite(m_dev_handle, m_hid_overlap_write, m_stack, buf, len, nullptr);
return _IOWrite(m_dev_handle, m_hid_overlap_write, buf, len, nullptr);
}

// invokes callback for each found Wiimote Bluetooth device
Expand Down
10 changes: 0 additions & 10 deletions Source/Core/Core/HW/WiimoteReal/WiimoteRealBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,3 @@
// It's 23. NOT 32!
#define MAX_PAYLOAD 23
#define WIIMOTE_DEFAULT_TIMEOUT 1000

#ifdef _WIN32
// Available bluetooth stacks for Windows.
enum win_bt_stack_t
{
MSBT_STACK_UNKNOWN,
MSBT_STACK_MS,
MSBT_STACK_BLUESOLEIL
};
#endif

0 comments on commit c244c6f

Please sign in to comment.